#include "vymview.h"

#include "branchitem.h"
#include "dockeditor.h"
#include "mainwindow.h"
#include "mapeditor.h"
#include "slideeditor.h"
#include "treedelegate.h"
#include "treeeditor.h"

extern Main *mainWindow;
extern Settings settings;

extern QString editorFocusInStyle;

VymView::VymView(VymModel *m)
{
    model = m;
    model->setView(this);

    // Create TreeView
    treeEditor = new TreeEditor(model);

    selModel = new QItemSelectionModel(model);
    model->setSelectionModel(selModel);

    treeEditor->setSelectionModel(selModel);
    treeEditor->setColumnWidth(0, 150);
    treeEditor->setAnimated(true);
    treeEditor->resize(20, 200);

    TreeDelegate *delegate = new TreeDelegate(this);
    treeEditor->setItemDelegate(delegate);

    // Add Escape-keys to editors
    QAction *a = new QAction("Cancel", treeEditor);
    a->setShortcut(Qt::Key_Escape);     // Escape in NoteEditor
    a->setShortcutContext(Qt::WidgetWithChildrenShortcut);
    treeEditor->connect(a, SIGNAL(triggered()), mainWindow, SLOT(escapePressed()));
    treeEditor->addAction(a);

    DockEditor *de;
    de = new DockEditor(tr("Tree Editor", "Title of dockable editor widget"),
                        this, model);
    de->setWidget(treeEditor);
    de->setAllowedAreas(Qt::AllDockWidgetAreas);
    de->setVisible(settings.value("/mainwindow/view/showTreeEditors", true).toBool());
    addDockWidget(Qt::LeftDockWidgetArea, de);
    connect(de, SIGNAL(visibilityChanged(bool)), this, SLOT(treeEditorVisibilityChanged()));
    treeEditorDE = de;

    // Create good old MapEditor
    mapEditor = model->getMapEditor();
    if (!mapEditor)
        mapEditor = new MapEditor(model);
    setCentralWidget(mapEditor);

    // Create SlideEditor
    slideEditor = new SlideEditor(model);

    de = new DockEditor(tr("Slide Editor", "Title of dockable editor widget"),
                        this, model);
    de->setWidget(slideEditor);
    de->setAllowedAreas(Qt::AllDockWidgetAreas);
    de->setVisible(settings.value("/mainwindow/view/showSlideEditors", false).toBool());
    addDockWidget(Qt::RightDockWidgetArea, de);
    connect(de, SIGNAL(visibilityChanged(bool)), this, SLOT(slideEditorVisibilityChanged()));
    slideEditorDE = de;

    // Connect selections

    // Selection in Model changed
    connect(
        selModel,
        SIGNAL(selectionChanged(const QItemSelection &, const QItemSelection &)),
        this,
        SLOT(changeSelection(const QItemSelection &, const QItemSelection &)));

    // Connect data changed signals
    connect(model,
            SIGNAL(dataChanged(const QModelIndex &, const QModelIndex &)),
            mapEditor, SLOT(updateData(const QModelIndex &)));

    connect(model,
            SIGNAL(dataChanged(const QModelIndex &, const QModelIndex &)), this,
            SLOT(updateDockWidgetTitles())); // FIXME-5 connect directly to
                                             // MainWindow and rename method
                                             // (also updates selection in BPE)

    connect(model,
            SIGNAL(dataChanged(const QModelIndex &, const QModelIndex &)),
            mainWindow, SLOT(updateHeadingEditor()));

    connect(model, SIGNAL(updateQueries(VymModel *)), mainWindow,
            SLOT(updateQueries(VymModel *)));

    connect(model, SIGNAL(expandAll()), this, SLOT(expandAll()));

    connect(model, SIGNAL(expandOneLevel()), this, SLOT(expandOneLevel()));

    connect(model, SIGNAL(collapseOneLevel()), this, SLOT(collapseOneLevel()));

    connect(model, SIGNAL(collapseUnselected()), this,
            SLOT(collapseUnselected()));

    connect(model, SIGNAL(showSelection(bool, bool)), this, SLOT(showSelection(bool, bool)));

    connect(model, SIGNAL(updateLayout()), mapEditor, SLOT(autoLayout()));

    mapEditor->setAntiAlias(mainWindow->isAliased());
    mapEditor->setSmoothPixmap(mainWindow->hasSmoothPixmapTransform());
}

VymModel *VymView::getModel() { return model; }

MapEditor *VymView::getMapEditor() { return mapEditor; }

void VymView::initFocus() { mapEditor->setFocus(); }

void VymView::nextSlide() { slideEditor->nextSlide(); }

void VymView::previousSlide() { slideEditor->previousSlide(); }

