#include "oven.h"

#include <QtDebug>
#include <cmath>

Oven::Oven(QObject *parent) : QObject(parent)
{
    interface = NULL;

    cookingTimer.setSingleShot(true);
    connect(&cookingTimer, SIGNAL(timeout()), this, SLOT(stopCooking()));

    humidificationTimer.setSingleShot(true);
    connect(&humidificationTimer, SIGNAL(timeout()), this, SLOT(stopHumidification()));
}

void Oven::setInterface(OvenInterface *interface)
{
    if (this->interface)
        this->interface->disconnect();

    this->interface = interface;
    connect(interface, SIGNAL(doorOpened()), this, SLOT(onDoorOpened()));
    connect(interface, SIGNAL(doorClosed()), this, SLOT(onDoorClosed()));
}

void Oven::setMode(Mode mode)
{
    if (setMode_(mode))
        emit changed(this);
}

bool Oven::setMode_(Mode mode)
{
    switch (mode)
    {
    case HeatMode:
    case SteamMode:
    case CombinationMode:
        break;
    default:
        return false;
    }

    if (mode != mode_)
    {
        mode_ = mode;
        return true;
    }

    return false;
}

void Oven::setDefault(Mode mode)
{
    setMode_(mode);
    switch (mode)
    {
    case HeatMode:
        setHumidity_(0);
        setTemp_(160);
        break;
    case SteamMode:
        setHumidity_(100);
        setTemp_(100);
        break;
    case CombinationMode:
        setHumidity_(50);
        setTemp_(100);
        break;
    }

    setTime(0);
    setInterTempEnabled_(false);
    setFan_(4);

    cooking_ = false;
    preheating_ = false;
    cooldown_ = false;
    damper_ = false;
    humidification_ = false;
    washing_ = false;
    door_ = interface->door();
    paused_ = false;

    emit changed(this);
}

void Oven::setHumidity(int percentage)
{
    if (setHumidity_(percentage))
        emit changed(this);
}

bool Oven::setHumidity_(int percentage)
{
    if (percentage < 0 || percentage > 100)
        return false;

    if (percentage != humidity_)
    {
        humidity_ = percentage;
        interface->setHumidity(percentage);

        return true;
    }

    return false;
}

void Oven::setTemp(int celsius)
{
    if (setTemp_(celsius))
        emit changed(this);
}

bool Oven::setTemp_(int celsius)
{
    if (celsius < minTemp() || celsius > maxTemp())
        return false;

    if (celsius != temp_)
    {
        temp_ = celsius;
        interface->setTemp(celsius);

        return true;
    }

    return false;
}

int Oven::time()
{
    int left = cookingTimer.remainingTime();
    int interval = cookingTimer.interval();
    if (left > interval)
        left = interval;

    if (cooking())
        return ceil(left / 1000.0);

    return time_;
}

void Oven::setTime(int secs)
{
    time_ = secs;
    cookingTimer.setInterval(secs * 1000);
}

void Oven::setInterTempEnabled(bool enabled)
{
    if (setInterTempEnabled_(enabled))
        emit changed(this);
}

bool Oven::setInterTempEnabled_(bool enabled)
{
    if (interTempEnabled_ != enabled)
    {
        interTempEnabled_ = enabled;
        return true;
    }

    return false;
}

void Oven::setInterTemp(int celsius)
{
    if (setInterTemp_(celsius))
        emit changed(this);
}

bool Oven::setInterTemp_(int celsius)
{
    if (celsius < minInterTemp() || celsius > maxInterTemp())
        return false;

    if (celsius != interTemp_)
    {
        interTemp_ = celsius;
        interface->setInterTemp(celsius);

        return true;
    }

    return false;
}

void Oven::setFan(int speed)
{
    if (setFan_(speed))
        emit changed(this);
}

