/***************************************************************************
**
**  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: 2007-05-30
**  Copyright: 2007-2019
**    Marc Wathelet
**    Marc Wathelet (LGIT, Grenoble, France)
**
***************************************************************************/

#ifndef LINELAYER_H
#define LINELAYER_H

#include "GraphContentLayer.h"
#include "SciFigsDLLExport.h"
#include "LineEditor.h"
#include "AbstractLine.h"
#include "Legend.h"

namespace SciFigs {

class LineProperties;
class XMLSciFigs;

class SCIFIGS_EXPORT LineLayer : public GraphContentLayer
{
  Q_OBJECT
  // Compatibility
  Q_PROPERTY(bool logErrorBars READ dummyPropertyInt WRITE setLogErrorBar SCRIPTABLE true)

  Q_PROPERTY(QString errorBar READ errorBarString WRITE setErrorBar SCRIPTABLE true)
public:
  LineLayer(AxisWindow * parent=nullptr);
  ~LineLayer();

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

  void setReferenceLine(AbstractLine * l);
  void setReferencePen(const Pen& p);
  void setReferenceSymbol(const Symbol& s);

  void clear();
  void removeLine(int i);
  void removeLine(AbstractLine * l);
  void removeEmptyLines();

  AbstractLine * addLine();
  AbstractLine * addLine(const Pen& pen, const Symbol& sym);

  AbstractLine * line(int i) {return _lines.at(i);}
  const AbstractLine * line(int i) const {return _lines.at(i);}
  QList<AbstractLine *> lines() const;

  void setVisible(int i, bool v);
  void setSelected(int i, bool s);
  virtual Legend legend() const;

  // Return the number of curves
  int count() const {return _lines.count();}
  virtual bool trackRectangle(int, double rx1, double ry1, double rx2, double ry2, Qt::KeyboardModifiers m);
  // Calculate the rectangle that includes all the curves
  virtual Rect boundingRect() const;
  virtual void paintData(const LayerPainterRequest& lp, QPainter& p, double dotpercm) const;

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

  enum ErrorBar {NoBar, VerticalBar, HorizontalBar, VerticalLogBar, HorizontalLogBar};
  void setLogErrorBar(bool b) {_errorBar=b ? VerticalLogBar : VerticalBar;} // Compatibility
  void setErrorBar(ErrorBar b) {_errorBar=b;}
  ErrorBar errorBar() const {return _errorBar;}
  void setErrorBar(QString b);
  QString errorBarString() const;

  void setPointOptions(CurvePointOptions * o) {_pointOptions=o;}
  CurvePointOptions * pointOptions() {return _pointOptions;}
  const CurvePointOptions * pointOptions() const {return _pointOptions;}

  enum TrackingModes{Select=0, Pick, PickOrdered, Edit};
  virtual bool mousePressEvent (QMouseEvent * e, int id=-1);
  virtual bool mouseReleaseEvent (QMouseEvent * e, int id=-1);
  virtual void mouseMoveEvent (const QPoint& pt, Qt::MouseButtons buttons, Qt::KeyboardModifiers modifiers);
  virtual bool wheelEvent (QWheelEvent * e);
  virtual bool keyPressEvent (QKeyEvent* e);
  virtual void toggleTrackingAction(bool checked, int id=-1);

  typedef QList<AbstractLine *>::const_iterator const_iterator;
  const_iterator begin() const {return _lines.begin();}
  const_iterator end() const {return _lines.end();}

  virtual bool hasProperties() {return true;}
  virtual void addProperties(PropertyProxy * pp);
  virtual void removeProperties(PropertyProxy * pp);
  void resetLineProperties();
signals:
  void beginPointAdd(AbstractLine * line, int pointIndex);
  void endPointAdd(AbstractLine * line, int pointIndex);
  void pickLine(AbstractLine * line);
  void lineEdited(int lineIndex);
public slots:
  Q_SCRIPTABLE void setPenColor(int curveIndex, int red, int green, int blue);
  Q_SCRIPTABLE void setPenStyle(int curveIndex, double width, QString lineStyle, QString capStyle, QString joinStyle);
  Q_SCRIPTABLE void setSymType(int curveIndex, QString type);
  Q_SCRIPTABLE void setSymSize(int curveIndex, double size);
  Q_SCRIPTABLE void setSymPenColor(int curveIndex, int red, int green, int blue);
  Q_SCRIPTABLE void setSymPenStyle(int curveIndex, double width, QString lineStyle, QString capStyle, QString joinStyle);
  Q_SCRIPTABLE void setSymBrushColor(int curveIndex, int red, int green, int blue);
  Q_SCRIPTABLE void setSymBrushStyle(int curveIndex, QString brushStyle);
  Q_SCRIPTABLE void rmStdDev(int curveIndex);
  Q_SCRIPTABLE void attributesHelp();
  Q_SCRIPTABLE virtual void setLegend(Legend legend);
protected:
  virtual void xml_writeChildren(XML_WRITECHILDREN_ARGS) const;
  virtual XMLMember xml_member(XML_MEMBER_ARGS);
  virtual bool xml_setProperty(XML_SETPROPERTY_ARGS);

  void drawCurve(const GraphContentOptions& gc, QPainter& p, double dotpercm, int h,
                 Rect& r, const AbstractLine& line, int startAt, int endAt) const;

  int _currentLine;
  LineEditor * _lineEditor;
  ErrorBar _errorBar;
  CurvePointOptions * _pointOptions;
  AbstractLine * _referenceLine;
private:
  void resetLayerProperties();

  QList<AbstractLine *> _lines;
  static uint _tabLineLayer;

  inline void drawVerticalErrorBar(double x, double minY, double maxY, const GraphContentOptions& gc,
                                    QPainter& p, Rect& r, int tickLength) const;
  inline void drawHorizontalErrorBar(double y, double minX, double maxX, const GraphContentOptions& gc,
                                      QPainter& p, Rect& r, int tickLength) const;
};

class LineLayerContext: public XMLContext
{
public:
  LineLayerContext(XMLSciFigs * parent, CurvePointOptions * options) {
    _parent=parent;
    _pointOptions=options;
  }

  CurvePointOptions * options() const {return _pointOptions;}
  XMLSciFigs * parent() const {return _parent;}
private:
  XMLSciFigs * _parent;
  CurvePointOptions * _pointOptions;
};

} // namespace SciFigs

#endif // LINELAYER_H
