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

#ifndef GRAPHICSHEET_H
#define GRAPHICSHEET_H

#include <QtGui>

#include "GraphicObjectList.h"
#include "SelectionWidget.h"

namespace SciFigs {

class GraphicObject;
class SelectionWidget;
class AxisWindow;
class GraphContent;
class TextEdit;
class OrderTip;
class GraphicSheetProperties;
class SheetSelectionWidget;

class SCIFIGS_EXPORT GraphicSheet : public QScrollArea, public PropertyContext, 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(QString objectList READ dummyPropertyString WRITE setDummyProperty STORED false)
  Q_PROPERTY(QString objectOrder READ dummyPropertyString WRITE setDummyProperty STORED false)
  // Use only in scripts
  Q_PROPERTY(int transparency READ transparency WRITE setTransparency)
  Q_PROPERTY(bool transparentMask READ transparentMask WRITE setTransparentMask)
  DUMMY_PROPERTIES
public:
  GraphicSheet(QWidget *parent=nullptr);
  ~GraphicSheet();

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

  void clear(bool force);
  QString objectList() const;
  void setObjectList(QString list);
  void setObjectOrder(QString list);
  // Count the palette currently in the sheet
  int paletteCount();
  bool removeObject(GraphicObject * obj, bool force);

  AxisWindow * addGraph();
  TextEdit * addText();
  void addObject(GraphicObject * obj, bool show=true);
  void showObject(GraphicObject * obj);

  // Set status bar where to show messages
  void setStatusBar(QStatusBar * s) {_statusBar=s;}
  QStatusBar * statusBar() {return _statusBar;}
  bool isOrderIndex() const {return _orderIndex >= 0;}
  void setOrderIndex(GraphicObject * obj);
  // Caluclate max right and bottom coordinate of child graphs and resize content
  void autoResizeContent();
  double printBottom();
  double printRight();
  // Find maximum printer resolution in all graphs (!! in dpi !!)
  int maximumResolution();
  template <typename T> inline QList<T *> findChildren() const;
  template <typename T> QList<T *> selectedObjects() const;
  GraphicObject * activeObject(const char * inherits=0);
  void print(QPrinter& printer);
  Point2D currentOrigin();

  void addFileActions(QMenu * m, QToolBar * tb, bool shortcuts=true);
  void addEditActions(QMenu * m, QToolBar * tb, bool shortcuts=true);
  void addFormatActions(QMenu * m, bool shortcuts=true);
  void addInsertActions(QMenu * m, QToolBar * tb, bool shortcuts=true);
  void addMenu(QMenu * m);

  SelectionWidget * addSelection(GraphicObject * obj);

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

  void setTransparency(int val) {_transparency=val;}
  void setTransparentMask(bool val);

  int transparency() const {return _transparency;}
  bool transparentMask() const {return _transparentMask;}

  virtual QSize minimumSizeHind() const {return QSize(100,100);}

  bool isMouseTrackingActive() const;
  const QRect& mouseTrackingRect() const {return *_mouseTrackingRect;}

  GraphicObjectList objects() const {return findChildren<GraphicObject>();}
  GraphicObjectList selectedObjects() const {return selectedObjects<GraphicObject>();}
protected:
  virtual void mousePressEvent (QMouseEvent *e);
  virtual void mouseReleaseEvent (QMouseEvent *e);
  virtual void mouseMoveEvent(QMouseEvent *e);
  virtual void resizeEvent(QResizeEvent *e);
  void addActions();
  void addRecentFile(const QString& fileName);
private:
  SelectionWidget * _currentActiveSelection;
  void printSvg(const QString& fileName, int dpi);
  void printSize(double& x0, double& y0, double& x1, double& y1,
                  double& mx0, double& my0, double& mx1, double& my1);

  bool _transparentMask;
  int _transparency;

  int _orderIndex;
  // Smartly remember the last loaded file
  QString _currentFile;
  // Smoother drag engine
  QTimer _dragDelay;
  /* Pointer to a status bar where to show messages
   (allways check if non null before using it!!) */
  QStatusBar * _statusBar;
  // List of objects added during xml restore
  QList<GraphicObject *> _loadedObjects;
  QRect * _mouseTrackingRect;
  QPoint _mouseTrackingPoint;
  SheetSelectionWidget * _selection;

