/****************************************************************************
 **
 ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
 ** All rights reserved.
 ** Contact: Nokia Corporation (qt-info@nokia.com)
 **
 ** This file is part of the examples of the Qt Toolkit.
 **
 ** $QT_BEGIN_LICENSE:LGPL$
 ** Commercial Usage
 ** Licensees holding valid Qt Commercial licenses may use this file in
 ** accordance with the Qt Commercial License Agreement provided with the
 ** Software or, alternatively, in accordance with the terms contained in
 ** a written agreement between you and Nokia.
 **
 ** GNU Lesser General Public License Usage
 ** Alternatively, this file may be used under the terms of the GNU Lesser
 ** General Public License version 2.1 as published by the Free Software
 ** Foundation and appearing in the file LICENSE.LGPL included in the
 ** packaging of this file.  Please review the following information to
 ** ensure the GNU Lesser General Public License version 2.1 requirements
 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
 **
 ** In addition, as a special exception, Nokia gives you certain additional
 ** rights.  These rights are described in the Nokia Qt LGPL Exception
 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
 **
 ** GNU General Public License Usage
 ** Alternatively, this file may be used under the terms of the GNU
 ** General Public License version 3.0 as published by the Free Software
 ** Foundation and appearing in the file LICENSE.GPL included in the
 ** packaging of this file.  Please review the following information to
 ** ensure the GNU General Public License version 3.0 requirements will be
 ** met: http://www.gnu.org/copyleft/gpl.html.
 **
 ** If you have questions regarding the use of this file, please contact
 ** Nokia at qt-info@nokia.com.
 ** $QT_END_LICENSE$
 **
 ****************************************************************************/

#ifndef CODEEDITOR_H
#define CODEEDITOR_H

#include <QPlainTextEdit>
#include <QObject>
#include "highlighter.h"

#if defined Q_WS_WIN || defined Q_OS_WIN
#define FONTFAM "Lucida Console"
#elif defined Q_WS_MAC || defined Q_OS_MAC
#define FONTFAM "Monaco"
#else
#define FONTFAM "Droid Sans Mono"
#endif

QT_BEGIN_NAMESPACE
class QPaintEvent;
class QResizeEvent;
class QSize;
class QCompleter;
class QWidget;
class ChGL;
QT_END_NAMESPACE

class LineNumberArea;
class AfixHighlightArea;

/*! \brief CodeEditor is the editor of shelXle featuring syntax higlighter, code completer, LineNumberArea, AfixHighlightArea and Part Higlighter.
 *
 *
 */
class CodeEditor : public QPlainTextEdit {
  Q_OBJECT

  public:
    CodeEditor(QWidget *parent = 0);
    ~CodeEditor();
    QList<int> sfac;//!<List of Scattering factors.
    int sortierWeise;
    int midCursorpos;
    bool ListFile;
    bool uCanSeeMe;
    QString unitAlt, unitNeu;
    //QSyntaxHighlighter *highlighter;//!< Highlighter is the syntax higlighter. 
    Highlighter *highlighter;//!< Highlighter is the syntax higlighter. 
    void setCompleter(QCompleter *c);//!< setCompleter sets the QCompleter for the editor.
    QCompleter *completer() const;//!< completer is the QCompleter
    QStringList blocks; //!< blocks is a QStringList containing the lines of the editor.
    QList<int> errorInLine; //!< A list of line numbers with syntax errors.

