#include "manualcookwindow.h"
#include "ui_manualcookwindow.h"

#include <QSignalMapper>
#include <QTimer>
#include <QtDebug>

#include "soundplayer.h"
#include "preheatpopup.h"
#include "cooldownpopup.h"
#include "cookhistory.h"
#include "favoritenamepopup.h"
#include "confirmpopup.h"
#include "stringer.h"
#include "config.h"
#include "coretempsettingpopup.h"
#include "reservetimepopup.h"
#include "reservedtimepopup.h"

#include <QTime>

ManualCookWindow::ManualCookWindow(QWidget *parent, Define::Mode mode) :
    QMainWindow(parent),
    ui(new Ui::ManualCookWindow),
    repeat(false)
{
    ui->setupUi(this);

    ui->clockContainer->setParent(ui->upperStack);
    ui->closeDoorWidget->setParent(ui->upperStack);
    setAttribute(Qt::WA_DeleteOnClose);

    oven = Oven::getInstance();
    connect(oven, SIGNAL(changed(Oven*)), this, SLOT(onOvenUpdated(Oven*)));

    connect(ui->humiditySlider, SIGNAL(valueChanged(int)), oven, SLOT(setHumidity(int)));
    connect(ui->tempSlider, SIGNAL(valueChanged(int)), oven, SLOT(setTemp(int)));
    connect(ui->timeSlider, SIGNAL(valueChanged(int)), oven, SLOT(setTime(int)));
    connect(ui->timeSlider, SIGNAL(valueChanged(int)), &startCookingTimer, SLOT(start()));
    connect(ui->timeSlider, SIGNAL(valueChanged(int)), this, SLOT(updateLabels()));
    connect(ui->interTempSlider, SIGNAL(valueChanged(int)), oven, SLOT(setInterTemp(int)));

    connect(ui->humiditySlider, SIGNAL(sliderMoved(int)), this, SLOT(updateLabels()));
    connect(ui->tempSlider, SIGNAL(sliderMoved(int)), this, SLOT(updateLabels()));
    connect(ui->timeSlider, SIGNAL(sliderMoved(int)), this, SLOT(updateLabels()));
    connect(ui->interTempSlider, SIGNAL(sliderMoved(int)), this, SLOT(updateLabels()));

    startCookingTimer.setSingleShot(true);
    startCookingTimer.setInterval(2000);
    connect(&startCookingTimer, SIGNAL(timeout()), SLOT(start()));

    showCurrentHumidityTimer.setSingleShot(true);
    showCurrentHumidityTimer.setInterval(2000);
    connect(&showCurrentHumidityTimer, SIGNAL(timeout()), SLOT(showCurrentHumidity()));

    showCurrentTempTimer.setSingleShot(true);
    showCurrentTempTimer.setInterval(2000);
    connect(&showCurrentTempTimer, SIGNAL(timeout()), SLOT(showCurrentTemp()));

    oven->setDefault(mode);

    checkTimeTimer.setInterval(100);
    connect(&checkTimeTimer, SIGNAL(timeout()), SLOT(checkTime()));
    checkTimeTimer.start();

    foreach (QPushButton *button, findChildren<QPushButton *>())
        connect(button, &QPushButton::pressed, SoundPlayer::playClick);

    QTimer::singleShot(0, this, SLOT(setupAnimation()));
}

ManualCookWindow::ManualCookWindow(QWidget *parent, ManualCookSetting setting)
    : ManualCookWindow(parent, setting.mode)
{
    oven->setHumidity(setting.humidity);
    oven->setTemp(setting.temp);
    oven->setTime(setting.time);
    oven->setFan(setting.fan);
    oven->setInterTempEnabled(setting.coreTempEnabled);
    oven->setInterTemp(setting.coreTemp);

    startCookingTimer.start();

    onOvenUpdated(oven);
}

ManualCookWindow::~ManualCookWindow()
{
    delete ui;
}

void ManualCookWindow::setupAnimation()
{
    ui->openDoorAnimation->load(":/images/animation/door_big_09.png");
    ui->openDoorAnimation->load(":/images/animation/door_big_08.png");
    ui->openDoorAnimation->load(":/images/animation/door_big_07.png");
    ui->openDoorAnimation->load(":/images/animation/door_big_06.png");
    ui->openDoorAnimation->load(":/images/animation/door_big_05.png");
    ui->openDoorAnimation->load(":/images/animation/door_big_04.png");
    ui->openDoorAnimation->load(":/images/animation/door_big_03.png");
    ui->openDoorAnimation->load(":/images/animation/door_big_02.png");
    ui->openDoorAnimation->load(":/images/animation/door_big_01.png");
    ui->openDoorAnimation->start(300);
}

