/* BEGIN software license
 *
 * msXpertSuite - mass spectrometry software suite
 * -----------------------------------------------
 * Copyright(C) 2009,...,2018 Filippo Rusconi
 *
 * http://www.msxpertsuite.org
 *
 * This file is part of the msXpertSuite project.
 *
 * The msXpertSuite project is the successor of the massXpert project. This
 * project now includes various independent modules:
 *
 * - massXpert, model polymer chemistries and simulate mass spectrometric data;
 * - mineXpert, a powerful TIC chromatogram/mass spectrum viewer/miner;
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program 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 General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
 *
 * END software license
 */


#ifndef SEQUENCE_EDITOR_GRAPHICS_VIEW_HPP
#define SEQUENCE_EDITOR_GRAPHICS_VIEW_HPP


/////////////////////// Qt includes
#include <QGraphicsView>
#include <QLineEdit>


/////////////////////// Local includes
#include <massxpert/nongui/Polymer.hpp>
#include <massxpert/nongui/ChemEntVignette.hpp>
#include <massxpert/gui/SequenceSelection.hpp>

namespace msXpSmassXpert
{

enum MxtCursorLinePosition
{
  START_OF_LINE,
  END_OF_LINE
};

enum MxtCardinalDirection
{
  CENTER,
  NORTH,
  NORTH_EAST,
  EAST,
  SOUTH_EAST,
  SOUTH,
  SOUTH_WEST,
  WEST,
  NORTH_WEST
};


class SequenceEditorWnd;
class MonomerCodeEvaluator;
class Coordinates;


class SequenceEditorGraphicsView : public QGraphicsView
{
  Q_OBJECT

  private:
  // Unallocated, this pointer points to the m_polymer member of the
  // parent instance into which this graphics view packed. Usually
  // that is the SequenceEditorWnd sequence editor window were
  // this view is the m_editorView member.
  QPointer<Polymer> mp_polymer;
  SequenceEditorWnd *mp_editorWnd;
  MonomerCodeEvaluator *mpa_monomerCodeEvaluator;

  bool m_sequenceDrawn;

  int m_columns;
  int m_rows;

  int m_lastClickedVignette;

  SequenceSelection *mpa_selection;

  bool m_mouseDragging;
  bool m_ongoingMouseMultiSelection;
  bool m_ongoingKeyboardMultiSelection;

  QPointF m_selectionFirstPoint;
  QPointF m_selectionSecondPoint;

  int m_selectionFirstIndex;
  int m_selectionSecondIndex;

  double m_xScaleFactor;
  double m_yScaleFactor;

  int m_leftMargin;

  int m_requestedVignetteSize; // the width in fact.

  QSvgRenderer *mpa_cursorRenderer;
  QGraphicsSvgItem *mpa_cursorVignette;

  // This list will hold pointers to allocated
  // ChemEntVignette items, but we do not possess
  // these. The possessor of these items is the scene that is a member
  // of the sequence editor window. We have this list that somehow
  // duplicates the internal scene list(that is returned by the
  // items() call) because we needed to be able to access the graphics
  // items in the polar order of the polymer sequence(the items()
  // call returns an un-ordered list of items).
  QList<ChemEntVignette *> m_monomerVignetteList;

  // This list will hold pointers to allocated QGraphicsTextItem
  // items, but we do not possess these. The possessor of these items
  // is the scene that is a member of the sequence editor window. We
  // have this list that somehow duplicates the internal scene list
  //(that is returned by the items() call) because we needed to be
  // able to access the text items apart from all the other
  // items. Indeed, these items are the text labels that are displayed
  // in the left margin area to indicate the position of the monomer
  // in the polymer sequence at each beginning of scene line.
  QList<QGraphicsTextItem *> m_labelList;

  void focusOutEvent(QFocusEvent *);


  protected:
  void paintEvent(QPaintEvent *);
  void resizeEvent(QResizeEvent *);

  void mouseMoveEvent(QMouseEvent *);
  void mousePressEvent(QMouseEvent *);
  void mouseReleaseEvent(QMouseEvent *);

  void keyPressEvent(QKeyEvent *);
  void keyReleaseEvent(QKeyEvent *);

