/*
    SuperCollider Qt IDE
    Copyright (c) 2012 Jakob Leben & Tim Blechmann
    http://www.audiosynth.com

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

    This program 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 this program; if not, write to the Free Software
    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301  USA
*/

#include "documents_dialog.hpp"
#include "main_window.hpp"
#include "../core/main.hpp"

#include <QVBoxLayout>
#include <QHBoxLayout>
#include <QDialogButtonBox>
#include <QPushButton>
#include <QHeaderView>
#include <QDir>
#include <QApplication>

namespace ScIDE {

DocumentsDialog::DocumentsDialog(Mode mode, QWidget* parent): QDialog(parent) { init(mode); }

DocumentsDialog::DocumentsDialog(const QList<Document*>& docs, Mode mode, QWidget* parent): QDialog(parent) {
    init(mode, docs);
}

void DocumentsDialog::init(Mode mode, const QList<Document*>& docs) {
    DocumentManager* mng = Main::documentManager();
    connect(mng, &DocumentManager::changedExternally, this, &DocumentsDialog::onDocumentChangedExternally);

    mMode = mode;

    mLabel = new QLabel;
    mLabel->setWordWrap(true);

    mDocTree = new QTreeWidget;
    mDocTree->setRootIsDecorated(false);

    QStringList headerLabels;
    headerLabels << tr("Document") << tr("Path", "File path.");
    if (mode == ExternalChange)
        headerLabels << tr("Status");
    mDocTree->setHeaderLabels(headerLabels);

    mDocTree->header()->setStretchLastSection(false);
    mDocTree->header()->setSectionResizeMode(1, QHeaderView::Stretch);
    if (mode == ExternalChange)
        mDocTree->header()->setSectionResizeMode(2, QHeaderView::ResizeToContents);

    switch (mode) {
    case ExternalChange:
        setWindowTitle(tr("Externally Changed Documents"));
        mLabel->setText(tr("The following documents have changed externally.\n\n"
                           "Apply the desired actions to selected documents, until the list is empty."));
        break;
    case Quit:
        setWindowTitle(tr("Unsaved Documents"));
        mLabel->setText(tr("The following documents have unsaved changes.\n\n"
                           "Apply desired actions to selected documents, until the list is empty."));
        break;
    }

    foreach (Document* doc, docs)
        addDocument(doc);

    QDialogButtonBox* dialogBtnBox = new QDialogButtonBox();
    QPushButton* btn;
    QPushButton* defaultBtn;
    if (mode == ExternalChange) {
        defaultBtn = btn = dialogBtnBox->addButton(tr("&Reload"), QDialogButtonBox::ActionRole);
        btn->setIcon(QIcon::fromTheme("view-refresh"));
        connect(btn, &QPushButton::clicked, this, &DocumentsDialog::reloadSelected);

        btn = dialogBtnBox->addButton(tr("Over&write"), QDialogButtonBox::ActionRole);
        btn->setIcon(QIcon::fromTheme("document-save"));
        connect(btn, &QPushButton::clicked, this, &DocumentsDialog::saveSelected);

        btn = dialogBtnBox->addButton(tr("&Ignore"), QDialogButtonBox::AcceptRole);
        btn->setIcon(QIcon::fromTheme("window-close"));
        connect(btn, &QPushButton::clicked, this, &DocumentsDialog::ignoreSelected);

        btn = dialogBtnBox->addButton(tr("&Close"), QDialogButtonBox::AcceptRole);
        btn->setIcon(QIcon::fromTheme("window-close"));
        connect(btn, &QPushButton::clicked, this, &DocumentsDialog::closeSelected);
    } else {
        defaultBtn = btn = dialogBtnBox->addButton(tr("&Save"), QDialogButtonBox::ActionRole);
        btn->setIcon(QIcon::fromTheme("document-save"));
        connect(btn, &QPushButton::clicked, this, &DocumentsDialog::saveSelected);

        btn = dialogBtnBox->addButton(tr("&Discard"), QDialogButtonBox::ActionRole);
        btn->setIcon(QIcon::fromTheme("window-close"));
        connect(btn, &QPushButton::clicked, this, &DocumentsDialog::ignoreSelected);

        btn = dialogBtnBox->addButton(tr("&Cancel"), QDialogButtonBox::RejectRole);
        btn->setIcon(QIcon::fromTheme("window-close"));
        connect(btn, &QPushButton::clicked, this, &DocumentsDialog::reject);
    }

    QPushButton* selectAllBtn = new QPushButton(tr("Select &All"));
    connect(selectAllBtn, &QPushButton::clicked, this, &DocumentsDialog::selectAll);

    QPushButton* selectNoneBtn = new QPushButton(tr("Select N&one"));
    connect(selectNoneBtn, &QPushButton::clicked, this, &DocumentsDialog::selectNone);

    QLabel* iconLabel = new QLabel;
    iconLabel->setPixmap(QApplication::style()->standardIcon(QStyle::SP_MessageBoxWarning).pixmap(48, 48));
    iconLabel->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);

