#include "logicmain.h"
#include "src/frame/logger.h"
#include "src/frame/configuration.h"
#include "src/frame/signals.h"
#include "src/po/translation.h"
#include "src/model/monitorcdrom.h"
#include "src/model/menufactory.h"
#include "src/data/datacdrom.h"
#include "src/view/modaldialog.h"
#include "src/view/filefilterrules.h"
#include "src/frame/signals.h"
#include <unistd.h>
#include <pwd.h>
#include <QDebug>
#include <QStandardPaths>
#include <QFileInfo>
#include <QMutex>
#include <QThread>
#include <QDebug>

LogicMain *LogicMain::m_oInstance = nullptr;
QMutex     LogicMain::m_oMutex;

LogicMain::LogicMain(QObject *parent) :
    QObject(parent),
    m_iBusness(-1),
    m_oTheme(nullptr)
{
    QFileInfo f;
    struct passwd *pwd;


    connect(this, SIGNAL(info(QString)), LOGGER, SLOT(info(QString)));
    connect(this, SIGNAL(warn(QString)), LOGGER, SLOT(warn(QString)));
    connect(this, SIGNAL(error(QString)), LOGGER, SLOT(error(QString)));
    connect(this, SIGNAL(debug(QString)), LOGGER, SLOT(debug(QString)));
    LOGGER->registerName(this, _("MAIN"));

    m_oCDROMS.clear();

    if (QGSettings::isSchemaInstalled("org.ukui.style"))
    {
        m_oTheme = new QGSettings("org.ukui.style");
        m_oCurrentIcon = m_oTheme->get("iconThemeName").toString();
        connect(m_oTheme, &QGSettings::changed, [=](){
            if (m_oCurrentIcon != m_oTheme->get("iconThemeName").toString())
            {
                m_oCurrentIcon = m_oTheme->get("iconThemeName").toString();
                emit g_user_signal->iconChange(QIcon::fromTheme("burner"));
            }
        });
    }

    pwd = getpwuid(getuid());

    msg = QDBusMessage::createMethodCall( QString("com.kylinUserGuide.hotel_%1")
                                          .arg(pwd->pw_gid),"/", "com.guide.hotel",
                                          "showGuide");
    f.setFile("/usr/share/kylin-user-guide/data/guide/kylin-burner");
    msg << "kylin-burner";
    msg.setDelayedReply(false);
#if 0
    else
    {
        f.setFile("/usr/share/kylin-user-guide/data/guide/burner");
        if (f.exists()) msg << "kylin-burner";
        else
        {
            error(_("Cannot find help document."));
            return;
        }
    }
#endif

    connect(MONITOR, SIGNAL(addCDROM(QString)), this, SLOT(createCDROM(QString)));
    connect(MONITOR, SIGNAL(changeCDROM(QString)), this, SLOT(changeCDROM(QString)));
    connect(MONITOR, SIGNAL(removeCDROM(QString)), this, SLOT(removeCDROM(QString)));
    debug(_("Connect MONITOR signal addCDROM to createCDROM, for creating new"
            " cdrom information."));

    connect(MENU, SIGNAL(burnSetting(bool)), this, SLOT(slotsMenuBurnSetting()));    
    connect(this, SIGNAL(cdrom(void*)), MENU, SLOT(newCDROM(void*)));
    connect(MENU, SIGNAL(dataSetting(bool)), this, SLOT(slotsDataSetting()));
    connect(MENU, SIGNAL(diskCheck(bool)), this, SLOT(slotsDiskCheck()));
    connect(MENU, SIGNAL(help(bool)), this, SLOT(slotsHelp()));
    connect(this, SIGNAL(deleteCDROM(void*)), MENU, SLOT(takeCDROM(void*)));
    connect(g_user_signal, &GlobalUserSignal::noMedium, this, &LogicMain::noMedium);
}

LogicMain *LogicMain::instance()
{
    if (nullptr == m_oInstance)
    {
        QMutexLocker locker(&m_oMutex);

        if (nullptr == m_oInstance)
        {
            m_oInstance = new LogicMain();
        }
    }
    return m_oInstance;
}

void LogicMain::initISO()
{
    DataCDROM *c;
    QString path;

    path = QStandardPaths::writableLocation(QStandardPaths::DocumentsLocation);
    createCDROM(CFG->get("CreateISO", "DefaultPath", path).toString());
    path = QStandardPaths::writableLocation(QStandardPaths::DocumentsLocation);
    path = CFG->get("CopyImage", "DefaultPath", path).toString();
    if (!path.endsWith("/")) path.append("/");

    c = new DataCDROM(path, this);
    createCopyImage(c);
}

QString LogicMain::theme()
{
    QString ret;

    ret = m_oTheme->get("styleName").toString();
    if (ret == "ukui-dark") ret = "ukui-black";
    return ret;
}

