/*
 *   This file is part of Dianara
 *   Copyright 2012-2019  JanKusanagi JRR <jancoding@gmx.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 "listsmanager.h"

ListsManager::ListsManager(PumpController *pumpController,
                           QWidget *parent) : QWidget(parent)
{
    m_pumpController = pumpController;
    connect(m_pumpController, &PumpController::personListReceived,
            this, &ListsManager::setPersonsInList);
    connect(m_pumpController, &PumpController::personAddedToList,
            this, &ListsManager::addPersonItemToList);
    connect(m_pumpController, &PumpController::personRemovedFromList,
            this, &ListsManager::removePersonItemFromList);


    // To show the current lists
    m_listsTreeWidget = new QTreeWidget(this);
    m_listsTreeWidget->setColumnCount(2);
    m_listsTreeWidget->setHeaderLabels(QStringList{ tr("Name"),
                                                    tr("Members") });
    m_listsTreeWidget->setSortingEnabled(true);
    m_listsTreeWidget->sortByColumn(0, Qt::AscendingOrder);
    m_listsTreeWidget->setAlternatingRowColors(true);
    m_listsTreeWidget->setSizePolicy(QSizePolicy::Minimum,
                                     QSizePolicy::MinimumExpanding);
    connect(m_listsTreeWidget, &QTreeWidget::itemSelectionChanged,
            this, &ListsManager::enableDisableDeleteButtons);


    // Buttons to add/remove people from lists, and the lists; Initially disabled
    m_addPersonButton = new QPushButton(QIcon::fromTheme("list-add-user",
                                                         QIcon(":/images/list-add.png")),
                                        tr("Add Mem&ber"),
                                        this);
    m_addPersonButton->setDisabled(true);
    connect(m_addPersonButton, &QAbstractButton::clicked,
            this, &ListsManager::showAddPersonDialog);

    m_removePersonButton = new QPushButton(QIcon::fromTheme("list-remove-user",
                                                            QIcon(":/images/list-remove.png")),
                                           tr("&Remove Member"),
                                           this);
    m_removePersonButton->setDisabled(true);
    connect(m_removePersonButton, &QAbstractButton::clicked,
            this, &ListsManager::removePerson);


    m_deleteListButton = new QPushButton(QIcon::fromTheme("edit-table-delete-row",
                                                          QIcon(":/images/button-delete.png")),
                                         tr("&Delete Selected List"),
                                         this);
    m_deleteListButton->setDisabled(true);
    connect(m_deleteListButton, &QAbstractButton::clicked,
            this, &ListsManager::deleteList);


    // Groupbox for the "create new list" stuff
    m_newListGroupbox = new QGroupBox(tr("Add New &List"), this);

    m_newListNameLineEdit = new QLineEdit(this);
    m_newListNameLineEdit->setPlaceholderText(tr("Type a name for the new list..."));
    m_newListNameLineEdit->setClearButtonEnabled(true);
    connect(m_newListNameLineEdit, &QLineEdit::textChanged,
            this, &ListsManager::enableDisableCreateButton);
    connect(m_newListNameLineEdit, &QLineEdit::returnPressed,
            this, &ListsManager::createList);


    m_newListDescTextEdit = new QTextEdit(this);
    m_newListDescTextEdit->setPlaceholderText(tr("Type an optional description here"));
    m_newListDescTextEdit->setToolTip(m_newListDescTextEdit->placeholderText());
    m_newListDescTextEdit->setTabChangesFocus(true);


    m_createListButton = new QPushButton(QIcon::fromTheme("edit-table-insert-row-above",
                                                          QIcon(":/images/list-add.png")),
                                         tr("Create L&ist"),
                                         this);
    m_createListButton->setDisabled(true); // Disabled until user types a name
    connect(m_createListButton, &QAbstractButton::clicked,
            this, &ListsManager::createList);


    // Widget to find and select a contact
    m_peopleWidget = new PeopleWidget(tr("&Add to List"),
                                      PeopleWidget::StandaloneWidget,
                                      m_pumpController,
                                      this);
    connect(m_peopleWidget, &PeopleWidget::addButtonPressed,
            this, &ListsManager::addPerson);


    // Layout
    m_buttonsLayout = new QHBoxLayout();
    m_buttonsLayout->addWidget(m_addPersonButton,    0, Qt::AlignLeft);
    m_buttonsLayout->addWidget(m_removePersonButton, 0, Qt::AlignLeft);
    m_buttonsLayout->addStretch(1);
    m_buttonsLayout->addWidget(m_deleteListButton,   0, Qt::AlignRight);


    m_groupboxLeftLayout = new QVBoxLayout();
    m_groupboxLeftLayout->addWidget(m_newListNameLineEdit);
    m_groupboxLeftLayout->addWidget(m_newListDescTextEdit);

    m_groupboxMainLayout = new QHBoxLayout();
    m_groupboxMainLayout->addLayout(m_groupboxLeftLayout);
    m_groupboxMainLayout->addWidget(m_createListButton, 0, Qt::AlignBottom);
    m_newListGroupbox->setLayout(m_groupboxMainLayout);


    m_mainLayout = new QVBoxLayout();
    m_mainLayout->addWidget(m_listsTreeWidget, 5);
    m_mainLayout->addLayout(m_buttonsLayout,   1);
    m_mainLayout->addStretch(1);
    m_mainLayout->addWidget(m_newListGroupbox, 3);
    this->setLayout(m_mainLayout);

    qDebug() << "ListsManager created";
}


ListsManager::~ListsManager()
{
    qDebug() << "ListsManager destroyed";
}



void ListsManager::setListsList(QVariantList listsList)
{
    qDebug() << "Setting person lists contents";

    // Disable to avoid users messing with it while it loads
    this->setDisabled(true);

    m_listsTreeWidget->clear();
    m_personListsUrlList.clear();

    QString listName;
    QString listDescription;
    QString listMembersCount;
    QVariant listId;
    QVariant listUrl;

    foreach (const QVariant list, listsList)
    {
        QVariantMap listMap = list.toMap();
        listName = listMap.value("displayName").toString();
        listDescription = listMap.value("content").toString();
        if (!listDescription.isEmpty())
        {
            listDescription.prepend("<b></b>"); // HTMLize it so it gets wordwrapped
        }

        listMembersCount = listMap.value("members").toMap()
                                  .value("totalItems").toString();
        listId = listMap.value("id");
        listUrl = listMap.value("members").toMap().value("url");
        qDebug() << "list ID:" << listId.toString();
        qDebug() << "list URL:" << listUrl.toString();


        QTreeWidgetItem *listItem = new QTreeWidgetItem();
        listItem->setText(0, listName);
        listItem->setToolTip(0, listDescription);
        listItem->setText(1, listMembersCount);
        listItem->setToolTip(1, listDescription);
        listItem->setData(0, Qt::UserRole, listId);
        listItem->setData(0, Qt::UserRole + 1, listUrl);


        m_listsTreeWidget->addTopLevelItem(listItem);

        QString membersUrl = listMap.value("members").toMap()
                                    .value("url").toString();
        m_personListsUrlList.append(membersUrl);
    }

    // Get list of people in each list
    foreach (const QString url, m_personListsUrlList)
    {
        m_pumpController->getPersonList(url);
    }


    // m_listsTreeWidget->expandAll();
    m_listsTreeWidget->resizeColumnToContents(0);

    // Re-enable
    this->setEnabled(true);
}



QTreeWidgetItem *ListsManager::createPersonItem(QString id, QString name,
                                                QString avatarFile)
{
    QTreeWidgetItem *personItem = new QTreeWidgetItem();

    avatarFile = MiscHelpers::getCachedAvatarFilename(avatarFile);
    QPixmap avatarPixmap = QPixmap(avatarFile);
    if (avatarPixmap.isNull())
    {
        personItem->setIcon(0, QIcon::fromTheme("user-identity",
                                                QIcon(":/images/no-avatar.png")));
    }
    else
    {
        personItem->setIcon(0, QIcon(avatarPixmap));
    }
    personItem->setText(0, name);
    personItem->setText(1, id);


    return personItem;
}



/****************************************************************************/
/********************************* SLOTS ************************************/
/****************************************************************************/


