#include "mprogrammanager.h"
#include "ui_mprogrammanager.h"

mProgramManager::mProgramManager(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::mProgramManager),
    m_itemEditing(nullptr),
    m_pRoot("")
{
    ui->setupUi(this);

    LoAppConfig *cfg = LoAppConfig::getInstance();
    QString doc_path = cfg->DocumentsLocation();;
    if(!doc_path.isEmpty()) {
        QString app_path  = doc_path + "\\" + cfg->ApplicationName();
        QString pRoot = app_path + "\\NPrograms";
        QDir root_dir = QDir(pRoot);
        if(!root_dir.exists()) {
            QDir app_dir(app_path);
            app_dir.mkdir("NPrograms");
        }
        m_pRoot = pRoot;
    }

    QAction *search = new QAction(ui->txtSearch);
    search->setIcon(QIcon(":/res/ProgramManager/bnSearch.png"));
    ui->txtSearch->addAction(search, QLineEdit::LeadingPosition);
    ui->txtSearch->setClearButtonEnabled(true);
    ui->txtSearch->setProperty("ssType", "progManageTool");
    ui->txtSearch->setProperty("ssName", "searchProg");

    ui->bnNew   ->setProperty("ssName", "newProg");
    ui->bnNew   ->setProperty("ssType", "progManageTool");   
    ui->bnEdit  ->setProperty("ssType", "progManageTool");
    ui->bnDelete->setProperty("ssType", "progManageTool");
    ui->bnImport->setProperty("ssType", "progManageTool");
    ui->bnExport->setProperty("ssType", "progManageTool");
    ui->bnSend  ->setProperty("ssType", "progManageTool");

    connect(ui->bnNew,    SIGNAL(clicked(bool)), this, SLOT(onNewClicked(bool)));
    connect(ui->bnEdit,   SIGNAL(clicked(bool)), this, SLOT(onEditClicked(bool)));
    connect(ui->bnDelete, SIGNAL(clicked(bool)), this, SLOT(onDeleteClicked(bool)));

    m_bnSelectAll = new QCheckBox(ui->wProgramList);
    m_bnSelectAll->setProperty("ssType", "topList");
    m_bnSelectAll->setProperty("ssName", "selectAll");
    QRect rect;
    rect.setX(23);
    rect.setY(12);
    rect.setWidth(m_bnSelectAll->width());
    rect.setHeight(m_bnSelectAll->height());
    m_bnSelectAll->setGeometry(rect);
    m_bnSelectAll->setChecked(false);

    QTreeWidgetItem *headerItem = new QTreeWidgetItem();
    headerItem->setData(0, 0, "");
    headerItem->setData(1, 0, tr("Name"));
    headerItem->setData(2, 0, tr("Resolution"));
    headerItem->setData(3, 0, tr("File Size"));
    headerItem->setData(4, 0, tr("Last Modify"));
    headerItem->setData(5, 0, tr("Export"));
    headerItem->setData(6, 0, tr("Send"));
    headerItem->setTextAlignment(1, Qt::AlignLeft | Qt::AlignVCenter);
    for(int i=2; i<7; i++) {
        headerItem->setTextAlignment(i, Qt::AlignCenter);
    }
    ui->wProgramList->setProperty("ssType", "topList");
    ui->wProgramList->setHeaderItem(headerItem);
    ui->wProgramList->header()->setSectionResizeMode(0, QHeaderView::Fixed);
    ui->wProgramList->header()->setSectionResizeMode(1, QHeaderView::Stretch);
    ui->wProgramList->header()->setSectionResizeMode(2, QHeaderView::Stretch);
    ui->wProgramList->header()->setSectionResizeMode(3, QHeaderView::Stretch);
    ui->wProgramList->header()->setSectionResizeMode(4, QHeaderView::Stretch);
    ui->wProgramList->header()->setSectionResizeMode(5, QHeaderView::Fixed);
    ui->wProgramList->header()->setSectionResizeMode(6, QHeaderView::Fixed);
    ui->wProgramList->header()->setStretchLastSection(false);
    ui->wProgramList->setColumnWidth(0, 72);
    ui->wProgramList->setColumnWidth(5, 72);
    ui->wProgramList->setColumnWidth(6, 72);

    connect(m_bnSelectAll, SIGNAL(toggled(bool)), this, SLOT(onCheckAll(bool)));
    connect(ui->wProgramList, SIGNAL(itemClicked(QTreeWidgetItem*,int)),
            this, SLOT(onItemClicked(QTreeWidgetItem*,int)));

    if(!m_pRoot.isEmpty()) {
        QDir root_dir(m_pRoot);
        QStringList pro_list = root_dir.entryList(QDir::Dirs | QDir::NoDotAndDotDot | QDir::NoSymLinks);
        foreach(QString pro_name, pro_list) {
            QDir pro_dir(m_pRoot + "\\" + pro_name);
            if(pro_dir.exists("pro.json")) {
                QFile fPro(pro_dir.path() + "\\pro.json");
                fPro.open(QIODevice::ReadOnly);
                QJsonDocument pro = QJsonDocument::fromJson(fPro.readAll());
                fPro.close();
                onRestoreProgram(pro);
            }
        }
    }
}

