/***************************************************************************
 *   copyright       : (C) 2008 by Benito van der Zander                   *
 *   http://www.xm1math.net/texmaker/                                      *
 *                                                                         *
 *   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 2 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 ***************************************************************************/

#ifndef LATEXEDITORVIEW_H
#define LATEXEDITORVIEW_H
#include "mostQtHeaders.h"
#include "qdocument.h"
#include "syntaxcheck.h"
#include "grammarcheck.h"
#include "bibtexreader.h"
#include "cursorposition.h"

class QDocumentLineHandle;

class LatexDocument;
class QCodeEdit;
class QEditor;
class QLineMarkPanel;
class QLineNumberPanel;
class QSearchReplacePanel;
class QGotoLinePanel;
class QStatusPanel;
class LatexCompleter;
class SpellerUtility;
class SpellerManager;
class DefaultInputBinding;
class LatexEditorViewConfig;

struct LinkOverlay {
	enum LinkOverlayType {Invalid, RefOverlay, FileOverlay, UsepackageOverlay, BibFileOverlay, CiteOverlay};
	// for simpler access everything is public - only access for reading
	LinkOverlayType type;
	QDocumentLine docLine;
	QFormatRange formatRange;
	LatexParser::ContextType context;

	LinkOverlay() : type(Invalid), context(LatexParser::Unknown) {}
	LinkOverlay(const LinkOverlay &o);
	LinkOverlay(const QDocumentCursor &cur, LatexParser::ContextType ctx, LinkOverlayType ltype);

	bool isValid() const { return type != Invalid; }
	bool operator ==(const LinkOverlay& o) const { return (docLine == o.docLine) && (formatRange == o.formatRange); }
	QString text() const;
};

class LatexEditorView : public QWidget  {
	Q_OBJECT
public:
	
	LatexEditorView(QWidget *parent, LatexEditorViewConfig* aconfig,LatexDocument *doc=0);
	~LatexEditorView();
	
	QCodeEdit *codeeditor;
	QEditor *editor;
	
	LatexDocument* document;
	
	QDateTime lastUsageTime;

	QEditor * getEditor() const { return editor; }
	LatexDocument* getDocument() const { return document; } 
	Q_PROPERTY(QEditor* editor READ getEditor);
	Q_PROPERTY(LatexDocument* document READ getDocument);     //<- semicolon necessary due to qt bug 22992
	
	Q_INVOKABLE	QString displayName() const;

	//  FindWidget *findwidget;
	//Functions affecting the editor
	
	Q_INVOKABLE void complete(int flags);
	bool gotoLineHandleAndSearchCommand(const QDocumentLineHandle* dlh, const QSet<QString>& searchFor, const QString& id);
	Q_INVOKABLE bool gotoToLabel(const QString& label);
	Q_INVOKABLE bool gotoToBibItem(const QString& bibId);
	
	static QList<QAction *> getBaseActions();
	static void setBaseActions(QList<QAction *> baseActions);
	void setSpellerManager(SpellerManager* manager);
	bool setSpeller(const QString &name);
	Q_INVOKABLE QString getSpeller();
	
	static void setCompleter(LatexCompleter* newCompleter);
	static LatexCompleter* getCompleter();
    bool containsBibTeXId(QString id);

    void updateCitationFormats();
    void updatePackageFormats();
	
	void clearLogMarks();
	void addLogEntry(int logEntryNumber, int lineNumber, int markID);
	void setLogMarksVisible(bool visible);
	QMultiHash<QDocumentLineHandle*, int> lineToLogEntries;
	QHash<int, QDocumentLineHandle*> logEntryToLine;
	QHash<int, int> logEntryToMarkID;
	
	static int hideTooltipWhenLeavingLine;
	
	void setLineMarkToolTip(const QString& tooltip);
	void updateSettings();
	static void updateFormatSettings();
	
	QPoint getHoverPosistion(){
		return m_point;
	}
	
