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

#ifndef GRAPHCONTENT_H
#define GRAPHCONTENT_H

#include "SciFigsDLLExport.h"
#include "Axis.h"
#include "GraphContentOptions.h"
#include "GraphContentLayer.h"
#include "PaintProgress.h"

namespace SciFigs {

/* Current timing results:

  NVIDIA accelerated device

  For intensive resizing, QPixmap and QImage have the same efficiency (job is distributed differently between
  X11 and application, but global load is the same.
  For intensive repaint, draw operation took 15 ms for QImage while QPixmap is 0. QPixmap waste time in SetPixmap() (13ms).

  ATI Radeon Mobility X1600, with experimental X11 driver radeonhd without acceleted graphics

  QPixmap is rather heavy on resize...
*/
//#define GRAPHCONTENT_PIXMAP

class CoordTip;
class LayerMouseTracking;
class MouseTracking;
class LayerPainter;
class PaintProgress;

typedef QMap<GraphContentLayer *, QImage> LayerImages;

class SCIFIGS_EXPORT GraphContent : public QWidget, public PropertyItem, public XMLClass
{
  Q_OBJECT
  // Overload to mark the beginning of properties to save to XML
  Q_PROPERTY(QString objectName READ objectName WRITE setObjectName STORED true)
  // Kept only to avoid warning on loading old files
  Q_PROPERTY(QString name READ dummyPropertyString WRITE setObjectName STORED false)
  Q_PROPERTY(double printLineWeight READ dummyPropertyDouble WRITE setLineWeights STORED false)

  Q_PROPERTY(bool gridLines READ gridLines WRITE setGridLines SCRIPTABLE true)
  Q_PROPERTY(QColor gridLineColor READ gridLineColor WRITE setGridLineColor SCRIPTABLE true)
  Q_PROPERTY(bool printBitmap READ printBitmap WRITE setPrintBitmap SCRIPTABLE true)
  Q_PROPERTY(bool transparentMask READ transparentMask WRITE setTransparentMask SCRIPTABLE true)
  Q_PROPERTY(double gridLineWeight READ gridLineWeight WRITE setGridLineWeight SCRIPTABLE true)
  Q_PROPERTY(double contourWeight READ contourWeight WRITE setContourWeight SCRIPTABLE true)
  DUMMY_PROPERTIES
public:
  GraphContent(AxisWindow * parent);
  ~GraphContent();

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

  virtual void polish();

  void appendLayer(GraphContentLayer * layer);
  void prependLayer(GraphContentLayer * layer);
  void removeLayer(GraphContentLayer * layer);
  void moveLayerUp(GraphContentLayer * layer);
  void moveLayerDown(GraphContentLayer * layer);

  AxisWindow * graph() const {return reinterpret_cast<AxisWindow *>(parent());}

  const GraphContentOptions& options() const {return _options;}

  Scale& scaleX() {return _options.scaleX();}
  Scale& scaleY() {return _options.scaleY();}
  const Scale& constScaleX() const {return _options.scaleX();}
  const Scale& constScaleY() const {return _options.scaleY();}

  void paintMask(QPainter& p);
  void print (QPainter& p, double dotpercm, int w, int h, bool mask);

  bool gridLines() const {return _options.gridLines();}
  void setGridLines(bool gl) {_options.setGridLines(gl);}

  const QColor& gridLineColor() const {return _options.gridLineColor();}
  void setGridLineColor(const QColor& c) {_options.setGridLineColor(c);}

  double gridLineWeight() const {return _options.gridLineWeight();}
  void setGridLineWeight(double lw) {_options.setGridLineWeight(lw);}

  double contourWeight() const {return _options.contourWeight();}
  void setContourWeight(double lw) {_options.setContourWeight(lw);}

  void setLineWeights(double lw);  // kept for compatibility

  bool transparentMask() const {return _options.transparentMask();}
  void setTransparentMask(bool tm) {_options.setTransparentMask(tm);}

  bool printBitmap() const {return _options.printBitmap();}
  void setPrintBitmap(bool sbmp) {_options.setPrintBitmap(sbmp);}

#ifdef GRAPHCONTENT_PIXMAP
  QPixmap * pixmap() {if(_pixmap.isNull()) return nullptr; else return &_pixmap;}
#else
  QImage * pixmap() {if(_pixmap.isNull()) return nullptr; else return &_pixmap;}
#endif
  QAction * action(QString actionName);
  QAction * addAction(QString actionName);
  void zoomIn (const QPoint& c);
  Rect boundingRect() const;
  void swapAxes() {_options.swapAxes();}