mProgramManager::~mProgramManager()
{
    delete ui;
}

void mProgramManager::paintEvent(QPaintEvent *event)
{
    Q_UNUSED(event);
    QStyleOption opt;
    opt.init(this);
    QPainter p(this);
    style()->drawPrimitive(QStyle::PE_Widget, &opt, &p, this);
}

void mProgramManager::isAllChecked()
{
    bool isAllChecked = true;
    int cnt = ui->wProgramList->topLevelItemCount();
    if(cnt == 0) {
        isAllChecked = false;
    } else {
        for(int i=0; i<cnt; i++) {
            if(ui->wProgramList->topLevelItem(i)->checkState(0) == Qt::Unchecked) {
                isAllChecked = false;
                break;
            }
        }
    }
    m_bnSelectAll->blockSignals(true);
    if((!m_bnSelectAll->isChecked()) && isAllChecked) {
        m_bnSelectAll->setChecked(true);
    } else if((m_bnSelectAll->isChecked()) && (!isAllChecked)) {
        m_bnSelectAll->setChecked(false);
    }
    m_bnSelectAll->blockSignals(false);
}

void mProgramManager::onNewClicked(bool f)
{
    Q_UNUSED(f);
    wNewProgram *dlg = new wNewProgram(this);
    connect(dlg, SIGNAL(sigAcceptData(QString,QSize,QString)), this, SLOT(onCreateNewProgram(QString,QSize,QString)));
    dlg->exec();
}

void mProgramManager::onEditClicked(bool f)
{
    Q_UNUSED(f);
    QTreeWidgetItem *item = checkIfProgramChecked();
    if(nullptr == item) return;
    QJsonDocument pro = item->data(0, Qt::UserRole).toJsonDocument();
    QString name    = pro["name"].toString();
    QSize   res     = QSize(pro["resolution"]["w"].toInt(), pro["resolution"]["h"].toInt());
    QString remarks = pro["remarks"].toString();
    wNewProgram *dlg = new wNewProgram(name, res, remarks, this);
    connect(dlg, SIGNAL(sigAcceptData(QString,QSize,QString)), this, SLOT(onEditHead(QString,QSize,QString)));
    dlg->exec();
}

QString mProgramManager::convertFileSize(int n)
{
    QString res;
    if(n < 1024) {
        res = QString("%1B").arg(n);
    } else if(n < 1024 * 1024) {
        res = QString("%1KB").arg(n/1024);
    } else if(n < 1024 * 1024 * 1024) {
        res = QString("%1MB").arg(n/(1024 * 1024));
    } else {
        res = QString("%1GB").arg(n/(1024 * 1024 * 1024));
    }
    return res;
}

bool mProgramManager::checkIfNameRepeated(const QString &name, QTreeWidgetItem *skip)
{
    int cnt = ui->wProgramList->topLevelItemCount();
    for(int i=0; i<cnt; i++) {
        QTreeWidgetItem *item = ui->wProgramList->topLevelItem(i);
        if(item == skip) {
            continue;
        }
        QPushButton *item_name = static_cast<QPushButton*>(ui->wProgramList->itemWidget(item, 1));
        if(name == item_name->text()) {
            auto *mb = new LoUIMsgBoxOk(tr("Program name conflicted"), this);
            mb->exec();
            return true;
        }
    }
    return false;
}

QTreeWidgetItem* mProgramManager::checkIfProgramChecked()
{
    QTreeWidgetItem *res = nullptr;
    int cnt = ui->wProgramList->topLevelItemCount();
    for(int i=0; i<cnt; i++) {
        QTreeWidgetItem *item = ui->wProgramList->topLevelItem(i);
        if(Qt::Checked == item->checkState(0)) {
            res = item;
            break;
        }
    }
    return res;
}

