#include "taskeditor.h"

#include <QAbstractTableModel>
#include <QAction>
#include <QDebug>
#include <QHeaderView>
#include <QMenu>
#include <QSortFilterProxyModel>
#include <QTextEdit>
#include <QToolBar>
#include <QVBoxLayout>

#include "branchitem.h"
#include "mainwindow.h"
#include "task.h"
#include "taskmodel.h"
#include "vymmodel.h"

extern Main *mainWindow;
extern Settings settings;
extern QMenu *taskContextMenu;
extern TaskModel *taskModel;

extern QString editorFocusStyle;

TaskEditor::TaskEditor(QWidget *)
{
    // Creat Table view
    view = new QTableView;

    setMinimumWidth(350);

    QVBoxLayout *mainLayout = new QVBoxLayout;

    QToolBar *tb = new QToolBar("TaskEditor filters");
    tb->setToolButtonStyle(Qt::ToolButtonTextBesideIcon);
    mainLayout->addWidget(tb);

    // Original icon from KDE:
    // /usr/share/icons/oxygen/16x16/actions/view-filter.png

    QIcon icon = QIcon(":/taskfilter-currentmap.png");
    QAction *a =
        new QAction(icon, "", this); // tr( "Current map","TaskEditor" ),this );
    a->setToolTip(
        tr("Show only tasks from current map", "Filters in task Editor"));
    a->setCheckable(true);
    a->setChecked(settings.value("/taskeditor/filterMap", true).toBool());
    tb->addAction(a);
    connect(a, SIGNAL(triggered()), this, SLOT(toggleFilterMap()));
    actionToggleFilterMap = a;

    icon = QIcon(":/taskfilter-activetask.png");
    a = new QAction(icon, "", this); // tr( "Active tasks","TaskEditor" ),this
                                     // );
    a->setToolTip(tr("Show only active tasks", "Filters in task Editor"));
    a->setCheckable(true);
    a->setChecked(settings.value("/taskeditor/filterActive", true).toBool());
    tb->addAction(a);
    connect(a, SIGNAL(triggered()), this, SLOT(toggleFilterActive()));
    actionToggleFilterActive = a;

    icon = QIcon(":/taskfilter-newtask.png");
    a = new QAction(icon, "", this); // tr( "New tasks","TaskEditor" ),this );
    a->setToolTip(tr("Show only new tasks", "Filters in task Editor"));
    a->setCheckable(true);
    a->setChecked(settings.value("/taskeditor/filterNew", false).toBool());
    tb->addAction(a);
    connect(a, SIGNAL(triggered()), this, SLOT(toggleFilterNew()));
    actionToggleFilterNew = a;

    icon = QIcon(":/flag-stopsign.svg");
    a = new QAction(icon, "", this); // tr( "New tasks","TaskEditor" ),this );
    a->setToolTip(tr("Show only blocker tasks", "Filters in task Editor"));
    a->setCheckable(true);
    a->setChecked(settings.value("/taskeditor/filterBlocker", false).toBool());
    tb->addAction(a);
    connect(a, SIGNAL(triggered()), this, SLOT(toggleFilterBlocker()));
    actionToggleFilterBlocker = a;

    icon = QIcon(":/flag-arrow-up.svg");
    a = new QAction(icon, "", this);
    a->setToolTip(tr("Show only tasks marked with this arrow-up flag",
                     "Filters in task Editor"));
    a->setCheckable(true);
    a->setChecked(settings.value("/taskeditor/filterFlags1", false).toBool());
    tb->addAction(a);
    connect(a, SIGNAL(triggered()), this, SLOT(toggleFilterFlags1()));
    actionToggleFilterFlags1 = a;

    icon = QIcon(":/flag-arrow-2up.svg");
    a = new QAction(icon, "", this);
    a->setToolTip(tr("Show only tasks marked with this arrow-up flag",
                     "Filters in task Editor"));
    a->setCheckable(true);
    a->setChecked(settings.value("/taskeditor/filterFlags2", false).toBool());
    tb->addAction(a);
    connect(a, SIGNAL(triggered()), this, SLOT(toggleFilterFlags2()));
    actionToggleFilterFlags2 = a;

    icon = QIcon(":/flag-no-arrow-up.png");
    a = new QAction(icon, "", this);
    a->setToolTip(tr("Show only tasks marked without any arrow-up flag",
                     "Filters in task Editor"));
    a->setCheckable(true);
    a->setChecked(settings.value("/taskeditor/filterFlags3", false).toBool());
    tb->addAction(a);
    connect(a, SIGNAL(triggered()), this, SLOT(toggleFilterFlags3()));
    actionToggleFilterFlags3 = a;

    // Clone actions defined in MainWindow
    foreach (QAction *qa, mainWindow->taskEditorActions) {
        a = new QAction(this);
        a->setShortcut(qa->shortcut());
        a->setShortcutContext(Qt::WidgetWithChildrenShortcut);
        connect(a, SIGNAL(triggered()), qa, SLOT(trigger()));
        addAction(a);
    }

    mainLayout->addWidget(view);
    setLayout(mainLayout);

    view->setSelectionBehavior(QAbstractItemView::SelectRows);
    view->horizontalHeader()->setStretchLastSection(true);
    view->verticalHeader()->hide();
    // view->setEditTriggers(QAbstractItemView::NoEditTriggers);

    filterActiveModel = new TaskFilterModel;
    filterActiveModel->setSourceModel(taskModel);
    filterActiveModel->setDynamicSortFilter(true);

    view->setModel(filterActiveModel);
    view->setSortingEnabled(true);
    view->setIconSize(QSize(64, 64));

    QHeaderView *hv = view->horizontalHeader();
    hv->setSortIndicator(0, Qt::AscendingOrder);
    view->sortByColumn(hv->sortIndicatorSection(), hv->sortIndicatorOrder());

    view->setSelectionMode(QAbstractItemView::ExtendedSelection);
    view->setDragEnabled(true);
    view->setAcceptDrops(true);
    view->setDropIndicatorShown(true);
    view->setAutoScroll(false);

    blockExternalSelect = false;

    connect(view->selectionModel(),
            SIGNAL(selectionChanged(QItemSelection, QItemSelection)), this,
            SLOT(selectionChanged(QItemSelection, QItemSelection)));

    connect(view, SIGNAL(clicked(QModelIndex)),
            this, SLOT(cellClicked(QModelIndex)));

    // Enable wordwrap when data changes
    if (settings.value("/taskeditor/wordWrap", true)
            .toBool()) // FIXME-3 not working or only sometimes?
    {
        connect(taskModel, SIGNAL(dataChanged(QModelIndex, QModelIndex)), view,
                SLOT(resizeRowsToContents()));
        connect(view->horizontalHeader(), SIGNAL(sectionResized(int, int, int)),
                view, SLOT(resizeRowsToContents()));
    }

    // Initialize view filters according to previous settings
    setFilterMap();
    setFilterActive();
    setFilterNew();
    setFilterBlocker();
    setFilterFlags1();
    setFilterFlags2();
    setFilterFlags3();

    // Initialize display of parents of a task
    bool ok;
    int i = settings.value("/taskeditor/showParentsLevel", 0).toInt(&ok);
    if (ok)
        taskModel->setShowParentsLevel(i);

    view->horizontalHeader()->setContextMenuPolicy(Qt::CustomContextMenu);
    connect(view->horizontalHeader(),
            SIGNAL(customContextMenuRequested(QPoint)),
            SLOT(headerContextMenu()));

    view->setStyleSheet("QTableView:focus {" + editorFocusStyle + "}");

    updateColumnLayout();
}