	static int syntaxErrorFormat;
	static int deleteFormat,insertFormat,replaceFormat;
    static int preEditFormat;
	
	void reCheckSyntax(int linenr=0, int count=-1);
	
	Q_INVOKABLE void closeCompleter();
	Q_INVOKABLE void removeBookmark(int lineNr,int bookmarkNumber);
	void removeBookmark(QDocumentLineHandle *dlh,int bookmarkNumber);
	Q_INVOKABLE void addBookmark(int lineNr,int bookmarkNumber);
	Q_INVOKABLE bool hasBookmark(int lineNr,int bookmarkNumber);
	bool hasBookmark(QDocumentLineHandle *dlh,int bookmarkNumber);
	
	QList<QDocumentCursor> autoPreviewCursor;

	static int bookMarkId(int bookmarkNumber);

	static void selectOptionInLatexArg(QDocumentCursor &cur);
    void getEnv(int lineNumber,StackEnvironment &env); // get Environment for syntax checking, number of cols is now part of env
	QDocumentCursor parenthizedTextSelection(const QDocumentCursor &cursor, bool includeParentheses=true);
    void setLatexPackageList(QSet<QString> *lst){
        latexPackageList=lst;
    }

private:
	QAction *lineNumberPanelAction, *lineMarkPanelAction, *lineFoldPanelAction, *lineChangePanelAction, 
	*statusPanelAction, *searchReplacePanelAction, *gotoLinePanelAction;
	QLineMarkPanel* lineMarkPanel;
	QLineNumberPanel* lineNumberPanel;
	QSearchReplacePanel* searchReplacePanel;
	QGotoLinePanel* gotoLinePanel;
	QStatusPanel* statusPanel;
	
	QPoint m_point;
	
	static int environmentFormat,referencePresentFormat,referenceMissingFormat,referenceMultipleFormat, citationMissingFormat, citationPresentFormat,structureFormat,
	packagePresentFormat,packageMissingFormat,packageUndefinedFormat,
	wordRepetitionFormat, wordRepetitionLongRangeFormat, badWordFormat, grammarMistakeFormat, grammarMistakeSpecial1Format, grammarMistakeSpecial2Format, grammarMistakeSpecial3Format, grammarMistakeSpecial4Format,
	numbersFormat, verbatimFormat, pictureFormat, pweaveDelimiterFormat, pweaveBlockFormat, sweaveDelimiterFormat, sweaveBlockFormat, math_DelimiterFormat;
	static QList<int> grammarFormats;
	static QVector<bool> grammarFormatsDisabled;
	static QList<int> formatsList;

    QSet<QString> *latexPackageList;
	
	friend class DefaultInputBinding;
	friend class SyntaxCheckTest;
	
	SpellerManager* spellerManager;
	SpellerUtility* speller;
	bool useDefaultSpeller;
	static LatexCompleter* completer;
	QList<CursorPosition> changePositions; //line, index
	int curChangePos;
	
	LatexEditorViewConfig* config;
	
    SyntaxCheck SynChecker;
	Environment unclosedEnv;
	
	bibtexReader *bibReader;
	QPoint lastPos;

	LinkOverlay linkOverlay;
	QCursor linkOverlayStoredCursor;

	QList<QPair<QDocumentLine, QFormatRange> > tempHighlightQueue;

	static QStringList checkedLanguages; // languages for online checking

	
private slots:
	void requestCitation(); //emits needCitation with selected text
	void openExternalFile();
	void openPackageDocumentation(QString package = QString());
	void emitChangeDiff();
	void emitGotoDefinitionFromAction();
	void emitSyncPDFFromAction();
	void lineMarkClicked(int line);
	void lineMarkToolTip(int line, int mark);
	void checkNextLine(QDocumentLineHandle *dlh,bool clearOverlay,int ticket);
	void triggeredThesaurus();
	void reloadSpeller();
	void changeSpellingDict(const QString &name);
	void copyImageFromAction();
	void saveImageFromAction();
public slots:
	void cleanBib();
	
