/***
   This file is part of fly-ocr.

   Copyright (C) 2016-2020 Sandro Mani <manisandro@gmail.com>
   Copyright (C) 2021 LLC "RusBITech-Astra" (https://astralinux.ru)

    Based on gImageReader source code by Sandro Mani under the GNU
    General Public License (GPL) version 3 or later

   Foobar 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 3 of the License, or
   (at your option) any later version.

   Foobar is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
   GNU General Public License for more details.

   You should have received a copy of the GNU General Public License
   along with fly-ocr. If not, see <https://www.gnu.org/licenses/>.
***/

#ifndef OUTPUTEDITORHOCR_H
#define OUTPUTEDITORHOCR_H

#include <QTimer>

#include "outputeditor.h"
#include "outputeditorhocr_ui.h"

class DisplayerToolHOCR;
class HOCRDocument;
class HOCRItem;
class HOCRPage;
class HOCRProofReadWidget;
class QGraphicsPixmapItem;
struct HOCRReadSessionData;

class OutputEditorHOCR : public OutputEditor
{
    Q_OBJECT
public:
    class HOCRBatchProcessor : public BatchProcessor
    {
    public:
        QString fileSuffix() const override { return QString(".html"); }
        void writeHeader(QIODevice* dev, const PageInfo& pageInfo) const override;
        void writeFooter(QIODevice* dev) const override;
        void appendOutput(QIODevice* dev, OcrEngine* engine, const PageInfo& pageInfos, bool firstArea) const override;
    };

    OutputEditorHOCR(DisplayerToolHOCR* tool, QWidget* parent = nullptr);
    ~OutputEditorHOCR();

    void read(int pageNumber, const SourceDocumentPage* page) override;
    bool isModified() const override;
    void commit() override;
    void clear() override;
    void setLanguage(const QString& lang) override;

//    QWidget* getUI() override;
    //ReadSessionData* initRead(OcrEngine* engine) override;
    //void read(OcrEngine* engine, ReadSessionData* data) override;
    //void readError(const QString& errorMsg, ReadSessionData* data) override;
    //void finalizeRead(ReadSessionData* data) override;
    BatchProcessor* createBatchProcessor(const QMap<QString, QVariant>& /*options*/) const override { return new HOCRBatchProcessor; }
    //bool containsSource(const QString& source, int sourcePage) const override;

    HOCRDocument* getDocument() const { return m_document; }
    DisplayerToolHOCR* getTool() const { return m_tool; }
//    bool open(InsertMode mode, QStringList files = QStringList());
//    bool selectPage(int nr);

public slots:
    //bool open(const QString& filename) override { return open(InsertMode::Replace, {filename}); }
    //bool clear(bool hide = true) override;
    //void onVisibilityChanged(bool visible) override;
    //bool save(const QString& filename = QString()) override;
    //bool exportToODT();
//    bool exportToPDF();
    //    bool exportToText();
//    bool exportToDOCX();
    void removeItem();

private slots:
    void bboxDrawn(const QRect& bbox, int action);
    void expandItemClass();
    void collapseItemClass();
    void navigateTargetChanged();
    void navigateNext();
    void navigatePrev();
    void pickItem(const QPoint& point);
    void setFont();
    void setModified();
    void showItemProperties(const QModelIndex& index, const QModelIndex& prev = QModelIndex());
    void showTreeWidgetContextMenu(const QPoint& point);
    void toggleWConfColumn(bool active);
    void itemAttributeChanged(const QModelIndex& itemIndex, const QString& name, const QString& value);
    void updateSourceText();
    void updateCurrentItemBBox(QRect bbox);
    void findReplace(const QString& searchstr, const QString& replacestr, bool matchCase, bool backwards, bool replace);
    void replaceAll(const QString& searchstr, const QString& replacestr, bool matchCase);
    void applySubstitutions(const QMap<QString, QString>& substitutions, bool matchCase);
    void sourceChanged();
    void previewToggled(bool active);
    void updatePreview();

private:
    class HTMLHighlighter;

    friend struct QMetaTypeId<HOCRReadSessionData>;

    QWidget* createAttrWidget(const QModelIndex& itemIndex, const QString& attrName, const QString& attrValue, const QString& attrItemClass = QString(), bool multiple = false);
    void expandCollapseChildren(const QModelIndex& index, bool expand) const;
    void expandCollapseItemClass(bool expand);
    void navigateNextPrev(bool next);
    bool findReplaceInItem(const QModelIndex& index, const QString& searchstr, const QString& replacestr, bool matchCase, bool backwards, bool replace, bool& currentSelectionMatchesSearch);
    bool showPage(const HOCRPage* page);
    int currentPage();
    void drawPreview(QPainter& painter, const HOCRItem* item);

    DisplayerToolHOCR* m_tool;
    QGraphicsPixmapItem* m_preview = nullptr;
    HOCRProofReadWidget* m_proofReadWidget = nullptr;
    QTimer m_previewTimer;
    OutputEditorHOCRUi m_ui;
    HTMLHighlighter* m_highlighter;
    bool m_modified = false;
    bool m_blockSourceChanged = false;
    QString m_filebasename;
    HOCRDocument* m_document;
    int m_page = -1;
};

class HOCRAttributeEditor : public QLineEdit
{
    Q_OBJECT
public:
    HOCRAttributeEditor(const QString& value, HOCRDocument* doc, const QModelIndex& itemIndex, const QString& attrName, const QString& attrItemClass);

protected:
    void focusOutEvent(QFocusEvent* ev) override;

private:
    HOCRDocument* m_doc;
    QModelIndex m_itemIndex;
    QString m_attrName;
    QString m_origValue;
    QString m_attrItemClass;

private slots:
    void updateValue(const QModelIndex& itemIndex, const QString& name, const QString& value);
    void validateChanges(bool force = false);
};

class HOCRAttributeCheckbox : public QCheckBox
{
    Q_OBJECT
public:
    HOCRAttributeCheckbox(Qt::CheckState value, HOCRDocument* doc, const QModelIndex& itemIndex, const QString& attrName, const QString& attrItemClass);

private:
    HOCRDocument* m_doc;
    QModelIndex m_itemIndex;
    QString m_attrName;
    QString m_attrItemClass;

private slots:
    void updateValue(const QModelIndex& itemIndex, const QString& name, const QString& value);
    void valueChanged();
};

class HOCRAttributeLangCombo : public QComboBox
{
    Q_OBJECT
public:
    HOCRAttributeLangCombo(const QString& value, bool multiple, HOCRDocument* doc, const QModelIndex& itemIndex, const QString& attrName, const QString& attrItemClass);

private:
    HOCRDocument* m_doc;
    QModelIndex m_itemIndex;
    QString m_attrName;
    QString m_attrItemClass;

private slots:
    void updateValue(const QModelIndex& itemIndex, const QString& name, const QString& value);
    void valueChanged();
};

#endif // OUTPUTEDITORHOCR_H
