#include "programmingmanualwindow.h"
#include "ui_programmingmanualwindow.h"

#include <QKeyEvent>

#include "oven.h"
#include "stringer.h"
#include "programmingmanualcoretemppopup.h"
#include "cookprogram.h"
#include "soundplayer.h"
#include "configwindow.h"
#include "mainwindow.h"
#include "manualviewerdlg.h"

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

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

    ui->humiditySlider->setSubPixmap(":/images/slider/humidity.png");
    ui->humiditySlider->setRange(0, 100);
    ui->humiditySlider->bigTickInterval = 50;
    ui->humiditySlider->tickInterval = 10;

    ui->tempSlider->setSubPixmap(":/images/slider/temp.png");
    ui->tempSlider->bigTickInterval = 50;
    ui->tempSlider->tickInterval = 10;

    ui->timeSlider->setSubPixmap(":/images/slider/time.png");
    ui->timeSlider->setRange(0, 342);
    ui->timeSlider->bigTicks.append(0);
    ui->timeSlider->bigTicks.append(180);
    ui->timeSlider->bigTicks.append(270);
    ui->timeSlider->bigTicks.append(342);
    ui->timeSlider->ticks.append(60);
    ui->timeSlider->ticks.append(120);
    ui->timeSlider->ticks.append(180 + 30);
    ui->timeSlider->ticks.append(180 + 60);
    ui->timeSlider->ticks.append(270 + 4 * 6);
    ui->timeSlider->ticks.append(270 + 4 * 12);

    ui->interTempSlider->setSubPixmap(":/images/slider/core.png");
    ui->interTempSlider->setRange(30, 99);

    Oven *oven = Oven::getInstance();

    QList<int> &bigTicks = ui->interTempSlider->bigTicks;
    bigTicks.append(oven->minInterTemp());
    bigTicks.append(oven->minInterTemp() + (oven->maxInterTemp() - oven->minInterTemp()) / 2);
    bigTicks.append(oven->maxInterTemp());

    QList<int> &ticks = ui->interTempSlider->ticks;
    for (int i = 1; i < 3; i++)
        ticks.append(bigTicks.at(0) + i * (bigTicks.at(1) - bigTicks.at(0)) / 3);
    for (int i = 1; i < 3; i++)
        ticks.append(bigTicks.at(1) + i * (bigTicks.at(2) - bigTicks.at(1)) / 3);

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

    connect(ui->humiditySlider, SIGNAL(sliderPressed()), SLOT(updateView()));
    connect(ui->tempSlider, SIGNAL(sliderPressed()), SLOT(updateView()));
    connect(ui->timeSlider, SIGNAL(sliderPressed()), SLOT(updateView()));
    connect(ui->interTempSlider, SIGNAL(sliderPressed()), SLOT(updateView()));

    lastFan = -1;
    lastInterTempEnabled = true;

    setDefault(mode);

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

    setFocus();

    afterThreeSecsTimer.setSingleShot(true);
    afterThreeSecsTimer.setInterval(3000);
    connect(&afterThreeSecsTimer, SIGNAL(timeout()), SLOT(afterThreeSecs()));

    foreach (QWidget *w, findChildren<QWidget *>())
        w->installEventFilter(this);

    installEventFilter(this);

    afterThreeSecsTimer.start();
}

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

bool ProgrammingManualWindow::eventFilter(QObject */*watched*/, QEvent *event)
{
    switch (event->type())
    {
    case QEvent::KeyPress:
    case QEvent::KeyRelease:
    case QEvent::MouseButtonPress:
    case QEvent::MouseButtonRelease:
    case QEvent::MouseMove:
        afterThreeSecsTimer.start();
        break;
    default:
        break;
    }

    return false;
}

void ProgrammingManualWindow::keyPressEvent(QKeyEvent *event)
{
    switch (event->key())
    {
    case 0x01000032:    // Turn left
        onEncoderLeft();
        break;
    case 0x01000031:    // Push
        pushed = focusWidget();
        break;
    case 0x01000030:    // Turn right
        onEncoderRight();
        break;
    }
}

