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 WashingProgram2 extends ActorThread<WashingMessage> {

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

    public WashingProgram2(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 {
            System.out.println("WashingProgram2 Started...");
            // Lock the hatch
            io.lock(true);

            // Let water into the machine
            water.send(new WashingMessage(this, WATER_FILL));
            receive();

            // Heat to 40 C
            temp.send(new WashingMessage(this, TEMP_SET_40));
            receive();

            // Keep the temperature for 20 min
            Thread.sleep(20 * 60000 / Settings.SPEEDUP);

            // Drain
            temp.send(new WashingMessage(this, TEMP_IDLE));
            receive();
            water.send(new WashingMessage(this, WATER_DRAIN));
            receive();

            // Let water into the machine
            water.send(new WashingMessage(this, WATER_FILL));
            receive();
            // Heat to 60 C
            temp.send(new WashingMessage(this, TEMP_SET_60));
            receive();

            // Keep the temperature for 20 min
            Thread.sleep(30 * 60000 / Settings.SPEEDUP);

            // Kill the heat
            temp.send(new WashingMessage(this, TEMP_IDLE));
            receive();

            // Rinse 5*2 minutes in cold water
            for(int a = 0; a < 5; a++) {
                water.send(new WashingMessage(this, WATER_FILL));
                receive();

                Thread.sleep(2 * 60000 / Settings.SPEEDUP);

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

            // Centrifuge for five minutes
            spin.send(new WashingMessage(this, SPIN_FAST));
            receive();
            Thread.sleep(5 * 60000 / Settings.SPEEDUP);

            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("WashingProgram2 Finished...");
        } catch (InterruptedException e) {
            System.out.println("WashingProgram2 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));
        }
    }
}
