/*
 * (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 <algorithm>
#include <iomanip>
#include <sstream>

#include "atlas/domain.h"
#include "atlas/grid/StructuredGrid.h"
#include "atlas/runtime/Log.h"
#include "atlas/util/Config.h"

#include "tests/AtlasTestEnvironment.h"

namespace atlas {
namespace test {

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

CASE( "test_domain_rectangular" ) {
    Domain domain = RectangularDomain( {0, 180}, {-25, 25} );
    EXPECT( not domain.global() );
    EXPECT( domain.type() == std::string( "rectangular" ) );

    util::Config domain_cfg = domain.spec();
    Domain from_cfg( domain_cfg );
    Log::info() << from_cfg.spec() << std::endl;
    EXPECT( from_cfg.type() == std::string( "rectangular" ) );
}

CASE( "test_domain_rectangular_tolerance" ) {
    using grid::LinearSpacing;

    Domain domain        = RectangularDomain( {-27, 45}, {33, 73} );
    RectangularDomain rd = domain;

    StructuredGrid::XSpace xspace( LinearSpacing( rd.xmin(), rd.xmax(), 721, true ) );
    StructuredGrid::YSpace yspace( LinearSpacing( rd.ymin(), rd.ymax(), 401 ) );

    StructuredGrid grid( xspace, yspace, StructuredGrid::Projection(), rd );

    EXPECT( grid.nx( 0 ) == 721 );
    EXPECT( grid.ny() == 401 );
}

CASE( "test_domain_zonal_from_rectangular" ) {
    Domain domain = RectangularDomain( {0, 360}, {-25, 25} );
    EXPECT( not domain.global() );
    EXPECT( domain.type() == std::string( "zonal_band" ) );

    util::Config domain_cfg = domain.spec();
    Domain from_cfg( domain_cfg );
    Log::info() << from_cfg.spec() << std::endl;
    EXPECT( from_cfg.type() == std::string( "zonal_band" ) );
}

CASE( "test_domain_global_from_rectangular" ) {
    Domain domain = RectangularDomain( {-180, 180}, {-90, 90} );
    EXPECT( domain.global() );
    EXPECT( domain.type() == std::string( "global" ) );

    util::Config domain_cfg = domain.spec();
    Domain from_cfg( domain_cfg );
    Log::info() << from_cfg.spec() << std::endl;
    EXPECT( from_cfg.type() == std::string( "global" ) );

    RectangularDomain rd = domain;
    EXPECT( rd == true );
    EXPECT( rd.xmin() == -180. );
    EXPECT( rd.xmax() == 180. );
    EXPECT( rd.ymin() == -90. );
    EXPECT( rd.ymax() == 90. );

    ZonalBandDomain zd = domain;
    EXPECT( zd == true );
    EXPECT( zd.xmin() == -180. );
    EXPECT( zd.xmax() == 180. );
    EXPECT( zd.ymin() == -90. );
    EXPECT( zd.ymax() == 90. );
}

CASE( "test_domain_global_from_zonalband" ) {
    Domain domain = ZonalBandDomain( {-45, 45} );
    EXPECT( not domain.global() );
    EXPECT( domain.type() == std::string( "zonal_band" ) );

    util::Config domain_cfg = domain.spec();
    Domain from_cfg( domain_cfg );
    Log::info() << from_cfg.spec() << std::endl;
    EXPECT( from_cfg.type() == std::string( "zonal_band" ) );

    RectangularDomain rd = domain;
    EXPECT( rd == true );
    EXPECT( rd.xmin() == 0 );
    EXPECT( rd.xmax() == 360. );
    EXPECT( rd.ymin() == -45. );
    EXPECT( rd.ymax() == 45. );

    ZonalBandDomain zd = domain;
    EXPECT( zd == true );
    EXPECT( zd.ymin() == -45. );
    EXPECT( zd.ymax() == 45. );
}

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

}  // namespace test
}  // namespace atlas

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