void VymView::updateColors()
{
    // Set selection color, link color and background color in editors:
    // TreeEditor, HeadingEditor and MapEditor

    QString s;

    MapDesign *mapDesign = model->mapDesign();

    // Background image
    if (mapDesign->hasBackgroundImage())
        mapEditor->getScene()->setBackgroundBrush(mapDesign->backgroundImageBrush());
    else 
        mapEditor->getScene()->setBackgroundBrush(mapDesign->backgroundColor());

    s += "selection-background-color: " + mapDesign->selectionBrush().color().name() + ";" + "background-color: " + mapDesign->backgroundColor().name();

    // FIXME-5 maybe use gradient with pen/brush colors for selection? //
    // https://stackoverflow.com/questions/34187874/setting-qtreeview-selected-item-style-in-qss
    // https://doc.qt.io/qt-6/stylesheet-examples.html#customizing-qtreeview
    /*
    s += "QTreeView { show-decoration-selected: 1; }";
    s += "QTreeView::item { border: 1px solid #d9d9d9; border-top-color: transparent; border-bottom-color: transparent; }";
    s += "QTreeView::item:hover { background: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1, stop: 0 #0000fd, stop: 1 #cbdaf1); border: 1px solid #ff2222; }";
    s += "QTreeView::item:selected { border: 1px solid #56ffbc; }";
    s += "QTreeView::item:selected:active{ background: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1, stop: 0 #6ea1f1, stop: 1 #ff0000); }";
    //s += "QTreeView::item:selected:!active { background: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1, stop: 0 #6b9be8, stop: 1 #577fbf); } ";
    */
    mainWindow->updateHeadingEditor();

    // Link colors in TreeEditor // FIXME-3  palette only works, if no stylesheet is written!
    /* 
    */
    QPalette palette = treeEditor->palette();
    palette.setColor(QPalette::Text, model->mapDesign()->defaultLinkColor());
    //qDebug() << "VV setting TE links to " <<model->mapDesign()->defaultLinkColor().name();
    treeEditor->setPalette(palette);

    // s += "QTreeView::branch {color: red; background: palette(base);}";
    treeEditor->setStyleSheet("QTreeView{" + s + "} QTreeView:focus{" + editorFocusInStyle + "}");
}

void VymView::changeSelection(const QItemSelection &newsel,
                              const QItemSelection &desel)
{
    // Update note editor and heading editor // FIXME-5 improve this, evtl. move
    // from mainwindow to here
    model->updateSelection(newsel, desel);
    mainWindow->changeSelection(model, newsel, desel);
    mainWindow->updateDockWidgetTitles(model);

    //qDebug() << "VymView::changeSel";
    if (model->selectedItemsCount() < 4)
        // Only show all selected items for a few items 
        // to avoid massive zooming out
        showSelection(false, false);
}

void VymView::updateDockWidgetTitles()
{
    mainWindow->updateDockWidgetTitles(model);
}

void VymView::expandAll() { treeEditor->expandAll(); }

void VymView::expandOneLevel()
{
    int level = 999999;
    int d;
    BranchItem *cur = nullptr;
    BranchItem *prev = nullptr;
    QModelIndex pix;

    // Find level to expand
    model->nextBranch(cur, prev);
    while (cur) {
        pix = model->index(cur);
        d = cur->depth();
        if (!treeEditor->isExpanded(pix) && d < level)
            level = d;
        model->nextBranch(cur, prev);
    }

    // Expand all to level
    cur = nullptr;
    prev = nullptr;
    model->nextBranch(cur, prev);
    while (cur) {
        pix = model->index(cur);
        d = cur->depth();
        if (!treeEditor->isExpanded(pix) && d <= level &&
            cur->branchCount() > 0)
            treeEditor->setExpanded(pix, true);
        model->nextBranch(cur, prev);
    }
}

void VymView::collapseOneLevel()
{
    int level = -1;
    int d;
    BranchItem *cur = nullptr;
    BranchItem *prev = nullptr;
    QModelIndex pix;

    // Find level to collapse
    model->nextBranch(cur, prev);
    while (cur) {
        pix = model->index(cur);
        d = cur->depth();
        if (treeEditor->isExpanded(pix) && d > level)
            level = d;
        model->nextBranch(cur, prev);
    }

    // collapse all to level
    cur = nullptr;
    prev = nullptr;
    model->nextBranch(cur, prev);
    while (cur) {
        pix = model->index(cur);
        d = cur->depth();
        if (treeEditor->isExpanded(pix) && d >= level)
            treeEditor->setExpanded(pix, false);
        model->nextBranch(cur, prev);
    }
}

void VymView::collapseUnselected()
{
    QModelIndex pix;

    // Find level to collapse
    BranchItem *selbi = model->getSelectedBranch();
    if (!selbi)
        return;

    QList<BranchItem *> itemPath;

    // Do not include selected branch,
    // this one also should be collapsed later
    BranchItem *cur = selbi->parentBranch();
    BranchItem *prev = nullptr;

    while (cur->parentBranch()) {
        itemPath << cur;
        cur = cur->parentBranch();
    }

    cur = nullptr;

    // collapse all to level
    model->nextBranch(cur, prev);
    while (cur) {
        pix = model->index(cur);
        if (treeEditor->isExpanded(pix) && itemPath.indexOf(cur) < 0) {
            treeEditor->setExpanded(pix, false);
        }
        model->nextBranch(cur, prev);
    }
}

void VymView::showSelection(bool scaled, bool rotated)
{
    QModelIndex ix = model->getSelectedIndex();
    treeEditor->scrollTo(ix, QAbstractItemView::EnsureVisible);
    mapEditor->ensureSelectionVisibleAnimated(scaled, rotated);
}

void VymView::treeEditorVisibilityChanged()
{
    mainWindow->setTreeEditorsVisibility(treeEditorDE->isVisible());
}

void VymView::setTreeEditorVisibility(bool b)
{
    if (b)
        treeEditorDE->show();
    else
        treeEditorDE->hide();
}

void VymView::slideEditorVisibilityChanged()
{
    mainWindow->setSlideEditorsVisibility(slideEditorDE->isVisible());
}

void VymView::setSlideEditorVisibility(bool b)
{
    if (b)
        slideEditorDE->show();
    else
        slideEditorDE->hide();
}

void VymView::setFocusMapEditor() { mapEditor->setFocus(); }
void VymView::setFocusTreeEditor() { treeEditor->setFocus(); }
void VymView::setFocusSlideEditor() { slideEditor->setFocus(); }