/*
 * Fill one of the person lists with the names and ID's of the members
 *
 */
void ListsManager::setPersonsInList(QVariantList personList, QString listUrl)
{
    qDebug() << "ListsManager::setPersonsInList()" << listUrl;

    // Find out which TreeWidgetItem matches this list
    QTreeWidgetItem  *listItem = 0; // Avoid 'not initialized' warning
    foreach (QTreeWidgetItem *item, m_listsTreeWidget->findItems(QString(), Qt::MatchContains))
    {
        listItem = item;

        // Data in UserRole+1 is the Members Url
        if (listItem->data(0, Qt::UserRole + 1).toString() == listUrl)
        {
            break;
        }
    }


    foreach (const QVariant personVariant, personList)
    {
        // FIXME: this should use ASPerson()
        QVariantMap personMap = personVariant.toMap();

        QString id = ASPerson::cleanupId(personMap.value("id").toString());
        QString name = personMap.value("displayName").toString();
        QString avatar = personMap.value("image").toMap().value("url").toString();

        if (listItem != 0) // Ensure it's initialized!
        {
            QTreeWidgetItem *childItem = this->createPersonItem(id, name, avatar);
            listItem->addChild(childItem);
        }
    }
}



void ListsManager::createList()
{
    QString listName = m_newListNameLineEdit->text().trimmed();
    QString listDescription = m_newListDescTextEdit->toPlainText().trimmed();
    listDescription.replace("\n", "<br>");

    if (!listName.isEmpty())
    {
        qDebug() << "Creating list:" << listName;
        m_pumpController->createPersonList(listName, listDescription);

        m_newListNameLineEdit->clear();
        m_newListDescTextEdit->clear();
    }
    else
    {
        qDebug() << "Error: List name is empty!";
    }
}


