#include <QDebug>
#include <QDateTime>
#include <QFile>
#include <QIODevice>
#include <QApplication>
#include "config.h"
#include "configdatetimedlg.h"
#include "configlanguagedlg.h"
#include "configtemptypedlg.h"
#include "configbacklightdlg.h"
#include "configtimeformatdlg.h"
#include "configresttimeformatdlg.h"
#include "configmastervolumedlg.h"
#include "configsoundselelectdlg.h"
#include "yesnopopupdlg.h"
#include "usbcheckpopupdlg.h"
#include "configipdlg.h"
#include "configfileprocessdlg.h"
#include "confighalfenergydlg.h"
#include "config1digitsetdlg.h"
#include "configdutywashdlg.h"
#include "configsteamwashdlg.h"
#include "fileprocessor.h"
#include "backlight.h"
#include "udphandler.h"
#include "system.h"
#include "unistd.h"
#include "configdemomodedlg.h"

using namespace Define;
using namespace System;


Config* Config::instance = NULL;

Config::Config(QObject *parent) : QObject(parent)
{
    //memcpy(config_format,config_format_kr,MAX_CONFIG_COUNT*64);
    loadConfig();
    loadFavorite();
    qApp->installEventFilter(&watcher);
    applyCurrentConfigLanguage();
    applyConfig();


//    m_setFavorite.insert(2);
//    m_setFavorite.insert(3);
//    m_setFavorite.insert(1);
//    QSetIterator<uint32_t> i = getConstBeginFavorite();
//    while(i.hasNext()){
//        temp = i.next();
//        qDebug() << temp;
//    }
//    while(i.hasPrevious()){
//        temp = i.previous();
//        qDebug() << temp;
//    }
}

Config::~Config(){

}

Config* Config::getInstance(QObject *parent){
    if(instance ==NULL){
        instance = new Config(parent);
    }
    return instance;
}

void Config::initConfig(){
    memset(configlist.data,0x00,MAX_CONFIG_COUNT * 4);
    configlist.items.language.d32=0;
    configlist.items.datetime.d32=0;
    configlist.items.temptype.d32=0;
    configlist.items.backlight.d32=7;
    configlist.items.stop_delay.d32=10;
    configlist.items.best_dish_weight.d32=0;
    configlist.items.party_dish_weight.d32=0;
    configlist.items.ilc_rack_number.d32=10;
    configlist.items.ilc_rack_sequnece.d32=0x30201;
    configlist.items.ilc_cook_wait_time.d32=30;
    configlist.items.cooktime_format.d32=0;
    configlist.items.time_type.d32=1;
    configlist.items.resttime_format.d32=0;
    configlist.items.marster_vol.d32=7;
    configlist.items.keypad_sound1.d32=0;
    configlist.items.keypad_sound2.d32=7;
    configlist.items.request_loadexec.d32=6;
    configlist.items.programstep_finish.d32=7;
    configlist.items.cooktime_finish.d32=8;
    configlist.items.stoperror_distinguish.d32=9;
    configlist.items.sound_factory_reset.d32=0;
    configlist.items.haccp_data_download.d32=0;
    configlist.items.info_data_download.d32=0;
    configlist.items.service_data_download.d32=0;
    configlist.items.program_download.d32=0;
    configlist.items.program_upload.d32=0;
    configlist.items.program_initialize.d32=0;
    configlist.items.ip.d8.d8_0 = 192;
    configlist.items.ip.d8.d8_1 = 168;
    configlist.items.ip.d8.d8_2 = 0;
    configlist.items.ip.d8.d8_3 = 2;
    configlist.items.gateway.d8.d8_0 = 192;
    configlist.items.gateway.d8.d8_1 = 168;
    configlist.items.gateway.d8.d8_2 = 0;
    configlist.items.gateway.d8.d8_3 = 1;
    configlist.items.netmask.d32=0x00ffffff;
    configlist.items.set_download.d32=0;
    configlist.items.set_upload.d32=0;
    configlist.items.set_half_energy.d32=0;
    configlist.items.set_auto_darkness.d32=5;
    configlist.items.set_ilc_cook_temphumi_ready.d32=0;
    configlist.items.set_load_ready.d32=5;
    configlist.items.duty_wash.d32=0;
    configlist.items.loading_door_monitoring.d32=0;
    configlist.items.cooking_door_monitoring.d32=0;
    configlist.items.software_info.d32=0;
    configlist.items.hotline_chef.d32=0;
    configlist.items.hotline_service.d32=0;
    configlist.items.steam_wash.d32=0;
    configlist.items.demo_mode.d32=0;
    configlist.items.enter_engineer_mode.d32=0;
    configlist.items.model.d32 = model_electric_20;
    configlist.items.burner1_pwr1_normal_rpm.d32 = 4000;
    configlist.items.burner1_pwr1_half_rpm.d32 = 4000;
    configlist.items.burner1_pwr2_normal_rpm.d32 =  6000;
    configlist.items.burner1_pwr2_half_rpm.d32 = 4500;
    configlist.items.burner23_pwr1_normal_rpm.d32 = 2300;
    configlist.items.burner23_pwr1_half_rpm.d32 =  2300;
    configlist.items.burner23_pwr2_normal_rpm.d32 = 6500;
    configlist.items.burner23_pwr2_half_rpm.d32 = 4500;
    qDebug() << "Init Config lists";
}