  static void init();
  static void clear();
  QString coordinateTipText(const QPoint& mousePos);
  void delayPainting();

  inline void setProgressMaximum(int value);
  inline void setProgressValue(int value);
  void setProgressEnd();

  void addProperties(PropertyProxy * pp);
  void addProperties(GraphContentLayer * layer);
  void removeProperties(PropertyProxy * pp);
  virtual void properties(PropertyWidget * w) const;
  virtual void setProperty(uint wid, int pid, QVariant val);

  int layerCount() {return _layers.count();}
  GraphContentLayer * findLayer(QString tagName, QString layerName=QString(), int startIndex=0);
public slots:
  void zoom();
  void zoomIn();
  void browse();
  void saveLayers(QString fileName=QString());
  void appendLayers(QString fileName=QString());
  void prependLayers(QString fileName=QString());
  void copyLayers();
  void pasteLayers();
  void deepUpdate(int fromLayer=0);
  void showProperties();
private:
  friend class GraphContentLayer;
  friend class LayerPropertiesItem;
  friend class CoordTip;
  // Events Handlers
  virtual bool event(QEvent * e);
  virtual void keyPressEvent(QKeyEvent * e);
  virtual void keyReleaseEvent(QKeyEvent * e);
  virtual void mouseDoubleClickEvent(QMouseEvent * e);
  virtual void mousePressEvent(QMouseEvent * e);
  virtual void mouseReleaseEvent(QMouseEvent * e);
  virtual void mouseMoveEvent(QMouseEvent * e);
  virtual void wheelEvent(QWheelEvent * e);
  virtual void leaveEvent(QEvent *);
  virtual void enterEvent(QEvent *);
  virtual void paintEvent(QPaintEvent * e);
  virtual void resizeEvent(QResizeEvent *);

  void setDefaultCursor();
  void addActions();

  enum TrackingModes{Zoom=0, Browse};
  void beginMouseTracking(const LayerMouseTracking& layer);
  void endMouseTracking(GraphContentLayer * layer, int id);
  bool isMouseTracking(const GraphContentLayer *layer, int id) const;
  MouseTracking * _mouseTracking;

  // List of all layers
  QList<GraphContentLayer *> _layers;

  int indexOf(GraphContentLayer * layer) {return _layers.indexOf(layer);}
  GraphContentLayer * layer(int index) {return _layers.at(index);}

  static CoordTip * _coordTip;

  // Paint operations
  void resizePixmap();
#ifdef GRAPHCONTENT_PIXMAP
  QPixmap _pixmap;
#else
  QImage _pixmap;
#endif
  LayerImages _layerImages;
  QElapsedTimer _paintEventTiming;
  QTimer _paintEventDelay;
  int _paintDepth;
  static LayerPainter * _layerPainter;
  PaintProgress * _progress;

  // Options
  GraphContentOptions _options;

  // Smoother mouse move engine
  QPoint _mouseMovePoint;
  Qt::MouseButtons _mouseMoveButtons;
  Qt::KeyboardModifiers _mouseMoveModifiers;
  QTimer _mouseMoveDelay;
  static QCursor * _defaultCursor;

  static uint _categoryGraphic, _categoryLayers, _tabGraphicFormat, _tabGraphicLayers;
protected:
  virtual void xml_writeProperties(XML_WRITEPROPERTIES_ARGS) const;
  virtual void xml_writeChildren(XML_WRITECHILDREN_ARGS) const;
  virtual XMLMember xml_member(XML_MEMBER_ARGS);
  virtual void xml_polishChild(XML_POLISHCHILD_ARGS);
  virtual bool xml_polish(XML_POLISH_ARGS);
  virtual bool xml_setProperty(XML_SETPROPERTY_ARGS) {return qobject_setProperty(this, memberID, tag, attributes, content, context);}
private slots:
  void delayedMouseMoveEvent();
  void setPixmap(QImage image, LayerImages layerImages);
  void paintProgress();
signals:
  void zoomIn(double, double, double, double);
  void zoomOut();
  void browse(QRect& r);
  void mouseTrackingBegin();
  void mouseTrackingEnd();
  void mouseMoved(QPoint, Qt::MouseButtons, Qt::KeyboardModifiers);
  void mouseInside(bool);
};

inline void GraphContent::setProgressMaximum(int value)
{
  _progress->setMaximum(value);
}

inline void GraphContent::setProgressValue(int value)
{
  _progress->setValue(value);
}

} // namespace SciFigs

#endif // GRAPHCONTENT_H
