#include "menufactory.h"
#include "src/frame/logger.h"
#include "src/po/translation.h"
#include "src/model/logicmain.h"
#include "src/data/datacdrom.h"
#include "src/view/filefilterrules.h"
#include "src/view/kybaboutdialog.h"

#include <QApplication>
#include <QDBusMessage>
#include <QDBusConnection>
#include <QFileInfo>
#include <QDebug>

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

MenuFactory::MenuFactory(QObject *parent) :
    QObject(parent),
    m_oActionSetting(new QAction(/*QIcon::fromTheme("ukui-icon-setting"),*/ _("Setting"), this)),
    m_oActionDataSetting(new QAction(/*QIcon::fromTheme("ukui-icon-allsetting"),*/ _("Data Setting"), this)),
    m_oActionFileFilter(new QAction(_("File Filter"), this)),
    m_oActionFileFilterView(new QAction(/*QIcon::fromTheme("view-filter-symbolic"),*/ _("View Filter File(s)"), this)),
    m_oActionDiskCheck(new QAction(_("Disk Check"), this)),
    m_oActionBurnerSetting(new QAction(/*QIcon::fromTheme("drive-cdrom"),*/ _("Burner Setting"), this)),
    m_oActionEject(new QAction(/*QIcon::fromTheme("media-eject-symbolic"),*/ _("Eject"), this)),
    m_oActionEarse(new QAction(/*QIcon::fromTheme("accessories-system-cleaner"),*/ _("Earse"), this)),
    m_oActionVersion(new QAction(/*QIcon::fromTheme("burner"),*/ _("Version"), this)),
    m_oActionAbout(new QAction(/*QIcon::fromTheme("burner"),*/ _("About"), this)),
    m_oActionHelp(new QAction(/*QIcon::fromTheme("help"),*/ _("Help"), this)),
    m_oActionExit(new QAction(/*QIcon::fromTheme("exit-symbolic"),*/ _("Exit"), this)),
    m_oSubEject(new QMenu()),
    m_oSubErase(new QMenu())
{

    QMenu *menu;

    /*
    QFont f;
    f = m_oActionAbout->font();
    f.setPixelSize(14);
    m_oActionAbout->setFont(f);
    m_oActionBurnerSetting->setFont(f);
    m_oActionDataSetting->setFont(f);
    m_oActionDiskCheck->setFont(f);
    m_oActionEarse->setFont(f);
    m_oActionEject->setFont(f);
    m_oActionExit->setFont(f);
    m_oActionFileFilter->setFont(f);
    m_oActionFileFilterView->setFont(f);
    m_oActionHelp->setFont(f);
    m_oActionSetting->setFont(f);
    m_oActionVersion->setFont(f);
    */

    m_oCommonActions.clear();
    m_oMenus.clear();
    m_oEjects.clear();
    m_oErases.clear();

    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)));

    m_oEjectActions.clear();
    m_oEjectActions << m_oSubEject->addAction(QIcon::fromTheme("media-eject-symbolic"), _("Eject All"), this, SIGNAL(eject(bool)));
    m_oEraseActions.clear();
    //m_oEraseActions << m_oSubErase->addAction(QIcon::fromTheme("accessories-system-cleaner"), _("Earse All"), this, SIGNAL(earse(bool)));

    //m_oActionSetting->setShortcut(QKeySequence(Qt::Key_F3));
    //m_oActionSetting->setShortcutContext(Qt::ApplicationShortcut);
    connect(m_oActionSetting, SIGNAL(triggered(bool)), this, SIGNAL(setting(bool)));

    //m_oActionDataSetting->setShortcut(QKeySequence(Qt::ShiftModifier + Qt::Key_F3));
    //m_oActionDataSetting->setShortcutContext(Qt::ApplicationShortcut);
    connect(m_oActionDataSetting, SIGNAL(triggered(bool)), this, SIGNAL(dataSetting(bool)));

    //m_oActionFileFilter->setShortcut(QKeySequence(Qt::AltModifier + Qt::Key_F));
    //m_oActionFileFilter->setShortcutContext(Qt::ApplicationShortcut);
    connect(m_oActionFileFilter, SIGNAL(triggered(bool)), this, SIGNAL(fileFilter(bool)));

    //m_oActionFileFilterView->setShortcut(QKeySequence(Qt::AltModifier + Qt::Key_V));
    //m_oActionFileFilterView->setShortcutContext(Qt::ApplicationShortcut);
    connect(m_oActionFileFilterView, SIGNAL(triggered(bool)), this, SIGNAL(viewFilterFile(bool)));

    connect(m_oActionDiskCheck, SIGNAL(triggered(bool)), this, SIGNAL(diskCheck(bool)));

    //m_oActionBurnerSetting->setShortcut(QKeySequence(Qt::ControlModifier + Qt::ShiftModifier + Qt::Key_F3));
    //m_oActionBurnerSetting->setShortcutContext(Qt::ApplicationShortcut);
    connect(m_oActionBurnerSetting, SIGNAL(triggered(bool)), this, SIGNAL(burnSetting(bool)));

    connect(m_oActionEject, SIGNAL(triggered(bool)), this, SIGNAL(eject(bool)));
    connect(m_oActionEarse, SIGNAL(triggered(bool)), this, SIGNAL(earse(bool)));

    //m_oActionVersion->setShortcut(QKeySequence(Qt::AltModifier + Qt::Key_F10));
    //m_oActionVersion->setShortcutContext(Qt::ApplicationShortcut);
    connect(m_oActionVersion, SIGNAL(triggered(bool)), this, SIGNAL(version(bool)));

    connect(m_oActionAbout, SIGNAL(triggered(bool)), this, SIGNAL(about(bool)));
    connect(m_oActionAbout,SIGNAL(triggered(bool)),this,SLOT(showabout()));
    
    //m_oActionAbout->setShortcut(QKeySequence(Qt::Key_F10));
    //m_oActionAbout->setShortcutContext(Qt::ApplicationShortcut);

    //m_oActionHelp->setShortcut(QKeySequence(Qt::Key_F1));
    //m_oActionHelp->setShortcutContext(Qt::ApplicationShortcut);
    connect(m_oActionHelp, SIGNAL(triggered(bool)), this, SIGNAL(help(bool)));

    //m_oActionExit->setShortcut(QKeySequence(Qt::AltModifier + Qt::Key_F4));
    //m_oActionExit->setShortcutContext(Qt::ApplicationShortcut);
    connect(m_oActionExit, &QAction::triggered, [=](){
        qApp->quit();
    });
    // common actions
    // m_oCommonActions << m_oActionVersion << m_oActionAbout << m_oActionHelp << m_oActionExit;
    m_oCommonActions << m_oActionAbout << m_oActionHelp << m_oActionExit;
    connect(this, SIGNAL(setSetting(bool)), m_oActionBurnerSetting, SLOT(setEnabled(bool)));
    connect(this, SIGNAL(setViewFilterFile(bool)), m_oActionFileFilterView, SLOT(setEnabled(bool)));
    // create iso
    menu = new QMenu();
    //menu->addAction(m_oActionSetting);
    menu->addAction(m_oActionDataSetting);
    menu->addAction(m_oActionFileFilter);
    menu->addAction(m_oActionFileFilterView);
    m_oSeparator = menu->addSeparator();
    menu->addAction(m_oActionBurnerSetting);
    menu->addAction(m_oActionEject);
    menu->addAction(m_oActionEarse);
    menu->addSeparator();
    menu->addActions(m_oCommonActions);
    menu->addSeparator();
    m_oMenus << menu;

    // burn data
    menu = new QMenu();
    //menu->addAction(m_oActionSetting);
    menu->addAction(m_oActionDataSetting);
    menu->addAction(m_oActionFileFilter);
    menu->addAction(m_oActionFileFilterView);
    menu->addSeparator();
    menu->addAction(m_oActionBurnerSetting);
    menu->addAction(m_oActionEject);
    menu->addAction(m_oActionEarse);
    menu->addAction(m_oActionDiskCheck);
    menu->addAction(m_oSeparator);
    menu->addActions(m_oCommonActions);
    m_oMenus << menu; // burn data same as add burn

    // burn image
    menu = new QMenu();
    //menu->addAction(m_oActionSetting);
    //menu->addSeparator();
    menu->addAction(m_oActionBurnerSetting);
    menu->addAction(m_oActionEject);
    menu->addAction(m_oActionEarse);
    menu->addAction(m_oActionDiskCheck);
    menu->addAction(m_oSeparator);
    menu->addActions(m_oCommonActions);
    m_oMenus << menu; // burn data same as add burn

    // default is disabled for eject and earse
    m_oActionEject->setEnabled(false);
    m_oActionEarse->setEnabled(false);
}