QString LogicMain::icon()
{
    return m_oTheme->get("iconThemeName").toString();
}

void LogicMain::createCDROM(QString blockName)
{
    //当插入光驱后在打开刻录 不会接收到changeDevice信号；
    //当打开软件后 在插入光驱，会有一个creatDevice信号，2个changeDevice信号。
    //光驱门 打开后 发出两个changeDevice信号
    //光驱门 关闭   发出

    DataCDROM *cdrom;

    if (nullptr == sender())
    {
        blockName.append("/");
        blockName.append(CFG->get("CreateISO", "VolumnID", _("KylinBurner")).toString());
        blockName.append(".iso");
    }
    debug(_("Creating new cdrom named %1").arg(blockName));
    if (!MODAL->isHidden()) MODAL->accept();
    cdrom = static_cast<DataCDROM *>(m_oCDROMS.value(blockName));
    if (cdrom)
    {
        error(_("CDROM %1 already loaded.").arg(cdrom->display()));
        return;
    }
    else
    {
        qDebug()<<__LINE__<<__func__<<"Creating new cdrom named"<<blockName;
        cdrom = new DataCDROM(blockName, this);
        m_oCDROMS.insert(blockName, cdrom);



    }

    if (cdrom->isCDROM())
    {
        QThread::msleep(200);
        qDebug()<<__LINE__<<__func__<<"new cdrom "<<blockName << "is real CDROM";
        connect(cdrom, SIGNAL(empty()),this, SLOT(slotsEmptyMedium()));
        connect(cdrom, SIGNAL(appendale()), this, SLOT(slotsAppendableMedium()));
        connect(cdrom, SIGNAL(finished()), this, SLOT(slotsFinishedMedium()));

        if(!cdrom->m_bUpdateStart)
        {
            cdrom->m_bUpdateStart = true;
            qDebug()<<"createCDROM update() start " << blockName;
            cdrom->update();
            qDebug()<<"createCDROM update() end " << blockName;
            cdrom->m_bUpdateStart = false;
         }
    }
    else
    {
        emit createISO(cdrom);
    }
    emit this->cdrom(cdrom);

    //运行完update()可能光驱被拔出了，所以要判断一下，不要出现段错误
    if(cdrom->m_iUsing > 0 && cdrom->isCDROM())//有光驱
    {
        cdrom->use();
        //qDebug() << "createDROM update()运行完后，有光驱";
        if(cdrom->mediumStatus() >=0)//有光盘
        {
            //cdrom->sendMediumStatusToOtherView();
            //qDebug() << "createDROM update()运行完后，有光驱，有光盘发信号haveMedium";
            emit g_user_signal->haveMedium(cdrom);
        }
        else
        {
            emit noMedium(cdrom);
            //qDebug() << "createDROM update()运行完后，有光驱，没有光盘";
        }
        cdrom->release();
    }
    else
    {
            //qDebug() << "createDROM update()运行完后，没有光驱";
    }


//    if(cdrom->m_iUsing > 0 && cdrom->isCDROM() && cdrom->mediumStatus() >=0)
//    {
//        qDebug() << "开始加载数据";
//        cdrom->sendMediumStatusToOtherView();
//    }

}

/*
 * changeCDROM接收来自光驱的信号，当插入光驱、弹出光驱托盘、关光驱托盘都会接收到changeCDROM信号
 * 注意：不同光驱接收到的changeCDROM信号次数不太一样
 *
 */

//插入光盘： 接收一次createCDROM 和 两次changeCDROM（插入光驱打开刻录软件和打开刻录软件在再插入光驱接收到的changeCDROM信号次数不一样）
  //       createCDROM