    QHBoxLayout* lblBox = new QHBoxLayout();
    lblBox->addWidget(iconLabel);
    lblBox->addWidget(mLabel);

    QHBoxLayout* selectionBox = new QHBoxLayout();
    selectionBox->addWidget(selectAllBtn);
    selectionBox->addWidget(selectNoneBtn);

    QVBoxLayout* vbox = new QVBoxLayout();
    vbox->addLayout(lblBox);
    vbox->addWidget(mDocTree);
    vbox->addLayout(selectionBox);
    vbox->addWidget(dialogBtnBox);

    setLayout(vbox);

    defaultBtn->setDefault(true);
    defaultBtn->setFocus(Qt::OtherFocusReason);

    resize(500, 300);
}

void DocumentsDialog::addDocument(Document* doc) {
    Item* item = new Item(doc);
    mDocTree->addTopLevelItem(item);
}

void DocumentsDialog::selectAll() {
    int c = count();
    for (int i = 0; i < c; ++i)
        item(i)->setChecked(true);
}

void DocumentsDialog::selectNone() {
    int c = count();
    for (int i = 0; i < c; ++i)
        item(i)->setChecked(false);
}

void DocumentsDialog::saveSelected() {
    int i = 0;
    while (i < count()) {
        Item* itm = item(i);
        if (itm->isChecked()) {
            if (!MainWindow::save(itm->document()))
                return;
            delete itm;
        } else
            ++i;
    }
    if (!count())
        accept();
}

void DocumentsDialog::reloadSelected() {
    DocumentManager* mng = Main::documentManager();

    int i = 0;
    while (i < count()) {
        Item* itm = item(i);
        if (itm->isChecked()) {
            if (!mng->reload(itm->document()))
                return;
            delete itm;
        } else
            ++i;
    }
    if (!count())
        accept();
}

void DocumentsDialog::ignoreSelected() {
    int i = 0;
    while (i < count()) {
        Item* itm = item(i);
        if (itm->isChecked())
            delete itm;
        else
            ++i;
    }
    if (!count())
        accept();
}

void DocumentsDialog::closeSelected() {
    DocumentManager* mng = Main::documentManager();

    int i = 0;
    while (i < count()) {
        Item* itm = item(i);
        if (itm->isChecked()) {
            mng->close(itm->document());
            delete itm;
        } else
            ++i;
    }
    if (!count())
        accept();
}

void DocumentsDialog::onDocumentChangedExternally(Document* doc) {
    int c = count();
    for (int i = 0; i < c; ++i) {
        Item* itm = item(i);
        if (itm->document() == doc) {
            itm->update();
            return;
        }
    }

    addDocument(doc);
}

DocumentsDialog::Item::Item(Document* doc): mDoc(doc) { update(); }

void DocumentsDialog::Item::update() {
    setTitle(mDoc->title());
    setPath(mDoc->filePath());
    if (!mDoc->filePath().isEmpty() && !QFile::exists(mDoc->filePath())) {
        setStatus(tr("Removed"));
        setChecked(false);
    } else {
        setStatus(tr("Modified"));
        setChecked(true);
    }
}

}