MenuFactory *MenuFactory::instance()
{
    if (nullptr == m_oInstance)
    {
        QMutexLocker locker(&m_oMutex);
        if (nullptr == m_oInstance)
        {
            m_oInstance = new MenuFactory();
        }
    }
    return m_oInstance;
}

QMenu *MenuFactory::getMenu(int i)
{
    //m_oMenus有3个menu，m_oMenus[0]对应creatISO，m_oMenus[1]对应burnData,m_oMenus[2]对应burnImage.
    //在枚举Busness中添加了值，这里也得改，否则会导致返回值为NULL
    //bug92741 【刻录】点击刻录镜像界面后点击菜单栏，菜单栏打不开;
    switch(i)
    {
    case 0:
        //CreateISO
        //qDebug()<<"getMenu:: case 0 creatISO";
        return m_oMenus.at(0);
    case 1:
        //BurnData
        //qDebug()<<"getMenu:: case 1 BurnData";
    case 2:
        //BurnUDFData
        //qDebug()<<"getMenu:: case 2 burnUDFData";
    case 3:
        //AddBurn
        //qDebug()<<"getMenu:: case 3 addBurn";
        return m_oMenus.at(1);
    case 4:
        //qDebug()<<"getMenu:: case 4 burnIamge";
    case 5:
        //qDebug()<<"getMenu:: case 5 CopyData";
    case 6:
        //qDebug()<<"getMenu:: case 6  GetISO";
        return m_oMenus.at(2);
    default:
        //qDebug()<<"getMenu:: default";
        break;
    }
    return nullptr;

}

