/*
 * (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 Node.cc
    \brief Implementation of the Template class Node.

    Magics Team - ECMWF 2004

    Started: Wed 11-Feb-2004

    Changes:

*/

#include "Node.h"
#include "Layout.h"
#include "Legend.h"
#include "MagTranslator.h"
#include "MagicsManager.h"
#include "PaperDimension.h"
#include "Title.h"


using namespace magics;


class magics::FrameNode : public BaseSceneObject {
public:
    FrameNode(const RootNode& root) : width_(root.getWidth()), height_(root.getHeight()), x_(0), y_(0) {
        layout_ = new Layout();
        layout_->set(this);
        layout_->setLevel(1);
        layout_->box();
        // layout_->needsNewPage();
        addChild(new LayoutTask(layout_));
    }
    ~FrameNode() {}
    virtual void set(const map<string, string>&) {}
    void setFrame(FrameBase* frame) { (*layout_)["superroot"]->setFrame(frame); }
    void attachFrameTask() { addChild(new FrameTask(*layout_, "superroot")); }
    double width() const { return width_; }
    double height() const { return height_; }
    void needsNewPage() { layout_->needsNewPage(); }

    double rootWidth() const { return width_; }
    double rootHeight() const { return height_; }

    double x() const { return x_; }
    double y() const { return y_; }

    virtual double percentWidth() const { return 100; }
    virtual double percentX() const { return 0; }
    virtual double percentHeight() const { return 100; }
    virtual double percentY() const { return 0; }
    Layout& getLayout() { return *layout_; }


protected:
    double width_;
    double height_;
    double x_;
    double y_;
    Layout* layout_;
};

RootNode::RootNode() : frameNode_(0), width_(0), height_(0), frame_(0), metaData_(0), needsNewPage_(false) {}

RootNode::~RootNode() {}


void RootNode::set(const map<string, string>& params) {
    SuperPageAttributes attributes;
    attributes.set(params);
    set(attributes);
}

void RootNode::set(const XmlNode& params) {
    static bool needsNewPage = false;
    XmlPageAttributes attributes;
    attributes.set(params);
    set(attributes);
    if (needsNewPage)
        frameNode_->needsNewPage();
    else
        needsNewPage = true;
}

void RootNode::set(const SuperPageAttributes& params) {
    width_  = params.getWidth();
    height_ = params.getHeight();

    frame_         = params.getFrame().clone();
    Colour* colour = new Colour(params.getColour());
    frame_->setColour(colour);
    frame_->setStyle(params.getStyle());
    frame_->setThickness(params.getThickness());
    delete colour;
}

void RootNode::set(const XmlPageAttributes& params) {
    PaperDimension* dimension = MagTranslator<string, PaperDimension>()(params.getFormat());
    dimension->setOrientation(params.getOrientation());

    width_  = dimension->getWidth();
    height_ = dimension->getHeight();
    ParameterManager::set("SUPER_PAGE_X_LENGTH", width_);
    ParameterManager::set("SUPER_PAGE_Y_LENGTH", height_);


    // MagLog::dev()<< "dispatch[" << width_ << ", " << height_ << "]\n";
    MagicsManager::dispatchDimension(width_, height_);


    if (!frameNode_) {
        frameNode_ = new FrameNode(*this);
        (*frameNode_).setParent(this);
        children_.push_back(frameNode_);
    }
    frame_    = params.getFrame().clone();
    metaData_ = params.getMeta().clone();

    frameNode_->setFrame(frame_);
    frameNode_->attachFrameTask();


    MagLog::debug() << " setting of the Root..." << *this << "\n";

    delete dimension;
}


BaseSceneObject* RootNode::newXmlNode() {
    XmlPageAttributes attributes;
    set(attributes);

    return frameNode_;
}


BaseSceneObject* RootNode::newFortranNode() {
    SuperPageAttributes attributes;
    set(attributes);
    frameNode_ = new FrameNode(*this);
    (*frameNode_).setParent(this);
    children_.push_back(frameNode_);
    frameNode_->setFrame(frame_);
    frameNode_->attachFrameTask();
    return frameNode_;
}

BaseSceneObject* RootNode::newMetviewNode(const SuperPageAttributes& attributes) {
    set(attributes);
    ParameterManager::set("SUPER_PAGE_X_LENGTH", width_);
    ParameterManager::set("SUPER_PAGE_Y_LENGTH", height_);

    frameNode_ = new FrameNode(*this);
    (*frameNode_).setParent(this);
    children_.push_back(frameNode_);
    frameNode_->setFrame(frame_);
    frameNode_->attachFrameTask();
    return frameNode_;
}


void RootNode::addChild(BaseSceneObject* child) {
    if (!frameNode_)
        newXmlNode();
    frameNode_->addChild(child);
}

void RootNode::print(ostream& out) const {
    out << "Root[";
    BaseSceneObject::print(out);
    out << "]";
}

Layout& RootNode::getLayout() {
    ASSERT(frameNode_);
    return frameNode_->getLayout();
}


void RootNode::clear() {
    children_.clear();
    frameNode_    = 0;
    needsNewPage_ = false;
}

void RootNode::prepareGraphics() {
    BaseSceneObject::prepareGraphics();

    if (!metaData_)
        return;


    visit(*metaData_);


    metaData_->close();
}
