#include "fman.hpp"

// FManList
FManList::FManList(QWidget* parent) : QListView(parent) {
    setSelectionMode(QListView::ExtendedSelection);
    filterText = "";
    fsModel = new QFileSystemModel();
    fsModel->setResolveSymlinks(false);
    fsModel->setRootPath(QDir::currentPath());

    fsProxy = new QSortFilterProxyModel();
    fsProxy->setFilterKeyColumn(0);
    fsProxy->setRecursiveFilteringEnabled(true);
    fsProxy->setSourceModel(fsModel);

    // will update selection when filter is changed
    connect(this, &FManList::filterChanged, 
            this, &FManList::checkSelection, Qt::QueuedConnection);

    // will update selection when data is changed
    connect(fsProxy, &QSortFilterProxyModel::layoutChanged,
            this, &FManList::updateFilter, Qt::QueuedConnection);

    setModel(fsProxy);
}

void FManList::checkSelection(QString) {
    // If there was a selection any rows that are now filtered are unselected
    QList<QModelIndex> results = selectedIndexes();
    if (results.size() > 0) {
        return;
    }
    // otherwise select the top item
    // b/c we're mapping a tree model onto a list, carefully setting the parent
    // (ie. rootIndex) is required when requesting indexes.
    QModelIndex parent = fsProxy->mapFromSource(fsModel->index(QDir::currentPath()));
    QModelIndex index = model()->index(0, 0, parent);
    if (!index.isValid()) {
        DEBUG("FManList::checkSelection: Invalid index");
        return;
    }
    DEBUG("FManList::checkSelection: selected: " << 
            model()->data(index).toString().toStdString());
    selectionModel()->select(index, QItemSelectionModel::ClearAndSelect | QItemSelectionModel::Rows);
}

void FManList::updateFilter() {
    fsProxy->setFilterRegExp(QString(".*").prepend(filterText));
    setRootIndex(fsProxy->mapFromSource(fsModel->index(QDir::currentPath())));
    emit filterChanged(filterText);
}

QList<QString> FManList::getSelected() {
    //QList<QModelIndex> ids = selectedIndexes();
    QList<QModelIndex> ids = selectionModel()->selectedIndexes();
    QList<QString> results;
    for (int i=0; i < ids.size(); ++i) {
        results.append(QDir::current().absoluteFilePath(ids.at(i).data().toString()));
    }
    return results;
}

void FManList::keyPressEvent(QKeyEvent* event) {
    if (event->key() == Qt::Key_Up) {
        // move cursor
        QListView::keyPressEvent(event);
    } else if (event->key() == Qt::Key_Down) {
        // move cursor
        QListView::keyPressEvent(event);
    } else if (event->key() == Qt::Key_Space) {
        // un/mark
        QListView::keyPressEvent(event);
    } else if (event->key() == Qt::Key_Left) {
        // up a level
        QDir cwd = QDir::current();
        cwd.cdUp();
        QDir::setCurrent(cwd.absolutePath());
        updateFilter();
    } else if (event->key() == Qt::Key_Return) {
        // if selection is a single directory change to it
        QList<QString> filenames = getSelected();
        QDir cwd = QDir::current();
        if (filenames.size() == 1 and cwd.cd(filenames.at(0))) {
            QDir::setCurrent(cwd.absolutePath());
            updateFilter();
        } else {
        // else exit w/ selection
            emit selectionMade(filenames);
        }
    } else if (event->key() == Qt::Key_Delete) {
        if (filterText.size() > 0) {
            // clear filter
            filterText = "";
            updateFilter();
            clearSelection();
        } else {
            // exit w/o select
            emit cancel();
        }
    } else if (event->key() == Qt::Key_Backspace) {
        // remove last char in filter
        filterText = filterText.remove(filterText.size()-1, 1);
        updateFilter();
    } else {
        // attempt to add the key text to the filter
        QString t = event->text();
        int mods = event->modifiers();
        if (t.size() > 0 && (mods == Qt::NoModifier || mods == Qt::ShiftModifier)) {
            filterText += t;
            updateFilter();
        } else {
            // propagate
            QListView::keyPressEvent(event);
        }
    }
}

// FMan
FMan::FMan() : Tool() {
    type = ToolType::FMan;
    QString cwd = QDir::currentPath();
    label = "File Manager: " + QDir::currentPath();
    helpLabel = new QLabel();
    pickList = new FManList(this);

    QVBoxLayout *lo = new QVBoxLayout(this);
    lo->addWidget(helpLabel);
    lo->addWidget(pickList);

    setFocusProxy(pickList);

    QObject::connect(pickList, &FManList::filterChanged, helpLabel, &QLabel::setText);
    QObject::connect(pickList, &FManList::cancel, this, &FMan::handleCancel);
    QObject::connect(pickList, &FManList::selectionMade, this, &FMan::handleSelection);
}

QString FMan::currentFilename() {
    // TODO: handle multiple selections
    // TODO: handle no-selection
    DEBUG("FMan: currentFilename()");
    return pickList->getSelected()[0];
}

void FMan::handleCancel() {
    emit cancel();
}

void FMan::handleSelection(QList<QString> results) {
    emit selectionMade(results);
}
