#include "egif.h"
#include "cfg.h"
#include "tools.h"
#include <QBoxLayout>
#include <QDir>
#include <QLabel>
#include <QLineEdit>
#include <QMessageBox>
#include <QMovie>
#include <QPainter>
#include <QPushButton>
#include <QSpinBox>

EGif *EGif::create(const QString &file, PageListItem *pageItem, EBase *multiWin) {
    auto movie = new QMovie(file);
    if(! movie->isValid()) {
        QMessageBox::critical(gMainWin, "Gif Error", Tools::readErrStr(movie->lastError())+": "+movie->lastErrorString()+"\n"+file);
        return nullptr;
    }
    movie->setCacheMode(QMovie::CacheAll);
    movie->jumpToFrame(0);
    QFileInfo info(file);
    return new EGif(movie, info.absolutePath(), info.fileName(), pageItem, multiWin);
}
EGif *EGif::create(const QJsonObject &json, PageListItem *pageItem, EBase *multiWin) {
    auto widget = json["widget"];
    auto dir = widget["path"].toString();
    auto name = widget["file"].toString();
    if(! QFileInfo::exists(dir)) dir = pageItem->mPageDir;
    QString file = dir + "/" + name;
    if(QFileInfo::exists(file)) ;
    else if(QFileInfo::exists(file = pageItem->mPageDir + "/" + name)) dir = pageItem->mPageDir;
    else return nullptr;
    auto movie = new QMovie(file);
    if(! movie->isValid()) return nullptr;
    movie->setCacheMode(QMovie::CacheAll);
    movie->jumpToFrame(0);
    auto ins = new EGif(movie, dir, name, pageItem, multiWin);
    ins->setBaseAttr(json);
    auto play = json["play"];
    ins->mDuration = play["playDuration"].toInt();
    ins->mPlayTimes = play["playTimes"].toInt();
    return ins;
}

EGif::EGif(QMovie *movie, const QString &dir, const QString &name, PageListItem *pageItem, EBase *multiWin) : EBase(multiWin), mMovie(movie), mDir(dir), mName(name), mPageItem(pageItem) {
    mType = EBase::Gif;
}
EGif::~EGif() {
    if(mMovie!=nullptr) delete mMovie;
}
void EGif::paint(QPainter *painter, const QStyleOptionGraphicsItem *a, QWidget *b) {
    if(mMovie!=nullptr) {
        painter->setRenderHints(QPainter::Antialiasing|QPainter::SmoothPixmapTransform);
        painter->drawPixmap(innerRect(), mMovie->currentPixmap(), QRectF());
        if(timer==nullptr) {
            auto delay = mMovie->nextFrameDelay();
            if(delay!=0) {
                timer = new SyncTimer(delay);
                connect(timer, &SyncTimer::timeout, this, &EGif::sltNext, Qt::BlockingQueuedConnection);
                timer->start();
            }
        }
    }
    EBase::paint(painter, a, b);
}
void EGif::sltNext() {
    if(isVisible() && mMovie!=nullptr) {
        mMovie->jumpToNextFrame();
        timer->inter = mMovie->nextFrameDelay();
        update();
    } else if(timer!=nullptr) {
        timer->stop();
        timer = nullptr;
    }
}
void EGif::loadFiles() {
    if(mMovie!=nullptr) return;
    if(! QFileInfo::exists(mDir + "/" + mName)) return;
    mMovie = new QMovie(mDir + "/" + mName, QByteArray());
    mMovie->setCacheMode(QMovie::CacheAll);
    mMovie->jumpToFrame(0);
}
void EGif::freeFiles() {
    if(mMovie==nullptr) return;
    delete mMovie;
    mMovie = nullptr;
}

