#include "progpanel.h"
#include "globaldefine.h"
#include "tools.h"
#include "gutil/qgui.h"
#include "cfg.h"
#include "player/playwin.h"
#include "program/progcreatedlg.h"
#include "program/progeditorwin.h"
#include "program/copydirthread.h"
#include <QApplication>
#include <QHeaderView>
#include <QMessageBox>
#include <QStandardPaths>
#include <QProgressBar>

ProgPanel::ProgPanel(QSettings &settings, QWidget *parent) : QWidget(parent) {
    setAttribute(Qt::WA_DeleteOnClose);
    setAutoFillBackground(true);
    QPalette pal;
    pal.setBrush(QPalette::Window, QColor(0xeeeeee));
    setPalette(pal);

    auto vBox = new QVBoxLayout(this);
    vBox->setContentsMargins(0, 0, 0, 0);
    vBox->setSpacing(0);
    auto hBox = new QHBoxLayout();
    hBox->setContentsMargins(6,6,6,6);
    hBox->setSpacing(6);
    vBox->addLayout(hBox);

    bnNew = new QPushButton(tr("New"));
    bnNew->setFixedSize(88, 38);
    bnNew->setProperty("ssType", "progManageTool");
    hBox->addWidget(bnNew);
    connect(bnNew, &QPushButton::clicked, this, [this] {
        ProgCreateDlg dlg("", 512, 256, "", "", this);
        if(dlg.exec() != QDialog::Accepted) return;
        if(checkIfNameRepeated(dlg.fdName->text())) return;
        auto splitWidths = dlg.fdSplitWidths->text().split(" ", Qt::SkipEmptyParts);
        QList<int> widths; int max = 0, ttl = 0;
        foreach(auto splitWidth, splitWidths) {
            int val = splitWidth.toInt();
            if(val==0) continue;
            if(max < val) max = val;
            ttl += val;
            widths.append(val);
        }
        auto width = dlg.fdWidth->value();
        if(max) {
            while(ttl < width) {
                widths.append(max);
                ttl += max;
            }
            if(ttl > width) widths.last() -= ttl - width;
        }
        auto item = new ProgItem(mProgsDir, dlg.fdName->text(),  width,  dlg.fdHeight->value(),  dlg.fdRemark->toPlainText(), widths, max, mProgTree, this);
        item->save();//保存pro.json
        mProgTree->adjustCheckState();
        auto editor = new ProgEditorWin(item, gMainWin);
        editor->show();
    });

    bnEdit = new QPushButton(tr("Edit"));
    bnEdit->setFixedSize(QSize(88, 38));
    bnEdit->setProperty("ssType", "progManageTool");
    bnEdit->setEnabled(false);
    hBox->addWidget(bnEdit);
    connect(bnEdit,   SIGNAL(clicked(bool)), this, SLOT(onEditClicked(bool)));

    bnDelete = new QPushButton(tr("Delete"));
    bnDelete->setFixedSize(QSize(88, 38));
    bnDelete->setProperty("ssType", "progManageTool");
    bnDelete->setEnabled(false);
    hBox->addWidget(bnDelete);
    connect(bnDelete, SIGNAL(clicked(bool)), this, SLOT(onDeleteClicked(bool)));

    bnImport = new QPushButton(tr("Import"));
    bnImport->setFixedSize(88, 38);
    bnImport->setProperty("ssType", "progManageTool");
    hBox->addWidget(bnImport);
    connect(bnImport, &QPushButton::clicked, this, [this] {
        auto dir = QFileDialog::getExistingDirectory(this, tr("Choose Directory"), "/home", QFileDialog::ShowDirsOnly | QFileDialog::DontResolveSymlinks);
        if(dir.isEmpty()) return;
        QString progsDir = programsDir();
        if(dir.contains(progsDir, Qt::CaseInsensitive)) {
            QMessageBox::warning(this, tr("Tip"), tr("The imported directory is already in the working directory, so there is no need to import it again!"));
            return;
        }
        QStringList progDirs;
        if(QFileInfo::exists(dir + "/pro.json")) progDirs.append(dir);
        else {
            QStringList subdirNames = QDir(dir).entryList(QDir::Dirs | QDir::NoDotAndDotDot | QDir::NoSymLinks);
            foreach(QString subdirName, subdirNames) {
                auto subdir = dir + "/" + subdirName;
                if(! QFileInfo::exists(subdir + "/pro.json")) continue;
                if(QFileInfo::exists(progsDir + "/" + subdirName)) {
                    auto res = QMessageBox::information(gMainWin, tr("Tip Info"), subdirName + tr(":solution(s) already exist.are you sure you want to overwrite the existing solution(s)?"), QMessageBox::Yes, QMessageBox::No);
                    if(res == QMessageBox::No) continue;
                }
                progDirs.append(subdir);
            }
            if(progDirs.isEmpty()) return;
        }
        ProgPortDlg dlg(this, tr("Import"));
        dlg.table->setRowCount(progDirs.count());
        for(int i=0; i<progDirs.count(); i++) {
            dlg.table->setItem(i, 0, new QTableWidgetItem(QFileInfo(progDirs[i]).fileName()));
            dlg.table->setCellWidget(i, 1, new QProgressBar);
        }
        connect(dlg.bnOK, &QPushButton::clicked, this, [=, &dlg] {
            for(int i=0; i<progDirs.count(); i++) ((QProgressBar*)dlg.table->cellWidget(i, 1))->setMaximum(dirFileSize(progDirs[i]));
            auto thread = new CopyDirThread();
            thread->dirSrcs = progDirs;
            thread->dirDst = progsDir;
            connect(thread, &CopyDirThread::sigProgress, &dlg, [&dlg](int i, int value) {
                ((QProgressBar*)dlg.table->cellWidget(i, 1))->setValue(value);
            });
            thread->start();
        });
        dlg.exec();

        mProgTree->clear();
        QStringList progNames = QDir(mProgsDir).entryList(QDir::Dirs | QDir::NoDotAndDotDot | QDir::NoSymLinks);
        foreach(QString pro_name, progNames) {
            QFile jFile(mProgsDir + "/" + pro_name + "/pro.json");
            if(! jFile.exists()) continue;
            if(! jFile.open(QIODevice::ReadOnly)) continue;
            auto data = jFile.readAll();
            jFile.close();
            m_pwPorgramItemList.append(new ProgItem(mProgsDir, QJsonDocument::fromJson(data).object(), mProgTree,this));
        }
    });

    bnExport = new QPushButton(tr("Export"));
    bnExport->setFixedSize(QSize(88, 38));
    bnExport->setEnabled(false);
    bnExport->setProperty("ssType", "progManageTool");
    hBox->addWidget(bnExport);
    connect(bnExport, &QPushButton::clicked, this, [=] {
        int cnt = mProgTree->topLevelItemCount();
        QStringList progNames;
        for(int i=0; i<cnt; i++) if(mProgTree->topLevelItem(i)->checkState(0) == Qt::Checked) progNames.append(static_cast<ProgItem*>(mProgTree->topLevelItem(i))->mName);
        if(progNames.isEmpty()) return;

        ProgPortDlg dlg(this, tr("Export"));
        dlg.table->setRowCount(progNames.count());
        for(int i=0; i<progNames.count(); i++) {
            dlg.table->setItem(i, 0, new QTableWidgetItem(progNames[i]));
            dlg.table->setCellWidget(i, 1, new QProgressBar);
        }
        connect(dlg.bnOK, &QPushButton::clicked, this, [=, &dlg] {
            QString dirDst = QFileDialog::getExistingDirectory(this, tr("Choose Directory"), "/home", QFileDialog::ShowDirsOnly | QFileDialog::DontResolveSymlinks);
            if(dirDst.isEmpty()) return;
            auto progsDir = programsDir();
            auto thread = new CopyDirThread();
            for(int i=0; i<progNames.count(); i++) {
                auto dir = progsDir+"/"+progNames[i];
                ((QProgressBar*)dlg.table->cellWidget(i, 1))->setMaximum(dirFileSize(dir));
                thread->dirSrcs.append(dir);
            }
            thread->dirDst = dirDst;
            connect(thread, &CopyDirThread::sigProgress, &dlg, [&dlg](int i, int value) {
                ((QProgressBar*)dlg.table->cellWidget(i, 1))->setValue(value);
            });
            thread->start();
        });
        dlg.exec();
    });

    bnSend = new QPushButton(tr("Send"));
    bnSend->setFixedSize(QSize(88, 38));
    bnSend->setProperty("ssType", "progManageTool");
    bnSend->setEnabled(false);
    bnSend->hide();
    hBox->addWidget(bnSend);

    btnPlay = new QPushButton(tr("Play")+"/"+tr("Stop"));
    btnPlay->setFixedSize(QSize(88, 38));
    btnPlay->setProperty("ssType", "progManageTool");
    hBox->addWidget(btnPlay);
    connect(btnPlay, &QPushButton::clicked, this, [this](){
        if(PlayWin::self!=nullptr) PlayWin::self->close();
        else {
            int cnt = mProgTree->topLevelItemCount();
            for(int i=0; i<cnt; i++) if(mProgTree->topLevelItem(i)->checkState(0) == Qt::Checked) {
                auto item = static_cast<ProgItem*>(mProgTree->topLevelItem(i));
                QString dir = mProgsDir+"/"+item->mName+"_tmp";
                QFile file(dir+"/program");
                if(! file.open(QIODevice::ReadOnly | QIODevice::Text)) return;
                QString value = file.readAll();
                file.close();
                QJsonParseError jsErr;
                QJsonObject prog = QJsonDocument::fromJson(value.toUtf8(), &jsErr).object();
                if(jsErr.error) return;
                if(PlayWin::self!=nullptr) PlayWin::self->close();
                if(item->mSplitWidths.isEmpty()) PlayWin::self = PlayWin::newIns(item->mWidth, item->mHeight, dir, prog);
                else PlayWin::self = PlayWin::newIns(item->mMaxWidth, item->mHeight * item->mSplitWidths.size(), dir, prog);
                break;
            }
        }
    });

    hBox->addStretch();


    auto txtSearch = new QLineEdit(this);
    txtSearch->setFixedSize(QSize(240, 36));
    QAction *search = new QAction(txtSearch);
    search->setIcon(QIcon(":/res/program/bnSearch.png"));
    txtSearch->addAction(search, QLineEdit::LeadingPosition);
    txtSearch->setClearButtonEnabled(true);
    txtSearch->setStyleSheet("border: 2px solid #aaaaaa;");
    hBox->addWidget(txtSearch);
    connect(txtSearch,SIGNAL(textChanged(const QString &)),this,SLOT(FilterProgram(const QString &)));

    mProgTree = new LoQTreeWidget();
    mProgTree->setIndentation(10);
    mProgTree->setSortingEnabled(true);
    m_headerItem = new QTreeWidgetItem();
    for(int i=1; i<ENUM_PROGRAMLISTHEADERITEM_END; i++) m_headerItem->setTextAlignment(i, Qt::AlignCenter);
    m_headerItem->setData(ENUM_PROGRAMLISTHEADERITEM_CHECK, Qt::DisplayRole, "");
    m_headerItem->setData(ENUM_PROGRAMLISTHEADERITEM_NAME, Qt::DisplayRole, tr("Name"));
    m_headerItem->setData(ENUM_PROGRAMLISTHEADERITEM_RESOLUTION, Qt::DisplayRole, tr("Resolution"));
    m_headerItem->setData(ENUM_PROGRAMLISTHEADERITEM_SIZE, Qt::DisplayRole, tr("File Size"));
    m_headerItem->setData(ENUM_PROGRAMLISTHEADERITEM_LASTTIME, Qt::DisplayRole, tr("Last Modify"));
    m_headerItem->setData(ENUM_PROGRAMLISTHEADERITEM_USB_EXPORT, Qt::DisplayRole, tr("Usb playback"));
    m_headerItem->setData(ENUM_PROGRAMLISTHEADERITEM_SEND, Qt::DisplayRole, tr("Publish"));
    mProgTree->setHeaderItem(m_headerItem);
    mProgTree->header()->setSectionResizeMode(ENUM_PROGRAMLISTHEADERITEM_CHECK, QHeaderView::Fixed);
    mProgTree->header()->setSectionResizeMode(ENUM_PROGRAMLISTHEADERITEM_NAME, QHeaderView::Stretch);
    mProgTree->header()->setSectionResizeMode(ENUM_PROGRAMLISTHEADERITEM_RESOLUTION, QHeaderView::Stretch);
    mProgTree->header()->setSectionResizeMode(ENUM_PROGRAMLISTHEADERITEM_SIZE, QHeaderView::Stretch);
    mProgTree->header()->setSectionResizeMode(ENUM_PROGRAMLISTHEADERITEM_LASTTIME, QHeaderView::Stretch);
    mProgTree->header()->setSectionResizeMode(ENUM_PROGRAMLISTHEADERITEM_USB_EXPORT, QHeaderView::Fixed);
    mProgTree->header()->setSectionResizeMode(ENUM_PROGRAMLISTHEADERITEM_SEND, QHeaderView::Fixed);
    mProgTree->header()->setStretchLastSection(false);
    mProgTree->setColumnWidth(ENUM_PROGRAMLISTHEADERITEM_CHECK, 66);
    mProgTree->setColumnWidth(ENUM_PROGRAMLISTHEADERITEM_USB_EXPORT, 100);
    mProgTree->setColumnWidth(ENUM_PROGRAMLISTHEADERITEM_SEND, 72);
    vBox->addWidget(mProgTree);
    connect(mProgTree, &LoQTreeWidget::sigCheckStateChanged, this, [this](int f){
        switch(f) {
        case LoQTreeWidget::CheckNone:
            bnEdit->setEnabled(false);
            bnDelete->setEnabled(false);
            bnExport->setEnabled(false);
            bnSend->setEnabled(false);
            break;
        case LoQTreeWidget::CheckOne:
            bnEdit  ->setEnabled(true);
            bnDelete->setEnabled(true);
            bnExport->setEnabled(true);
            bnSend  ->setEnabled(true);
            break;
        case LoQTreeWidget::CheckMulti:
            bnEdit  ->setEnabled(false);
            bnDelete->setEnabled(true);
            bnExport->setEnabled(true);
            bnSend  ->setEnabled(true);
            break;
        default: break;
        }
    });

    QString doc_path = QStandardPaths::writableLocation(QStandardPaths::DocumentsLocation);
    if(!doc_path.isEmpty()) {
        QString app_path = doc_path + "/" + QApplication::applicationName();
        mProgsDir = app_path + "/NPrograms";
        if(!QFileInfo::exists(mProgsDir)) {
            QDir app_dir(app_path);
            app_dir.mkdir("NPrograms");
            app_dir.mkdir("ApkStore");
        }
    }

    //connect(search, SIGNAL(triggered(bool)), this, SLOT(FilterProgram()));
    //查找根路径下的项目文件夹,查找文件夹下的节目pro.json信息,包括节目名称,大小,像素,备注等信息
    if(!mProgsDir.isEmpty()) {
        QDir root_dir(mProgsDir);
        QStringList pro_list = root_dir.entryList(QDir::Dirs | QDir::NoDotAndDotDot | QDir::NoSymLinks);
        foreach(QString pro_name, pro_list) {
            QDir pro_dir(mProgsDir + "/" + 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();
                m_pwPorgramItemList.append(new ProgItem(mProgsDir, pro.object(), mProgTree,this));
            }
        }
    }
    if(settings.value("ProgramListSortOrder").toInt()==0) mProgTree->sortByColumn(settings.value("ProgramListSortColumn").toInt(),Qt::SortOrder::AscendingOrder);
    else mProgTree->sortByColumn(settings.value("ProgramListSortColumn").toInt(),Qt::SortOrder::DescendingOrder);

//    ui->wProgramList->setSortingEnabled( false ); //不使能QT的自动排序
//    ui->wProgramList->header()->setSortIndicatorShown( true ); // 设置三角标识符可见
//    ui->wProgramList->header()->setSectionsClickable( true ); // 设置标题栏单击响应使能
//    connect( ui->wProgramList->header(), SIGNAL( sectionClicked(int) ), this, SLOT( OnClickColumn(int) ) );
}