bool Config::saveConfig(void){
    char buff[sizeof(config_lists)+1];
    qint64 writelen;
    QFile file(CONFIG_FILE_NAME);+
    memcpy(buff, configlist.data, sizeof(config_lists));
    buff[sizeof(config_lists)] = 0x9C;
    if(file.open(QIODevice::WriteOnly)){
        writelen = file.write(buff,sizeof(config_lists)+1);
        file.close();
        sync();
        if(writelen == (sizeof(config_lists)+1)){
            qDebug() << "config file saved";
            return true;
        }
    }
    qDebug() << "saving config file is fail!";
    return false;
}

bool Config::loadConfig(){
    char buff[sizeof(config_lists)+1];
    qint64 readlen;
    QFile file(CONFIG_FILE_NAME);
    initConfig();
    if(file.open(QIODevice::ReadOnly)){
        readlen = file.read(buff,sizeof(config_lists)+1);
        file.close();
        if(readlen != (sizeof(configlist)+1)){
            //File size is wrong. apply default config value & save default value;
            qDebug() << "config file size wrone, apply defult setting!";
            saveConfig();
            return false;
        }
        if(buff[sizeof(config_lists)] ==0x9c){
            memcpy(configlist.data,buff,sizeof(config_lists));
            qDebug() << "loading config file success";
        }
        else {
            qDebug()<<"loading config file fail";
            saveConfig();
            return false;
        }
    }
    else{
        saveConfig();
    }
    return false;
}

void Config::applyConfig(){
    watcher.setDelay(configlist.items.set_auto_darkness.d32);
    Backlight::set(configlist.items.backlight.d32);
    UdpHandler* udp = UdpHandler::getInstance();

    switch (configlist.items.model.d32)
    {
    case Define::model_gas_lng_10:
    case Define::model_gas_lng_20:
    case Define::model_gas_lng_24:
    case Define::model_gas_lng_40:
    case Define::model_gas_lpg_10:
    case Define::model_gas_lpg_20:
    case Define::model_gas_lpg_24:
    case Define::model_gas_lpg_40:
        if (configlist.items.set_half_energy.d32)
        {
            udp->set(TG_BURNER1_1_RPM, configlist.items.burner1_pwr1_half_rpm.d32);
            udp->set(TG_BURNER1_2_RPM, configlist.items.burner1_pwr2_half_rpm.d32);
            udp->set(TG_BURNER23_1_RPM, configlist.items.burner23_pwr1_half_rpm.d32);
            udp->set(TG_BURNER23_2_RPM, configlist.items.burner23_pwr2_half_rpm.d32);
        }
        else
        {            
            udp->set(TG_BURNER1_1_RPM, configlist.items.burner1_pwr1_normal_rpm.d32);
            udp->set(TG_BURNER1_2_RPM, configlist.items.burner1_pwr2_normal_rpm.d32);
            udp->set(TG_BURNER23_1_RPM, configlist.items.burner23_pwr1_normal_rpm.d32);
            udp->set(TG_BURNER23_2_RPM, configlist.items.burner23_pwr2_normal_rpm.d32);
        }
        UdpHandler::getInstance()->set(TG_PRODUCT_TYPE, 1);
        break;
    default:
        UdpHandler::getInstance()->set(TG_PRODUCT_TYPE, 2);
        break;
    }

    switch (configlist.items.model.d32)
    {
    case Define::model_electric_10:
    case Define::model_gas_lng_10:
    case Define::model_gas_lpg_10:
        UdpHandler::getInstance()->set(TG_MODEL_TYPE, 3);
        break;
    case Define::model_electric_20:
    case Define::model_gas_lng_20:
    case Define::model_gas_lpg_20:
        UdpHandler::getInstance()->set(TG_MODEL_TYPE, 2);
        break;
    case Define::model_electric_24:
    case Define::model_gas_lng_24:
    case Define::model_gas_lpg_24:
        UdpHandler::getInstance()->set(TG_MODEL_TYPE, 1);
        break;
    case Define::model_electric_40:
    case Define::model_gas_lng_40:
    case Define::model_gas_lpg_40:
        UdpHandler::getInstance()->set(TG_MODEL_TYPE, 0);
        break;
    }

    System::IPData ipdata;

    ipdata.address = QString("%1.%2.%3.%4").arg(configlist.items.ip.d8.d8_0).arg(configlist.items.ip.d8.d8_1).arg(configlist.items.ip.d8.d8_2).arg(configlist.items.ip.d8.d8_3);
    ipdata.gateway = QString("%1.%2.%3.%4").arg(configlist.items.gateway.d8.d8_0).arg(configlist.items.gateway.d8.d8_1).arg(configlist.items.gateway.d8.d8_2).arg(configlist.items.gateway.d8.d8_3);
    ipdata.netmask = QString("%1.%2.%3.%4").arg(configlist.items.netmask.d8.d8_0).arg(configlist.items.netmask.d8.d8_1).arg(configlist.items.netmask.d8.d8_2).arg(configlist.items.netmask.d8.d8_3);

    System::setIP(ipdata);
    //All Error Reset
    UdpHandler::getInstance()->set(TG_ERROR_CLEAR,0xCECE);
}