void ProgrammingManualWindow::keyReleaseEvent(QKeyEvent *event)
{
    switch (event->key())
    {
    case 0x01000032:    // Turn left
        onEncoderLeft();
        break;
    case 0x01000031:    // Push
        if (focusWidget() == pushed)
            onEncoderClicked(pushed);

        pushed = NULL;
        break;
    case 0x01000030:    // Turn right
        onEncoderRight();
        break;
    }
}

int ProgrammingManualWindow::sliderToTime(int value)
{
    if (value <= 180)
        return value * 60;
    if (value <= 270)
        return 180 * 60 + (value - 180) * 2 * 60;
    return 360 * 60 + (value - 270) * 15 * 60;
}

int ProgrammingManualWindow::timeToSlider(int secs)
{
    if (secs <= 180 * 60)
        return secs / 60;
    if (secs <= 360 * 60)
        return 180 + (secs - 180 * 60) / 2 / 60;
    return 270 + (secs - 360 * 60) / 15 / 60;
}

void ProgrammingManualWindow::onEncoderLeft()
{
    focusPreviousChild();

    QWidget *focused = focusWidget();
    if (focused == ui->steamButton)
    {
        if (ui->steamButton->isChecked())
            focusPreviousChild();
    }
    else if (focused == ui->combiButton)
    {
        if (ui->combiButton->isChecked())
            focusPreviousChild();
    }
    else if (focused == ui->dryheatButton)
    {
        if (ui->dryheatButton->isChecked())
            focusPreviousChild();
    }
}

void ProgrammingManualWindow::onEncoderRight()
{
    QWidget *focused = focusWidget();
    if (focused == NULL || focused == this)
    {
        if (ui->steamButton->isChecked() || ui->dryheatButton->isChecked())
            ui->tempButton->setFocus();
        else if (ui->combiButton->isChecked())
            ui->humidityButton->setFocus();
    }
    else
    {
        focusNextChild();

        focused = focusWidget();
        if (focused == ui->steamButton)
        {
            if (ui->steamButton->isChecked())
                focusNextChild();
        }
        else if (focused == ui->combiButton)
        {
            if (ui->combiButton->isChecked())
                focusNextChild();
        }
        else if (focused == ui->dryheatButton)
        {
            if (ui->dryheatButton->isChecked())
                focusNextChild();
        }
    }
}

void ProgrammingManualWindow::onEncoderClicked(QWidget *clicked)
{
    if (clicked == NULL)
        return;

    if (clicked->inherits("QPushButton"))
    {
        QPushButton *b = qobject_cast<QPushButton *>(clicked);
        if (b)
        {
            b->click();

            if (b == ui->steamButton || b == ui->dryheatButton)
                ui->tempButton->setFocus();
            else if (b == ui->combiButton)
                ui->humidityButton->setFocus();
        }
    }
    else if (clicked->inherits("Slider"))
    {
        Slider *slider = qobject_cast<Slider *>(clicked);
        if (slider)
        {
            if (slider == ui->humiditySlider)
                ui->humidityButton->setFocus();
            else if (slider == ui->tempSlider)
                ui->tempButton->setFocus();
            else if (slider == ui->timeSlider)
                ui->timeButton->setFocus();
            else if (slider == ui->interTempSlider)
                ui->interTempButton->setFocus();

            updateView();
        }
    }
}

void ProgrammingManualWindow::setDefault(Define::Mode mode)
{
    switch (mode)
    {
    case Define::SteamMode:
        ui->steamButton->setChecked(true);
        ui->combiButton->setChecked(false);
        ui->dryheatButton->setChecked(false);
        ui->humiditySlider->setEnabled(false);
        ui->humiditySlider->setValue(100);
        ui->tempSlider->setRange(30, 130);
        ui->tempSlider->setValue(100);
        ui->timeSlider->setValue(0);
        ui->interTempSlider->setEnabled(false);
        ui->interTempSlider->setSubVisible(false);
        ui->interTempSlider->setValue(30);
        setFan(4);
        updateView();
        this->mode = mode;
        break;
    case Define::CombiMode:
        ui->steamButton->setChecked(false);
        ui->combiButton->setChecked(true);
        ui->dryheatButton->setChecked(false);
        ui->humiditySlider->setEnabled(true);
        ui->humiditySlider->setValue(50);
        ui->tempSlider->setRange(30, 300);
        ui->tempSlider->setValue(100);
        ui->timeSlider->setValue(0);
        ui->interTempSlider->setEnabled(false);
        ui->interTempSlider->setSubVisible(false);
        ui->interTempSlider->setValue(30);
        setFan(4);
        updateView();
        this->mode = mode;
        break;
    case Define::DryMode:
        ui->steamButton->setChecked(false);
        ui->combiButton->setChecked(false);
        ui->dryheatButton->setChecked(true);
        ui->humiditySlider->setEnabled(false);
        ui->humiditySlider->setValue(0);
        ui->tempSlider->setRange(30, 300);
        ui->tempSlider->setValue(160);
        ui->timeSlider->setValue(0);
        ui->interTempSlider->setEnabled(false);
        ui->interTempSlider->setSubVisible(false);
        ui->interTempSlider->setValue(30);
        setFan(4);
        updateView();
        this->mode = mode;
        break;
    default:
        return;
    }
}

