/*
 * (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 Mapper_H
#define Mapper_H

#include "Exceptions.h"
#include "Reshape.h"

#include <iostream>

template<class T>
class Mapper {
public:
    Mapper(std::vector<T> &v, std::vector<bool> &set, bool &overlap);
    Mapper(Mapper<T> &parent, const std::vector<Reshape *> &reshape);
    ~Mapper();

    void overlap(bool on) {
        overlap_ = on;
    }

    void set(size_t i, T value);


private:

    std::vector<T> &v_;
    std::vector<bool> &set_;
    std::vector<Reshape *> reshapes_;
    bool &overlap_;

};

template<class T>
Mapper<T>::Mapper(std::vector<T> &v, std::vector<bool> &set, bool &overlap):
    v_(v), set_(set), overlap_(overlap)
{
}

template<class T>
Mapper<T>::Mapper(Mapper<T> &parent, const std::vector<Reshape *> &reshapes):
    v_(parent.v_),
    set_(parent.set_),
    overlap_(parent.overlap_)
{
    Reshape *r = 0;
    for (std::vector<Reshape *>::const_iterator j = reshapes.begin(); j != reshapes.end(); ++j) {
        if (r && r->merge(*(*j))) {
            // Pass
        }
        else {
            r = (*j);
            r->attach();
            reshapes_.push_back(r);
        }
    }

    for (std::vector<Reshape *>::iterator j = parent.reshapes_.begin(); j != parent.reshapes_.end(); ++j) {
        if (r && r->merge(*(*j))) {
            // Pass
        }
        else {
            r = (*j);
            r->attach();
            reshapes_.push_back(r);
        }
    }
}

template<class T>
Mapper<T>::~Mapper() {
    for (std::vector<Reshape *>::iterator j = reshapes_.begin(); j != reshapes_.end(); ++j) {
        (*j)->detach();
    }
}

template<class T>
void Mapper<T>::set(size_t i, T v) {

    for (std::vector<Reshape *>::iterator j = reshapes_.begin(); j != reshapes_.end(); ++j) {
        Reshape *m = (*j);
        size_t k = (*m)(i);
        ASSERT(k >= i);
        i = k;
    }

    ASSERT(i < v_.size());

    if (!overlap_)
    {
        if (v_[i] != v)
        {
            ASSERT(!set_[i]);
        }
    }
    set_[i] = true;

    v_[i] = v;
}
#endif