Define::config_item Config::getConfigValue(Define::ConfigType idx){
    return configlist.values[idx];
}



void Config::setConfigValue(Define::ConfigType idx, Define::config_item& itemdata){
    configlist.values[idx] = itemdata;
}


QString Config::getValueString(Define::ConfigType idx){
    QString qstrTemp="";
    if( (config_data_type[(uint32_t)idx] & 0x80) ==0){
        switch(config_data_type[(uint32_t)idx]){
        case 0:
            //qstrTemp.sprintf(config_format[(uint32_t)idx], configlist.values[(uint32_t)idx].d32);
            qstrTemp= tr(config_format[(uint32_t)idx]).arg(configlist.values[(uint32_t)idx].d32);
        break;
        case 1:
            qstrTemp.sprintf(config_format[(uint32_t)idx], configlist.values[(uint32_t)idx].f32);
            break;
        case 2:
            qstrTemp = tr(config_format[(uint32_t)idx]);
            break;
        case 3:
            //qstrTemp.sprintf(config_format[(uint32_t)idx], configlist.values[(uint32_t)idx].d32+1);
            qstrTemp= tr(config_format[(uint32_t)idx]).arg(configlist.values[(uint32_t)idx].d32+1);
            break;
        case 0x7f:
            qstrTemp = "";
            break;
        }
        return qstrTemp;
    }

    QDateTime qdt = QDateTime::currentDateTime();

    switch(idx){
        case config_language:
        if(configlist.items.language.d32 >=3) configlist.items.language.d32 = 0;
        qstrTemp = tr(language_menu[configlist.items.language.d32]);
        break;

    case config_datetime:
        qstrTemp = qdt.toString("yyyy.MM.dd hh:mm");
        break;
    case config_temptype:
        if(configlist.items.temptype.d32 >=2 ) configlist.items.temptype.d32 = 0;
        qstrTemp = tr(temptype_menu[configlist.items.temptype.d32]);
        break;
    case config_best_dish_weight:
        if(configlist.items.best_dish_weight.d32 >=4) configlist.items.best_dish_weight.d32 = 0;
        qstrTemp = tr(best_dish_weight_menu[configlist.items.best_dish_weight.d32]);
        break;
    case config_party_dish_weight:
        if(configlist.items.party_dish_weight.d32 >=4) configlist.items.party_dish_weight.d32 = 0;
        qstrTemp = tr(best_dish_weight_menu[configlist.items.party_dish_weight.d32]);
        break;
    case config_time_type:
        if(configlist.items.time_type.d32 >=2) configlist.items.time_type.d32 = 0;
        qstrTemp = tr(time_type_menu[configlist.items.time_type.d32]);
        break;
    case config_resttime_format:
        if(configlist.items.resttime_format.d32 >=2) configlist.items.resttime_format.d32 = 0;
        qstrTemp = tr(rest_time_type_menu[configlist.items.resttime_format.d32]);
        break;
    case config_ip:
        qstrTemp.sprintf("%3d.%3d.%3d.%3d", configlist.items.ip.d8.d8_0,configlist.items.ip.d8.d8_1,configlist.items.ip.d8.d8_2,configlist.items.ip.d8.d8_3);
        break;
    case config_set_half_energy:
        if(configlist.items.set_half_energy.d32 >=2) configlist.items.set_half_energy.d32 = 0;
        qstrTemp = tr(set_unset_menu[configlist.items.set_half_energy.d32]);
        break;
    case config_duty_wash:
        if(configlist.items.duty_wash.d32 >=2) configlist.items.duty_wash.d32 = 0;
        qstrTemp = tr(active_on_off_menu[configlist.items.duty_wash.d32]);
        break;
    case config_cooking_door_monitoring:
        //qstrTemp.sprintf(config_format[(uint32_t)idx],configlist.items.cooking_door_monitoring.d8.d8_0);
        qstrTemp = tr(config_format[(uint32_t)idx]).arg(configlist.items.cooking_door_monitoring.d8.d8_0);
        break;
    case config_loading_door_monitoring:
        qstrTemp = tr(config_format[(uint32_t)idx]).arg(configlist.items.loading_door_monitoring.d8.d8_0);
        break;
    case config_demo_mode:
        if(configlist.items.demo_mode.d32 >=2) configlist.items.demo_mode.d32 = 0;
        qstrTemp = tr(on_off_menu[configlist.items.demo_mode.d32]);
        break;
    default:
        qstrTemp = "";
        break;
    }
    return qstrTemp;
}

