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.ConnectException;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.net.SocketAddress;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.Iterator;

import de.reinhardt_karlheinz.pcc.enums.ConnectionType;
import de.reinhardt_karlheinz.pcc.events.PCCMessageEvent;
import de.reinhardt_karlheinz.pcc.events.PCConnectionEvent;
import de.reinhardt_karlheinz.pcc.listeners.PCCMsgListener;
import de.reinhardt_karlheinz.pcc.listeners.PCConnectionListener;
@Deprecated
/**
 * 
 * (c) Copyright 2012, Karlheinz Reinhardt. All rights reserved.<br>
 * 
 * TODO USE WAIT and NOTIFY instead of synchronized
 * 
 * @author Karlheinz Reinhardt
 * @version 0.0.0.1
 */
public class ServerConnection {
  Thread svrThread;

  // ## SERVER
  private Socket socket;

  private int port;

  // ## STREAMS
  private BufferedReader inStrm;

  private PrintWriter outStrm;

  // ## OTHER
  private boolean connection;

  public ServerConnection(int port) {
    this.port = port;
    connection = false;
    addShutdownHook();
  }

  private void addShutdownHook() {
    Runtime.getRuntime().addShutdownHook(new Thread() {
      @Override
      public void run() {
        try {
          stopServer();
        } catch (IOException e) {
          e.printStackTrace();
        }
      }
    });
  }

  public void startrunning(){
  svrThread = new Thread() {
    
    @Override
    public void run() {
      while (connection == true) {
        if (null == readInStrm()) {
          connection = false;
        }
      }
      try {
        stopServer();
      } catch (IOException e) {
        e.printStackTrace();
      }
    }
  };
  svrThread.start();
}

  private String readInStrm() {
    String input = null;
    try {
      input = inStrm.readLine();
    } catch (IOException e) {
      e.printStackTrace();
    }
    if (input != null && input.isEmpty() == false && "".equals(input) == false) {
      if (input.startsWith("\\")) {
        fireCommandReceivedEvent(input.substring(1));
      } else {
        fireMsgReceivedEvent(input);
      }
    }
    return input;
  }

  public synchronized void sendTxt(String txt) {
    outStrm.println(txt);
    outStrm.flush();
  }

  // // TODO
  // public synchronized void sendMsg(String sender, String msg) {
  // sendTxt(":sndr:" + sender + ":msg:" + msg);
  // }

  public void sendCmd(String cmd) {
    sendTxt("\\" + cmd);
  }

  public boolean startServer() throws UnknownHostException, IOException,
      ConnectException {
    // # 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 (isConnected() == true) {
      // inputstrm is NOT null --> server on Android is running
      fireConnectionEstablishedEvent();
      this.startrunning();
      System.out.println("svr ret true");
      return true;// FIXME
    }
    // inputstrm is null --> server on Android is NOT running
    System.out.println("svr ret fls");
    return false;
  }

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

  private void closeConnections() throws IOException {
    connection = false;
    outStrm.flush();
    outStrm.close();
    inStrm.close();
    socket.close();
  }

  // ### LISTENER STUFF ###

  private ArrayList<PCConnectionListener> _connectionListeners = new ArrayList<PCConnectionListener>();

  private ArrayList<PCCMsgListener> _messageListeners = new ArrayList<PCCMsgListener>();

  public void addPCConnectionListener(PCConnectionListener listener) {
    _connectionListeners.add(listener);
  }

  public void removePCConnectionListener(PCConnectionListener listener) {
    _connectionListeners.remove(listener);
  }

  public void addPCCMsgListener(PCCMsgListener listener) {
    _messageListeners.add(listener);
  }

  public void removePCCMsgListener(PCCMsgListener listener) {
    _messageListeners.remove(listener);
  }

  private void fireConnectionEstablishedEvent() {
    connection = true;
    PCConnectionEvent event = new PCConnectionEvent(this, ConnectionType.USB);
    Iterator<PCConnectionListener> i = _connectionListeners.iterator();
    while (i.hasNext()) {
      i.next().onPCConnectionEstablished(event);
    }
  }

  private void fireConnectionLostEvent() {
    PCConnectionEvent event = new PCConnectionEvent(this, ConnectionType.USB);
    Iterator<PCConnectionListener> i = _connectionListeners.iterator();
    while (i.hasNext()) {
      i.next().onPCConnectionLost(event);
    }
  }

  private void fireMsgReceivedEvent(String msg) {
    PCCMessageEvent event = new PCCMessageEvent(this, msg);
    Iterator<PCCMsgListener> i = _messageListeners.iterator();
    while (i.hasNext()) {
      i.next().onMsgReceived(event);
    }
  }

  private void fireCommandReceivedEvent(String msg) {
    PCCMessageEvent event = new PCCMessageEvent(this, msg);
    Iterator<PCCMsgListener> i = _messageListeners.iterator();
    while (i.hasNext()) {
      i.next().onCommandReceived(event);
    }
  }

  // ################

  public boolean isConnected() {
    connection = null == readInStrm() ? false : true;
    return connection;
  }

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

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

}