void ManualCookWindow::checkTime()
{
    if (!ui->timeSlider->isSliderDown())
    {
        bool old = ui->timeSlider->blockSignals(true);
        ui->timeSlider->setSliderPosition(oven->time());
        ui->timeSlider->blockSignals(old);

        updateLabels();
    }

    if (oven->interTempEnabled() && oven->currentInterTemp() >= oven->interTemp())
    {
        oven->stopCooking();
    }

    if (repeat && !oven->cooking())
    {
        repeat = false;

        ui->repeatButton->setStyleSheet("\
QPushButton { background-image: url(:/images/manual_button/repeat.png); }\
QPushButton:pressed { background-image: url(:/images/manual_button/repeat_ov.png); }");

        oven->setMode(repeatSetting.mode);
        oven->setHumidity(repeatSetting.humidity);
        oven->setTemp(repeatSetting.temp);
        oven->setTime(repeatSetting.time);
        oven->setInterTempEnabled(repeatSetting.coreTempEnabled);
        oven->setInterTemp(repeatSetting.coreTemp);
    }
}

void ManualCookWindow::showCurrentHumidity()
{
    showCurrentHumidity_ = true;
    updateLabels();
}

void ManualCookWindow::hideCurrentHumidity()
{
    showCurrentHumidity_ = false;
    updateLabels();
}

void ManualCookWindow::showCurrentTemp()
{
    showCurrentTemp_ = true;
    updateLabels();
}

void ManualCookWindow::hideCurrentTemp()
{
    showCurrentTemp_ = false;
    updateLabels();
}

void ManualCookWindow::updateLabels()
{
    QString buf;

    int humidity;
    if (showCurrentHumidity_)
        humidity = oven->currentHumidity();
    else if (ui->humiditySlider->isSliderDown())
        humidity = ui->humiditySlider->sliderPosition();
    else
        humidity = oven->humidity();

    ui->humidityLabel->setText(buf.sprintf("%d%%", humidity));

    int temp;
    if (showCurrentTemp_)
        temp = oven->currentTemp();
    else if (ui->tempSlider->isSliderDown())
        temp = ui->tempSlider->sliderPosition();
    else
        temp = oven->temp();

    ui->tempLabel->setText(Stringer::temperature(temp, Stringer::fontSize14));

    int msecs;
    if (ui->timeSlider->isSliderDown())
        msecs = ui->timeSlider->sliderPosition() * 1000;
    else
        msecs = oven->msecs();

    ui->timeLabel->setText(Stringer::remainingTime(msecs, Stringer::fontSize14));

    if (oven->interTempEnabled())
    {
        int interTemp;
        if (ui->interTempSlider->isSliderDown())
            interTemp = ui->interTempSlider->sliderPosition();
        else
            interTemp = oven->interTemp();

        ui->interTempLabel->setText(Stringer::temperature(interTemp, Stringer::fontSize14));
    }
    else
        ui->interTempLabel->setText(Stringer::unusedTemperature(Stringer::fontSize14));
}