TaskEditor::~TaskEditor()
{
    settings.setValue("/taskeditor/filterMap",
                      actionToggleFilterMap->isChecked());
    settings.setValue("/taskeditor/filterActive",
                      actionToggleFilterActive->isChecked());
    settings.setValue("/taskeditor/filterNew",
                      actionToggleFilterNew->isChecked());
    settings.setValue("/taskeditor/filterBlocker",
                      actionToggleFilterBlocker->isChecked());
    settings.setValue("/taskeditor/filterFlags1",
                      actionToggleFilterFlags1->isChecked());
    settings.setValue("/taskeditor/filterFlags2",
                      actionToggleFilterFlags2->isChecked());
    settings.setValue("/taskeditor/filterFlags3",
                      actionToggleFilterFlags3->isChecked());
    settings.setValue("/taskeditor/showParentsLevel",
                      taskModel->getShowParentsLevel());

    for (int i = 0; i <= 8; i++) {
        settings.setValue(QString("/taskeditor/column/%1/width").arg(i),
                          view->columnWidth(i));
        settings.setValue(QString("/taskeditor/column/%1/hidden").arg(i),
                          view->isColumnHidden(i));
    }
}

void TaskEditor::setMapName(const QString &n)
{
    currentMapName = n;

    setFilterMap();
}