bool mProgramManager::addProgram(QTreeWidgetItem *item, QString name, QSize res, QString fSize, QString eLast)
{
    if(checkIfNameRepeated(name)) {
        return false;
    }

    item->setData(2, 0, QString("%1 x %2").arg(res.width()).arg(res.height()));
    item->setData(3, 0, fSize);
    item->setData(4, 0, eLast);
    item->setTextAlignment(1, Qt::AlignLeft | Qt::AlignVCenter);
    for(int i=2; i<7; i++) {
        item->setTextAlignment(i, Qt::AlignCenter);
    }
    item->setFlags(Qt::ItemIsUserCheckable | Qt::ItemIsEnabled);
    item->setCheckState(0, Qt::Unchecked);
    ui->wProgramList->addTopLevelItem(item);

    LoQPushButton *bnName = new LoQPushButton(name);
    bnName->setProperty("ssType", "topList");
    bnName->setProperty("ssName", "itemName");
    bnName->setCustomData(item);
    ui->wProgramList->setItemWidget(item, 1, bnName);
    connect(bnName, SIGNAL(sigClicked(LoQPushButton*,bool)), this, SLOT(onEditProgram(LoQPushButton*,bool)));

    QPushButton *bnExport = new QPushButton();
    bnExport->setProperty("ssType", "progItemTool");
    bnExport->setProperty("ssName", "progExport");
    ui->wProgramList->setItemWidget(item, 5, bnExport);

    QPushButton *bnSend = new QPushButton();
    bnSend->setProperty("ssType", "progItemTool");
    bnSend->setProperty("ssName", "progSend");
    ui->wProgramList->setItemWidget(item, 6, bnSend);

    m_bnSelectAll->blockSignals(true);
    m_bnSelectAll->setChecked(false);
    m_bnSelectAll->blockSignals(false);
    return true;
}

void mProgramManager::setProgram(QTreeWidgetItem *item, QString name, QSize res, QString fSize, QString eLast)
{
    LoQPushButton *bnName = static_cast<LoQPushButton*>(ui->wProgramList->itemWidget(item, 1));
    bnName->setText(name);
    item->setData(2, 0, QString("%1 x %2").arg(res.width()).arg(res.height()));
    item->setData(3, 0, fSize);
    item->setData(4, 0, eLast);
}

void mProgramManager::onRestoreProgram(const QJsonDocument &pro)
{
    QString name    = pro["name"].toString();
    QSize   res     = QSize(pro["resolution"]["w"].toInt(), pro["resolution"]["h"].toInt());
    int     fSize   = pro["file_size"].toInt();
    QString eLast   = pro["last_edit"].toString();
    QString remarks = pro["remarks"].toString();
    QTreeWidgetItem *item = new QTreeWidgetItem();
    if(!addProgram(item, name, res, convertFileSize(fSize), eLast)) {
        delete item;
        return;
    }
    item->setData(0, Qt::UserRole, pro);
}

void mProgramManager::onCreateNewProgram(QString name, QSize res, QString remarks)
{
    QString eLast = QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss");
    QTreeWidgetItem *item = new QTreeWidgetItem();
    if(!addProgram(item, name, res, "0B", eLast)) {
        delete item;
        return;
    }

    QJsonObject obj_root;
    QJsonObject obj_size;
    obj_root["name"]       = QJsonValue(name);
    obj_size["w"]          = QJsonValue(res.width());
    obj_size["h"]          = QJsonValue(res.height());
    obj_root["resolution"] = obj_size;
    obj_root["file_size"]  = QJsonValue(0);
    obj_root["last_edit"]  = QJsonValue(eLast);
    obj_root["remarks"]    = QJsonValue(remarks);
    QJsonDocument pro(obj_root);
    item->setData(0, Qt::UserRole, pro);

    QString pro_path(m_pRoot + "\\" + name);
    QDir pro_dir(pro_path);
    if(!pro_dir.exists()) {
        QDir root_dir(m_pRoot);
        root_dir.mkdir(name);
    }
    if(pro_dir.exists()) {
        QFile f(pro_path + "\\pro.json");
        f.open(QIODevice::WriteOnly);
        f.write(pro.toJson());
        f.close();
    }
}