void ManualCookWindow::onOvenUpdated(Oven *oven)
{
    switch (oven->mode())
    {
    case Define::DryMode:
        ui->dryheatButton->setChecked(true);
        break;
    case Define::SteamMode:
        ui->steamButton->setChecked(true);
        break;
    case Define::CombiMode:
        ui->combiButton->setChecked(true);
        break;
    default:
        break;
    }

    bool old;
    old = ui->humiditySlider->blockSignals(true);
    ui->humiditySlider->setValue(oven->humidity());
    ui->humiditySlider->setEnabled(oven->mode() == Define::CombiMode);
    ui->humiditySlider->blockSignals(old);

    old = ui->tempSlider->blockSignals(true);
    ui->tempSlider->setRange(oven->minTemp(), oven->maxTemp());
    ui->tempSlider->setValue(oven->temp());
    ui->tempSlider->blockSignals(old);

    if (!ui->timeSlider->isSliderDown())
    {
        old = ui->timeSlider->blockSignals(true);
        ui->timeSlider->setValue(oven->time());
        ui->timeSlider->blockSignals(old);
    }

//    ui->interTempButton->setChecked(oven->interTempEnabled());
    if (oven->interTempEnabled())
        ui->interTempButton->setStyleSheet("\
QPushButton {\
    image: url(:/images/slider_icon/core_temp_enabled.png);\
}\
QPushButton:pressed {\
    image: url(:/images/slider_icon/core_temp_ov.png);\
}");
    else
        ui->interTempButton->setStyleSheet("\
QPushButton {\
    image: url(:/images/slider_icon/core_temp.png);\
}\
QPushButton:pressed {\
    image: url(:/images/slider_icon/core_temp_ov.png);\
}");

    old = ui->interTempSlider->blockSignals(true);
    ui->interTempSlider->setEnabled(oven->interTempEnabled());
    ui->interTempSlider->setRange(oven->minInterTemp(), oven->maxInterTemp());
    ui->interTempSlider->setValue(oven->interTemp());
    ui->interTempSlider->blockSignals(old);

    if (oven->cooking())
        ui->runStopButton->setStyleSheet(
                    "border-image: url(:/images/manual_button/stop.png)");
    else
        ui->runStopButton->setStyleSheet(
                    "border-image: url(:/images/manual_button/run.png)");

    if (oven->damper())
        ui->damperButton->setStyleSheet(
                    "background-image: url(:/images/manual_button/damper_open.png)");
    else
        ui->damperButton->setStyleSheet(
                    "background-image: url(:/images/manual_button/damper_close.png)");

    if (oven->humidification())
        ui->humidificationButton->setStyleSheet(
                    "background-image: url(:/images/manual_button/side_nozzle_open.png)");
    else
        ui->humidificationButton->setStyleSheet(
                    "background-image: url(:/images/manual_button/side_nozzle_close.png)");

    switch (oven->fan())
    {
    case 1:
        ui->fanButton->setStyleSheet(
                    "background-image: url(:/images/manual_button/fan_1.png)");
        break;
    case 2:
        ui->fanButton->setStyleSheet(
                    "background-image: url(:/images/manual_button/fan_2.png)");
        break;
    case 3:
        ui->fanButton->setStyleSheet(
                    "background-image: url(:/images/manual_button/fan_3.png)");
        break;
    case 4:
        ui->fanButton->setStyleSheet(
                    "background-image: url(:/images/manual_button/fan_4.png)");
        break;
    case 5:
        ui->fanButton->setStyleSheet(
                    "background-image: url(:/images/manual_button/fan_5.png)");
        break;
    default:
        ui->fanButton->setStyleSheet(
                    "background-image: url(:/images/manual_button/fan_1.png)");
        break;
    }

    if (oven->paused() && !oven->cooldown() && oven->door())
        ui->upperStack->setCurrentIndex(1);
    else
        ui->upperStack->setCurrentIndex(0);

    if (oven->cooking() || oven->cooldown() || oven->preheating())
    {
        ui->reserveButton->hide();
        ui->favoriteButton->hide();
        ui->repeatButton->show();
    }
    else
    {
        ui->reserveButton->show();
        ui->favoriteButton->show();
        ui->repeatButton->hide();
    }

    updateLabels();
}

void ManualCookWindow::setOvenDefault(Define::Mode mode)
{
    stop();

    oven->setDefault(mode);
}

void ManualCookWindow::start()
{
    if (oven->cooking())
        return;

    SoundPlayer::playStart();

    if (oven->time() > 0)
    {
        if (startCookingTimer.isActive())
            startCookingTimer.stop();

        oven->startCooking();

        ManualCookSetting s;
        s.mode = oven->mode();
        s.humidity = oven->humidity();
        s.temp = oven->temp();
        s.time = oven->time();
        s.fan = oven->fan();
        s.coreTempEnabled = oven->interTempEnabled();
        s.coreTemp = oven->interTemp();

        CookHistory::record(s);
    }
}

void ManualCookWindow::stop()
{
    if (oven->cooking())
        SoundPlayer::playStop();

    oven->stop();
    startCookingTimer.stop();
}

void ManualCookWindow::on_steamButton_clicked()
{
    setOvenDefault(Define::SteamMode);
}

void ManualCookWindow::on_combiButton_clicked()
{
    setOvenDefault(Define::CombiMode);
}

void ManualCookWindow::on_dryheatButton_clicked()
{
    setOvenDefault(Define::DryMode);
}

void ManualCookWindow::on_humidityButton_pressed()
{
    showCurrentHumidityTimer.start();
}