void ProgPanel::OnClickColumn(int iColumn) {
    if(iColumn!=ENUM_PROGRAMLISTHEADERITEM_CHECK && iColumn!=ENUM_PROGRAMLISTHEADERITEM_SEND) mProgTree->sortByColumn(iColumn, mProgTree->header()->sortIndicatorOrder());
}
void ProgPanel::changeEvent(QEvent *event) {
    QWidget::changeEvent(event);
    if(event->type() == QEvent::LanguageChange) transUi();
}
void ProgPanel::transUi() {
    m_headerItem->setData(ENUM_PROGRAMLISTHEADERITEM_CHECK, 0, "");
    m_headerItem->setData(ENUM_PROGRAMLISTHEADERITEM_NAME, 0, tr("Name"));
    m_headerItem->setData(ENUM_PROGRAMLISTHEADERITEM_RESOLUTION, 0, tr("Resolution"));
    m_headerItem->setData(ENUM_PROGRAMLISTHEADERITEM_SIZE, 0, tr("File Size"));
    m_headerItem->setData(ENUM_PROGRAMLISTHEADERITEM_LASTTIME, 0, tr("Last Modify"));
    m_headerItem->setData(ENUM_PROGRAMLISTHEADERITEM_USB_EXPORT, 0, tr("Usb playback"));
    m_headerItem->setData(ENUM_PROGRAMLISTHEADERITEM_SEND, 0, tr("Publish"));
    bnNew->setText(tr("New"));
    bnEdit->setText(tr("Edit"));
    bnDelete->setText(tr("Delete"));
    bnImport->setText(tr("Import"));
    bnExport->setText(tr("Export"));
    bnSend->setText(tr("Send"));
    btnPlay->setText(tr("Play")+"/"+tr("Stop"));
    for(int i=0;i<m_pwPorgramItemList.count();i++) m_pwPorgramItemList.at(i)->refreshLable();
}

