package wash.control;

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

public final class ControllerSpin extends ActorThread<WashingMessage> {
    private WashingIO io;
    private Spin spin = new Spin();
    private WashingMessage m;

    public ControllerSpin(WashingIO io) {
        this.io = io;
    }

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

    @Override
    public void run() {
        spin.start();
        listener(); // Drop into a recursive listener method
    }

    /** Recursive listener method */
    public void listener() {
        m = poll(60000 / Settings.SPEEDUP).orElse(new WashingMessage(this, Order.NOOP));

        switch (m.order()) {
            case Order.SPIN_OFF -> spin.setMode(WashingIO.Spin.IDLE);
            case Order.SPIN_FAST -> spin.setMode(WashingIO.Spin.FAST);
            case Order.SPIN_SLOW -> spin.setMode(WashingIO.Spin.LEFT);
            default -> {
                listener();
            }
        }

        listener();
    }

    private final class Spin extends Thread {
        private WashingIO.Spin spinMode;
        boolean changed = false;

        public Spin() {
            spinMode = WashingIO.Spin.IDLE;
        }

        public synchronized void setMode(WashingIO.Spin m) {
            spinMode = m;
            changed = true;
        }

        private void loop() {
            io.setSpinMode(spinMode);

            if (changed) {
                sendAck();
                changed = false;
            }

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

        @Override
        public void run() {
            loop();
        }
    }
}