QString Config::getTitleString(Define::ConfigType idx){
    return tr(config_title[idx]);//strTemp;
}

bool Config::isFavorite(Define::ConfigType idx){
    return m_setFavorite.contains((uint32_t)idx);
    return true;
}

QSetIterator<uint32_t> Config::getConstBeginFavorite(){
    QSetIterator<uint32_t> i(m_setFavorite);
    return i;
}

QList<uint32_t> Config::getConstSortedFavorite(){
    QList<uint32_t> list = m_setFavorite.toList();
    qSort(list);
    return list;
}

bool Config::loadFavorite(void){
    bool rst;
    uint32_t itemp;
    QFile file(FAVORITE_FILE_NAME);
    if(file.open(QIODevice::ReadOnly | QIODevice::Text)){
        m_setFavorite.clear();
        while(!file.atEnd()){
            QByteArray line = file.readLine();
            QString strTemp = tr(line);
            itemp = strTemp.toInt(&rst,10);
            if(rst && itemp < (uint32_t)config_invalid)  {
                m_setFavorite.insert(itemp);
            }
        }
        file.close();
        qDebug() << "loading Favorite Menu Success";
    }
    else{
        qDebug() << "Favorite File Not Found";
    }
    return false;
}

bool Config::saveFavorite(void){
    uint32_t itemp;
    QFile file(FAVORITE_FILE_NAME);
    if(file.open(QIODevice::WriteOnly | QIODevice::Text)){
        QTextStream out(&file);
        QSetIterator<uint32_t> itr(m_setFavorite);
        while(itr.hasNext()){
            itemp = itr.next();
            out << itemp << "\n";
            qDebug() << "save favorite index" << itemp;
        }
        file.close();
        sync();
        qDebug()<<"saving Favorite menu success";
        return true;
    }
    else{
        qDebug() << "saving favorite fail";
    }
    return false;
}

//Sytem Config Area Copy
void Config::copyConfigArea(const char *buff)
{
    config_item* end = &configlist.items.model;
    config_item *start = &configlist.values[0];

    uint32_t size = end - start;

    qDebug() << "size is "<< size;

    memcpy(&configlist.data[0], buff, sizeof(config_item)*size);
}

void Config::insertFavorite(Define::ConfigType idx){
    m_setFavorite.insert((uint32_t)idx);
}
void Config::removeFavorite(Define::ConfigType idx){
    m_setFavorite.remove((uint32_t)idx);
}

QString Config::getProductSerial()
{
    QString strProductSerial;
    strProductSerial = DEFAULT_PRODUCT_SERIAL;
    return strProductSerial;
}