  // KEYBOARD HANDLERS ///////////////////////////////////////////////////
  void MoveToPreviousChar(QKeyEvent *);
  void MoveToNextChar(QKeyEvent *);
  void MoveToPreviousLine(QKeyEvent *);
  void MoveToNextLine(QKeyEvent *);
  void MoveToPreviousPage(QKeyEvent *);
  void MoveToNextPage(QKeyEvent *);
  void MoveToStartOfLine(QKeyEvent *);
  void MoveToEndOfLine(QKeyEvent *);
  void MoveToStartOfDocument(QKeyEvent *);
  void MoveToEndOfDocument(QKeyEvent *);
  void SelectNextChar(QKeyEvent *);
  void SelectPreviousChar(QKeyEvent *);
  void SelectNextLine(QKeyEvent *);
  void SelectPreviousLine(QKeyEvent *);
  void SelectNextPage(QKeyEvent *);
  void SelectPreviousPage(QKeyEvent *);
  void SelectStartOfLine(QKeyEvent *);
  void SelectEndOfLine(QKeyEvent *);
  void SelectStartOfDocument(QKeyEvent *);
  void SelectEndOfDocument(QKeyEvent *);
  void SelectAll(QKeyEvent *);

  void keyPressEventKeyEscape(QKeyEvent *);
  void keyPressEventKeyReturn(QKeyEvent *);
  void keyPressEventKeyBackspace(QKeyEvent *);
  void keyPressEventKeyDelete(QKeyEvent *);
  void keyPressEventAlpha(QKeyEvent *);


  public:
  SequenceEditorGraphicsView(SequenceEditorWnd * = 0);
  ~SequenceEditorGraphicsView();

  bool m_kbdShiftDown;
  bool m_kbdCtrlDown;
  bool m_kbdAltDown;

  int requestedVignetteSize();
  int leftMargin();
  int columns();
  int rows();

  int lastClickedVignette();

  void setPolymer(Polymer *);
  const Polymer *polymer() const;

  void setEditorWnd(SequenceEditorWnd *);

  void setMonomerCodeEvaluator(MonomerCodeEvaluator *evaluator);

  void updateColumns();
  void updateMonomerPosition(int);
  void updateVScrollBar();
  void updateSceneRect();

  int vignetteIndex(const QPointF &);
  QPointF vignetteLocation(int, MxtCardinalDirection = NORTH_WEST);

  void setSelection(const Coordinates &coordinates, bool, bool);
  void setSelection(const CoordinateList &, bool, bool);
  void setSelection(int start, int end, bool, bool);

  void resetSelection();
  void resetSelectionButLastRegion();
  void resetMultiSelectionRegionsButFirstSelection();

  bool selectionIndices(CoordinateList * = 0);

  void setOngoingMouseMultiSelection(bool);

  // SCENE-DRAWING FUNCTIONS /////////////////////////////////////////////
  bool renderCursor();

  bool scaleCursor();

  bool positionCursor(MxtCursorLinePosition = START_OF_LINE);
  bool positionCursor(const QPointF &, MxtCursorLinePosition = START_OF_LINE);
  bool positionCursor(double, double, MxtCursorLinePosition = START_OF_LINE);
  bool positionCursor(int, MxtCursorLinePosition = START_OF_LINE);
  bool positionCursor(const RegionSelection &,
                      MxtCursorLinePosition = START_OF_LINE);

  ChemEntVignette *renderVignette(const Monomer &);

  bool modifyVignetteAt(int, Modif *);
  bool unmodifyVignetteAt(int, Modif *);

  bool crossLinkVignetteAt(int, CrossLinker *);
  bool uncrossLinkVignetteAt(int, CrossLinker *);

  bool removeVignetteAt(int);
  bool renderVignettes();
  bool scaleVignette(ChemEntVignette *);
  bool scaleVignettes();
  bool positionVignette(ChemEntVignette *, int);
  bool positionVignettes();

  int drawSequence(bool = false);
  bool updateSequence();

  // POLYMER SEQUENCE-MODIFYING FUNCTIONS ///////////////////////////////
  int insertMonomerAt(const Monomer *, int, bool = false);
  int insertMonomerAtPoint(const Monomer *, bool = false);
  int insertSequenceAtPoint(Sequence &);

  int removeMonomerAt(int, bool = false);
  bool prepareMonomerRemovalAt(int);

  int removeSelectedOligomer();
  int removeSequenceRegion(int, int);


  public slots:
  ////////////////////////////// SLOTS ///////////////////////////////
  void vScrollBarActionTriggered(int);
  bool requestVignetteSize(int);
};

} // namespace msXpSmassXpert


#endif // SEQUENCE_EDITOR_GRAPHICS_VIEW_HPP
