/*
 * (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/FieldCreatorArraySpec.h"

#include <algorithm>
#include <sstream>

#include "eckit/config/Parametrisation.h"

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

namespace atlas {
namespace field {

FieldImpl* FieldCreatorArraySpec::createField(const eckit::Parametrisation& params) const {
    std::vector<long> shape;
    if (!params.get("shape", shape)) {
        throw_Exception("Could not find parameter 'shape' in Parametrisation");
    }

    std::vector<idx_t> s(shape.size());

    bool fortran(false);
    params.get("fortran", fortran);
    if (fortran) {
        std::reverse_copy(shape.begin(), shape.end(), s.begin());
    }
    else {
        s.assign(shape.begin(), shape.end());
    }

    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);
    }

    int alignment = 1;
    params.get("alignment", alignment);

    std::string name;
    params.get("name", name);
    Log::trace() << "Create field " << name << "\t shape=[";
    for (size_t i = 0; i < s.size(); ++i) {
        Log::trace() << s[i] << (i < s.size() - 1 ? "," : "");
    }
    Log::trace() << "]" << std::endl;
    auto field = FieldImpl::create(name, datatype, array::ArraySpec(std::move(s), array::ArrayAlignment(alignment)));
    field->callbackOnDestruction([field]() { Log::trace() << "Destroy field " << field->name() << std::endl; });
    return field;
}

namespace {
static FieldCreatorBuilder<FieldCreatorArraySpec> __ArraySpec("ArraySpec");
}

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

}  // namespace field
}  // namespace atlas