void Config::applyCurrentConfigLanguage()
{
    if(configlist.items.language.d32 == 0){
//        QApplication::removeTranslator();
//        QTranslator* trans = new QTranslator();
//        qDebug() << trans->load(":/lang_en.qm");
//        QApplication::removeTranslator(QApplication::)
    }
    else if(configlist.items.language.d32 ==2){
        QTranslator* trans = new QTranslator();
        qDebug() << trans->load(":/lang_en.qm");
        QApplication::installTranslator(trans);
    }
    else if(configlist.items.language.d32 == 2){
        //QTranslator *tr
    }
}

void Config::execConfigWindow(QWidget *parent, Define::ConfigType idx){
    QDialog *dlg;
    QString usbPath = "";
    switch(idx){
    case config_language:
        dlg = new ConfigLanguageDlg(parent);
        break;
    case config_temptype:
        dlg = new ConfigTempTypeDlg(parent);
        break;
    case config_backlight:
        dlg = new ConfigBackLightDlg(parent);
        break;
    case config_time_type:
        dlg = new ConfigTimeFormatDlg(parent);
        break;
    case config_resttime_format:
        dlg = new configResttimeFormatDlg(parent);
        break;
    case config_marster_vol:
        dlg = new ConfigVolumeDlg(parent, idx);
        break;
    case config_keypad_sound2:
        dlg = new ConfigVolumeDlg(parent, idx);
        break;
    case config_keypad_sound1:
    case config_request_loadexec:
    case config_programstep_finish:
    case config_cooktime_finish:
    case config_stoperror_distinguish:
        dlg = new ConfigSoundSelelectDlg(parent,idx);
        break;
     case config_sound_factory_reset:
        dlg = new YesNoPopupDlg(parent, tr("모든 음향설정 값을 공장초기화\r하시겠습니까?"));
        break;
    case config_ip:
        dlg=new ConfigIpDlg(parent);
        break;
    case config_haccp_data_download:
    case config_info_data_download:
    case config_service_data_download:
    case config_program_download:
    case config_set_download:
        if(!FileProcessor::detectUSB(usbPath)){
            dlg = new UsbCheckPopupDlg(parent);
            dlg->exec();
        }
        if(FileProcessor::detectUSB(usbPath)){
            dlg = new ConfigFileProcessDlg(parent,idx);
            dlg->exec();
        }
        return;
    case config_set_upload:
    case config_program_upload:

        if(!FileProcessor::detectUSB(usbPath)){
            dlg = new UsbCheckPopupDlg(parent);
            dlg->exec();
        }
        if(FileProcessor::detectUSB(usbPath)){
            dlg = new ConfigFileProcessDlg(parent,idx,false);
            dlg->exec();
        }
        return;
    case config_program_initialize:
        dlg = new YesNoPopupDlg(parent, tr("모든 프로그램을\r삭제하시겠습니까?"));
        break;
    case config_set_half_energy:
        dlg = new ConfigHalfEnergyDlg(parent);
        break;
     case config_set_auto_darkness:
        dlg = new Config1DigitSetDlg(parent,idx);
        break;
    case config_duty_wash:
        dlg = new ConfigDutyWashDlg(parent);
        break;
    case config_demo_mode:
        dlg = new ConfigDemoModeDlg(parent);
        break;
    case config_steam_wash:
        dlg = new ConfigSteamWashDlg(parent);
        break;
    default:
        dlg=NULL;
    }
    if(dlg == NULL) return;
    dlg->setWindowModality(Qt::WindowModal);
    dlg->exec();
    if(dlg->result() == QDialog::Accepted){
        qDebug()<<"Accepted";
        if(idx == config_sound_factory_reset){
            //Sound Fatory Reset
            soundConfigReset();
            qDebug() << "Process Sound Config Reset";
        }
        else if(idx==config_program_initialize){
            qDebug() << "All Program Reset";
        }
    }
    else{
        qDebug() << "rejected";
    }
}

void Config::soundConfigReset(){
    configlist.items.marster_vol.d32=7;
    configlist.items.keypad_sound1.d32=0;
    configlist.items.keypad_sound2.d32=7;
    configlist.items.request_loadexec.d32=6;
    configlist.items.programstep_finish.d32=7;
    configlist.items.cooktime_finish.d32=8;
    configlist.items.stoperror_distinguish.d32=9;
}