package com.interpress_project.modernshare.client.controller.delegate.secureguard;

import java.io.IOException;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.SocketException;
import java.net.UnknownHostException;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

import com.interpress_project.modernshare.client.controller.model.PropertyManager;
import com.interpress_project.modernshare.ipcommon.SystemBase;

public class SVNproxy extends Thread {
	private final SystemBase sb = SystemBase.getInstance();
	private final PropertyManager propmgr = PropertyManager.getInstance();
	private int THREAD_INITIALCOUNT = 16;
	private int THREAD_MAXCOUNT = 32;
	private int LISTEN_PORT = 0;
	private ServerSocket serverSocket = null;
	private ThreadPoolExecutor requestThreadPool = null, workThreadPool = null;
	private InetAddress hostaddr = null;
	private boolean shutdown = false;

	/**
	 * @stereotype creates
	 */
	/*#com.interpress_project.modernshare.client.controller.delegate.secureguard.WorkerThread Dependency20*/

	/**
	 * SVNproxy
	 */
	@SuppressWarnings("unchecked")
	public SVNproxy() {
		LISTEN_PORT = propmgr.getSecureGuardPort();

		try {
			hostaddr = InetAddress.getByName("127.0.0.1");
		}
		catch (UnknownHostException ex) {
			sb.getLogger().fatal("ローカルループバック取得に失敗しました。アプリケーションを終了します。", ex);
			System.exit(-1);
		}

		requestThreadPool = new ThreadPoolExecutor(THREAD_INITIALCOUNT, THREAD_MAXCOUNT, 180, TimeUnit.SECONDS,
		  new LinkedBlockingQueue());
		workThreadPool = new ThreadPoolExecutor(THREAD_INITIALCOUNT, THREAD_MAXCOUNT, 180, TimeUnit.SECONDS,
		  new LinkedBlockingQueue());

		try {
			/**
			 * アプリケーションが RFC1323 で定義されている 64K バイトを超える受信ウィンドウを
			 * 使用可能にする必要がある場合には、 ローカルアドレスにバインドする前に 推奨値を
			 * ServerSocket で設定する必要があります。 
			 */
			serverSocket = new ServerSocket();
			serverSocket.setReceiveBufferSize(propmgr.getTcpBufSz());
			serverSocket.setReuseAddress(false);
			serverSocket.setSoTimeout(30 * 1000);

			InetSocketAddress endpoint = new InetSocketAddress(hostaddr, LISTEN_PORT);
			serverSocket.bind(endpoint, 32);
		}
		catch (IOException ex) {
			requestThreadPool.shutdown();
			sb.getLogger().fatal("セキュアガードの起動に失敗しました。アプリケーションを終了します。", ex);
			System.exit(-1);
		}
	}

	/**
	 * dispose
	 */
	public void dispose() {
		this.shutdown = true;
		this.interrupt();

		requestThreadPool.shutdownNow();
		workThreadPool.shutdownNow();

		try {
			Socket clientSocket = new Socket("127.0.0.1", LISTEN_PORT);
			clientSocket.close();
		}
		catch (Exception ex) {
		}
	}

	/**
	 * run
	 */
	public void run() {
		int tcpbufsz = 0;
		int timeout = 0;

		sb.getLogger().debug("Secure guard port: " + LISTEN_PORT);
		sb.getLogger().debug("Secure guard svn host: " + propmgr.getSVNHost());
		sb.getLogger().debug("Secure guard svn port: " + propmgr.getSVNPort());

		try {
			tcpbufsz = serverSocket.getReceiveBufferSize();
			sb.getLogger().debug("Secure guard buffer size: " + tcpbufsz + "(byte)");
		}
		catch (SocketException ex) {
		}

		timeout = propmgr.getConnectionTimeout();

		sb.getLogger().debug("Secure guard thread pool(min): " + THREAD_INITIALCOUNT);
		sb.getLogger().debug("Secure gurad thread pool(max): " + THREAD_MAXCOUNT);

		sb.getLogger().debug("Secure guard started.");

		while (!shutdown) {
			try {
				Socket socket = serverSocket.accept();
				sb.getLogger().debug("Connection accepted from SVNAdapter...");
				requestThreadPool.execute(new WorkerThread(socket, propmgr.getSVNHost(), propmgr.getSVNPort(), workThreadPool,
				  tcpbufsz, timeout));
			}
			catch (Exception ex) {
				continue;
			}
		}
		sb.getLogger().debug("セキュアガードが終了しました。");
	}
}
