package net.bakingpowder.jspl.tcprelay.buffering;

import java.net.Socket;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.IOException;

/**
 * @author Tomoo D. Mizukami/JAIST/Softbank Publishing Inc.
 *
 * This Class is a multi thread class for controling trafic between InputStream/OutputStream and buffer-interchange-function
 */
public class ConnectControl implements Runnable {
	private boolean connectionClosed = false;
	private InputStream destIn, srcIn;
	private OutputStream srcOut, destOut;

	private Input2Output src2dst, dst2src;
	private TCPRelay myp;
	private Socket srcSocket, destSocket;

	private String destHost;
	private int destPort;

	/**
	 * @param s Source Socket
	 * @param destHost Destination Host
	 * @param destPort Destination Host's Port
	 */
	public ConnectControl(Socket s, String destHost, int destPort) {
		srcSocket = s;
		this.destHost = destHost;
		this.destPort = destPort;

		try {
			srcIn = s.getInputStream();
			srcOut = s.getOutputStream();
			Thread t = new Thread(this);
			t.start();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	public synchronized void ThreadArrivedEnd(Input2Output a) {
		if (connectionClosed)
			return;

		this.closeSrc();
		this.closeDest();

		connectionClosed = true;
	}

	private void closeDest() {
		try {
			destIn.close();
			destOut.close();
			destSocket.close();
		} catch (Exception e) {
		}
	}

	private void closeSrc() {
		try {
			srcIn.close();
			srcOut.close();
			srcSocket.close();
		} catch (Exception e) {
		}
	}

	private boolean connectToDest() {
		try {
			destSocket = new Socket(destHost, destPort);
			destIn = destSocket.getInputStream();
			destOut = destSocket.getOutputStream();
		} catch (Exception e) {
			System.err.println("[Proxy Connection Error]");
			return false;
		}

		return true;
	}

	public void stopd(){
		src2dst.stopd();
		dst2src.stopd();
		try {
			destIn.close();
			destOut.close();
			srcIn.close();
			srcOut.close();
			destSocket.close();
			srcSocket.close();
			
		} catch (IOException e) {
			e.printStackTrace();
		}
		
	}

	public void run() {
		if (!connectToDest()) {
			closeSrc();
		} else {
			src2dst = new Input2Output(srcIn, destOut, this);
			dst2src = new Input2Output(destIn, srcOut, this);
		}
	}
}