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

    Magics Team - ECMWF 2004

    Started: Mon 2-Feb-2004

    Changes:

*/

#include "GridPlotting.h"
#include "BasicSceneObject.h"
#include "Transformation.h"


using namespace magics;

GridPlotting::GridPlotting() : layer_(0) {}

GridPlotting::~GridPlotting() {}

void NoGridPlotting::longitudes(vector<double>& lons, int freq) const {
    int i      = 0;
    double min = minx_ - lonIncrement_;
    double max = maxx_ + lonIncrement_;
    for (double lon = lonReference_; lon > min; lon -= lonIncrement_) {
        if ((i % freq) == 0) {
            lons.push_back(lon);
        }
        i++;
    }
    i = 0;
    for (double lon = lonReference_ + lonIncrement_; lon < max; lon += lonIncrement_) {
        i++;
        if ((i % freq) == 0) {
            lons.push_back(lon);
        }
    }
}
void NoGridPlotting::latitudes(vector<double>& lats, int freq) const {
    int i      = 0;
    double min = miny_ - latIncrement_;
    double max = maxy_ + latIncrement_;
    for (double lat = latReference_; lat > min; lat -= latIncrement_) {
        if (i % freq == 0) {
            if (lat < -90)
                lats.push_back(180. + lat);
            else
                lats.push_back(lat);
        }
        i++;
    }
    i = 0;
    for (double lat = latReference_ + latIncrement_; lat < max; lat += latIncrement_) {
        i++;
        if (i % freq == 0) {
            lats.push_back(lat);
        }
    }
}

const vector<double>& NoGridPlotting::longitudes(const Transformation& transformation) const {
    transformation.boundingBox(minx_, miny_, maxx_, maxy_);
    minx_      = -190;
    maxx_      = +370;
    miny_      = std::max(miny_, -85.);
    maxy_      = std::min(maxy_, 85.);
    double min = minx_ - lonIncrement_;
    double max = maxx_ + lonIncrement_;

    if (longitudes_.empty()) {
        for (double lon = lonReference_; lon > min; lon -= lonIncrement_) {
            longitudes_.push_back(lon);
        }
        for (double lon = lonReference_ + lonIncrement_; lon < max; lon += lonIncrement_) {
            longitudes_.push_back(lon);
        }
    }

    // Here we prepare a small point in the middle!
    ::sort(longitudes_.begin(), longitudes_.end(), std::greater<double>());
    return longitudes_;
}

const vector<double>& NoGridPlotting::latitudes(const Transformation& transformation) const {
    transformation.boundingBox(minx_, miny_, maxx_, maxy_);
    maxy_      = std::min(85., maxy_);
    maxy_      = 90.;
    double min = miny_ - latIncrement_;
    double max = maxy_ + latIncrement_;
    if (latitudes_.empty()) {
        for (double lat = latReference_; lat > min; lat -= latIncrement_) {
            latitudes_.push_back(lat);
        }
        for (double lat = latReference_ + latIncrement_; lat < max; lat += latIncrement_) {
            latitudes_.push_back(lat);
        }
    }
    ::sort(latitudes_.begin(), latitudes_.end(), std::greater<double>());
    return latitudes_;
}

void NoGridPlotting::operator()(DrawingVisitor& out) {
    const Transformation& transformation = out.transformation();

    this->latitudes(transformation);
    this->longitudes(transformation);
}

void GridPlotting::operator()(DrawingVisitor& out) {
    const Transformation& transformation = out.transformation();

    layer_ = out.layoutPtr();

    latitudes(transformation);
    longitudes(transformation);

    // Wrep :here we add a small line in the lowerleft corner..
    // to force the driver to compute the output size even if
    // no grid are going to be plotted
    Polyline* grid = new Polyline();
    grid->setColour(Colour("none"));
    grid->setThickness(0);

    grid->push_back(PaperPoint(transformation.getMinPCX(), transformation.getMinPCY()));
    grid->push_back(PaperPoint(transformation.getMinPCX(), transformation.getMinPCY()));
    out.push_back(grid);

    transformation.gridLongitudes(*this);
    transformation.gridLatitudes(*this);
}

void GridPlotting::operator()(magics::PreviewVisitor&) {}
void GridPlotting::addFrame(Polyline& poly) const {
    if (!grid_frame_)
        return add(poly);


    poly.setColour(*grid_frame_colour_);
    poly.setThickness(grid_frame_thickness_);
    poly.setLineStyle(grid_frame_style_);
    poly.reproject(*layer_);
}
void GridPlotting::add(Polyline& poly) const {
    poly.setColour(*colour_);
    poly.setThickness(thickness_);
    poly.setLineStyle(style_);
    poly.reproject(*layer_);
}


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