void ProgPanel::onEditClicked(bool){
    int cnt = mProgTree->topLevelItemCount();
    for(int i=0; i<cnt; i++) {
        if(mProgTree->topLevelItem(i)->checkState(0) == Qt::Checked) {
            auto item = static_cast<ProgItem*>(mProgTree->topLevelItem(i));
            auto editor = new ProgEditorWin(item, gMainWin);
            editor->show();
            break;
        }
    }
}

bool ProgPanel::checkIfNameRepeated(const QString &name, QTreeWidgetItem *skip){
    int cnt = mProgTree->topLevelItemCount();
    for(int i=0; i<cnt; i++) {
        auto item = static_cast<ProgItem*>(mProgTree->topLevelItem(i));
        if(item == skip) continue;
        if(name == item->mName) {
            QMessageBox::warning(this, tr("Warning"), tr("Program name conflicted"));
            return true;
        }
    }
    return false;
}
void ProgPanel::onCreateNewProgramOnOpenEditProgramWidget(QString name, QSize res, QString remarks, QList<int> &splitWidths, int max)
{
    if(checkIfNameRepeated(name)) return;
    auto item = new ProgItem(mProgsDir, name, res.width(), res.height(), remarks, splitWidths, max, mProgTree, this);
    item->save();//保存pro.json
    mProgTree->adjustCheckState();
    auto editor = new ProgEditorWin(item, gMainWin);
    editor->show();
}
void ProgPanel::onDeleteClicked(bool){
    auto res = QMessageBox::information(this, tr("Tip Info"), tr("You will delete the selected solution(s),are you sure?"), QMessageBox::Ok, QMessageBox::Cancel);
    if(res == QMessageBox::Ok) {
        int cnt = mProgTree->topLevelItemCount();
        QList<ProgItem*> list;
        for(int i=0; i<cnt; i++) {
            if(mProgTree->topLevelItem(i)->checkState(0) == Qt::Checked) {
                auto item = static_cast<ProgItem*>(mProgTree->topLevelItem(i));
                list.push_back(item);
            }
        }
        while(!list.isEmpty()) {
            auto item = list.takeFirst();
            item->del();
            delete item;
        }
        mProgTree->adjustCheckState();
    }
}