	void jumpChangePositionBackward();
	void jumpChangePositionForward();
	
	void jumpToBookmark(int bookmarkNumber);
	bool toggleBookmark(int bookmarkNumber, QDocumentLine line = QDocumentLine());
	
	void foldEverything(bool unFold);
	void foldLevel(bool unFold, int level);
	void foldBlockAt(bool unFold, int line);
	
	void documentContentChanged(int linenr, int count);
	void lineDeleted(QDocumentLineHandle* l);
	void spellCheckingReplace();
	void spellCheckingAlwaysIgnore();
	void addListToContextMenu(const QStringList& list, bool italic, const char* action);
	void spellCheckingListSuggestions();
	void spellRemoveMarkers(const QString& newIgnoredWord);
	void mouseHovered(QPoint pos);
	bool closeSomething();
	void insertHardLineBreaks(int newLength, bool smartScopeSelection, bool joinLines);
	void viewActivated();
	void clearOverlays();
    void updateLtxCommands(bool updateAll=false);
    void setLtxCommands(const LatexParser& cmds);
	void paste();
    void insertMacro(QString macro, const QRegExp& trigger = QRegExp(), int triggerId = 0, bool allowWrite=false);

	void checkForLinkOverlay(QDocumentCursor cursor);
	bool hasLinkOverlay() const { return linkOverlay.isValid(); }
	const LinkOverlay & getLinkOverlay() const { return linkOverlay; }
private:
	void setLinkOverlay(const LinkOverlay &overlay);
	void removeLinkOverlay();
	bool isNonTextFormat(int format);
	QString extractMath(QDocumentCursor cursor);
	void showMathEnvPreview(QDocumentCursor cursor, QString command, QString environment, QPoint pos);
public slots:
	void temporaryHighlight(QDocumentCursor cur);
	void removeTemporaryHighlight();

	void displayLineGrammarErrorsInternal(int lineNr, const QList<GrammarError>& errors);
	void lineGrammarChecked(const void* doc, const void* line, int lineNr, const QList<GrammarError>& errors);
	void updateGrammarOverlays();
	
	void bibtexSectionFound(QString content);
public:
	static void setGrammarOverlayDisabled(int type, bool show);

signals:
	void lineHandleDeleted(QDocumentLineHandle* l);
	void showMarkTooltipForLogMessage(QList<int> logMessages);
	void needCitation(const QString& id);//request a new citation 
	void showPreview(const QString& text);
	void showPreview(const QDocumentCursor& c);
	void showImgPreview(const QString& fileName);
	void openFile(const QString& name);
	void openFile(const QString& baseName, const QString& defaultExtension);
	void thesaurus(int line,int col);
	void changeDiff(QPoint pt);
	void spellerChanged(const QString &name);
	void gotoDefinition(QDocumentCursor c);
	void syncPDFRequested(QDocumentCursor c);
	void bookmarkRemoved(QDocumentLineHandle *dlh);
	void bookmarkAdded(QDocumentLineHandle *dlh,int nr);
	void saveCurrentCursorToHistoryRequested();
	
	void mouseBackPressed();
	void mouseForwardPressed();
	void cursorChangeByMouse();
	void colonTyped();

	void linesChanged(QString language, const void * doc, const QList<LineInfo>& lines, int firstLineNr);
	void searchBibtexSection(QString file,QString bibId);
    void openInternalDocViewer(QString package,QString command="");
private slots:
	void lineMarkContextMenuRequested(int lineNumber, QPoint globalPos);
	void foldContextMenuRequested(int lineNumber, QPoint globalPos);
};


class BracketInvertAffector: public PlaceHolder::Affector{
public:
	virtual QString affect(const QKeyEvent *e, const QString& base, int ph, int mirror) const;
	static BracketInvertAffector* instance();
};
#endif