void MenuFactory::newCDROM(void *cdrom)
{
    DataCDROM *c;
    DataCDROM *d;

    if (!cdrom) return;
    c = (DataCDROM *)cdrom;
    //c->use();


    if (c->m_iUsing <= 0)  //光驱是不存在的,m_oSeting类被delete，后面调用isEjected会调用m_oSetting成员函数出错
    {
        return;
    }

    if (!c->isCDROM())
    {
        return;
    }
    if (!c->isEjected())
    {
        m_oActionEject->setEnabled(true);
    }
    connect(this, SIGNAL(eject(bool)), c, SLOT(eject()));
    if (-1 == m_oEjects.indexOf(cdrom))
    {
        for (int i = 0; i < m_oEjects.size(); ++i)
        {
            d = static_cast<DataCDROM *>(m_oEjects.at(i));
            if (!d) continue;
            if (c->device() == d->device()) return;
        }
        m_oEjectActions << m_oSubEject->addAction(c->mediumIcon(),
                                                  c->display(),
                                                  c, SLOT(eject()));
        m_oEjectActions.last()->setToolTip(c->mDisplay());
        if (c->isEjected())
        {
            m_oEjectActions.last()->setEnabled(false);
        }
        connect(c, SIGNAL(eject(bool)), m_oEjectActions.last(), SLOT(setEnabled(bool)));
        connect(c, SIGNAL(eject(bool)), this, SLOT(checkEject(bool)));
        m_oEjects << cdrom;
    }
    if (m_oEjectActions.size() > 2)
    {
        c = static_cast<DataCDROM *>(m_oEjects.first());
        disconnect(c, SIGNAL(eject(bool)), m_oActionEject, SLOT(setEnabled(bool)));
        m_oActionEject->setMenu(m_oSubEject);
    }
    else
    {
        connect(c, SIGNAL(eject(bool)), m_oActionEject, SLOT(setEnabled(bool)));
    }
}

void MenuFactory::checkEject(bool)
{
    int i;
    DataCDROM *c;

    for (i = 0; i < m_oEjects.size(); ++i)
    {
        c = static_cast<DataCDROM *>(m_oEjects.at(i));
        if (!c->isEjected()) break;
    }
    if (i == m_oEjects.size())
        m_oActionEject->setEnabled(false);
    else
        m_oActionEject->setEnabled(true);
}


/*
 * LogicMain中信号appendableMedium()、finishedMedium()和noMedium()更新可删除Action
 * 注意：在noMedium信号调用时光驱可能被拔出
 */