void ProgrammingManualWindow::setFan(int level)
{
    fan = level;

    updateFanButton();
}

void ProgrammingManualWindow::updateView()
{
    updateHumidityLabel();
    updateTempLabel();
    updateTimeLabel();
    updateCoreTempButton();
    updateCoreTempLabel();
    updateFanButton();

    QWidget *focused = focusWidget();
    ui->humidityButton->setChecked(focused == ui->humiditySlider);
    ui->tempButton->setChecked(focused == ui->tempSlider);
    ui->timeButton->setChecked(focused == ui->timeSlider);
    ui->interTempButton->setChecked(focused == ui->interTempSlider);
}

void ProgrammingManualWindow::updateHumidityLabel()
{
    ui->humidityLabel->setText(QString("%1%").arg(ui->humiditySlider->sliderPosition()));
}

void ProgrammingManualWindow::updateTempLabel()
{
    ui->tempLabel->setText(Stringer::temperature(ui->tempSlider->sliderPosition(), Stringer::fontSize14));
}

void ProgrammingManualWindow::updateTimeLabel()
{
    ui->timeLabel->setText(Stringer::remainingTime(sliderToTime(ui->timeSlider->sliderPosition()) * 1000, Stringer::fontSize14));
}

void ProgrammingManualWindow::updateCoreTempButton()
{
    if (ui->interTempSlider->isEnabled() == lastInterTempEnabled)
        return;

    lastInterTempEnabled = ui->interTempSlider->isEnabled();

    QString interTempButtonStyleSheet("\
QPushButton\
{ image: url(%1); }\
QPushButton:pressed,\
QPushButton:focus\
{ image: url(:/images/slider_icon/011_icon_04_active.png); }\
QPushButton:checked\
{ image: url(:/images/slider_icon/core_temp_ov.png); }");

    if (ui->interTempSlider->isEnabled())
        ui->interTempButton->setStyleSheet(interTempButtonStyleSheet.arg(":/images/slider_icon/core_temp_enabled.png"));
    else
        ui->interTempButton->setStyleSheet(interTempButtonStyleSheet.arg(":/images/slider_icon/core_temp.png"));

    ui->interTempButton->setChecked(focusWidget() == ui->interTempSlider);
}

void ProgrammingManualWindow::updateCoreTempLabel()
{
    if (ui->interTempSlider->isEnabled())
        ui->interTempLabel->setText(Stringer::temperature(ui->interTempSlider->sliderPosition(), Stringer::fontSize14));
    else
        ui->interTempLabel->setText(Stringer::unusedTemperature(Stringer::fontSize14));
}

void ProgrammingManualWindow::updateFanButton()
{
    if (fan == lastFan)
        return;

    lastFan = fan;
    QString fanStyleSheet("\
QPushButton { background-image: url(%1); }\
QPushButton:focus { background-image: url(%2); }");

    switch (fan)
    {
    case 1:
        ui->fanButton->setStyleSheet(fanStyleSheet
                                     .arg(":/images/manual_button/fan_1.png")
                                     .arg(":/images/manual_button/013_sys_icon_06_active.png"));
        break;
    case 2:
        ui->fanButton->setStyleSheet(fanStyleSheet
                                     .arg(":/images/manual_button/fan_2.png")
                                     .arg(":/images/manual_button/013_sys_icon_06_01_active.png"));
        break;
    case 3:
        ui->fanButton->setStyleSheet(fanStyleSheet
                                     .arg(":/images/manual_button/fan_3.png")
                                     .arg(":/images/manual_button/013_sys_icon_06_02_active.png"));
        break;
    case 4:
        ui->fanButton->setStyleSheet(fanStyleSheet
                                     .arg(":/images/manual_button/fan_4.png")
                                     .arg(":/images/manual_button/013_sys_icon_06_03_active.png"));
        break;
    case 5:
        ui->fanButton->setStyleSheet(fanStyleSheet
                                     .arg(":/images/manual_button/fan_5.png")
                                     .arg(":/images/manual_button/013_sys_icon_06_04_active.png"));
        break;
    default:
        ui->fanButton->setStyleSheet(fanStyleSheet
                                     .arg(":/images/manual_button/fan_6.png")
                                     .arg(":/images/manual_button/013_sys_icon_06_active.png"));
        break;
    }
}

