/*******************************************************************************
**
** SPDX-FileCopyrightText: Copyright 2023 Open Mobile Platform LLC <community@omp.ru>
** SPDX-License-Identifier: BSD-3-Clause
** This file is part of the OfficeViewer project.
**
** Redistribution and use in source and binary forms,
** with or without modification, are permitted provided
** that the following conditions are met:
**
** * Redistributions of source code must retain the above copyright notice,
**   this list of conditions and the following disclaimer.
** * Redistributions in binary form must reproduce the above copyright notice,
**   this list of conditions and the following disclaimer
**   in the documentation and/or other materials provided with the distribution.
** * Neither the name of the copyright holder nor the names of its contributors
**   may be used to endorse or promote products derived from this software
**   without specific prior written permission.
**
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
** AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
** THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
** FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
** IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
** FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
** OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
** PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
** LOSS OF USE, DATA, OR PROFITS;
** OR BUSINESS INTERRUPTION)
** HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
** WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
** (INCLUDING NEGLIGENCE OR OTHERWISE)
** ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
** EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
**
*******************************************************************************/


#pragma once

#include <QQuickItem>

#include "basedocument.h"

class DocumentMapper;
class BaseAnnotation;
class BookmarksModel;
class DocItemSearchHighlight;
class DocView : public QQuickItem
{
    Q_OBJECT

    Q_PROPERTY(int count READ count NOTIFY countChanged)
    Q_PROPERTY(qreal contentHeight READ contentHeight NOTIFY contentHeightChanged)
    Q_PROPERTY(qreal contentWidth READ contentWidth NOTIFY contentWidthChanged)
    Q_PROPERTY(qreal contentY READ contentY WRITE setContentY NOTIFY contentYChanged)
    Q_PROPERTY(qreal contentX READ contentX WRITE setContentX NOTIFY contentXChanged)
    Q_PROPERTY(int currentIndex READ currentIndex NOTIFY currentIndexChanged)
    Q_PROPERTY(qreal catchBound READ catchBound WRITE setCatchBound NOTIFY catchBoundChanged)
    Q_PROPERTY(Qt::Orientation typeScroll READ typeScroll WRITE setTypeScroll NOTIFY typeScrollChanged)
    Q_PROPERTY(qreal lastPageIndent READ lastPageIndent NOTIFY lastPageIndentChanged)
    Q_PROPERTY(qreal itemScale READ itemScale WRITE setItemScale NOTIFY itemScaleChanged)
    Q_PROPERTY(bool annotationsPaint READ annotationsPaint WRITE setAnnotationsPaint NOTIFY annotationsPaintChanged)
    Q_PROPERTY(bool notesPaint READ notesPaint WRITE setNotesPaint NOTIFY notesPaintChanged)
    Q_PROPERTY(BaseDocument* documentProvider READ documentProvider WRITE setDocumentProvider NOTIFY documentProviderChanged)
    Q_PROPERTY(QString path READ path WRITE setPath NOTIFY pathChanged)
    Q_PROPERTY(BaseDocument::DocumentStatus status READ status NOTIFY statusChanged)
    Q_PROPERTY(qreal contentTopMargin READ contentTopMargin NOTIFY contentTopMarginChanged)
    Q_PROPERTY(qreal topMargin READ topMargin WRITE setTopMargin NOTIFY topMarginChanged)
    Q_PROPERTY(BookmarksModel* bookmarksModel READ bookmarksModel NOTIFY bookmarksModelChanged)
    Q_PROPERTY(int fileVersion READ fileVersion NOTIFY fileVersionChanged)
    Q_PROPERTY(bool documentEdited READ documentEdited NOTIFY documentEditedChanged)
    Q_PROPERTY(QColor highLightColor READ highLightColor WRITE setHighLightColor NOTIFY highLightColorChanged)
    Q_PROPERTY(QQuickItem* cursorDelegate READ cursor WRITE setCursor NOTIFY cursorChanged)
    Q_PROPERTY(QQuickItem *startSelectionMarker READ startSelectionMarker WRITE setStartSelectionMarker NOTIFY startSelectionMarkerChanged)
    Q_PROPERTY(QQuickItem *endSelectionMarker READ endSelectionMarker WRITE setEndSelectionMarker NOTIFY endSelectionMarkerChanged)
    Q_PROPERTY(bool selectionMode READ selectionMode NOTIFY selectionModeChanged)
    Q_PROPERTY(QString selectionText READ selectionText NOTIFY selectionTextChanged)

public:
    explicit DocView(QQuickItem *parent = nullptr);
    ~DocView() override;

