package scheduler;

import java.io.IOException;

import common.Direction;
import common.Motor;
import communication.MessageSender;
import communication.Port;
import communication.messages.ElevatorActionMessage;
import communication.messages.FloorArrivalMessage;
import communication.messages.ElevatorSensorMessage;
import elevator.Elevator.ElevatorAction;
import error.UnknownAddressException;

/**
 * This class represents a task to tell an elevator to move up or down after
 * arriving at a floor sensor
 *
 */
public class ElevatorMovedTask implements SchedulerTask {

	private final int elevatorId;
	private final MetaElevator elevator;
	private final int sensorFloor;
	/**
	 * Used when a forced action was performed
	 */
	private boolean isForce = false;
	private boolean isForceClosed = false;

	public ElevatorMovedTask(ElevatorSensorMessage msg) {
		elevatorId = msg.getElevatorId();
		sensorFloor = msg.getCurrentFloor();
		elevator = Scheduler.getMetaElevatorById(elevatorId);
	}

	public ElevatorMovedTask(ElevatorSensorMessage msg, boolean isForce, boolean isForceClosed) {
		elevatorId = msg.getElevatorId();
		sensorFloor = msg.getCurrentFloor();
		elevator = Scheduler.getMetaElevatorById(elevatorId);
		this.isForce = isForce;
		this.isForceClosed = isForceClosed;
	}

	/**
	 * This method is called each time the elevator moves a floor. On each floor
	 * change, we send a CURRENT_FLOOR message to ElevatorSubsystem. If the floor is
	 * the destination floor, we open the doors of the elevator and tell the
	 * FloorSubsystem we arrived so that it can turn one of its lights off.
	 */
	@Override
	public void run(MessageSender messageSender) throws IOException, UnknownAddressException {
		elevator.cancelTimer();
		if (isForce || sensorFloor == elevator.getNextDestination()) {
			if (!isForce) {
				elevator.removeDestinationFloor();
				// send floorMessage telling the floor we arrived
				messageSender.sendMessage(new FloorArrivalMessage(sensorFloor,
						elevator.getMotorStatus() == Motor.UP ? Direction.UP : Direction.DOWN, elevator.getElevatorId()),
						Port.FLOOR);
			}
			if (isForceClosed) {
				int nextDestination = elevator.getNextDestination();
				boolean movingUp = nextDestination > elevator.getCurrentFloor();

				elevator.setMotorStatus(movingUp ? Motor.UP : Motor.DOWN);
				ElevatorAction upOrDown = movingUp ? ElevatorAction.MOVE_UP : ElevatorAction.MOVE_DOWN;
				messageSender.sendMessage(new ElevatorActionMessage(elevator.getElevatorId(), upOrDown, nextDestination), Port.ELEVATOR);

				elevator.startTimer(Scheduler.getFloorDelayTime());
			} else {
				// create message to tell elevator system that it has arrived and to open doors
				messageSender.sendMessage(new ElevatorActionMessage(elevator.getElevatorId(),
					ElevatorAction.ARRIVED_AT_DESTINATION, sensorFloor), Port.ELEVATOR);
			}
			if (!isForce) {
				elevator.setMotorStatus(Motor.STOPPED);
			}
		} else {
			// tell elevator that we moved a floor and to continue moving
			messageSender.sendMessage(
					new ElevatorActionMessage(elevator.getElevatorId(), ElevatorAction.CONTINUE_MOVING, sensorFloor),
					Port.ELEVATOR);
			elevator.startTimer(Scheduler.getFloorDelayTime());
		}
	}
}
