package wash.control;

import actor.ActorThread;
import wash.io.WashingIO;
import wash.control.WashingMessage.Order;

public final class ControllerTemp extends ActorThread<WashingMessage> {
    private WashingIO io;
    private Heater heater;
    private WashingMessage m;

    public ControllerTemp(WashingIO io) {
        this.io = io;
        heater = new Heater(0);
    }

    protected void sendAck() {
        m.sendAck(this);
    }

    @Override
    public void run() {
        heater.start();

        while (true) {
            m = poll(60000 / Settings.SPEEDUP).orElse(new WashingMessage(this, Order.NOOP));

            switch (m.order()) {
                case Order.TEMP_SET_40 -> heater.setTarget(40);
                case Order.TEMP_SET_60 -> heater.setTarget(60);
                case Order.TEMP_IDLE -> heater.setTarget(0);
                default -> {
                    continue;
                }
            }

        }
    }

    /**
     * Heater class that extends Thread and controls the temperature
     * of the washing machine.
     * 
     * Note that the heater has access to local variables in the
     * TemperatureController class.
     */
    class Heater extends Thread {
        double target;
        boolean hovering;

        Heater(double target) {
            this.target = target;
            this.hovering = true; // No acks before actual setpoint is acquired
        }

        synchronized public void setTarget(double target) {
            this.target = target;
            this.hovering = false;
        }

        @Override
        public void run() {
            double current;
            while (!isInterrupted()) {
                current = io.getTemperature();

                if (io.getWaterLevel() == 0) {
                    io.heat(false);
                    usleep(60000 / Settings.SPEEDUP);
                    continue;
                }

                if (current < target) {
                    io.heat(true);
                }

                else if (current >= target) {
                    io.heat(false);
                    if(!hovering) {
                        sendAck();
                        hovering = true;
                        usleep(60000 / Settings.SPEEDUP);
                        continue;
                    }
                }

                usleep(60000 / Settings.SPEEDUP);
            }
        }
    }
}
