package de.reinhardt_karlheinz.pcc.pc.servers;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.net.SocketAddress;

import de.reinhardt_karlheinz.pcc.enums.ConnectionType;
import de.reinhardt_karlheinz.pcc.interfaces.PCCConnection;

public class USBClient extends PCCConnection {
  // ## SERVER
  private Thread svrThread;

  private Socket socket;

  private int port;

  // ## STREAMS
  private BufferedReader inStrm;

  private PrintWriter outStrm;

  public USBClient(int port) {
    super(ConnectionType.USB);
    this.port = port;
    // TODO Auto-generated constructor stub
  }

  @Override
  protected void addShutdownHook() {
    Runtime.getRuntime().addShutdownHook(new Thread() {
      @Override
      public void run() {
        try {
          stopServer();
        } catch (IOException e) {
          // TODO Auto-generated catch block
          e.printStackTrace();
        }
      }
    });
  }

  public void startrunning() {
    svrThread = new Thread() {

      @SuppressWarnings("synthetic-access")
      @Override
      public void run() {
        while (isConnected() == true) {
          if (null == readInStrm()) {
            setConnected(false);
          }
        }
        // # close client
        try {
          stopServer();
        } catch (IOException e) {
          e.printStackTrace();
        }
      }
    };
    svrThread.start();
  }

  // TODO do not cll evaluate in this method
  private String readInStrm() {
    String input = null;
    try {
      input = inStrm.readLine();
    } catch (IOException e) {
      e.printStackTrace();
    }
    evaluateInputString(input);
    return input;
  }

  @Override
  protected synchronized void sendString(String s) {
    outStrm.println(s);
    outStrm.flush();
  }

  @Override
  public boolean startServer() throws IOException {
    // # intit socket
    // socket = new Socket("localhost", port);
    SocketAddress addr = new InetSocketAddress("localhost", port);
    socket = new Socket();
    socket.connect(addr, 1000);
    // # open streams
    inStrm = new BufferedReader(new InputStreamReader(socket.getInputStream()));
    outStrm = new PrintWriter(new OutputStreamWriter(socket.getOutputStream()));
    // # test connection
    if (checkIfConnected() == true) {
      // inputstrm is NOT null --> server on Android is running
      fireConnectionEstablishedEvent();
      startrunning();
      return true;
    }
    // inputstrm is null --> server on Android is NOT running
    return false;
  }

  @Override
  public void stopServer() throws IOException {
    closeConnections();
    fireConnectionLostEvent();
  }

  @Override
  protected void closeConnections() throws IOException {
    setConnected(false);
    outStrm.flush();
    outStrm.close();
    inStrm.close();
    socket.close();
  }

  @Override
  /**
   * true if connected false if not
   */
  protected boolean checkIfConnected() {
    setConnected(null == readInStrm() ? false : true);
    return isConnected();
  }

  /**
   * @return the socket
   */
  public Socket getSocket() {
    return socket;
  }

  /**
   * @return the port
   */
  public int getPort() {
    return port;
  }

}