void ManualCookWindow::on_humidityButton_released()
{
    if (showCurrentHumidityTimer.isActive())
        showCurrentHumidityTimer.stop();
    else
        hideCurrentHumidity();
}

void ManualCookWindow::on_tempButton_pressed()
{
    showCurrentTempTimer.start();
}

void ManualCookWindow::on_tempButton_released()
{
    if (showCurrentTempTimer.isActive())
        showCurrentTempTimer.stop();
    else
        hideCurrentTemp();
}

void ManualCookWindow::on_interTempButton_clicked()
{
    if (oven->interTempEnabled())
        oven->setInterTempEnabled(false);
    else
    {
        CoreTempSettingPopup *p = new CoreTempSettingPopup(this);
        p->show();
    }
}

void ManualCookWindow::on_runStopButton_clicked()
{
    if (oven->cooking())
        stop();
    else
        start();
}

void ManualCookWindow::on_fanButton_clicked()
{
    int fan = oven->fan() + 1;
    if (fan > oven->maxFan())
        fan = oven->minFan();

    oven->setFan(fan);
}

void ManualCookWindow::on_preheatButton_clicked()
{
    startCookingTimer.stop();

    PreheatPopup *p = new PreheatPopup(this, oven);
    p->setWindowModality(Qt::WindowModal);
    p->showFullScreen();
}

void ManualCookWindow::on_damperButton_clicked()
{
    if (oven->damper())
        oven->closeDamper();
    else
        oven->openDamper();
}

void ManualCookWindow::on_humidificationButton_clicked()
{
    if (oven->humidification())
        oven->stopHumidification();
    else
        oven->startHumidification();
}

void ManualCookWindow::on_repeatButton_clicked()
{
    if (repeat)
    {
        repeat = false;
        ui->repeatButton->setStyleSheet("\
QPushButton { background-image: url(:/images/manual_button/repeat.png); }\
QPushButton:pressed { background-image: url(:/images/manual_button/repeat_ov.png); }");
    }
    else
    {
        repeat = true;
        ui->repeatButton->setStyleSheet("\
QPushButton { background-image: url(:/images/manual_button/repeat_ov.png); }\
QPushButton:pressed { background-image: url(:/images/manual_button/repeat.png); }");
        repeatSetting.mode = oven->mode();
        repeatSetting.humidity = oven->humidity();
        repeatSetting.temp= oven->temp();
        repeatSetting.time = oven->time();
        repeatSetting.coreTempEnabled = oven->interTempEnabled();
        repeatSetting.coreTemp = oven->interTemp();
    }
}

void ManualCookWindow::on_cooldownButton_clicked()
{
    startCookingTimer.stop();

    CooldownPopup *p = new CooldownPopup(this, oven);
    p->setWindowModality(Qt::WindowModal);
    p->showFullScreen();
}

void ManualCookWindow::on_reserveButton_clicked()
{
    if (oven->time() > 0)
    {
        startCookingTimer.stop();

        ReserveTimePopup *p = new ReserveTimePopup(this);
        connect(p, SIGNAL(timeout()), SLOT(start()));
        connect(p, SIGNAL(canceled()), &startCookingTimer, SLOT(start()));
        p->showFullScreen();
    }
}

void ManualCookWindow::on_favoriteButton_clicked()
{
    if (oven->cooking())
        return;

    ConfirmPopup *p = new ConfirmPopup(this, tr("즐겨찾기 항목에 추가하시겠습니까?"));
    p->showFullScreen();

    connect(p, SIGNAL(accepted()), SLOT(addFavorite()));

    if (startCookingTimer.isActive())
    {
        startCookingTimer.stop();
        connect(p, SIGNAL(rejected()), &startCookingTimer, SLOT(start()));
    }
}

void ManualCookWindow::on_goBackStackButton_clicked()
{
    ui->buttonStack->setCurrentIndex(1);
}

void ManualCookWindow::on_goFrontStackButton_clicked()
{
    ui->buttonStack->setCurrentIndex(0);
}

void ManualCookWindow::on_backButton_clicked()
{
    stop();
    close();
}

void ManualCookWindow::addFavorite()
{
    ManualCookSetting s;
    s.mode = oven->mode();
    s.humidity = oven->humidity();
    s.temp = oven->temp();
    s.time = oven->time();
    s.fan = oven->fan();
    s.coreTempEnabled = oven->interTempEnabled();
    s.coreTemp = oven->interTemp();

    FavoriteNamePopup *p = new FavoriteNamePopup(this, s);
    p->showFullScreen();
}