import com.phidgets.*;
import com.phidgets.event.*;
import java.net.*;
import java.io.*;


public class ChrisTest implements AttachListener, DetachListener,
					InputChangeListener, SensorChangeListener{

	public static final int KNOCKSENSOR = 7;
	public static final int SWITCH_CLOSED_CHANNEL = 0;
	public static final int SWITCH_OPENED_CHANNEL = 1;
	public static final int HANDICAP_SWITCH = 2;
	public static final int DOOR_OPEN_CHANNEL = 0;
	public static final int DOOR_CLOSE_CHANNEL = 1;
	public boolean safe = true;
	public enum DoorState {MOVING, STABLE, DETECTING};
	public DoorState doorstate = DoorState.STABLE;
	public InterfaceKitPhidget ik;
	public ServoPhidget sc;
	private ServerSocket ss;

	public boolean OPEN;

	public static final void main(String args[]) throws Exception {

		if (args.length == 0) {
			//throw new Exception("Give me a parameter FOO!");
		}
		ChrisTest door = new ChrisTest("close");
	}



	public ChrisTest(String action) throws Exception{

        try
        {
                ss = new java.net.ServerSocket(37337);
        }
      catch (java.net.BindException ex)
        {
                System.out.println("Instance already running!");
                System.exit(1);
        }
      catch (java.io.IOException ex)
        {
                ex.printStackTrace();
                System.exit(1);
        }

      //DoorServerWatcher dsw = new DoorServerWatcher();

      doorstate = DoorState.STABLE;
      ik = new InterfaceKitPhidget();
      ik.openAny();
      System.out.println("Waiting for attachments......");
      ik.waitForAttachment(3000);
      sc = new ServoPhidget();
      sc.openAny();
      sc.waitForAttachment(3000);

      Thread dsw = new Thread(new DoorServerWatcher());
      dsw.start();

      DoorOperate(action);
	}

	public synchronized void DoorOperate(String open){
		try {
		doorstate = DoorState.MOVING;

		ik.addSensorChangeListener(this);
		ik.addAttachListener(this);
		ik.addDetachListener(this);
		ik.addInputChangeListener(this);

//		boolean OPEN;
		boolean SEMI = false;

		//If they picked alt, decide if we need to open or close it
		if (open.equalsIgnoreCase("alt")) {
			safe = false;
			System.out.println("Open is ALT");
			if (ik.getInputState(SWITCH_OPENED_CHANNEL) == true && ik.getInputState(SWITCH_CLOSED_CHANNEL) == false)
				OPEN = false;
			else if (ik.getInputState(SWITCH_OPENED_CHANNEL) == false && ik.getInputState(SWITCH_CLOSED_CHANNEL) == true)
				OPEN = true;
			else {
				System.out.println("Alternative selected but door not in extereme state...attempting to open");
				OPEN = true;
			}
		}
		else if (open.equalsIgnoreCase("close")) {
			OPEN = false;
		}
		else if (open.equalsIgnoreCase("open")) {
			OPEN = true;
		}
		else if (open.equalsIgnoreCase("semi")) {
			SEMI = true;
			OPEN = true;
		}
		else //otherwise, parse the int
			OPEN = (Integer.parseInt(open) == 0 ? false : true);

			//Do safety check
		if (ik.getInputState(OPEN ? SWITCH_OPENED_CHANNEL : SWITCH_CLOSED_CHANNEL) == true && safe == true) {
			System.out.println("THE DOOR IS JUST FINE WHERE IT IS, thank you very much");
			killAll();
			return;
		}

		//Decide if we need to open the handle or not
		System.out.println("Starting " + (OPEN ? "OPEN" : "CLOSE ") + "sequence!");

		if (OPEN) {
			sc.setPosition(0, sc.getPositionMax(0));
			Thread.sleep(650);
		}
		else {
			sc.setPosition(0, 130);
			//sc.setEngaged(0, false);
		}


		//Kick off the solenoids
		ik.setOutputState(OPEN ? DOOR_OPEN_CHANNEL : DOOR_CLOSE_CHANNEL, true);

		if (SEMI) {
			Thread.sleep(1700);
		}
		else {
			Thread.sleep(5500);
		}
		//If its not over yet, finish it now!
	 	killAll();

		//Wait lets wait a bit more for it to stop jiggling
		Thread.sleep(1000);
		}
		catch (Exception e) {
			System.out.println("We've had some sort of epic fail in the door moving...dying:" + e);
			killAll();
		}



	 	doorstate = DoorState.STABLE;
	}


	public void attached(AttachEvent ae) {
		System.out.println(ae);
	}


	public void detached(DetachEvent de) {
		System.out.println("Interface lost!: " + de);
		killAll();
	}

	public void killAll() {
		try {
	//		System.out.println("Door output state should be false...");
			ik.setOutputState(DOOR_OPEN_CHANNEL, false);
		}
		catch (Exception e) {
			e.printStackTrace();
		}
		try {
			ik.setOutputState(DOOR_CLOSE_CHANNEL, false);
			}
			catch (Exception e) {
				System.out.println(e);
			}

		try {
			sc.setEngaged(0, false);
			//sc.close();
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	public void inputChanged(InputChangeEvent e) {
		if (e.getState() == true && e.getIndex() == HANDICAP_SWITCH && doorstate == DoorState.STABLE) {
			System.out.println("Handicap switch hit!");
			doorstate = DoorState.MOVING;
			DoorStarter dst = new DoorStarter("alt");
			Thread tt = new Thread(dst);
			tt.start();
		}
		else if (e.getState() == true) {
			System.out.println("A switch turned on!");
			killAll();
		}
	}


	public void sensorChanged(SensorChangeEvent s) {
		if (doorstate == DoorState.STABLE) {
			System.out.println("Sensor value changes...+ " + s.getValue());
			if (//ks == 0 &&
					(s.getIndex() == KNOCKSENSOR &&
					Math.abs(s.getValue() - 500) > 300)
					|| (s.getIndex() == SWITCH_OPENED_CHANNEL )// && Math.abs(s.getValue() - 500) < 300)
							// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~```
				)
			{
				System.out.println("DOOR TRIGGERED");;
				doorstate = DoorState.MOVING;
				DoorStarter dst = new DoorStarter("alt");
				Thread tt = new Thread(dst);
				tt.start();
			}
		}
	}


	public class DoorStarter implements Runnable {
		String cmd;
		public DoorStarter(String s) {
			cmd=s;
		}
		public void run() {
			DoorOperate(cmd);
		}
	}

	public void MoveDoorFor(int i) {
		DoorOperate("close");
		System.out.println("Door closed!");
		DoorStarter dst = new DoorStarter("alt");
		Thread tt = new Thread(dst);
		tt.start();
		try {
			Thread.sleep(i);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		//tt.stop();
		killAll();
	}

	public class DoorServerWatcher implements Runnable {
		public void run() {
			Socket clientSocket = null;
			while(true) {
				try {
					clientSocket = ss.accept();
					System.out.println(ss.getInetAddress());
					BufferedReader in = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
				    PrintWriter out = new PrintWriter(clientSocket.getOutputStream(), true);

					out.print("door is now ");

					String inputLine;
					while ((inputLine = in.readLine()) != null) {
						System.out.println(inputLine);

						if (inputLine.contains("awesomesauce alt")) {
							//clientSocket.close();
							doorstate = DoorState.MOVING;
							DoorStarter dst = new DoorStarter("alt");
							Thread tt = new Thread(dst);
							tt.start();

							if(OPEN) out.println("open");
							else out.println("closed");
							clientSocket.close();
							break;
						}
						else if (doorstate == DoorState.MOVING && inputLine.contains("awesomesauce stop")) {
							killAll();
							clientSocket.close();
							break;
						}
						else if (inputLine.contains("awesomesauce private")) {
							MoveDoorFor(1250);
							//MoveDoorFor(1000);
							clientSocket.close();
							break;
						}
						else if (inputLine.contains("awesomesauce movie")) {
							MoveDoorFor(2400);
							clientSocket.close();
							break;
						}
						else {
							clientSocket.close();
							break;
						}
					}

				} catch (IOException e) {
					System.out.println("Socket accept failed");
					e.printStackTrace();
				}
			}
		}
	}
}

