package wash.program;

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

import static wash.control.WashingMessage.Order.*;

/**
 * Program 3 for washing machine. This also serves as an example of how washing
 * programs can be structured.
 * 
 * This short program stops all regulation of temperature and water levels,
 * stops the barrel from spinning, and drains the machine of water.
 * 
 * It can be used after an emergency stop (program 0) or a power failure.
 */
public final class WashingProgram1 extends ActorThread<WashingMessage> {

    private WashingIO io;
    private ActorThread<WashingMessage> temp;
    private ActorThread<WashingMessage> water;
    private ActorThread<WashingMessage> spin;

    public WashingProgram1(WashingIO io,
            ActorThread<WashingMessage> temp,
            ActorThread<WashingMessage> water,
            ActorThread<WashingMessage> spin) {
        this.io = io;
        this.temp = temp;
        this.water = water;
        this.spin = spin;
    }

    @Override
    public void run() {
        try {
            // Lock the hatch
            io.lock(true);

            water.send(new WashingMessage(this, WATER_FILL));
            receive();

            // Instruct SpinController to rotate barrel slowly, back and forth
            // Expect an acknowledgment in response.
            spin.send(new WashingMessage(this, SPIN_SLOW));
            receive();

            // Spin for five simulated minutes (one minute == 60000 milliseconds)
            Thread.sleep(5 * 60000 / Settings.SPEEDUP);

            // Instruct SpinController to stop spin barrel spin.
            // Expect an acknowledgment in response.
            spin.send(new WashingMessage(this, SPIN_OFF));
            receive();

            temp.send(new WashingMessage(this, TEMP_IDLE));
            receive();

            water.send(new WashingMessage(this, WATER_DRAIN));
            receive();

            // Now that the barrel has stopped, it is safe to open the hatch.
            io.lock(false);

            System.out.println("WashingProgram1 Finished...");
            this.interrupt();
        } catch (InterruptedException e) {
            System.out.println("WashingProgram1 Interrupted...");

            // If we end up here, it means the program was interrupt()'ed:
            // set all controllers to idle
            temp.send(new WashingMessage(this, TEMP_IDLE));
            water.send(new WashingMessage(this, WATER_IDLE));
            spin.send(new WashingMessage(this, SPIN_OFF));
        }
    }
}
