protected void wash() throws InterruptedException {
		myMachine.setLock(true);
        myWaterController.putEvent(new WaterEvent(this, WaterEvent.WATER_DRAIN, 0d));
        mailbox.doFetch();

        // Pre-wash
        myWaterController.putEvent(new WaterEvent(this, WaterEvent.WATER_FILL, 0.5d));
        mailbox.doFetch();

        myWaterController.putEvent(new WaterEvent(this, WaterEvent.WATER_IDLE, 0d));
        myTempController.putEvent(new TemperatureEvent(this, TemperatureEvent.TEMP_SET, 40d));
        mailbox.doFetch();

        mySpinController.putEvent(new SpinEvent(this, SpinEvent.SPIN_SLOW));
        long sleepTime = System.currentTimeMillis () + (long) (15d * 60d * 1000d / mySpeed);
        while (sleepTime > System.currentTimeMillis()) { sleep(sleepTime - System.currentTimeMillis()); }

        mySpinController.putEvent(new SpinEvent(this, SpinEvent.SPIN_OFF));
        myTempController.putEvent(new TemperatureEvent(this, TemperatureEvent.TEMP_IDLE, 0d));
        myWaterController.putEvent(new WaterEvent(this, WaterEvent.WATER_DRAIN, 0d));
        mailbox.doFetch();

        myWaterController.putEvent(new WaterEvent(this, WaterEvent.WATER_IDLE, 0d));

        // Main wash
        myWaterController.putEvent(new WaterEvent(this, WaterEvent.WATER_FILL, 0.5d));
        mailbox.doFetch();

        myWaterController.putEvent(new WaterEvent(this, WaterEvent.WATER_IDLE, 0d));
        myTempController.putEvent(new TemperatureEvent(this, TemperatureEvent.TEMP_SET, 90d));
        mailbox.doFetch();

        mySpinController.putEvent(new SpinEvent(this, SpinEvent.SPIN_SLOW));
        sleepTime = System.currentTimeMillis () + (long) (30d * 60d * 1000d / mySpeed);
        while (sleepTime > System.currentTimeMillis()) { sleep(sleepTime - System.currentTimeMillis()); }

        mySpinController.putEvent(new SpinEvent(this, SpinEvent.SPIN_OFF));
        myTempController.putEvent(new TemperatureEvent(this, TemperatureEvent.TEMP_IDLE, 0d));
        myWaterController.putEvent(new WaterEvent(this, WaterEvent.WATER_DRAIN, 0d));
        mailbox.doFetch();

        myWaterController.putEvent(new WaterEvent(this, WaterEvent.WATER_IDLE, 0d));

        for (int i = 0; i < 5; i++) {
            myWaterController.putEvent(new WaterEvent(this, WaterEvent.WATER_FILL, 0.8d));
            mailbox.doFetch();

            myWaterController.putEvent(new WaterEvent(this, WaterEvent.WATER_IDLE, 0d));
            sleepTime = System.currentTimeMillis () + (long) (2d * 60d * 1000d / mySpeed);
            while (sleepTime > System.currentTimeMillis()) { sleep(sleepTime - System.currentTimeMillis()); }

            myWaterController.putEvent(new WaterEvent(this, WaterEvent.WATER_DRAIN, 0d));
            mailbox.doFetch();

            myWaterController.putEvent(new WaterEvent(this, WaterEvent.WATER_IDLE, 0d));
        }

        mySpinController.putEvent(new SpinEvent(this, SpinEvent.SPIN_FAST));
        sleepTime = System.currentTimeMillis () + (long) (2d * 60d * 1000d / mySpeed);
        while (sleepTime > System.currentTimeMillis()) { sleep(sleepTime - System.currentTimeMillis()); }
        mySpinController.putEvent(new SpinEvent(this, SpinEvent.SPIN_OFF));
		myMachine.setLock(false);
	}