package jp.hasc.hupserver;

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.SocketException;
import java.util.HashMap;

/*
 * HUPServer
 *   HASC Udp Proxy Server
 *   Get UDP Access from client.
 * 　　　最初からサーバの一覧を持つこととして、
 *   　　クライアント・サーバの接続アドレスは固定とする。
 *   
 */

public class HUPServer implements Runnable{
	static final int ServerPort = 9999;
	static final int BufSize = 1024;
	static HUPReporter logger = new SimpleReporter();
	
	DatagramSocket serverSoc_;
	byte[] buf_;
	boolean loopFlag_;
	HashMap<InetAddrAndPort,HUPWorker> workers = new HashMap<InetAddrAndPort,HUPWorker>();
	
	HUPServer(){
		buf_ = new byte[BufSize];		
		loopFlag_ = true;
	}
	
	public void startServer(){
		try {
			serverSoc_ = new DatagramSocket(ServerPort);
			logger.logln("Binding Socket on port:"+ServerPort);
		} catch (SocketException e) {
			logger.logln("Can't open UDP socket on port "+ServerPort);
			e.printStackTrace();
			System.exit(1);
		}
	}
	public void stopServer(){
		loopFlag_ = false;
		
	}
	
	
	@Override
	public void run() {
		InetAddress cAddr;
		int cPort;
		this.startServer();
		DatagramPacket rcvPacket = new DatagramPacket(buf_, BufSize);
		DatagramPacket sndPacket;
		logger.logln("Waiting connection.."+serverSoc_.getLocalAddress()+":"+serverSoc_.getLocalPort());
		while(loopFlag_){
			
			try {
				serverSoc_.receive(rcvPacket);
	            cAddr = rcvPacket.getAddress();
	            cPort = rcvPacket.getPort();
	            InetAddrAndPort iaap = new InetAddrAndPort(cAddr,cPort);
	            HUPWorker hup = workers.get(iaap);
	            if(hup == null){
	            	hup = new HUPWorker(iaap,this);
	            	if( hup.workerThread_ != null){
	            		hup.workerThread_.start();
	            		workers.put(iaap,hup);
	            	}	            
	            }else{// ? すでにあったら？無視？
	            	
	            }
            	int sPort = hup.sPort_;
            	if(sPort > 0){// ちゃんとできたなら            
            		String str = "#PortInfo "+sPort+"\n";
            		byte[] bts = str.getBytes();
            		sndPacket = new DatagramPacket(bts,bts.length);
            		sndPacket.setAddress(cAddr);
            		sndPacket.setPort(cPort);
//            		serverSoc_.send(sndPacket);
            		this.sendPacket(sndPacket);
            	}
			} catch (IOException e) {
				e.printStackTrace();
			}
		}		
	}
	public void sendPacket(DatagramPacket dp){
		try {
//			logger.logln("send packet "+dp.getLength() + "bytes to "+ dp.getAddress()+":"+dp.getPort());

			serverSoc_.send(dp);
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
	
	/**
	 * main
	 */
	public static void main(String[] args) {
		HUPServer hsv = new HUPServer();
		HUPWorker.logger = HUPServer.logger;
		new Thread(hsv).start();
	}


}