#if 0
void MenuFactory::newEarse(void *c)
{
    int idx;
    DataCDROM *cdrom;
    QAction *tmp;

    idx = m_oErases.indexOf(c);
    cdrom = static_cast<DataCDROM *>(c);


    //为了防止cdrom被delete后还调用成员函数cdrom->mediumStatus()造成段错误
    //RW光盘 && 没有在m_oEreases注册
    if (cdrom->mediumIsErasable() && -1 == idx)
    {
        //非空光盘，注册
        if (cdrom->mediumStatus() != DataMedium::MEDIUM_EMPTY)
        {
            m_oEraseActions << m_oSubErase->addAction(cdrom->mediumIcon(),
                                                      cdrom->mDisplay(),
                                                      cdrom, SLOT(earse()));
            m_oErases << cdrom;
        }
    }
    else
    {
        //光驱已在m_oEreases注册过的，移除
        if (-1 != idx)
        {
            tmp = m_oEraseActions.takeAt(idx);
            m_oSubErase->removeAction(tmp);
            delete tmp;
            m_oErases.takeAt(idx);
        }
    }
    if (m_oEraseActions.size())
        m_oActionEarse->setMenu(m_oSubErase);
    m_oActionEarse->setEnabled(m_oEraseActions.size());
}
#else
void MenuFactory::newEarse(void *c)
{
    int idx;
    DataCDROM *cdrom;

    idx = m_oErases.indexOf(c);
    cdrom = static_cast<DataCDROM *>(c);


    //为了防止cdrom被delete后还调用成员函数cdrom->mediumStatus()造成段错误
    //RW光盘 && 没有在m_oEreases注册
    if (cdrom->mediumIsErasable() && -1 == idx)
    {
        //非空光盘，注册
        if (cdrom->mediumStatus() != DataMedium::MEDIUM_EMPTY)
        {
            m_oEraseActions << m_oSubErase->addAction(cdrom->mediumIcon(),
                                                      cdrom->mDisplay(),
                                                      cdrom, SLOT(earse()));
            m_oErases << cdrom;
        }
    }
    else if(cdrom->mediumIsErasable() && idx > -1){
        if(cdrom->mediumStatus() != DataMedium::MEDIUM_EMPTY)
        {
            m_oEraseActions.clear();
            m_oSubErase->clear();
            m_oErases.clear();
            m_oEraseActions << m_oSubErase->addAction(cdrom->mediumIcon(),
                                                      cdrom->mDisplay(),
                                                      cdrom, SLOT(earse()));

            m_oErases << cdrom;

        }
    }
//逻辑对吗？还得再看
    if (m_oEraseActions.size())
        m_oActionEarse->setMenu(m_oSubErase);
    m_oActionEarse->setEnabled(m_oEraseActions.size());
}

void MenuFactory::removeEarse(void *c)
{

    int idx;
    QAction *tmp;

    idx = m_oErases.indexOf(c);

    //光驱已在m_oEreases注册过的，移除
    if (-1 != idx)
    {
        tmp = m_oEraseActions.takeAt(idx);
        m_oSubErase->removeAction(tmp);
        delete tmp;
        m_oErases.takeAt(idx);
    }
//逻辑对吗？还得再看
    if (m_oEraseActions.size())
        m_oActionEarse->setMenu(m_oSubErase);
    m_oActionEarse->setEnabled(m_oEraseActions.size());
}
#endif


void MenuFactory::takeCDROM(void * cdrom)
{
    int idx;
    DataCDROM *c;

    idx = 0;
    c = static_cast<DataCDROM *>(cdrom);

    idx = m_oEjects.indexOf(cdrom);

    //光驱m_oEjects在已注册过
    if (-1 != idx)
    {
        m_oEjects.takeAt(idx);
        delete m_oEjectActions.takeAt(idx);
    }
    checkEject(true);

    idx = 0;
    idx = m_oErases.indexOf(cdrom);
    if (-1 != idx)
    {
        m_oErases.takeAt(idx);
        delete m_oEraseActions.takeAt(idx);
    }
#if 1
    if (c) c->release();
#else
    if(c)
    {
        delete c;
        c = nullptr;
    }
#endif
}
void MenuFactory::showabout(){
    ABOUT->show();
}
MenuFactory::~MenuFactory()
{
    QMenu *menu;

    while (m_oMenus.size())
    {
        menu = m_oMenus.takeFirst();
        if (menu) delete menu;
    }
    m_oMenus.clear();
    delete m_oSubEject;
    delete m_oSubErase;
}