QWidget* EGif::attrWgt() {
    auto wgtAttr = new QWidget();
    auto vBox = new QVBoxLayout(wgtAttr);
    vBox->setContentsMargins(6, 0, 6, 0);
    if(mMultiWin!=nullptr) vBox->setSpacing(3);

    addBaseAttrWgt(vBox);

    auto hBox = new QHBoxLayout();
    hBox->addWidget(new QLabel(tr("Basic Properties")));

    auto line = new QFrame();
    line->setFrameShape(QFrame::HLine);
    line->setFrameShadow(QFrame::Sunken);
    hBox->addWidget(line, 1);

    vBox->addLayout(hBox);

    hBox = new QHBoxLayout();
    hBox->addSpacing(6);
    hBox->addWidget(new QLabel(tr("File")));

    auto wFile = new QLineEdit(mName);
    wFile->setReadOnly(true);
    hBox->addWidget(wFile);

    auto bnSelectFile = new QPushButton("...");
    bnSelectFile->setFixedWidth(30);
    bnSelectFile->setObjectName("bnSelectFile");
    connect(bnSelectFile, &QPushButton::clicked, this, [this, wFile] {
        auto file = QFileDialog::getOpenFileName(gMainWin, tr("Select File"), gFileHome, EGif::filters());
        if(file.isEmpty()) return;
        auto movie = new QMovie(file);
        if(! movie->isValid()) {
            QMessageBox::critical(gMainWin, "Gif Error", Tools::readErrStr(movie->lastError())+": "+movie->lastErrorString()+"\n"+file);
            return;
        }
        movie->setCacheMode(QMovie::CacheAll);
        movie->jumpToFrame(0);
        QFileInfo fileInfo(file);
        mName = fileInfo.fileName();
        wFile->setText(mName);
        mDir = fileInfo.absolutePath();
        gFileHome = mDir;
        if(mMovie!=nullptr) delete mMovie;
        mMovie = movie;
    });
    hBox->addWidget(bnSelectFile);

    vBox->addLayout(hBox);

    hBox = new QHBoxLayout();
    hBox->addWidget(new QLabel(tr("Play Properties")));

    line = new QFrame();
    line->setFrameShape(QFrame::HLine);
    line->setFrameShadow(QFrame::Sunken);
    hBox->addWidget(line, 1);

    vBox->addLayout(hBox);

    hBox = new QHBoxLayout();
    hBox->addSpacing(6);
    hBox->addWidget(new QLabel(tr("Play Duration")));

    auto wPlayDuration = new QSpinBox();
    wPlayDuration->setRange(1, 99999);
    wPlayDuration->setValue(mDuration);
    connect(wPlayDuration, (void(QSpinBox::*)(int))&QSpinBox::valueChanged, this, [this](int value) {
        mDuration = value;
    });
    hBox->addWidget(wPlayDuration);
    hBox->addWidget(new QLabel(tr("s")));
    hBox->addStretch();

    vBox->addLayout(hBox);

    hBox = new QHBoxLayout();
    hBox->addSpacing(6);
    hBox->addWidget(new QLabel(tr("Play Times")));

    auto wPlayTimes = new QSpinBox();
    wPlayTimes->setRange(1, 99999);
    wPlayTimes->setValue(mPlayTimes);
    connect(wPlayTimes, (void(QSpinBox::*)(int))&QSpinBox::valueChanged, this, [this](int value) {
        mPlayTimes = value;
    });
    hBox->addWidget(wPlayTimes);
    hBox->addStretch();

    vBox->addLayout(hBox);
    vBox->addStretch();
    return wgtAttr;
}

bool EGif::save(const QString &pageDir) {
    QString oldFile = mDir + PAGEDEL_SUFFIX + "/" + mName;
    if(QFileInfo::exists(oldFile)) ;
    else if(QFileInfo::exists(oldFile = mDir + "/" + mName)) ;
    else return false;
    QFile::copy(oldFile, pageDir + "/" + mName);
    mDir = pageDir;
    return true;
}

QJsonObject EGif::attrJson() const {
    QJsonObject oRoot;
    addBaseAttr(oRoot);
    oRoot["elementType"] = "Gif";
    oRoot["widget"] = QJsonObject{
        {"file", mName},
        {"path", mDir}
    };
    oRoot["play"] = QJsonObject{
        {"playDuration", mDuration},
        {"playTimes", mPlayTimes}
    };
    return oRoot;
}