  static uint _category, _tabPrint;
signals:
  void currentFileChanged(const QString& fileName);
  void activeSelectionChanged(GraphicObject * obj);
private slots:
  void dragObjects(QPoint p);
  void dragObjectsDelayed();
  void showOpenRecentMenu();
  void openRecentFile();
  void openMostRecentFile();
  bool scrollSelection();
public slots:
  void clear() {clear(false);}
  void fileNew();
  void fileOpen();
  bool fileOpen(QString fileName, double dx=0, double dy=0);
  void fileSave();
  void fileSaveAs();
  void fileSave(QString fileName);
  void setPreferences ();

  void undo();
  void redo();
  void cut();
  void copy();
  void copyImage();
  void paste();

  void selectAll();
  bool selectAll(QString actionTitle);
  void unselectAll() {selectObjects(nullptr, Qt::NoModifier);}
  void selectObjects(const QRect& r, Qt::KeyboardModifiers m=Qt::NoModifier);
  void selectObjects(GraphicObject * obj, Qt::KeyboardModifiers m=Qt::NoModifier);
  void select(GraphicObject * obj) {selectObjects(obj, Qt::NoModifier);}
  void addSelect(GraphicObject * obj)  {selectObjects(obj, Qt::ShiftModifier);}
  void selectNextChild();
  void addSelectNextChild();

  GraphicObject * addObject();
  bool removeObject(GraphicObject * obj) {return removeObject (obj, false);}
  void removeObjects(const QString& type, bool force);
  GraphicObject * object(QString objectName);
  GraphicObject * object(int index);

  void moveObject(GraphicObject * obj=0);
  void moveObjects(Point2D delta);
  void resizeObject();
  void startDragging() {selectedObjects().startDragging();}
  void exportFile(QString fileName=QString(), QString fileFormat=QString(), int dpi=0);
  void exportImage(QString fileName=QString(), QString imageFormat=QString(), int dpi=0);
  QPixmap image(int dpi=0);
  void print(int dpi=0);
  void print(bool outputToFile, QString name, int dpi);
  void updatePageLimits(QPrinter& p);
  void copyMakeUp();
  void pasteMakeUp();
  void saveMakeUp(QString fileName=QString());
  void restoreMakeUp(QString fileName=QString());
  void saveLayers(QString fileName=QString());
  void appendLayers();
  virtual void update();
  virtual void deepUpdate();
  void showOrderIndex(bool isOn);
  void alignLeft() {alignX(0.0);}
  void alignHCenter() {alignX(0.5);}
  void alignRight() {alignX(1.0);}
  void alignTop() {alignY(0.0);}
  void alignVCenter() {alignY(0.5);}
  void alignBottom() {alignY(1.0);}
  void alignX(double localPosition);
  void alignY(double localPosition);
  void alignGrid();
  void raiseSelection();
  void lowerSelection();
  void showProperties(uint category=PropertyProxy::invalidId);
  void groupObjects();
  void ungroupObjects();
protected:
  virtual bool xml_polish(XML_POLISH_ARGS);
  virtual void xml_polishChild(XML_POLISHCHILD_ARGS);
  virtual void xml_writeChildren(XML_WRITECHILDREN_ARGS) const;
  virtual XMLMember xml_member(XML_MEMBER_ARGS);
  virtual bool xml_setProperty(XML_SETPROPERTY_ARGS) {return qobject_setProperty(this, memberID, tag, attributes, content, context);}
};


template <typename T>
inline QList<T *> GraphicSheet::findChildren() const
{
  return widget()->findChildren<T *>(QString(), Qt::FindDirectChildrenOnly);
}

template <typename T>
QList<T *> GraphicSheet::selectedObjects() const
{
  QList<T *> wList;
  QList<SelectionWidget *> wSelList=findChildren<SelectionWidget>();
  SelectionWidget * wSel;
  foreach(wSel, wSelList) {
    if(wSel->state()!=SelectionWidget::Hoover) {
      GraphicObject * w=wSel->widget();
      T * castedW=qobject_cast<T *>(w);
      if(castedW) {
        wList << castedW;
      }
    }
  }
  return wList;
}

} // namespace SciFigs

#endif // GRAPHICSHEET_H