void ListsManager::deleteList()
{
    if (m_listsTreeWidget->currentItem() == 0) // if nothing selected, so NULL...
    {
        return;
    }

    QString listName = m_listsTreeWidget->currentItem()->text(0);

    int confirmation = QMessageBox::question(this, tr("WARNING: Delete list?"),
                                             tr("Are you sure you want to delete %1?",
                                                "1=Name of a person list")
                                              .arg("'" + listName + "'"),
                                             tr("&Yes, delete it"), tr("&No"),
                                             QString(), 1, 1);

    if (confirmation == 0)
    {
        // Avoid the possibility of deleting twice!
        m_deleteListButton->setDisabled(true);

        QString listId = m_listsTreeWidget->currentItem()->data(0, Qt::UserRole)
                                                          .toString();

        m_pumpController->deletePersonList(listId);
    }
    else
    {
        qDebug() << "Confirmation cancelled, not deleting the list";
    }
}


/*
 * Enable or disable the "Create List" button
 *
 */
void ListsManager::enableDisableCreateButton(QString listName)
{
    if (listName.trimmed().isEmpty())
    {
        m_createListButton->setDisabled(true);
    }
    else
    {
        m_createListButton->setEnabled(true);
    }
}


/*
 * Enable or disable the "remove person" and "delete list" buttons
 * according to what's currently selected
 *
 */
void ListsManager::enableDisableDeleteButtons()
{
    // A list is selected
    if (m_listsTreeWidget->currentItem()->parent() == 0)
    {
        m_deleteListButton->setEnabled(true);
        m_removePersonButton->setDisabled(true);
    }
    else  // One of the items inside a list is selected
    {
        m_deleteListButton->setDisabled(true);
        m_removePersonButton->setEnabled(true);
    }

    // Either way...
    m_addPersonButton->setEnabled(true);
}



