/***************************** LICENSE START ***********************************

 Copyright 2012 ECMWF and INPE. This software is distributed under the terms
 of the Apache License version 2.0. In applying this license, ECMWF does not
 waive the privileges and immunities granted to it by virtue of its status as
 an Intergovernmental Organization or submit itself to any jurisdiction.

 ***************************** LICENSE END *************************************/

#ifndef MacroEdit_H
#define MacroEdit_H

#include <iostream>
#include <MvRequest.h>
#include <MvQDragDrop.h>
#include "ui_MacroEdit.h"
#include "Highlighter.h"
#include "LanguageHelper.h"
#include "LanguageHelperFactory.h"
#include "VerbFunctionHelpDialog.h"
#include "MacroRunOptions.h"
#include "TabsSettings.h"

#include <QStandardItemModel>
#include <QPixmap>
#include <QPalette>
#include <QLabel>
#include <QTimer>
#include <QTime>
#include <QThread>

using namespace std;

class FindTextDialog;
class GotoLineDialog;
class TabsDialog;
class RunDialog;
class FunctionListDialog;
class CodeTemplateDialog;



template<class T>
class Handle {
	T* ptr_;
public:
      
	Handle(T* ptr = 0) : ptr_(ptr) 
		{ /*if(ptr_) ptr_->attach();*/ }

	virtual ~Handle()   
		{ /*if(ptr_) ptr_->detach();*/ }

	Handle(const Handle<T>& other): ptr_(other.ptr_) 
		{ /*if(ptr_) ptr_->attach();*/ }

	Handle<T>& operator=(const Handle<T>& other) 
	{
		if(ptr_ != other.ptr_)
		{
			/*if(ptr_) ptr_->detach();*/
			ptr_ = other.ptr_;
			/*if(ptr_) ptr_->attach();*/
		}
		return *this;
	}

	T* operator->() const { return ptr_; }
	T& operator*()  const { return *ptr_; }

	operator T*() const { return ptr_; }

	bool operator<(const Handle<T>& other) const
		{ return ptr_ < other.ptr_; }
	
};




//class Request;

//class ReplyObserver : public virtual Counted  {
class ReplyObserver : public QObject{

Q_OBJECT

public:

	ReplyObserver();
	virtual ~ReplyObserver(); // Change to virtual if base class

	virtual void reply(const MvRequest&,int) = 0;
	virtual void progress(const MvRequest&) = 0;
	virtual void message(const string&) = 0;
    void attach();   //ir
    void detach();   //ir

protected:

	void callService(const string&,const MvRequest&);

private:

// No copy allowed

	ReplyObserver(const ReplyObserver&);
	ReplyObserver& operator=(const ReplyObserver&);

};


class ReplyObserverH : public Handle<ReplyObserver> {
public:
	ReplyObserverH(ReplyObserver* o) : Handle<ReplyObserver>(o) {}
};






class MacroEdit;


//class MacroRunTask : public Task, public ReplyObserver {
class MacroRunTask : public ReplyObserver {

Q_OBJECT

public:

	MacroRunTask (MacroEdit *editor, QString &macro, MacroRunOptions options);
	virtual ~MacroRunTask(); // Change to virtual if base class
	virtual void start();


// we need signals/slots to communicate between threads
signals:
    void sendMessageToLog      (const string &s);
    void sendMacroFinishedMsg  (int err);
    void sendCurrentLineNumber (int line);


protected:

	 void print(ostream&) const; // Change to virtual if base class	

private:

// No copy allowed
    MacroRunTask(const MacroRunTask&);
	MacroRunTask& operator=(const MacroRunTask&);

	MacroEdit   *editor_;
    QString     &macro_;
//	Action      action_;
//	IconObjectH object_;
	MacroRunOptions options_;

// -- Overridden methods

	// From Task
	// From ReplyObserver
	virtual void reply(const MvRequest&, int);
	virtual void progress(const MvRequest&);  
	virtual void message(const string&);
};




class runMacroThread : public QThread
{

Q_OBJECT

public:
//    runMacroThread(MacroEdit *editor);
//    runMacroThread(QString &filename);
    runMacroThread(MacroEdit *editor, QString &filename, MacroRunOptions options);
    ~runMacroThread() {};
    void run();
    
private:
    MacroEdit      *editor_;
    QString         filename_;
	MacroRunOptions options_;
    MacroRunTask   *task_;

signals:
    void sendThreadFinishedMsg ();

};


/*
class MvPlainTextEdit : public QPlainTextEdit
{
    Q_OBJECT

public:
    MvPlainTextEdit(QWidget * parent = 0);
	~MvPlainTextEdit() {};
};
*/



//class MacroEdit : public QMainWindow, private Ui::MainWindow, public MacroRunTask
class MacroEdit : public QMainWindow, private Ui::MainWindow
{
    Q_OBJECT

public:
    MacroEdit(QString &appName, QWidget *parent = 0, QString *fileToLoad = NULL);
    ~MacroEdit();
    void metview_dnd   ();
    void loadTextFile  (const QString &fileToLoad);
    bool saveTextFile  (const QString &fileToSave);
    void setLanguage   (const QString &language);
    void autoInsertLicence();
    LanguageHelper*  languageHelper() {return languageHelper_;}

