/*
 * (C) Copyright 1996-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.
 */

// Baudouin Raoult - ECMWF Jan 2015

#ifndef Matrix_H
#define Matrix_H



#include "Counted.h"

#include <string>
#include <vector>

class Type;
class Value;
class Remapping;
class Codec;
class Reshape;
template<class T> class Mapper;

class Matrix : public Counted
{
public:

    Matrix(Type &type, const std::string &name, size_t size);


    Type &type() const;
    void type(Type &);

    const std::string &name() const;
    size_t size() const;

    Matrix *mergeData(Matrix *other, size_t size);
    Matrix *mergeCoordinates(Matrix *other, size_t size);

    template<class T>
    const std::vector<T> &values() const;

public:

    void decache() const;

    void dump(std::ostream &) const;
    virtual void dumpTree(std::ostream &, size_t) const;
    void save(int nc, int varid, const std::string &path) const;

    void printValues(std::ostream &) const;
    void missingValue(Value *) ;
    Value *missingValue() const;

    void codec(Codec *);
    Codec *codec() const;

    virtual Matrix *merged();
    // ========================================================

    void reshape(Reshape *);
    const std::vector<Reshape *> &reshape() const;

    // ========================================================

    virtual void fill(Mapper<double> &) const;
    virtual void fill(Mapper<float> &) const;
    virtual void fill(Mapper<short> &) const;
    virtual void fill(Mapper<long> &) const;
    virtual void fill(Mapper<unsigned char> &) const;

protected:

    virtual ~Matrix();

    // -- Members

    Type *type_;
    Value *missingValue_;
    Codec *codec_;
    std::string name_;
    size_t size_;
    std::vector<Reshape *> reshapes_;

private:

    Matrix(const Matrix &);
    Matrix &operator=(const Matrix &);

    // -- Members
    mutable std::vector<double> double_cache_;
    mutable std::vector<float> float_cache_;
    mutable std::vector<long> long_cache_;
    mutable std::vector<short> short_cache_;
    mutable std::vector<unsigned char> unsigned_char_cache_;
    mutable std::vector<std::string> string_cache_;

    void values(std::vector<double> &) const;
    void values(std::vector<float> &) const;
    void values(std::vector<long> &) const;
    void values(std::vector<short> &) const;
    void values(std::vector<unsigned char> &) const;
    void values(std::vector<std::string> &) const;


    // -- Methods
    template<class T> void _fill(std::vector<T> &v) const;

    template<class T>
    const std::vector<T> &cache() const;

    virtual void print(std::ostream &out) const = 0;


    // -- Friends
    friend std::ostream &operator<<(std::ostream &out, const Matrix &v)
    {
        v.print(out);
        return out;
    }
};


template<class T>
const std::vector<T> &Matrix::values() const {
    const std::vector<T> &vals = cache<T>();
    if (vals.empty()) {
        values(const_cast<std::vector<T>&>(vals));
    }
    return vals;
}

#endif