bool TaskEditor::isUsedFilterMap()
{
    return actionToggleFilterMap->isChecked();
}

void TaskEditor::setFilterMap()
{
    if (isUsedFilterMap())
        filterActiveModel->setMapFilter(currentMapName);
    else
        filterActiveModel->setMapFilter(QString());
    updateFilters();
}

bool TaskEditor::isUsedFilterActive()
{
    return actionToggleFilterActive->isChecked();
}

void TaskEditor::setFilterActive()
{
    filterActiveModel->setFilter(actionToggleFilterActive->isChecked());
    updateFilters();
}

void TaskEditor::setFilterNew()
{
    filterActiveModel->setFilterNew(actionToggleFilterNew->isChecked());
    updateFilters();
}

void TaskEditor::setFilterBlocker()
{
    filterActiveModel->setFilterBlocker(actionToggleFilterBlocker->isChecked());
    updateFilters();
}

void TaskEditor::setFilterFlags1()
{
    filterActiveModel->setFilterFlags1(actionToggleFilterFlags1->isChecked());
    updateFilters();
}

void TaskEditor::setFilterFlags2()
{
    filterActiveModel->setFilterFlags2(actionToggleFilterFlags2->isChecked());
    updateFilters();
}

void TaskEditor::setFilterFlags3()
{
    filterActiveModel->setFilterFlags3(actionToggleFilterFlags3->isChecked());
    updateFilters();
}

void TaskEditor::updateFilters()
{
    // ugly, but calling twice updates rows as expected  // FIXME-3 review...
    filterActiveModel->invalidate();
    filterActiveModel->invalidate();
}

bool TaskEditor::taskVisible(Task *task)
{
    return filterActiveModel->taskVisible(task);
}

void TaskEditor::showSelection()
{
    QModelIndexList list = view->selectionModel()->selectedIndexes();
    if (list.count() > 0)
        // Usually whole row is selected, so just go for first cell
        view->scrollTo(taskModel->index(taskModel->getTask(list.first())),
                       QAbstractItemView::EnsureVisible);
}

bool TaskEditor::select(Task *task)
{
    if (task) {
        blockExternalSelect = true;
        QModelIndex i0b = taskModel->index(task);
        QModelIndex i0e = taskModel->indexRowEnd(task);

        QModelIndex i1b = filterActiveModel->mapFromSource(i0b);
        QModelIndex i1e = filterActiveModel->mapFromSource(i0e);

        QItemSelection sel(i1b, i1e);

        view->selectionModel()->select(sel,
                                       QItemSelectionModel::ClearAndSelect);
        blockExternalSelect = false;
        return true;
    }
    return false;
}

void TaskEditor::clearSelection() { view->selectionModel()->clearSelection(); }

void TaskEditor::cellClicked(QModelIndex ix_unmapped)
{
    QModelIndex ix = filterActiveModel->mapToSource(ix_unmapped);
    if (ix.isValid() && ix.column() == 2)
        taskModel->getTask(ix)->getBranch()->getModel()->cycleTaskStatus();
}

void TaskEditor::headerContextMenu()
{
    // qDebug() << "TE::headerContextMenu()";
    // Trying to workaround https://bugreports.qt.io/browse/QTBUG-52307
    // view->horizontalHeader()->setStretchLastSection(true);
    // view->resizeColumnsToContents();
    // updateGeometry();
    // show();
}

