/***************************************************************************
 *   Copyright (C) 2005 by David Saxton                                    *
 *   david@bluehaze.org                                                    *
 *                                                                         *
 *   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 TEXTVIEW_H
#define TEXTVIEW_H

#include "config.h"
#include "view.h"

// #include <kate/view.h>
//#include <ktexteditor/view.h>
#include <KTextEditor/TextHintInterface>
#include <KTextEditor/View>

#include <QLabel>
#include <QPointer>

class QMouseEvent;
class RegisterInfo;
class TextDocument;
class TextView;
class VariableLabel;

/**
@author David Saxton
*/
class TextView : public View
{
    Q_OBJECT
public:
    TextView(TextDocument *textDocument, ViewContainer *viewContainer, uint viewAreaId);
    ~TextView() override;

    bool closeView() override;

    /**
     * Brings up the goto line dialog.
     */
    bool gotoLine(const int line); // { return m_view->setCursorPosition( line, 0/*m_view->cursorColumn()*/ ); }
    /**
     * Returns a pointer to the document as a text document
     */
    TextDocument *textDocument() const;
    void undo();
    void redo();
    void cut();   // { m_view->cut(); }
    void copy();  // { m_view->copy(); }
    void paste(); // { m_view->paste(); }
    void saveCursorPosition();
    void restoreCursorPosition();
    /**
     * Enable code actions depending on the type of code being edited
     */
    void initCodeActions();
    void setCursorPosition(uint line, uint col); // { m_view->setCursorPosition( line, col ); }
    unsigned currentLine();
    unsigned currentColumn();
    void disableActions();

    KTextEditor::View *kateView() const
    {
        return m_view;
    }

    // KTextEditor::View::saveResult save(); // { return m_view->save(); }
    bool save();
    // KTextEditor::View::saveResult saveAs(); // { return m_view->saveAs(); }
    bool saveAs();
    void print();

public slots:
    /**
     * Called when change line / toggle marks
     */
    void slotUpdateMarksInfo();
    void slotCursorPositionChanged();
    void toggleBreakpoint() override;
    /**
     * Initialize the actions appropriate for when the debugger is running
     * or stepping
     */
    void slotInitDebugActions();

protected slots:
    void slotWordHoveredOver(const QString &word, int line, int col);
    void slotWordUnhovered();
    void gotFocus();
    void slotSelectionmChanged();

protected:
    KTextEditor::View *m_view;
#ifndef NO_GPSIM
    VariableLabel *m_pTextViewLabel; ///< Pops up when the user hovers his mouse over a word
#endif

private:
    uint m_savedCursorLine;
    uint m_savedCursorColumn;
};

/**
This class is an event filter to be installed in the kate view, and is used to
do stuff like poping up menus and telling TextView that a word is being hovered
over (used in the debugger).

@author David Saxton
*/
class TextViewEventFilter : public QObject, public KTextEditor::TextHintProvider
{
    Q_OBJECT
public:
    TextViewEventFilter(TextView *textView);
    virtual ~TextViewEventFilter();

    bool eventFilter(QObject *watched, QEvent *e) override;

    // from TextHintInterface
    QString textHint(KTextEditor::View *view, const KTextEditor::Cursor &position) override;
signals:
    /**
     * When the user hovers the mouse for more than 700 milliseconds over a
     * word, "hover mode" is entered. When the user presses a key, clicks
     * mouse, etc, this mode is left. During the mode, any word that is
     * under the mouse cursor will be emitted as hoveredOver( word ).
     */
    void wordHoveredOver(const QString &word, int line, int col);
    /**
     * Emitted when focus is lost, the mouse moves to a different word, etc.
     */
    void wordUnhovered();

protected slots:
    void slotNeedTextHint(const KTextEditor::Cursor &position, QString &text);
    /**
     * Called when we are not in hover mode, but the user has had his mouse
     * in the same position for some time.
     */
    void hoverTimeout();
    /**
     * Called (from m_pSleepTimer) when we are in hover mode, but no word
     * has been hovered over for some time.
     */
    void gotoSleep();
    /**
     * @see m_pNoWordTimer
     */
    void slotNoWordTimeout();

protected:
    enum HoverStatus {
        /**
         * We are currently hovering - wordHoveredOver was emitted, and
         * wordUnhovered hasn't been emitted yet.
         */
        Active,
        /**
         * A word was unhovered recently. We will go straight to PoppedUp
         * mode if a word is hovered over again.
         */
        Hidden,
        /**
         * A word was not unhovered recentely. There will be a short display
         * before going to PoppedUp mode if a word is hovered over.
         */
        Sleeping
    };

    /**
     * Starts / stops timers, emits signals, etc. See other functions for an
     * idea of what this does.
     */
    void updateHovering(const QString &currentWord, int line, int col);
    /**
     * Started when the user moves his mouse over a word, and we are in
     * Sleeping mode. Reset when the user moves his mouse, etc.
     */
    QTimer *m_pHoverTimer;
    /**
     * Started when a word is unhovered. When this timeouts, we will go to
     * Sleeping mode.
     */
    QTimer *m_pSleepTimer;
    /**
     * Activated by the user moving the mouse. Reset by a call to
     * slotNeedTextHint. This timer is needed as KateViewInternal doesn't
     * bother updating us if the mouse cursor isn't over text.
     */
    QTimer *m_pNoWordTimer;

    TextView *m_pTextView;
    QString m_lastWord;
    int m_lastLine;
    int m_lastCol;
    HoverStatus m_hoverStatus;
};

#endif
