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

/*! \file FrameLoop.cc
    \brief Implementation of the Template class FrameLoop.

    Magics Team - ECMWF 2008

    Started: Fri 29-Aug-2008

    Changes:

*/


#include "AnimationRules.h"
#include <limits>
#include "BaseDriver.h"
#include "Data.h"
#include "Layer.h"
#include "PaperPoint.h"
#include "Text.h"

using namespace magics;


AnimationStep::AnimationStep(AnimationRules& rules) :
    rules_(rules),
    xResolution_(std::numeric_limits<double>::max()),
    yResolution_(std::numeric_limits<double>::max()) {}


AnimationStep::~AnimationStep() {}

/*!
 Class information are given to the output-stream.
*/
void AnimationStep::print(ostream& out) const {
    out << "AnimationStep[" << size() << " entries";
    TagHandler::print(out);
    for (map<Layer*, int>::const_iterator l = begin(); l != end(); ++l)
        out << *(l->first) << "---> " << l->second << endl;
    out << "]";
}


void AnimationStep::rules(vector<string>& rules) {
    rules_.rules(rules);
}

AnimationRules::AnimationRules() {}

AnimationRules::~AnimationRules() {}

/*!
 Class information are given to the output-stream.
*/
void AnimationRules::print(ostream& out) const {
    for (vector<AnimationStep*>::const_iterator step = begin(); step != end(); ++step)
        out << "step->" << **step << endl;
    //	out << endl;
}

void AnimationRules::rules(vector<string>&) const {}

void AsIsAnimationRules::rules(vector<string>& infos) const {
    infos.push_back("<grib_info key='shortName'/>");
    infos.push_back("<grib_info key='valid-date'/>");
    infos.push_back("<grib_info key='level'/>");
}


AsIsAnimationRules::AsIsAnimationRules() : AnimationRules() {}

AsIsAnimationRules::~AsIsAnimationRules() {}

void AnimationRules::add(StepLayer&) {
    ASSERT(false);
}

void AsIsAnimationRules::add(StepLayer& objects) {
    int i = 0;
    for (vector<SingleLayer*>::iterator object = objects.firstStep(); object != objects.endStep(); ++object) {
        int x = size() - 1;
        if (i > x)
            this->push_back(new AnimationStep(*this));
        (*this)[i]->insert(make_pair(&objects, i));
        i++;
    }
}

NoOverlayAnimationRules::NoOverlayAnimationRules() : AnimationRules() {}

NoOverlayAnimationRules::~NoOverlayAnimationRules() {}


void NoOverlayAnimationRules::add(StepLayer& objects) {
    int i = 0;
    for (vector<SingleLayer*>::iterator object = objects.firstStep(); object != objects.endStep(); ++object) {
        AnimationStep* step = new AnimationStep(*this);
        step->insert(make_pair(&objects, i));
        push_back(step);

        i++;
    }
}
void NoOverlayAnimationRules::rules(vector<string>& infos) const {
    infos.push_back("<grib_info key='shortName'/>");
    infos.push_back("<grib_info key='valid-date'/>");
    infos.push_back("<grib_info key='level'/>");
}

/*!
 Class information are given to the output-stream.
*/
void AsIsAnimationRules::print(ostream& out) const {
    out << "AsIsAnimationRules[" << this->size() << " steps";
    AnimationRules::print(out);
    out << "]";
}

/*!
 Class information are given to the output-stream.
*/
void NoOverlayAnimationRules::print(ostream& out) const {
    out << "NoOverlayAnimationRules[" << this->size() << " steps";
    AnimationRules::print(out);
    out << "]";
}


DateAnimationRules::DateAnimationRules() : AnimationRules() {}

DateAnimationRules::~DateAnimationRules() {}

/*!
 Class information are given to the output-stream.
*/
void DateAnimationRules::print(ostream& out) const {
    out << "DateAnimationRules[" << this->size() << " entries";
    out << "]";
}

void DateAnimationRules::rules(vector<string>& infos) const {
    infos.push_back("<grib_info key='shortName'/>");
    infos.push_back("<grib_info key='valid-date'/>");
    infos.push_back("<grib_info key='level'/>");
}


void DateAnimationRules::add(StepLayer& objects) {
    int i = 0;
    for (vector<SingleLayer*>::iterator object = objects.firstStep(); object != objects.endStep(); ++object) {
        DateDescription& valid((*object)->timeStamp());

        map<DateDescription, AnimationStep*>::iterator stepi = steps_.find(valid);
        AnimationStep* step;
        if (stepi == steps_.end()) {
            step = new AnimationStep(*this);
            steps_.insert(make_pair(valid, step));
        }
        else {
            stepi->first.update(valid);
            step = stepi->second;
        }

        step->insert(make_pair(&objects, i));
        i++;
    }
    // We rebuild the vector...
    clear();
    for (map<DateDescription, AnimationStep*>::iterator step = steps_.begin(); step != steps_.end(); ++step) {
        push_back(step->second);
    }
}
LevelAnimationRules::LevelAnimationRules() : AnimationRules() {}

LevelAnimationRules::~LevelAnimationRules() {}

/*!
 Class information are given to the output-stream.
*/
void LevelAnimationRules::print(ostream& out) const {
    out << "DateAnimationRules[" << this->size() << " entries";
    out << "]";
}
void LevelAnimationRules::rules(vector<string>& infos) const {
    infos.push_back("<grib_info key='shortName'/>");
    infos.push_back("<grib_info key='valid-date'/>");
    infos.push_back("<grib_info key='level'/>");
}

void LevelAnimationRules::add(StepLayer& objects) {
    int i = 0;
    for (vector<SingleLayer*>::iterator object = objects.firstStep(); object != objects.endStep(); ++object) {
        LevelDescription& level((*object)->dataLevel());

        map<LevelDescription, AnimationStep*>::iterator stepi = steps_.find(level);
        AnimationStep* step;
        if (stepi == steps_.end()) {
            step = new AnimationStep(*this);
            steps_.insert(make_pair(level, step));
        }
        else {
            stepi->first.update(level);
            step = stepi->second;
        }

        step->insert(make_pair(&objects, i));
        i++;
    }
    // We rebuild the vector...
    clear();
    for (map<LevelDescription, AnimationStep*>::iterator step = steps_.begin(); step != steps_.end(); ++step) {
        push_back(step->second);
    }
}