#if 0
void LogicMain::changeCDROM(QString blockName)
{
    DataCDROM *cdrom;
    debug(_("Change CDROM, block name is %1").arg(blockName));
    QThread::sleep(1);

    cdrom = static_cast<DataCDROM *>(m_oCDROMS.value(blockName));
    if (nullptr == cdrom)
    {
        // createCDROM(blockName);
        return;
    }

    qDebug() << "";
    qDebug() << "Loginc changCDROM("<< cdrom->device() << ") - - - - - - - ";
    qDebug() << "这是一个changCDROM  start";
    qDebug() << "Loginc changCDROM("<< cdrom->device() << ") - - - - - - - ";
    qDebug() << "";


    if(!cdrom->m_bStart)
    {
        //光驱没有开始刻录

        if(!cdrom->m_bUpdateStart)
        {
            //update没有开始

            qDebug() << "change update() 开始了";
            cdrom->m_bUpdateStart = true;

            if (!MODAL->isHidden() && !cdrom->isEjected()) MODAL->close();
            debug(_("Change CDROM %1").arg(cdrom->display()));
            noMedium(cdrom);

            qDebug()<<"changeCDROM update() "<< blockName;


            emit g_user_signal->showTip_loadMedium();
            cdrom->update();
            qDebug() << "changeCDROM update() 结束";
            qDebug()<< "";
            emit g_user_signal->hideTip_loadMedium();
            cdrom->m_bUpdateStart = false;


            //如果removeDevice后update()又执行完了，会delete 光驱。
            //如果不进行判断光驱是否存在，且不能用cdrom==null，因为没有置空，只能用计数值判断
            //否则cdrom->mediumStatus出错
            if(cdrom->m_iUsing > 0) //有光驱
            {
                if (cdrom->mediumStatus() < 0) //没光盘
                {
                    debug(_("There is no medium in CDROM %1").arg(cdrom->display()));
                    qDebug() << "changeDevice 执行update()后，光驱没有被拔，但没有光盘";
                    noMedium(cdrom);


                    qDebug() << "";
                    qDebug() << "这是一个changCDROM  end---------------";
                    qDebug() << "";


                    return;
                }
                else //有光盘
                {
                    qDebug() << "changeDevice 执行update()后，光驱没有被拔，且有光盘";
                }
            }
            else //没有光驱了，可能还在执行该条命令
            {
                qDebug() << "changeDevice 执行update()后，光驱被拔=NULL";
            }
        }
        else
        {
            qDebug() << "change update() 已经开始了，不操作了";


            qDebug() << "";
            qDebug() << "这是一个changCDROM  end---------------";
            qDebug() << "";

            return ;
        }
    }
    else
    {
        //光驱正在进行刻录，不进行操作
        qDebug() << "光驱正在进行刻录，不进行操作";
    }



    qDebug() << "";
    qDebug() << "这是一个changCDROM  end---------------";
    qDebug() << "";

}
#else
void LogicMain::changeCDROM(QString blockName)
{
    DataCDROM *cdrom;
    debug(_("Change CDROM, block name is %1").arg(blockName));
    qDebug()<<"Change CDROM, block name is "<<blockName;
    QThread::msleep(200);
    qDebug()<<"Change CDROM, block name is "<<blockName;

    cdrom = static_cast<DataCDROM *>(m_oCDROMS.value(blockName));
    if (nullptr == cdrom)
    {
        qDebug()<<"Change CDROM, block name is "<<blockName;
        // createCDROM(blockName);
        return;
    }

    if(!cdrom->m_bStart)
    {
        //光驱没有开始刻录
        if(!cdrom->m_bUpdateStart)
        {
            //update没有开始

            qDebug() << "change update() 开始了 " << blockName;
            cdrom->m_bUpdateStart = true;

            if (!MODAL->isHidden() && !cdrom->isEjected()) MODAL->close();
            debug(_("Change CDROM %1").arg(cdrom->display()));         
            noMedium(cdrom);
            cdrom->update();
            qDebug() << "changeCDROM update() end" << blockName;
            //qDebug()<< "";
            cdrom->m_bUpdateStart = false;


            //如果removeDevice后update()又执行完了，会delete 光驱。
            //如果不进行判断光驱是否存在，且不能用cdrom==null，因为没有置空，只能用计数值判断
            //否则cdrom->mediumStatus出错
            /*
            1判断有光驱
                2光驱门关   关门/插入光驱
                        3有光盘
                            4 关门/插入光驱  什么不都不做，return
                        3没光盘
                            4 关门/插入光盘---操作：向各界面传送移除光驱地址的信号（noMdium()							guan一致）newEarse分成两份
                    2光驱门开	弹出/插入光驱
                        操作：向各界面传送移除光驱地址的信号,noMdium()一致newEarse分成两份
            1没有光驱
            */
            if(cdrom->m_iUsing > 0) //有光驱
            {
                qDebug() << "changeDevice 执行update()后，有光驱";
                if(cdrom->doorIsOpen()) //光驱门开（光驱门开/插入光驱）
                {
                    //移除信号;
                    noMedium(cdrom);
                }
                else  //光驱门关（光驱门关/插入光驱）
                {
                    if (cdrom->mediumStatus() < 0) //没光盘
                    {
                        debug(_("There is no medium in CDROM %1").arg(cdrom->display()));
                        qDebug() << "changeDevice 执行update()后，光驱没有被拔，但没有光盘";
                        //移除信号
                        noMedium(cdrom);
                    }
                    else// 有光盘
                    {
                        qDebug() << "changeDevice 执行update()后，光驱没有被拔，且有光盘,发送信号haveMedium";

                        //cdrom->sendMediumStatusToOtherView();
                        emit g_user_signal->haveMedium(cdrom);
                        //return;
                    }
                }

            }
            else //没有光驱了，可能还在执行该条命令
            {
                //？？？还需要移除信号吗？？？
                noMedium(cdrom);
                qDebug() << "changeDevice 执行update()后，光驱被拔=NULL";
            }

            //if(cdrom->m_iUsing > 0 && cdrom->isCDROM() && cdrom->mediumStatus() >=0)
            //{
            //    //qDebug()<< "changeCDROM 加载数据";
            //    cdrom->sendMediumStatusToOtherView();
            //}

        }
        else
        {
            qDebug() << "change update() 已经开始了，不操作了";
            return ;
        }
    }
    else
    {
        //光驱正在进行刻录，不进行操作
        //qDebug() << "光驱正在进行刻录，不进行操作";
    }
}
#endif
void LogicMain::removeCDROM(QString block)
{
    DataCDROM *cdrom;
    cdrom = static_cast<DataCDROM *>(m_oCDROMS.value(block));
    if (!MODAL->isHidden()) MODAL->accept();
    if (nullptr == cdrom) return;
    debug(_("Remove CDROM %1").arg(cdrom->display()));
    qDebug()<<__LINE__<<__func__<<"Remove CDROM %1"<<cdrom->display();
    m_oCDROMS.remove(block);
    qDebug()<<__LINE__<<__func__<<"Remove CDROM %1"<<cdrom->display();
    emit g_user_signal->removeDisc(block);
    //cdrom->release();
    noMedium(cdrom); // 首先移除数据
    deleteCDROM(cdrom); // 移除界面展示中遗留的光驱信息。
}

