/*
 * (C) Copyright 2013 ECMWF.
 *
 * This software is licensed under the terms of the Apache Licence Version 2.0
 * which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
 * In applying this licence, ECMWF does not waive the privileges and immunities
 * granted to it by virtue of its status as an intergovernmental organisation
 * nor does it submit to any jurisdiction.
 */

#include "eckit/io/ResizableBuffer.h"
#include "eckit/serialisation/ResizableMemoryStream.h"

#include "atlas/mesh/Connectivity.h"
#include "tests/AtlasTestEnvironment.h"

using namespace atlas::mesh;

namespace atlas {
namespace test {

//-----------------------------------------------------------------------------

CASE( "test_stream_irregular_connectivity" ) {
    eckit::ResizableBuffer b{0};
    eckit::ResizableMemoryStream s{b};

    // Create stream
    {
        IrregularConnectivity conn( "bla" );

        constexpr idx_t vals[4] = {2, 3, 5, 6};
        conn.add( 1, 4, vals, /* fortran-array = */ false );

        constexpr idx_t vals2[6] = {1, 3, 4, 3, 7, 8};
        conn.add( 2, 3, vals2, /* fortran-array = */ false );
        s << conn;
    }


    s.rewind();
    // Read from stream
    {
        IrregularConnectivity conn( s );
        EXPECT( conn.rows() == 3 );
        EXPECT( conn.cols( 0 ) == 4 );
        EXPECT( conn.cols( 1 ) == 3 );
        EXPECT( conn.cols( 2 ) == 3 );
        EXPECT( conn( 0, 0 ) == 2 );
        EXPECT( conn( 0, 1 ) == 3 );
        EXPECT( conn( 0, 2 ) == 5 );
        EXPECT( conn( 0, 3 ) == 6 );
        EXPECT( conn( 1, 0 ) == 1 );
        EXPECT( conn( 1, 1 ) == 3 );
        EXPECT( conn( 1, 2 ) == 4 );
        EXPECT( conn( 2, 0 ) == 3 );
        EXPECT( conn( 2, 1 ) == 7 );
        EXPECT( conn( 2, 2 ) == 8 );
        EXPECT( conn.name() == "bla" );
    }


    s.rewind();
    // Read from stream
    {
        IrregularConnectivity conn;
        s >> conn;
        EXPECT( conn.rows() == 3 );
        EXPECT( conn.cols( 0 ) == 4 );
        EXPECT( conn.cols( 1 ) == 3 );
        EXPECT( conn.cols( 2 ) == 3 );
        EXPECT( conn( 0, 0 ) == 2 );
        EXPECT( conn( 0, 1 ) == 3 );
        EXPECT( conn( 0, 2 ) == 5 );
        EXPECT( conn( 0, 3 ) == 6 );
        EXPECT( conn( 1, 0 ) == 1 );
        EXPECT( conn( 1, 1 ) == 3 );
        EXPECT( conn( 1, 2 ) == 4 );
        EXPECT( conn( 2, 0 ) == 3 );
        EXPECT( conn( 2, 1 ) == 7 );
        EXPECT( conn( 2, 2 ) == 8 );
        EXPECT( conn.name() == "bla" );
    }
}

//-----------------------------------------------------------------------------

CASE( "test_stream_block_connectivity" ) {
    eckit::ResizableBuffer b{0};
    eckit::ResizableMemoryStream s{b};

    // Create stream
    {
        BlockConnectivity conn( 2, 3, {1, 3, 4, 3, 7, 8} );
        s << conn;
    }


    s.rewind();
    // Read from stream
    {
        BlockConnectivity conn( s );
        EXPECT( conn.rows() == 2 );
        EXPECT( conn.cols() == 3 );
        EXPECT( conn( 0, 0 ) == 1 );
        EXPECT( conn( 0, 1 ) == 3 );
        EXPECT( conn( 0, 2 ) == 4 );
        EXPECT( conn( 1, 0 ) == 3 );
        EXPECT( conn( 1, 1 ) == 7 );
        EXPECT( conn( 1, 2 ) == 8 );
    }


    s.rewind();
    // Read from stream
    {
        BlockConnectivity conn;
        s >> conn;
        EXPECT( conn.rows() == 2 );
        EXPECT( conn.cols() == 3 );
        EXPECT( conn( 0, 0 ) == 1 );
        EXPECT( conn( 0, 1 ) == 3 );
        EXPECT( conn( 0, 2 ) == 4 );
        EXPECT( conn( 1, 0 ) == 3 );
        EXPECT( conn( 1, 1 ) == 7 );
        EXPECT( conn( 1, 2 ) == 8 );
    }
}

CASE( "test_stream_multiblock_connectivity" ) {
    eckit::ResizableBuffer b{0};
    eckit::ResizableMemoryStream s{b};

    // Create stream
    {
        MultiBlockConnectivity conn( "mbc" );
        conn.add( BlockConnectivity{3, 5, {3, 7, 1, 4, 5, 6, 4, 56, 8, 4, 1, 3, 76, 4, 3}} );
        conn.add( BlockConnectivity{3, 2, {4, 75, 65, 45, 51, 35}} );
        s << conn;
    }

    s.rewind();
    // Read from stream
    {
        MultiBlockConnectivity conn{s};
        EXPECT( conn.name() == "mbc" );
        EXPECT( conn.blocks() == 2 );
        EXPECT( conn( 3, 1 ) == 75 );
        EXPECT( conn( 4, 1 ) == 45 );
        EXPECT( conn( 5, 0 ) == 51 );
        EXPECT( conn( 1, 0, 1 ) == 75 );
        EXPECT( conn( 1, 1, 1 ) == 45 );
        EXPECT( conn( 1, 2, 0 ) == 51 );
    }

    s.rewind();
    // Read from stream
    {
        MultiBlockConnectivity conn;
        s >> conn;
        EXPECT( conn.name() == "mbc" );
        EXPECT( conn.blocks() == 2 );
        EXPECT( conn( 3, 1 ) == 75 );
        EXPECT( conn( 4, 1 ) == 45 );
        EXPECT( conn( 5, 0 ) == 51 );
        EXPECT( conn( 1, 0, 1 ) == 75 );
        EXPECT( conn( 1, 1, 1 ) == 45 );
        EXPECT( conn( 1, 2, 0 ) == 51 );
    }
}

//-----------------------------------------------------------------------------

}  // namespace test
}  // namespace atlas

int main( int argc, char** argv ) {
    return atlas::test::run( argc, argv );
}