bool Oven::setFan_(int speed)
{
    if (speed < minFan() || speed > maxFan())
        return false;

    if (speed == fan_)
        return false;

    int rpm;
    switch (speed)
    {
    case 1:
        rpm = 500;
        break;
    case 2:
        rpm = 725;
        break;
    case 3:
        rpm = 950;
        break;
    case 4:
        rpm = 1175;
        break;
    case 5:
        rpm = 1400;
        break;
    }

    fan_ = speed;
    interface->setFan(rpm);

    return true;
}

bool Oven::cookingStartable()
{
    if (/*door() || */cooking())
        return false;

    return true;
}

bool Oven::preheatingStartable()
{
    if (door())
        return false;

    return true;
}

bool Oven::cooldownStartable()
{
    return true;
}

bool Oven::damperOpenable()
{
    return true;
}

bool Oven::humidificationStartable()
{
    return true;
}

void Oven::stop()
{
    if (cooking())
        stopCooking();

    if (preheating())
        stopPreheating();

    if (cooldown())
        stopCooldown();

    if (humidification())
        stopHumidification();

    if (washing())
        stopWashing();
}

void Oven::startCooking()
{
    paused_ = false;

    if (cookingStartable())
    {
        if (preheating())
            stopPreheating();

        if (cooldown())
            stopCooldown();

        cooking_ = true;
        cookingTimer.start();
        interface->startCooking();

        emit changed(this);
    }
}

void Oven::stopCooking()
{
    if (cooking())
    {
        if (time() > 0)
        {
            paused_ = true;
            setTime(time());
            cookingTimer.stop();
        }
        else
            setTime(0);

        cooking_ = false;
        interface->stopCooking();

        emit changed(this);
    }
}

void Oven::startPreheating()
{
    if (preheatingStartable())
    {
        preheating_ = true;
        interface->startPreheating();

        emit changed(this);
    }
}

void Oven::stopPreheating()
{
    if (preheating())
    {
        preheating_ = false;
        interface->stopPreheating();

        emit changed(this);
    }
}

void Oven::startCooldown()
{
    if (cooldownStartable())
    {
        if (cooking())
            stopCooking();

        cooldown_ = true;
        interface->startCooldown();

        emit changed(this);
    }
}

void Oven::stopCooldown()
{
    if (cooldown())
    {
        cooldown_ = false;
        interface->stopCooldown();

        emit changed(this);

        if (paused())
            startCooking();
    }
}

void Oven::startHumidification()
{
    if (humidificationStartable())
    {
        humidification_ = true;
        humidificationTimer.start(10 * 60 * 1000);
        interface->startHumidification();

        emit changed(this);
    }
}

void Oven::stopHumidification()
{
    if (humidification())
    {
        humidification_ = false;
        if (humidificationTimer.isActive())
            humidificationTimer.stop();

        interface->stopHumidification();

        emit changed(this);
    }
}

void Oven::startWashing()
{

}

void Oven::stopWashing()
{

}

void Oven::openDamper()
{

}

void Oven::closeDamper()
{

}





int Oven::maxTemp()
{
    switch (mode())
    {
    case HeatMode:
        return 300;
    case SteamMode:
        return 130;
    case CombinationMode:
        return 300;
    default:
        return 0;
    }
}

int Oven::minTemp()
{
    switch (mode())
    {
    case HeatMode:
        return 30;
    case SteamMode:
        return 30;
    case CombinationMode:
        return 30;
    default:
        return 0;
    }
}

int Oven::maxInterTemp()
{
    switch (mode())
    {
    case HeatMode:
        return 99;
    case SteamMode:
        return 99;
    case CombinationMode:
        return 99;
    default:
        return 0;
    }
}

int Oven::minInterTemp()
{
    switch (mode())
    {
    case HeatMode:
        return 30;
    case SteamMode:
        return 30;
    case CombinationMode:
        return 30;
    default:
        return 0;
    }
}

int Oven::maxFan()
{
    return 5;
}

int Oven::minFan()
{
    return 1;
}

void Oven::onDoorOpened()
{
    door_ = true;

    emit changed(this);

    if (cooking())
        stopCooking();
}

void Oven::onDoorClosed()
{
    door_ = false;

    emit changed(this);

    if (paused())
        startCooking();
}