void ProgrammingManualWindow::afterThreeSecs()
{
    Slider *slider = qobject_cast<Slider *>(focusWidget());
    if (slider)
    {
        if (slider == ui->humiditySlider)
            ui->humidityButton->setFocus();
        else if (slider == ui->tempSlider)
            ui->tempButton->setFocus();
        else if (slider == ui->timeSlider)
            ui->timeButton->setFocus();
        else if (slider == ui->interTempSlider)
            ui->interTempButton->setFocus();

        updateView();
    }
}

void ProgrammingManualWindow::onCoreTempEnabled(int celsius)
{
    ui->interTempSlider->setEnabled(true);
    ui->interTempSlider->setSubVisible(true);
    ui->interTempSlider->setValue(celsius);

    updateView();
}

void ProgrammingManualWindow::on_steamButton_clicked()
{
    setDefault(Define::SteamMode);
}

void ProgrammingManualWindow::on_combiButton_clicked()
{
    setDefault(Define::CombiMode);
}

void ProgrammingManualWindow::on_dryheatButton_clicked()
{
    setDefault(Define::DryMode);
}

void ProgrammingManualWindow::on_humidityButton_clicked()
{
    ui->humiditySlider->setFocus();

    updateView();
}

void ProgrammingManualWindow::on_tempButton_clicked()
{
    ui->tempSlider->setFocus();

    updateView();
}

void ProgrammingManualWindow::on_timeButton_clicked()
{
    ui->timeSlider->setFocus();

    updateView();
}

void ProgrammingManualWindow::on_interTempButton_clicked()
{
    if (ui->interTempSlider->isEnabled())
    {
        ui->interTempSlider->setEnabled(false);
        ui->interTempSlider->setSubVisible(false);

        updateView();
    }
    else
    {
        ProgrammingManualCoreTempPopup *p = new ProgrammingManualCoreTempPopup(this);
        connect(p, SIGNAL(coreTempEnabled(int)), SLOT(onCoreTempEnabled(int)));
        connect(p, SIGNAL(destroyed(QObject*)), SLOT(updateCoreTempButton()));
        connect(p, SIGNAL(destroyed(QObject*)), ui->interTempButton, SLOT(setFocus()));
        p->showFullScreen();
    }
}

void ProgrammingManualWindow::on_fanButton_clicked()
{
    fan++;
    if (fan > 5)
        fan = 1;

    updateFanButton();
}

void ProgrammingManualWindow::on_backButton_clicked()
{
    close();
}

void ProgrammingManualWindow::on_configButton_clicked()
{
    ConfigWindow *w = new ConfigWindow(MainWindow::getInstance());
    w->setWindowModality(Qt::WindowModal);
    w->showFullScreen();
    w->raise();

    MainWindow::jump(w);
}

void ProgrammingManualWindow::on_helpButton_clicked()
{
    ManualViewerDlg* dlg = new ManualViewerDlg(this);
    dlg->showFullScreen();
    dlg->raise();
}

void ProgrammingManualWindow::on_okButton_clicked()
{
    ManualCookSetting s;
    s.mode = mode;
    s.humidity = ui->humiditySlider->value();
    s.temp = ui->tempSlider->value();
    s.time = sliderToTime(ui->timeSlider->value());
    s.coreTempEnabled = ui->interTempSlider->isEnabled();
    s.coreTemp = ui->interTempSlider->value();
    s.fan = fan;

    CookProgram::add(s);

    emit added();
    close();
}