void LogicMain::slotsEmptyMedium()
{
    DataCDROM *cdrom;

    cdrom = qobject_cast<DataCDROM *>(sender());

    debug(_("Get empty medium in CDROM %1").arg(cdrom->display()));
    debug(_("BurnerName : %1 DiskName : %2").arg(cdrom->display()).arg(cdrom->mDisplay()));
    emptyMedium(sender());
}

void LogicMain::slotsAppendableMedium()
{
    DataCDROM *cdrom;

    cdrom = qobject_cast<DataCDROM *>(sender());

    //cdrom->use();
    debug(_("Get appendable medium in CDROM %1").arg(cdrom->display()));
    debug(_("BurnerName : %1 DiskName : %2").arg(cdrom->display()).arg(cdrom->mDisplay()));

    emit appendableMedium(sender());
    //cdrom->release();
}

void LogicMain::slotsFinishedMedium()
{
    DataCDROM *cdrom;

    cdrom = qobject_cast<DataCDROM *>(sender());

    debug(_("Get finished medium in CDROM %1").arg(cdrom->display()));
    debug(_("BurnerName : %1 DiskName : %2").arg(cdrom->display()).arg(cdrom->mDisplay()));
    emit finishedMedium(sender());
}

void LogicMain::slotsMenuBurnSetting()
{
    if (m_iBusness < CreateISO || m_iBusness > GetISO) return;
    if (m_iBusness < BurnImage) burnDataSetting();
    else if (m_iBusness == BurnImage) burnImageSetting();
    else burnCopySetting();
}

void LogicMain::slotsSetBusness(int bus)
{
    if (bus < CreateISO || bus > GetISO)
    {
        error(_("Undefined busness."));
        emit menu(GETMENU(bus));
        return;
    }
    m_iBusness = bus;
    emit menu(GETMENU(bus));
    debug(_("Change to do busness %1").arg(m_iBusness));
}

void LogicMain::slotsDoBusness()
{
    switch (m_iBusness)
    {
    case CreateISO:
        debug(_("Prepare to create iso file."));
        emit createISO();
        break;
    case BurnData:
        debug(_("Prepare to burn data."));
        emit burnData();
        break;
    case BurnUDFData:
        //qDebug() << "Prepare to burn UDF Format data.";
        debug(_("Prepare to burn UDF Format data."));
        emit burnUDFData();
        break;
    case AddBurn:
        debug(_("Prepare to append burn."));
        emit addBurn();
        break;
    case BurnImage:
        debug(_("Prepare to burn image."));
        emit burnImage();
        break;
    case CopyData:
        debug(_("Prepare to copy disk data."));
        emit copyData();
        break;
    case GetISO:
        debug(_("Prepare to get iso from disk data."));
        emit getISO();
        break;
    default:
        error(_("Invalid busness [%1]").arg(m_iBusness));
        break;
    }
}

void LogicMain::slotsDataSetting()
{
    DATASETTING;
    MODAL->show();
}

void LogicMain::slotsDiskCheck()
{
    DISKCHECK;
    MODAL->show();
}

void LogicMain::slotsHelp()
{
    QDBusConnection::sessionBus().call(msg);
}

LogicMain::~LogicMain()
{}