void mProgramManager::onDeleteClicked(bool f)
{
    Q_UNUSED(f);
    int cnt = ui->wProgramList->topLevelItemCount();
    QList<QTreeWidgetItem*> list;
    list.clear();
    for(int i=0; i<cnt; i++) {
        if(ui->wProgramList->topLevelItem(i)->checkState(0) == Qt::Checked) {
            QTreeWidgetItem *item = ui->wProgramList->topLevelItem(i);
            ui->wProgramList->removeItemWidget(item, 1);
            ui->wProgramList->removeItemWidget(item, 5);
            ui->wProgramList->removeItemWidget(item, 6);
            list.push_back(item);
        }
    }
    while(!list.isEmpty()) {
        QTreeWidgetItem *item = list.takeFirst();
        QJsonDocument pro = item->data(0, Qt::UserRole).toJsonDocument();
        QString pro_name = pro["name"].toString();
        QString pro_path(m_pRoot + "\\" + pro_name);
        QDir pro_dir(pro_path);
        pro_dir.removeRecursively();
        delete item;
    }
    if(0 == ui->wProgramList->topLevelItemCount()) {
        m_bnSelectAll->blockSignals(true);
        m_bnSelectAll->setChecked(false);
        m_bnSelectAll->blockSignals(false);
    }
}

void mProgramManager::editHead(QTreeWidgetItem *item, QString name, QSize res, QString remarks)
{
    QJsonDocument pro = item->data(0, Qt::UserRole).toJsonDocument();
    QString eLast = QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss");
    QString oldName = pro["name"].toString();
    QJsonObject obj_root = pro.object();
    QJsonObject obj_size = obj_root["resolution"].toObject();

    obj_root["name"]       = QJsonValue(name);
    obj_size["w"]          = QJsonValue(res.width());
    obj_size["h"]          = QJsonValue(res.height());
    obj_root["resolution"] = obj_size;
    obj_root["last_edit"]  = QJsonValue(eLast);
    obj_root["remarks"]    = QJsonValue(remarks);
    pro.setObject(obj_root);

    QDir root_dir(m_pRoot);
    if(oldName != name && !root_dir.rename(oldName, name)) {
        return;
    }

    item->setData(0, Qt::UserRole, pro);
    setProgram(item, name, res, convertFileSize(pro["file_size"].toInt()), eLast);

    QString pro_path(m_pRoot + "\\" + name);
    QDir pro_dir(pro_path);
    if(pro_dir.exists()) {
        QFile f(pro_path + "\\pro.json");
        f.open(QIODevice::WriteOnly);
        f.write(pro.toJson());
        f.close();
    }
}

void mProgramManager::onEditHead(QString name, QSize res, QString remarks)
{
    QTreeWidgetItem *item = checkIfProgramChecked();
    if(checkIfNameRepeated(name, item)) {
        return;
    }
    editHead(item, name, res, remarks);
}

void mProgramManager::onCheckAll(bool checked)
{
    int cnt = ui->wProgramList->topLevelItemCount();
    for(int i=0; i<cnt; i++) {
        ui->wProgramList->topLevelItem(i)->setCheckState(0, checked ? Qt::Checked : Qt::Unchecked);
    }
}

void mProgramManager::onItemClicked(QTreeWidgetItem *item, int column)
{
    if(column > 0) {
        item->setCheckState(0, item->checkState(0) == Qt::Unchecked ? Qt::Checked : Qt::Unchecked);
    }
    isAllChecked();
}

void mProgramManager::onEditProgram(LoQPushButton *obj, bool f)
{
    Q_UNUSED(f);
    m_itemEditing = static_cast<QTreeWidgetItem*>(obj->customData());
    QJsonDocument pro = m_itemEditing->data(0, Qt::UserRole).toJsonDocument();
    QString name = pro["name"].toString();
    wEditProgram *w = new wEditProgram(pro, m_pRoot + "\\" + name, this);
    connect(w, SIGNAL(sProgramChanged()), this, SLOT(onProgramChanged()));
    w->setWindowModality(Qt::WindowModal);
    w->show();
}

void mProgramManager::onProgramChanged()
{
    QJsonDocument pro = m_itemEditing->data(0, Qt::UserRole).toJsonDocument();
    QString name = pro["name"].toString();
    QSize res = QSize(pro["resolution"]["w"].toInt(), pro["resolution"]["h"].toInt());
    QString remarks = pro["remarks"].toString();
    editHead(m_itemEditing, name, res, remarks);
}