    void lineNumberAreaPaintEvent(QPaintEvent *event);//!< The paint event of LineNumberArea.
    void afixHighlightAreaPaintEvent(QPaintEvent *event);//!< The paint event of AfixHighlightArea.
    int lineNumberAreaWidth();//!< calulates the width of the LineNumberArea.
    void diffTo(QString org);//!< A simple line diff used for the SaveHistoryWidget. Changes back ground color of differering lines into orange. @param org The original file content. 
    QList<int> parenthesis;//!< List of lines.  If the line in an afix environment the value is greater than zero. 
    QList<int> parenthesis2;//!< List of lines. The value is the current part number.
    //    QList<bool> parenthesis3;//!< List of lines. If it is OK to have nested afixes like in afix 66 it is true.
    QList<bool> comment;//!< List of all lines true if they are comments
    QList<double> fv;//!< List of 'Free Variables' in the SHELX res or ins file. 
    int fvMinLine;//!< fvMinLine specifies the line number of the FVAR istruction. 
    QGroupBox  *suchbox;
    QLineEdit *searchLE, *replace;
    QToolButton *hidesearch;
    QToolButton *prev,*next,*replaceButton,*replacePButton,*replaceAButton; 
    QCheckBox *wholeLine;
    QGridLayout *slt;
    QComboBox *resiFinder;
    QString sortLabelList(CEnvironment &asymm, MyAtom &tatze);
    void searchchanged(bool current,bool back);
  //void searchchanged2(bool current,bool back);
signals:
    void findInStructure(const QString &);//!< findInStructure is emitted by a context menu to select and center an atom in the OpenGL representation of the structure.
    void openIncludeFile(const QString &);
    void electInStructure(const QString &);//!< electInStructure is emitted by a context menu to select atoms found in the editor text selection in the OpenGL representation.
    void deleteSelected();//!< deleteSelected is emitted by a context menu to select and delete atoms found in the editor text selection in the OpenGL representation.
    void saveMe(bool spell, bool loadafter);
    void updateLabel();//!< the rename mode is updated 
protected:
    void resizeEvent(QResizeEvent *event);
    bool viewportEvent(QEvent *event);
    void keyPressEvent(QKeyEvent *e);
    void focusInEvent(QFocusEvent *e);
    void contextMenuEvent(QContextMenuEvent *event);
public slots:
    void vis(bool b){ uCanSeeMe=b; }
    void updateLineNumberAreaWidth(int newBlockCount);//!< updateLineNumberAreaWidth sets the new width of LineNumberArea for the given amount of lines newBlockCount. @param newBlockCount number of lines in the editor.
    void insertAnis();//!< inserts ANIS instruction into the file.
    void insertActa();//!< inserts ACTA instruction into the file.
    void insertList6();//!< inserts a LIST 6 instruction into the file.
    void insertBind();//!< inserts a BIND instruction into the file.
    void insertFree();//!< inserts a FREE instruction into the file.
    void findResi(QString);//!<Searches a Residue via a string like "RESI 22 ALA" or "RESI ALA 22" in the editor and selects all atoms with the same residue number (eg: 22).
    void findText();//!<Find functionality of search and replace in the editor.
    void hideSearch();//!< Hides the search and replace widget for the editor.
    void replaceAll();//!<replace all functionality of search and replace in the editor.
    void replaceNext();//!<replace next functionality of search and replace in the editor.
    void replacePrev();//!<replace previous functionality of search and replace in the editor.
    void showSearch();//!< shows the search and repleace for the editor.
    void changeSortierWeise(QAction* action);//!<Changes the sorting option to action->data. @param action the calling QAction.
    void sortAtoms();//!< sorts atoms in file acording to the sort option.  
    void sortSelectedRegion();//!< sorts all atoms found in selected text in the structure @params info seleted text.
    void expandGreaterThan();//!< some SHELXL re- or constrainst use > to specify a range of atoms this is a problem for sorting atoms
    void findNext();//!<Find next (F3) functionality of search and replace in the editor. 
    void findPrev();//!<Find previous functionality of search and replace in the editor.
    void weedEmptySfacs();//!< weeds out unused scattering factors 
    void updateUnit();//!< the unit instruction gets the true amount of atoms per type
    void dispFromWave();//!<calculates f', f" and mu for the given wavelength and inserts DISP lines for each SFAC entry.
    void resiFinderDestroyed();
    void decreaseEdtiorFont();//!<Decreases the editor font by one point.
    void increaseEdtiorFont();//!< Increases the editor font by one point.
    void jumpToError();//!< the cursor points to the first syntax error in the file.a
    void jumpToAtom(int index);//!< if rename mode is visible the atom at index gets renamed if not the cursor of the editor is pointed to the specified atom.
    void omitsome(const QString &s);//!< insetrts a 'OMIT h k l\n' string in the res file.  
    void insertDFIX(double value, double esd, QList<MyAtom> selected, QString resiSpec=""); //!< Insert DFIX restraint into ins file
    void insertDANG(double value, double esd, QList<MyAtom> selected, QString resiSpec=""); //!< Insert DANG restraint into ins file
    void insertFLAT(double esd, QList<MyAtom> selected, QString resiSpec=""); //!< Insert FLAT restraint into ins file
    void insertEXYZ(QList<MyAtom> selected, QString resiSpec=""); //!< Insert EXYZ restraint into ins file
    void insertEADP(QList<MyAtom> selected, QString resiSpec=""); //!< Insert EADP restraint into ins file
    void insertDELU(double esd1, double esd2, QList<MyAtom> selected, QString resiSpec=""); //!< Insert DELU restraint into ins file
    void insertSIMU(double esd1, double esd2, double dmax, QList<MyAtom> selected, QString resiSpec=""); //!< Insert SIMU restraint into ins file
    void insertISOR(double esd1, double esd2, QList<MyAtom> selected, QString resiSpec=""); //!< Insert ISOR restraint into ins file
    void insertRIGU(double esd1, double esd2, QList<MyAtom> selected, QString resiSpec=""); //!< Insert RIGU restraint into ins file
    void insertCHIV(double vol, double esd1, QList<MyAtom> selected, QString resiSpec=""); //!< Insert CHIV restraint into ins file
    void insertANIS(QList<MyAtom> selected); //!< Insert ANIS for selected atoms
    void updateLineNumberArea(const QRect &, int);//!< updateLineNumberArea in the curent viewport.
    void updateAfix();//!< updateAfix updates the parenthesis list for the AfixHighlightArea. 
    void updateWght();//!< the WGHT instruction is updated from the back of the res file
    void insertCompletion(const QString &completion);//!< insertCompletion inserts the text selected in the completer. @param completion selected text of the completer.
    void searchInStructure();//!< Select and center an atom in the OpenGL representation of the structure.
    void openAnIncludeFile();
    void selectInStructure();//!< Select atoms found in the editor text selection in the OpenGL representation.
    void lineNumberToggled(QMouseEvent *event);//!< when the LineNumberArea is clicked the comment state of the secified line is toggled.
    void remark(int line);//!< toggles the comment state of the secified line. @param line The line number in file
    void toggleRemarks();//!< toggleRemarks toggles the comment state of the selected lines.
    void setgl(ChGL *g){
      chgl=g;
    }//!< setgl passes the ChGL widget to the CodeEditor

private:
    QString selectedRestraintsAtoms(QString buffer, QList<MyAtom> selected, QString resiSpec, bool exclude_H=false);
    QString textUnderCursor() const;
    QWidget *lineNumberArea;
    QCompleter *c;
    QWidget *afixHighlightArea;
    ChGL *chgl;
};

