/*
 * (C) Copyright 1996-2012 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 "odc/core/Codec.h"

#include "eckit/exception/Exceptions.h"

#include "odc/core/CodecFactory.h"

using namespace eckit;

namespace odc {
namespace core {

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

Codec::Codec(const std::string& name, api::ColumnType type) :
    name_(name),
    hasMissing_(false),
    missingValue_(odc::MDI::realMDI()),
    min_(missingValue_),
    max_(missingValue_),
    type_(type) {}

std::unique_ptr<Codec> Codec::clone() {
    auto c           = CodecFactory::instance().build<SameByteOrder>(name_, type_);
    c->hasMissing_   = hasMissing_;
    c->missingValue_ = missingValue_;
    c->min_          = min_;
    c->max_          = max_;
    return c;
}

Codec::~Codec() {}

void Codec::setDataStream(GeneralDataStream& ds) {
    if (ds.isOther()) {
        setDataStream(ds.other());
    }
    else {
        setDataStream(ds.same());
    }
}

void Codec::setDataStream(DataStream<SameByteOrder>&) {
    throw eckit::SeriousBug("Mismatched byte order between DataStream and Codec", Here());
}

void Codec::setDataStream(DataStream<OtherByteOrder>&) {
    throw eckit::SeriousBug("Mismatched byte order between DataStream and Codec", Here());
}

void Codec::load(GeneralDataStream& ds) {
    if (ds.isOther()) {
        load(ds.other());
    }
    else {
        load(ds.same());
    }
}

void Codec::load(DataStream<SameByteOrder>&) {
    throw eckit::SeriousBug("Mismatched byte order between DataStream and Codec", Here());
}

void Codec::load(DataStream<OtherByteOrder>&) {
    throw eckit::SeriousBug("Mismatched byte order between DataStream and Codec", Here());
}

void Codec::save(GeneralDataStream& ds) {
    if (ds.isOther()) {
        save(ds.other());
    }
    else {
        save(ds.same());
    }
}

void Codec::save(DataStream<SameByteOrder>&) {
    throw eckit::SeriousBug("Mismatched byte order between DataStream and Codec", Here());
}

void Codec::save(DataStream<OtherByteOrder>&) {
    throw eckit::SeriousBug("Mismatched byte order between DataStream and Codec", Here());
}

void Codec::missingValue(double v) {
    ASSERT("Cannot change missing value after encoding of column data started" && (min_ == missingValue_) &&
           (max_ == missingValue_));
    min_ = max_ = missingValue_ = v;
}

void Codec::gatherStats(const double& v) {
    if (v == missingValue_) {
        hasMissing_ = 1;
    }
    else {
        if (v < min_ || min_ == missingValue_)
            min_ = v;
        if (v > max_ || max_ == missingValue_)
            max_ = v;
    }
}

void Codec::print(std::ostream& s) const {
    s << name_ << ", range=<" << std::fixed << min_ << "," << max_ << ">"
      << ", hasMissing=" << (hasMissing_ ? "true" : "false");

    if (hasMissing_) {
        s << ", missingValue=" << missingValue_;
    }
}

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

}  // namespace core
}  // namespace odc
