/***************************************************************************
**
**  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: 2002-05-28
**  Copyright: 2002-2019
**    Marc Wathelet
**    Marc Wathelet (ULg, Liège, Belgium)
**    Marc Wathelet (LGIT, Grenoble, France)
**
***************************************************************************/

#ifndef XYCOLORLINES_H
#define XYCOLORLINES_H

#include <QGpGuiTools.h>

#include "GraphicObject.h"
#include "GraphContentLayer.h"
#include "GraphContentOptions.h"

namespace SciFigs {

  class XYColorLinesProperties;

  class SCIFIGS_EXPORT XYColorLines : public GraphContentLayer
  {
    Q_OBJECT
    Q_PROPERTY(double lineWeight READ lineWeight WRITE setLineWeight SCRIPTABLE true)
    Q_PROPERTY(double signChangeThreshold READ signChangeThreshold WRITE setSignChangeThreshold)
  public:
    XYColorLines(AxisWindow * parent=0, bool autoDelete=false);
    ~XYColorLines();

    virtual const QString& xml_tagName() const {return xmlXYColorLinesTag;}
    static const QString xmlXYColorLinesTag;

    Point2D * points() {return _points;}
    const Point2D * points() const {return _points;}

    const Color * colors() const {return _colors;}
    void setColors(Color * col);
    void setColor(int index, const Color& col);

    int curveCount() {return _curveCount;}
    void setPointCount(int nPoints, int nCurves, int * pointCounts);
    void setPointCount(int nPoints, const QVector<int>& pointCounts);
    void setPoints(const QVector<Point2D>& points);

    // Calculate the rectangle that includes all the curves
    Rect boundingRect() const;

    virtual bool trackRectangle(int, double rx1, double ry1, double rx2, double ry2, Qt::KeyboardModifiers);

    void setLineWeight (double lw);
    double lineWeight() const {return _lineWeight;}
    double lineWeightMM() const {return _lineWeight*10.0;}

    double signChangeThreshold() const {return _signChangeThreshold;}
    void setSignChangeThreshold(double s) {_signChangeThreshold=fabs(s);}

    void mulYbyX(double constant);
    void divYbyX(double constant);

    virtual bool hasProperties() {return true;}
    virtual void addProperties(PropertyProxy * pp);
    virtual void removeProperties(PropertyProxy * pp);
    virtual void properties(PropertyWidget * w) const;
    virtual void setProperty(uint wid, int pid, QVariant val);

    static uint _tab;
  public slots:
    void setColor(int curveIndex, int red, int green, int blue);
  signals:
    void dataSelected(int id, const QVector<int> * indexList);
  protected:
    void clear();
    virtual void paintData(const LayerPainterRequest& lp, QPainter& p, double dotpercm) const;

    bool _autoDelete;
    int _curveCount;
    int * _pointCounts;
    Point2D * _points;
    Color * _colors;
    // Line weight in cm
    double _lineWeight;
    double _signChangeThreshold;
    // Storage for pointer to tab widget
    XYColorLinesProperties * _propertiesTab;
  protected:
    virtual void xml_writeProperties(XML_WRITEPROPERTIES_ARGS) const;
    virtual void xml_writeBinaryData(XML_WRITEBINARYDATA_ARGS) const;
    virtual bool xml_setBinaryData(XML_SETBINARYDATA_ARGS);
    virtual bool xml_setBinaryData200411(XML_SETBINARYDATA_ARGS);

    inline void drawCurve(int countPoints, QPainter& p, const GraphContentOptions& gc,
                          int height, Point2D *& p1, Point2D *& p2) const;
    inline void drawCurveSignThreshold(int countPoints, QPainter& p, const GraphContentOptions& gc,
                                       int height, Point2D *& p1, Point2D *& p2) const;
  };

  inline void XYColorLines::drawCurve(int countPoints, QPainter& p, const GraphContentOptions& gc,
                                      int height, Point2D *& p1, Point2D *& p2) const
  {
    QPolygon ap(countPoints);
    QPoint pscreen1, pscreen2;
    int subCurveCount=0;
    for(int j=1; j<countPoints; j++) {
      p2=p1+1;
      if(gc.r2s( *p1, *p2, pscreen1, pscreen2)) {
        gc.checkOrigin(pscreen1, pscreen2, height);
        if(subCurveCount==0) {
          ap.setPoint(0, pscreen1);
          subCurveCount=1;
        } else {
          if(ap.point(subCurveCount-1)!=pscreen1) {
            p.drawPolyline(ap.data(), subCurveCount);
            ap.setPoint(0, pscreen1);
            subCurveCount=1;
          }
        }
        ap.setPoint(subCurveCount, pscreen2);
        subCurveCount++;
      } else if(subCurveCount>1) {
        p.drawPolyline(ap.data(), subCurveCount);
        subCurveCount=0;
      }
      p1=p2;
    }
    if(subCurveCount>1) {
      p.drawPolyline(ap.data(), subCurveCount);
    }
  }

  inline void XYColorLines::drawCurveSignThreshold(int countPoints, QPainter& p, const GraphContentOptions& gc,
                                                   int height, Point2D *& p1, Point2D *& p2) const
  {
    QPolygon ap(countPoints);
    QPoint pscreen1, pscreen2;
    int subCurveCount=0;
    for(int j=1; j<countPoints; j++) {
      p2=p1+1;
      if(gc.r2s( *p1, *p2, pscreen1, pscreen2) &&
         ((p1->y()>0.0 && p2->y()>0.0) ||
          (p1->y()<0.0 && p2->y()<0.0) ||
          fabs(p1->y())<_signChangeThreshold ||
          fabs(p2->y())<_signChangeThreshold)) {
        gc.checkOrigin(pscreen1, pscreen2, height);
        if(subCurveCount==0) {
          ap.setPoint(0, pscreen1);
          subCurveCount=1;
        } else {
          if(ap.point(subCurveCount-1)!=pscreen1) {
            p.drawPolyline(ap.data(), subCurveCount);
            ap.setPoint(0, pscreen1);
            subCurveCount=1;
          }
        }
        ap.setPoint(subCurveCount, pscreen2);
        subCurveCount++;
      } else if(subCurveCount>1) {
        p.drawPolyline(ap.data(), subCurveCount);
        subCurveCount=0;
      }
      p1=p2;
    }
    if(subCurveCount>1) {
      p.drawPolyline(ap.data(), subCurveCount);
    }
  }

} // namespace SciFigs

#endif // XYCOLORLINES_H