void ListsManager::showAddPersonDialog()
{
    if (m_listsTreeWidget->currentItem() == 0) // No list selected
    {
        return;
    }

    // Show the people widget, which will return the selected contact in a SIGNAL
    m_peopleWidget->resize(520, this->height());
    m_peopleWidget->resetWidget();
    m_peopleWidget->show();
}


void ListsManager::addPerson(QIcon icon, QString contactString,
                             QString contactName, QString contactId,
                             QString contactUrl)
{
    Q_UNUSED(icon)
    Q_UNUSED(contactString)
    Q_UNUSED(contactName)
    Q_UNUSED(contactUrl)

    m_peopleWidget->hide();

    if (contactId.isEmpty())
    {
        return;
    }

    QString listId;
    if (m_listsTreeWidget->currentItem()->parent() == 0) // If a list is selected
    {
        listId = m_listsTreeWidget->currentItem()->data(0, Qt::UserRole)
                                                 .toString();
    }
    else  // If a member is selected, get its matching list
    {
        listId = m_listsTreeWidget->currentItem()->parent()->data(0, Qt::UserRole)
                                                           .toString();
    }

    this->setDisabled(true);
    m_pumpController->addPersonToList(listId, "acct:" + contactId);
}


void ListsManager::removePerson()
{
    if (m_listsTreeWidget->currentItem() == 0) // Nothing selected, so it's NULL
    {
        return;
    }

    QString personId = m_listsTreeWidget->currentItem()->text(1);
    QString personName = m_listsTreeWidget->currentItem()->text(0);
    if (personName.isEmpty())
    {
        personName = personId;
    }

    QString listId;
    QString listName;
    if (m_listsTreeWidget->currentItem()->parent() != 0) // Ensure it's not a list
    {
        listId = m_listsTreeWidget->currentItem()->parent()->data(0, Qt::UserRole)
                                                           .toString();
        listName = m_listsTreeWidget->currentItem()->parent()->text(0);
    }

    int confirmation = QMessageBox::question(this, tr("Remove person from list?"),
                                             tr("Are you sure you want to remove %1 "
                                                "from the %2 list?",
                                                "1=Name of a person, "
                                                "2=name of a list")
                                             .arg(personName).arg(listName),
                                             tr("&Yes"), tr("&No"),
                                             QString(), 1, 1);

    if (confirmation == 0)
    {
        this->setDisabled(true);

        m_pumpController->removePersonFromList(listId,
                                               QStringLiteral("acct:") + personId);
    }
    else
    {
        qDebug() << "Confirmation cancelled, not removing" << personName
                 << "from" << listName;
    }
}


/*
 * Add the new item itself after a person is added correctly in PumpController
 *
 */
void ListsManager::addPersonItemToList(QString personId,
                                       QString personName,
                                       QString avatarUrl)
{
    QTreeWidgetItem *newItem = this->createPersonItem(personId,
                                                      personName,
                                                      avatarUrl);

    QTreeWidgetItem *selectedItem = m_listsTreeWidget->currentItem();
    // When the list itself is NOT selected, but a child, point to the parent
    if (selectedItem->parent() != 0)
    {
        selectedItem = selectedItem->parent();
    }    
    selectedItem->addChild(newItem);
    // Update member counter
    selectedItem->setText(1, QString::number(selectedItem->childCount()));

    this->setEnabled(true);
}


void ListsManager::removePersonItemFromList(QString personId)
{
    if (personId == m_listsTreeWidget->currentItem()->text(1))
    {
        QTreeWidgetItem *parentList = m_listsTreeWidget->currentItem()->parent();
        delete m_listsTreeWidget->currentItem();

        // Update member counter
        parentList->setText(1, QString::number(parentList->childCount()));
    }

    this->setEnabled(true);
}