void TaskEditor::updateColumnLayout()
{
    // Update column widths and visibility

    QString s = "/taskeditor/column/%1/";

    // Priority
    int i = 0;
    view->setColumnWidth(i, settings.value(s.arg(i) + "width", 80).toInt());
    view->setColumnHidden(i,
                          settings.value(s.arg(i) + "hidden", false).toBool());

    // Delta
    i = 1;
    view->setColumnWidth(i, settings.value(s.arg(i) + "width", 50).toInt());
    view->setColumnHidden(i,
                          settings.value(s.arg(i) + "hidden", false).toBool());

    // Status
    i = 2;
    view->setColumnWidth(i, settings.value(s.arg(i) + "width", 50).toInt());
    view->setColumnHidden(i,
                          settings.value(s.arg(i) + "hidden", false).toBool());

    // Age total
    i = 3;
    view->setColumnWidth(i, settings.value(s.arg(i) + "width", 50).toInt());
    view->setColumnHidden(i,
                          settings.value(s.arg(i) + "hidden", true).toBool());

    // Age mod
    i = 4;
    view->setColumnWidth(i, settings.value(s.arg(i) + "width", 50).toInt());
    view->setColumnHidden(i,
                          settings.value(s.arg(i) + "hidden", true).toBool());

    // Sleep
    i = 5;
    view->setColumnWidth(i, settings.value(s.arg(i) + "width", 80).toInt());
    view->setColumnHidden(i,
                          settings.value(s.arg(i) + "hidden", true).toBool());

    // Map
    i = 6;
    view->setColumnWidth(i, settings.value(s.arg(i) + "width", 100).toInt());
    view->setColumnHidden(i,
                          settings.value(s.arg(i) + "hidden", true).toBool());

    // Flags
    i = 7;
    view->setColumnWidth(i, settings.value(s.arg(i) + "width", 80).toInt());
    view->setColumnHidden(i,
                          settings.value(s.arg(i) + "hidden", false).toBool());

    // Taskname
    i = 8;
    view->setColumnWidth(i, settings.value(s.arg(i) + "width", 80).toInt());
    view->setColumnHidden(i,
                          settings.value(s.arg(i) + "hidden", false).toBool());
}

void TaskEditor::selectionChanged(const QItemSelection &selected,
                                  const QItemSelection &)
{
    // FIXME-3 what, if multiple selection in MapEditor?

    if (selected.indexes().isEmpty())
        // Avoid segfault on quit, when selected is empty
        return;

    QItemSelection sel0 = filterActiveModel->mapSelectionToSource(selected);
    QModelIndex ix = sel0.indexes().first();
    Task *t = taskModel->getTask(ix);
    if (t) {
        BranchItem *bi = t->getBranch();
        if (bi) {
            VymModel *m = bi->getModel();
            if (!blockExternalSelect)
                m->select(bi);
            if (m != mainWindow->currentModel())
                mainWindow->gotoModel(m);
            view->setStyleSheet(
                "QTableView {selection-background-color: " +
                m->getSelectionBrushColor().name() +
                "; selection-color:" + bi->getHeadingColor().name() + "}" +
                "QTableView:focus {" + editorFocusStyle + "}");
            view->scrollTo(selected.indexes().first());
        }
    }
}

void TaskEditor::contextMenuEvent(QContextMenuEvent *e)
{
    taskContextMenu->popup(e->globalPos());
}

void TaskEditor::toggleFilterMap() { setFilterMap(); }

void TaskEditor::toggleFilterActive() { setFilterActive(); }
void TaskEditor::toggleFilterNew() { setFilterNew(); }
void TaskEditor::toggleFilterBlocker() { setFilterBlocker(); }

void TaskEditor::toggleFilterFlags1() { setFilterFlags1(); }
void TaskEditor::toggleFilterFlags2() { setFilterFlags2(); }
void TaskEditor::toggleFilterFlags3() { setFilterFlags3(); }
