/*
 * (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.h
    \brief Definition of the Template class FrameLoop.

    Magics Team - ECMWF 2008

    Started: Fri 29-Aug-2008

    Changes:

*/

#ifndef FrameLoop_H
#define FrameLoop_H

#include "magics.h"

#include "BaseGraphicsObject.h"
#include "BasicSceneObject.h"
#include "TagHandler.h"

namespace magics {

class AnimationRules;
class AsIsAnimationRules;

class FrameEntry : public BasicSceneObject, public GraphicsList {
public:
    FrameEntry();
    virtual ~FrameEntry() override;
    void execute(const BaseDriver&);
    void add(BasicSceneObject* object) { BasicSceneObject::push_back(object); }
    void add(BaseGraphicsObject* object) { GraphicsList::push_back(object); }
    void visit(AnimationRules&);
    void tag(AnimationRules&);
    void animate(AsIsAnimationRules&);
    string label() const { return label_; }
    void index(int index) { index_ = index; }

protected:
    void print(ostream&) const;
    string label_;
    int index_;
};


class FrameLoop : public BaseGraphicsObject, public vector<FrameEntry*> {
public:
    FrameLoop();
    virtual ~FrameLoop() override;
    bool reproject(const Transformation&, BaseGraphicsList& out) const;
    void redisplay(const BaseDriver& driver) const override;

protected:
    //! Method to print string about this class on to a stream of type ostream (virtual).
    virtual void print(ostream&) const override;
    AnimationRules* rules_;  // Later will probably come from an Attributes!

private:
    //! Copy constructor - No copy allowed
    FrameLoop(const FrameLoop&);
    //! Overloaded << operator to copy - No copy allowed
    FrameLoop& operator=(const FrameLoop&);

    // -- Friends
    //! Overloaded << operator to call print().
    friend ostream& operator<<(ostream& s, const FrameLoop& p) {
        p.print(s);
        return s;
    }
};

class AnimationStep : public vector<FrameEntry*> {
public:
    AnimationStep();
    virtual ~AnimationStep() override;
    string label() { return label_; }
    void label(const string& label) { label_ = label; }

protected:
    //! Method to print string about this class on to a stream of type ostream (virtual).
    virtual void print(ostream&) const override;
    string label_;

private:
    //! Copy constructor - No copy allowed
    AnimationStep(const AnimationStep&);
    //! Overloaded << operator to copy - No copy allowed
    AnimationStep& operator=(const AnimationStep&);

    // -- Friends
    //! Overloaded << operator to call print().
    friend ostream& operator<<(ostream& s, const AnimationStep& p) {
        p.print(s);
        return s;
    }
};


class AnimationRules : public TagHandler, public vector<AnimationStep*> {
public:
    AnimationRules();
    virtual ~AnimationRules() override;
    virtual void callback(FrameEntry&) override {}

    string labelFormat() const { return labelFormat_; }

    virtual void getReady() override {}
    virtual void rules(vector<string>&) const override;


protected:
    //! Method to print string about this class on to a stream of type ostream (virtual).
    virtual void print(ostream&) const override;
    string labelFormat_;

private:
    //! Copy constructor - No copy allowed
    AnimationRules(const AnimationRules&);
    //! Overloaded << operator to copy - No copy allowed
    AnimationRules& operator=(const AnimationRules&);

    // -- Friends
    //! Overloaded << operator to call print().
    friend ostream& operator<<(ostream& s, const AnimationRules& p) {
        p.print(s);
        return s;
    }
};


class AsIsAnimationRules : public AnimationRules {
public:
    AsIsAnimationRules();
    virtual ~AsIsAnimationRules() override;
    virtual void callback(FrameEntry& entry) override { entry.animate(*this); }
    AnimationStep* step(int);
    void getReady();
    void rules(vector<string>&) const;

protected:
    //! Method to print string about this class on to a stream of type ostream (virtual).
    virtual void print(ostream&) const override;
    map<int, AnimationStep*> steps_;
};
class DateAnimationRules : public AnimationRules {
public:
    DateAnimationRules();
    virtual ~DateAnimationRules() override;


protected:
    //! Method to print string about this class on to a stream of type ostream (virtual).
    virtual void print(ostream&) const override;
};

}  // namespace magics
#endif
