/*
 * (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 "atlas/field/FieldCreatorIFS.h"

#include <cmath>
#include <sstream>

#include "eckit/config/Parametrisation.h"

#include "atlas/array/ArrayUtil.h"
#include "atlas/array/DataType.h"
#include "atlas/field/detail/FieldImpl.h"
#include "atlas/grid/Grid.h"
#include "atlas/runtime/Exception.h"
#include "atlas/runtime/Log.h"

namespace atlas {
namespace field {

FieldImpl* FieldCreatorIFS::createField( const eckit::Parametrisation& params ) const {
    size_t ngptot;
    size_t nblk;
    size_t nvar   = 1;
    size_t nproma = 1;
    size_t nlev   = 1;

    if ( !params.get( "ngptot", ngptot ) ) {
        throw_Exception( "Could not find parameter 'ngptot' in Parametrisation" );
    }
    params.get( "nproma", nproma );
    params.get( "nlev", nlev );
    params.get( "nvar", nvar );

    array::DataType datatype = array::DataType::create<double>();
    std::string datatype_str;
    if ( params.get( "datatype", datatype_str ) ) {
        datatype = array::DataType( datatype_str );
    }
    else {
        array::DataType::kind_t kind( array::DataType::kind<double>() );
        params.get( "kind", kind );
        if ( !array::DataType::kind_valid( kind ) ) {
            std::stringstream msg;
            msg << "Could not create field. kind parameter unrecognized";
            throw_Exception( msg.str() );
        }
        datatype = array::DataType( kind );
    }

    nblk = std::ceil( static_cast<double>( ngptot ) / static_cast<double>( nproma ) );

    array::ArrayShape s;
    bool fortran( false );
    params.get( "fortran", fortran );
    if ( fortran ) {
        s = array::make_shape( nproma, nlev, nvar, nblk );
    }
    else {
        s = array::make_shape( nblk, nvar, nlev, nproma );
    }

    std::string name;
    params.get( "name", name );
    Log::debug() << "Creating IFS " << datatype.str() << " field: " << name << "[nblk=" << nblk << "][nvar=" << nvar
                 << "][nlev=" << nlev << "][nproma=" << nproma << "]\n";

    return FieldImpl::create( name, datatype, s );
}

namespace {
static FieldCreatorBuilder<FieldCreatorIFS> __IFS( "IFS" );
}

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

}  // namespace field
}  // namespace atlas
