/***************************************************************************
**
**  This file is part of SciFigs.
**
**  This library is free software; you can redistribute it and/or
**  modify it under the terms of the GNU Lesser General Public
**  License as published by the Free Software Foundation; either
**  version 2.1 of the License, or (at your option) any later version.
**
**  This file is distributed in the hope that it will be useful, but WITHOUT
**  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
**  FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
**  License for more details.
**
**  You should have received a copy of the GNU Lesser General Public
**  License along with this library; if not, write to the Free Software
**  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
**
**  See http://www.geopsy.org for more information.
**
**  Created: 2008-03-26
**  Copyright: 2008-2019
**    Marc Wathelet
**    Marc Wathelet (LGIT, Grenoble, France)
**
***************************************************************************/

#include "ColorMapLayer.h"
#include "LayerPainterRequest.h"
#include "LayerLocker.h"
#include "GraphContentLayerFactory.h"
#include "AxisWindow.h"

namespace SciFigs {

/*!
  \class ColorMapLayer ColorMapLayer.h
  \brief Brief description of class still missing

  Full description of class still missing
*/

const QString ColorMapLayer::xmlColorMapLayerTag="ColorMapLayer";

REGISTER_GRAPHCONTENTLAYER(ColorMapLayer, "ColorMapLayer")
SYNONYM_GRAPHCONTENTLAYER(ColorPaletteLayer, "ColorMapLayer")

/*!
  Description of constructor still missing
*/
ColorMapLayer::ColorMapLayer(AxisWindow * parent)
    : GraphContentLayer(parent)
{
  TRACE;
  _axisType=XAxis;
}

void ColorMapLayer::setAxisType(AxisType a)
{
  TRACE;
  LayerLocker ll(this);
  _axisType=a;
}

inline void ColorMapLayer::paintX(double min, double max, double w, double h, const QColor& col,
                                      const GraphContentOptions& gc, QPainter& p)
{
  int xc=gc.xr2s(min);
  int wc=gc.xr2s(max)-xc;
  if(xc<0) {
    wc+=xc;
    xc=0;
  } else if(xc>w) {
    wc+=xc-w;
    xc=w;
  }
  p.fillRect(xc, 0, wc, h, col);
}

inline void ColorMapLayer::paintY(double min, double max, double w, double h, const QColor& col,
                                      const GraphContentOptions& gc, QPainter& p)
{
  int yc=gc.yr2s(min);
  int hc=gc.yr2s(max)-yc;
  if(yc<0) {
    hc+=yc;
    yc=0;
  } else if(yc>h) {
    hc+=yc-h;
    yc=h;
  }
  p.fillRect(0, yc, w, hc, col);
}

void ColorMapLayer::paintData(const LayerPainterRequest& lp, QPainter& p, double) const
{
  TRACE;
  const GraphContentOptions& gc=lp.options();
  ColorMap map=_colorMap; // A copy to avoid distrubances from changes to palette during painting
  int n=map.count()-1;
  if(n<0) return;
  int w=lp.size().width();
  int h=lp.size().height();
  QColor col;
  if(n==0) {
    guiColor(map.color(0), col);
    p.fillRect(0, 0, w, h, col);
    return;
  }
  if(_axisType==XAxis) {
    double vmin=gc.xs2r(0);
    double vmax=gc.xs2r(w);
    if(vmin>vmax) qSwap(vmin, vmax);
    int minIndex=map.index(vmin);
    int maxIndex=map.index(vmax);
    if(minIndex==0) {
      guiColor(map.color(0), col);
      paintX(vmin, map.upperValue(0), w, h, col, gc, p);
      minIndex++;
    }
    if(maxIndex==n) {
      guiColor(map.color(n), col);
      paintX(map.lowerValue(n), vmax, w, h, col, gc, p);
      maxIndex--;
    }
    for(int i=minIndex; i<=maxIndex; i++) {
      guiColor(map.color(i), col);
      paintX(map.lowerValue(i), map.upperValue(i), w, h, col, gc, p);
    }
  } else {
    double vmin=gc.ys2r(0);
    double vmax=gc.ys2r(h);
    if(vmin>vmax) qSwap(vmin, vmax);
    int minIndex=map.index(vmin);
    int maxIndex=map.index(vmax);
    if(minIndex==0) {
      guiColor(map.color(0), col);
      paintY(vmin, map.upperValue(0), w, h, col, gc, p);
      minIndex++;
    }
    if(maxIndex==n) {
      guiColor(map.color(n), col);
      paintY(map.lowerValue(n), vmax, w, h, col, gc, p);
      maxIndex--;
    }
    for(int i=minIndex; i<=maxIndex; i++) {
      guiColor(map.color(i), col);
      paintY(map.lowerValue(i), map.upperValue(i), w, h, col, gc, p);
    }
  }
}

Rect ColorMapLayer::boundingRect() const
{
  TRACE;
  if(_colorMap.count()<2) {
    return Rect(-std::numeric_limits<double>::infinity(), -std::numeric_limits<double>::infinity(), std::numeric_limits<double>::infinity(), std::numeric_limits<double>::infinity());
  }
  if(_axisType==XAxis) {
    if(_colorMap.count()==2) {
      return Rect(_colorMap.upperValue(0)-1.0, -std::numeric_limits<double>::infinity(), _colorMap.upperValue(0)+1.0, std::numeric_limits<double>::infinity());
    } else {
      return Rect(1.5*_colorMap.upperValue(0)-0.5*_colorMap.upperValue(1), -std::numeric_limits<double>::infinity(),
                  1.5*_colorMap.upperValue(_colorMap.count()-2)-0.5*_colorMap.upperValue(_colorMap.count()-3), std::numeric_limits<double>::infinity());
    }
  } else {
    if(_colorMap.count()==2) {
      return Rect( -std::numeric_limits<double>::infinity(), _colorMap.upperValue(0)-1.0, std::numeric_limits<double>::infinity(), _colorMap.upperValue(0)+1.0);
    } else {
      return Rect(-std::numeric_limits<double>::infinity(), 1.5*_colorMap.upperValue(0)-0.5*_colorMap.upperValue(1),
                  std::numeric_limits<double>::infinity(), 1.5*_colorMap.upperValue(_colorMap.count()-2)-0.5*_colorMap.upperValue(_colorMap.count()-3));
    }
  }
}

QString ColorMapLayer::coordinateTipInfo(const Point2D& p, const Point2D&) const
{
  TRACE;
  if(_colorMap.count()<2)
    return QString();
  else
    return QString("%2 ; %1")
        .arg(_colorMap.color(p.x()).name());
}

} // namespace SciFigs