        //void init(OdbMetaData*);
    QEventLoop      eventLoop_;   // xxxx should really be private!

public slots:
    //void searchInColTree(QString);
    //void searchInTableTree(QString);
    //void mousePressedInTableGraph(int,int);
    //void selectTableFromList(QModelIndex);
    void findDialog();
    void findReplaceDialog();
    void findNext();
    void findSelection();
    void findString(const QString &,QTextDocument::FindFlags,bool replace=false,const QString &r=emptyString_);
    void replaceString(const QString &,const QString &,QTextDocument::FindFlags);
    void replaceStringInSelectedText(const QString &,const QString &,QTextDocument::FindFlags);
    void replaceStringInFile(const QString &,const QString &,QTextDocument::FindFlags);
    void findClosed();
    void gotoLine();
    void gotoLine(int line);
    void onIndentLines();
    void onSelectionChanged();
    void onCommentLines();
    void tabsDialog();
    void runDialog();
    void functionListDialog();
    void codeTemplateDialog();
    void verbFunctionHelpDialog();
    //void onReadOnlyStatusChanged (bool readOnly);
    void onTabsSettingsChanged (TabsSettings settings);
    void onRunOptionsChanged (MacroRunOptions options);
    void onInsertFunctionName (QString);
    void onInsertCodeTemplate (QString);
    void onInsertTextIntoFunctionCall (QString);
    void clipboardDataChanged();
    void processDrop(MvQIconDropItem*);
    void run();
    //void debug();
    void stop();
    void monitor();
    void external();
    bool save();
    bool saveAs();
    bool reload();
    void print();
    void check_syntax();
    void documentWasModified();
    void cursorPositionWasChanged();
    void updateRowColLabel();
    void updateMessageLog();
    void logMessage      (const string &s);
    void macroFinished   (int errorCode);
    void stepLineNumber  (int line);
    void threadFinished  ();
    void enlargeFont();
    void shrinkFont ();
    void normalFont();
    void largeFont ();
    void showLineNumbers (bool show);
    void languageChosen(QAction *);
    void onFocusRegained();
    void onFocusLost();
    void insertLicenceText();
    void setAutoInsertLicenceOn()  {setAutoInsertLicence(true);};
    void setAutoInsertLicenceOff() {setAutoInsertLicence(false);};

signals:
    void selectionChanged(bool);


private:
    void setupEditor();
    bool AskToSave();
    void closeEvent(QCloseEvent *event);
    void setCurrentFile(const QString &fileName, bool lastSaveTimeOnly = false);
    QString strippedFileName(const QString &fullFileName);
    QString wordUnderCursor();
    void runMacro(MacroRunOptions options);
    void statusMessage(const QString &msg, int timeToDisplay = 0);
    bool checkForErrorMessage(const string &s);
    void enableRunActions(bool enable);
    void changeFontSize(int amount);
    void setFontSize(int newSize);
    void highlightLine(int line);
    void writeSettings();
    void readSettings();
    void showFindDialog(bool showReplaceOptions);
    void setLanguageMenuCheckedStatus();
    void enableActionsForCurrentLanguage(bool enable);
    void setAutoInsertLicence(bool setting);
//    void reply(const MvRequest& r,int err);

    /*void getTablePos(int,int,int&,int&);
    bool setSelectedTable(int,int);
    void renderTableGraph();
    void buildTableModel();
    bool searchInTree(QString,QTreeView*);
    void centreTableGraph(); */

    QString                  lastFindString_;
    QTextDocument::FindFlags lastFindFlags_;
    static QString           emptyString_;

    int                     fontSize_;
    int                     highlightedLine_;
    bool                    readOnly_;
    bool                    haveFocus_;
    bool                    autoInsertLicence_;
	MacroRunOptions         runOptions_;
    runMacroThread         *runThread_;
    QString                 appName_;
    FindTextDialog         *findDialog_;
    GotoLineDialog         *gotoLineDialog_;
    TabsDialog             *tabsDialog_;
    RunDialog              *runDialog_;
    FunctionListDialog     *functionListDialog_;
    CodeTemplateDialog     *codeTemplateDialog_;
    VerbFunctionHelpDialog *verbFunctionHelpDialog_;
    QString                 fileName_;
    QDateTime               lastSaveTime_;
    QLabel                 *rowColLabel_;
    QLabel                 *messageLabel_;
    LanguageHelperFactory   languageHelperFactory_;
    LanguageHelper         *languageHelper_;
    Highlighter            *highlighter_;
    QTimer                  logTimer_;
    QTimer                  buttonTimer_;
    QTime                   time_;
    vector<QAction*>        languageActions_;
    QString                 licenceText_;
    QActionGroup           *autoInsertLicenceGroup_;
};

#endif