void ProgPanel::FilterProgram(const QString &strtemp){
    if (strtemp.isEmpty())	//显示全部
    {
        for (int i = 0; i< mProgTree->topLevelItemCount(); ++i)
        {
            QTreeWidgetItem* topItem = mProgTree->topLevelItem(i);
            mProgTree->setRowHidden(i,mProgTree->indexFromItem(topItem->parent()),false);
        }
    }
    else
    {
        QList<QTreeWidgetItem*> resultList = mProgTree->findItems(strtemp, Qt::MatchContains,ENUM_PROGRAMLISTHEADERITEM_NAME);	//搜索结果
        if (resultList.size() > 0)
        {
            for (int i = 0; i< mProgTree->topLevelItemCount(); ++i)
            {
                QTreeWidgetItem* topItem = mProgTree->topLevelItem(i);
                if (resultList.contains(topItem))
                    mProgTree->setRowHidden(i,mProgTree->indexFromItem(topItem->parent()),false);	//显示匹配的结果
                else
                    mProgTree->setRowHidden(i,mProgTree->indexFromItem(topItem->parent()),true);	//隐藏不匹配的结果
            }
        }
        else {
            QList<QTreeWidgetItem*> resultList1 = mProgTree->findItems(strtemp, Qt::MatchContains,ENUM_PROGRAMLISTHEADERITEM_RESOLUTION);	//搜索结果
            if (resultList1.size() > 0){
                for (int i = 0; i< mProgTree->topLevelItemCount(); ++i){
                    QTreeWidgetItem* topItem = mProgTree->topLevelItem(i);
                    if (resultList1.contains(topItem)) mProgTree->setRowHidden(i,mProgTree->indexFromItem(topItem->parent()),false);	//显示匹配的结果
                    else mProgTree->setRowHidden(i,mProgTree->indexFromItem(topItem->parent()),true);	//隐藏不匹配的结果
                }
            }
            else {
                for (int i = 0; i< mProgTree->topLevelItemCount(); ++i){
                    QTreeWidgetItem* topItem = mProgTree->topLevelItem(i);
                    mProgTree->setRowHidden(i,mProgTree->indexFromItem(topItem->parent()),true);	//隐藏不匹配的结果
                }
            }
        }
    }

}

ProgPortDlg::ProgPortDlg(QWidget *parent, QString title) : QDialog(parent) {
    setWindowFlag(Qt::WindowContextHelpButtonHint, 0);
    resize(600, 400);
    setWindowTitle(title);

    auto vBox = new VBox(this);
    vBox->setContentsMargins(0, 0, 0, 6);

    table = new QTableWidget(0, 2);
    table->setSelectionMode(QTableWidget::NoSelection);
    table->setEditTriggers(QAbstractItemView::NoEditTriggers);
    table->setAlternatingRowColors(true);
    table->horizontalHeader()->setBackgroundRole(QPalette::Window);
    table->horizontalHeader()->setSectionResizeMode(0, QHeaderView::Stretch);
    table->horizontalHeader()->resizeSection(1, 200);
    table->setHorizontalHeaderLabels({tr("Solution Name"), tr("Progress")});
    vBox->addWidget(table);

    auto hBox = new HBox(vBox);
    hBox->addStretch();

    bnOK = new QPushButton(title);
    hBox->addWidget(bnOK);

    auto bnDone = new QPushButton(tr("Done"));
    connect(bnDone, &QPushButton::clicked, this, &BaseDlg::accept);
    hBox->addWidget(bnDone);
}