// Squawk messenger. 
// Copyright (C) 2019  Yury Gubich <blue@macaw.me>
// 
// 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 3 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, see <http://www.gnu.org/licenses/>.

#include "dialogqueue.h"
#include <QDebug>

DialogQueue::DialogQueue(const Models::Roster& p_roster):
    QObject(),
    currentSource(),
    currentAction(none),
    queue(),
    collection(queue.get<0>()),
    sequence(queue.get<1>()),
    prompt(nullptr),
    parent(nullptr),
    roster(p_roster)
{
}

DialogQueue::~DialogQueue()
{
}

void DialogQueue::quit()
{
    queue.clear();
    if (currentAction != none) {
        actionDone();
    }
}

void DialogQueue::setParentWidnow(QMainWindow* p_parent)
{
    parent = p_parent;
}

bool DialogQueue::addAction(const QString& source, DialogQueue::Action action)
{
    if (action == none) {
        return false;
    }
    if (currentAction == none) {
        currentAction = action;
        currentSource = source;
        performNextAction();
        return true;
    } else {
        if (currentAction != action || currentSource != source) {
            std::pair<Queue::iterator, bool> result = queue.emplace(source, action);
            return result.second;
        } else {
            return false;
        }
    }
}

bool DialogQueue::cancelAction(const QString& source, DialogQueue::Action action)
{
    if (source == currentSource && action == currentAction) {
        actionDone();
        return true;
    } else {
        Collection::iterator itr = collection.find(ActionId{source, action});
        if (itr != collection.end()) {
            collection.erase(itr);
            return true;
        } else {
            return false;
        }
    }
}

void DialogQueue::performNextAction()
{
    switch (currentAction) {
        case none:
            actionDone();
            break;
        case askPassword: {
            QInputDialog* dialog = new QInputDialog(parent);
            prompt = dialog;
            connect(dialog, &QDialog::accepted, this, &DialogQueue::onPropmtAccepted);
            connect(dialog, &QDialog::rejected, this, &DialogQueue::onPropmtRejected);
            dialog->setInputMode(QInputDialog::TextInput);
            dialog->setTextEchoMode(QLineEdit::Password);
            dialog->setLabelText(tr("Input the password for account %1").arg(currentSource));
            dialog->setWindowTitle(tr("Password for account %1").arg(currentSource));
            dialog->setTextValue("");
            dialog->exec();
        }
            break;
        case askCredentials: {
            CredentialsPrompt* dialog = new CredentialsPrompt(parent);
            prompt = dialog;
            connect(dialog, &QDialog::accepted, this, &DialogQueue::onPropmtAccepted);
            connect(dialog, &QDialog::rejected, this, &DialogQueue::onPropmtRejected);
            const Models::Account* acc = roster.getAccountConst(currentSource);
            dialog->setAccount(currentSource);
            dialog->setLogin(acc->getLogin());
            dialog->setPassword(acc->getPassword());
            dialog->exec();
        }
            break;
    }
}

void DialogQueue::onPropmtAccepted()
{
    switch (currentAction) {
        case none:
            break;
        case askPassword: {
            QInputDialog* dialog = static_cast<QInputDialog*>(prompt);
            emit responsePassword(currentSource, dialog->textValue());
        }
            break;
        case askCredentials: {
            CredentialsPrompt* dialog = static_cast<CredentialsPrompt*>(prompt);
            emit modifyAccountRequest(currentSource, {
                {"login", dialog->getLogin()},
                {"password", dialog->getPassword()}
            });
        }
            break;
    }
    actionDone();
}

void DialogQueue::onPropmtRejected()
{
    switch (currentAction) {
        case none:
            break;
        case askPassword:
        case askCredentials:
            emit disconnectAccount(currentSource);
            break;
    }
    actionDone();
}

void DialogQueue::actionDone()
{
    prompt->deleteLater();
    prompt = nullptr;

    if (queue.empty()) {
        currentAction = none;
        currentSource = "";
    } else {
        Sequence::iterator itr = sequence.begin();
        currentAction = itr->action;
        currentSource = itr->source;
        sequence.erase(itr);
        performNextAction();
    }
}

DialogQueue::ActionId::ActionId(const QString& p_source, DialogQueue::Action p_action):
    source(p_source),
    action(p_action) {}

bool DialogQueue::ActionId::operator < (const DialogQueue::ActionId& other) const
{
    if (action == other.action) {
        return source < other.source;
    } else {
        return action < other.action;
    }
}

DialogQueue::ActionId::ActionId(const DialogQueue::ActionId& other):
    source(other.source),
    action(other.action) {}