/***************************** 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 *************************************/

#pragma once

#include <QPlainTextEdit>
#include "TabsSettings.h"

class EditorTheme;
class LineNumberArea;
class LanguageHelper;

// ----------------------------------------------------------------------------
// MvPlainTextEdit
// This class extends the QPlainTextEdit with the following abilities:
//  o allow user-configurable behaviour when the TAB key is pressed
//    (insert tab character or multiple spaces)
//  o auto-indent when RETURN is pressed
//  o line number widget down the left-hand side (code adapted from Qt example)
// ----------------------------------------------------------------------------

class MvPlainTextEdit : public QPlainTextEdit
{
    Q_OBJECT

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

    bool useSpacesForTabs() const { return tabsSettings_.useSpacesForTabs; }
    void setUseSpacesForTabs(bool use) { tabsSettings_.useSpacesForTabs = use; }

    int numSpacesInTab() const { return tabsSettings_.numSpacesInTab; }
    void setNumSpacesInTab(int num) { tabsSettings_.numSpacesInTab = num; }

    bool useSpacesForDrops() const { return tabsSettings_.useSpacesForDrops; }
    void setUseSpacesForDrops(bool use) { tabsSettings_.useSpacesForDrops = use; }

    bool displayTabsAndSpaces() const { return tabsSettings_.displayTabsAndSpaces; }
    void setDisplayTabsAndSpaces(bool yes);

    bool autoIndent() const { return tabsSettings_.autoIndent; }
    void setAutoIndent(bool yes) { tabsSettings_.autoIndent = yes; }

    TabsSettings& tabsSettings() { return tabsSettings_; }

    bool showLineNumbers() const { return showLineNumbers_; }
    void setShowLineNumbers(bool yes);
    int totalLineNumber() const;
    void lineNumberAreaPaintEvent(QPaintEvent* event);
    int numLinesSelected();

    void insertTextIndent(QTextCursor& cursor, bool intelligentIndent);
    void cursorRowCol(int* row, int* col);
    QChar characterBehindCursor(QTextCursor* cursor = 0);
    QString textUnderCursor() const;
    QStringList textBeforeCursor(int maxLineNum) const;
    void textBeforeCursorLine(int maxLineNum, QStringList& lines, int& cursorPos) const;

    void setTheme(EditorTheme*);
    EditorTheme* theme() const { return theme_; }

    QString language() { return language_; }
    void setLanguage(const QString& lang) { language_ = lang; }
    void setLanguageHelper(LanguageHelper*);

private slots:
    void updateLineNumberAreaWidth(int newBlockCount);
    void updateLineNumberArea(const QRect&, int);

signals:
    void focusRegained();
    void focusLost();

protected:
    void keyPressEvent(QKeyEvent* e);
    void resizeEvent(QResizeEvent* event);
    void focusInEvent(QFocusEvent* event);
    void focusOutEvent(QFocusEvent* event);
    void changeEvent(QEvent*);
    void mouseDoubleClickEvent(QMouseEvent*);

    void dragEnterEvent(QDragEnterEvent*);
    void dragMoveEvent(QDragMoveEvent*);
    void dropEvent(QDropEvent*);

private:
    void autoIndentNewLine();

    TabsSettings tabsSettings_;
    LanguageHelper* languageHelper_;
    QString language_;  // programming language, e.g. Macro, Python
    bool showLineNumbers_;
    LineNumberArea* lineNumberArea;
    EditorTheme* theme_{nullptr};
};


class LineNumberArea : public QWidget
{
public:
    LineNumberArea(MvPlainTextEdit* editor);
    QSize sizeHint() const;
    void setTheme(EditorTheme*);
    int leftMargin() const { return leftMargin_; }
    int rightMargin() const { return rightMargin_; }
    QColor bgColour() const { return bgCol_; }
    QColor selectBgColour() const { return selectBgCol_; }
    QColor borderColour() const { return borderCol_; }
    QColor textColour() const { return textCol_; }
    void updateWidth();

protected:
    void paintEvent(QPaintEvent* event) { textEditor_->lineNumberAreaPaintEvent(event); }

private:
    int computedWidth(int) const;

    MvPlainTextEdit* textEditor_;
    mutable int digits_;
    int leftMargin_;
    mutable int rightMargin_;
    QColor bgCol_;
    QColor selectBgCol_;
    QColor borderCol_;
    QColor textCol_;
};