    QSGNode *updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *) override;
    void geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry) override;

    int count() const;
    qreal contentHeight() const;
    qreal contentWidth() const;
    qreal contentY() const;
    qreal contentX() const;
    int currentIndex() const;
    qreal catchBound() const;
    Qt::Orientation typeScroll() const;
    qreal lastPageIndent() const;
    qreal itemScale() const;
    bool annotationsPaint() const;
    bool notesPaint() const;
    BaseDocument* documentProvider() const;
    QString path() const;
    BaseDocument::DocumentStatus status() const;
    qreal contentTopMargin() const;
    qreal topMargin() const;
    BookmarksModel *bookmarksModel() const;
    int fileVersion() const;
    const QColor &highLightColor() const;

    Q_INVOKABLE void saveDocumentAs(const QString &path, const QString &format);
    bool documentEdited() const;
    Q_INVOKABLE void addAnnotation(const QRectF &rect,
                                   const QColor &color,
                                   const QString &author,
                                   const QString &content);
    Q_INVOKABLE void mousePress(const QPointF &pos);
    Q_INVOKABLE void mouseRelease(const QPointF &pos);
    Q_INVOKABLE void mouseDoubleClick(const QPointF &pos);
    Q_INVOKABLE void startSelectText(const QPointF &pos);
    Q_INVOKABLE void endSelectText(const QPointF &pos);
    Q_INVOKABLE void setSelectText(const QPointF &startPos, const QPointF &endPos);
    Q_INVOKABLE void resetSelectText();
    Q_INVOKABLE void startSearch(const QString &string, int direction);
    Q_INVOKABLE void stopSearch();

    QQuickItem *cursor() const;
    void setCursor(QQuickItem *newCursor);

    QQuickItem *startSelectionMarker() const;
    void setStartSelectionMarker(QQuickItem *newStartSelectionMarker);

    QQuickItem *endSelectionMarker() const;
    void setEndSelectionMarker(QQuickItem *newEndSelectionMarker);

    bool selectionMode() const;
    void setSelectionMode(bool newSelectionMode);

    const QString selectionText() const;

public slots:
    void setContentY(qreal contentY);
    void setContentX(qreal contentX);
    void setCatchBound(qreal catchBound);
    void positionViewAtIndex(int index);
    void setTypeScroll(Qt::Orientation typeScroll);
    void setItemScale(qreal itemScale);
    void scaleAroundPoint(const QPointF &center, qreal newScale);
    void setAnnotationsPaint(bool annotationsPaint);
    void setNotesPaint(bool notesPaint);
    void setDocumentProvider(BaseDocument* documentProvider);
    void setPath(const QString &path);
    void setTopMargin(qreal topMargin);
    void setHighLightColor(const QColor &highLightColor);

signals:
    void modelChanged(QObject* model);
    void countChanged(int count);
    void contentHeightChanged(qreal contentHeight);
    void contentWidthChanged(qreal contentWidth);
    void contentYChanged(qreal contentY);
    void contentXChanged(qreal contentX);
    void loadPages();
    void currentIndexChanged(int currentIndex);
    void catchBoundChanged(qreal catchBound);
    void contentChanged();
    void typeScrollChanged(Qt::Orientation typeScroll);
    void lastPageIndentChanged(qreal lastPageIndent);
    void itemScaleChanged(qreal itemScale);
    void annotationsPaintChanged(bool annotationsPaint);
    void clickedUrl(QString url);
    void cellClicked(QString cellContent);
    void clickedGoToPage(int pageNumber, QPointF coordinateOnPage);
    void notesPaintChanged(bool notesPaint);
    void noteActivated(QString text, QString author, QString dateTime);
    void documentProviderChanged(BaseDocument* documentProvider);
    void pathChanged(QString path);
    void statusChanged(BaseDocument::DocumentStatus status);
    void contentTopMarginChanged(qreal contentTopMargin);
    void bookmarksModelChanged(BookmarksModel *bookmarksModel);
    void fileVersionChanged(int fileVersion);
    void documentSaved(bool saveStatus);
    void documentEditedChanged(bool documentEdited);
    void topMarginChanged(qreal topMargin);
    void highLightColorChanged();
    void cursorChanged();
    void startSelectionMarkerChanged();
    void endSelectionMarkerChanged();
    void selectionModeChanged();
    void selectionTextChanged();

private slots:
    void _updateContentSize();
    void _positionPages();
    void _positionSelectionMarkers();
    void _positionCursor();
    void _updateAbsolutePosition();
    void _restoreAbsolutePosition();
    void _preparePages();
    void _calculateVisible();
    void _updateCurrentIndex();
    void _processActivatedAnnotation(BaseAnnotation *annotation);
    void _processActivatedCell(BaseAnnotation *annotation);
    void _processActivatedNote(BaseAnnotation *annotation);
    void _loadDocument();
    void _documentEdited();
    void _goToPosition(int pageIndex, QPointF pos);
    BaseDocument::InternalPosition _posToInternalPosition(const QPointF &pos);

private:
    DocumentMapper *m_mapper;
    int m_count;
    qreal m_contentHeight;
    qreal m_contentWidth;
    qreal m_contentY;
    qreal m_contentX;
    qreal m_moveDirection;
    QHash<int, QQuickItem *> m_pages;
    QList<int> m_paintedPages;
    QPointF m_absolutePosition;
    qreal m_paintedItemsSize;
    int m_currentIndex;
    qreal m_catchBound;
    Qt::Orientation m_orientation;
    qreal m_lastPageIndent;
    qreal m_itemScale;
    bool m_annotationsPaint;
    bool m_notesPaint;
    BaseDocument* m_documentProvider;
    QString m_path;
    qreal m_contentTopMargin;
    QTimer *m_timer;
    BookmarksModel *m_bookmarksModel;
    bool m_documentEdited;
    qreal m_topMargin;
    QColor m_highLightColor;
    QQuickItem *m_cursorDelegate;
    QQuickItem *m_startSelectionMarker;
    QQuickItem *m_endSelectionMarker;
    bool m_selectionMode;
};