/////////////////////////////////////////////////
/*! \brief AfixHighlightArea is a colored bar right of the LineNumberArea to indicate if the line is in a AFIX environment.
 *
 *  This is just a dummy class to reimplement the paintEvent which is impemented in CodeEditor.
 *
 */
class AfixHighlightArea : public QWidget{
  public:
    AfixHighlightArea(CodeEditor *editor) : QWidget(editor){
      codeEditor = editor;
    }
    QSize sizeHint() const {
      return QSize(5,0);
    }
  protected:
    void paintEvent(QPaintEvent *event){
      codeEditor->afixHighlightAreaPaintEvent(event);
    }//!< calls afixHighlightAreaPaintEvent().

  private:
    CodeEditor *codeEditor;
};
/////////////////////////////////////////////////
/*! \brief LineNumberArea is a area with line numbers left of the CodeEditor.
 *
 * This is just a dummy class to reimplement the paintEvent and mousePressEvent which are impemented in CodeEditor.
 */
class LineNumberArea : public QWidget{
  public:
    LineNumberArea(CodeEditor *editor) : QWidget(editor) {
      codeEditor = editor;
    }

    QSize sizeHint() const {
      return QSize(codeEditor->lineNumberAreaWidth(), 0);
    }

  protected:
    void paintEvent(QPaintEvent *event) {
      codeEditor->lineNumberAreaPaintEvent(event);
    }//!< calls lineNumberAreaPaintEvent().
    void mousePressEvent ( QMouseEvent * event ){
      codeEditor->lineNumberToggled(event);
    }//!< calls lineNumberToggled().

  private:
    CodeEditor *codeEditor;
};

#endif
