/*
 * GNU.FREE 2002
 *
 * Copyright (c) 1999, 2000, 2001, 2002
 * The Free Software Foundation (www.fsf.org)
 *
 * GNU.FREE Co-ordinator: Jason Kitcat <jeep@free-project.org>
 *
 * GNU site: http://www.gnu.org/software/free/
 * 
 * FREE e-democracy site: http://www.free-project.org
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with this program (COPYING); if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 *
 */
 
package ERServer;
 
import java.net.*;
import java.io.*;
import java.util.*;

import Free.util.*;

/**
 * The TCPServer Class opens a socket to listen for client connections
 * which, when received, are spun out into new threads to keep the listening
 * socket free to accept new clients.
 *
 * The class is based on original code from "Java Threads" from O'Reilly.
 *
 * @version 0.9  12 June 2001
 * @author Jason Kitcat
 */
public class TCPServer implements Cloneable, Runnable {

	Thread runner = null;
	ServerSocket server = null;
	Socket data = null;
	boolean shouldStop = false;
	
	/**
	 * startServer creates and runs a new thread for a session
	 *
	 * @param port	A number indicating the port being used for the session
	 */
	protected synchronized void startServer(int port) throws IOException {
	
		if (runner == null) {
			server = new ServerSocket(port);
			runner = new Thread(this);
			runner.start();
		}
	}
	
	
	/**
	 * stopServer does just that!
	 */
	protected synchronized void stopServer() {
	
		if (server != null) {
			shouldStop = true;
			runner.interrupt();
			runner = null;
			try {
				server.close();
			} catch (IOException ioe) {
				ERServer.NORM.error("IO Error closing server connection");
			}
			server = null;
		}
	}
	
	/**
	 * run listens and accepts new connections, spinning them off into new threads
	 *
	 * if we're already listening to a data socket, process the data with overloaded run
	 */
	public void run() {

		if (server != null) {
			while (!shouldStop) {
				try {
					Socket datasocket = server.accept();
					TCPServer newSocket = (TCPServer) clone();
					
					newSocket.server = null;
					newSocket.data = datasocket;
					newSocket.runner = new Thread(newSocket);
					newSocket.runner.start();
				} catch (Exception e) {
					ERServer.NORM.error("Error opening server connection.");
				}
			}
		} else {
			run(data);
		}
	}
	
	/**
	 * run this time the overloaded one deals with the data as we're on a data socket
	 *
	 * @param data	Data being sent by the client
	 */
	protected void run(Socket data) {
	
		try {

			BufferedReader in = new BufferedReader(new InputStreamReader(data.getInputStream()));
			PrintWriter out = new PrintWriter(new BufferedWriter(new OutputStreamWriter(data.getOutputStream())), true);
			
			String inputData, outputData;
			
			while (true) {
			
				if (in.ready()) {  // if there's data 
				
					inputData = in.readLine();
					
					if (!inputData.equals("")) { // check real data has arrived
					
						/* decrypt data */
						String[] tempiData = new String[] {"",""};
						tempiData = RSAEncrypt.splitnDecrypt(ERServer.er_private_key,inputData);
						inputData = tempiData[1];

						if(ERServer.DEV.isDebugEnabled()) {
							ERServer.DEV.debug("Received: " + inputData + " from " + data.toString());
						}
						/* now process data */
						outputData = ERServerProtocol.process(inputData, tempiData[0]);
						if ((outputData.equals("DONE"))|(outputData.equals("ERROR"))) {
						
							break;
							
						} else {
						
							out.println(outputData);
							
						}
						
					}
					
				}
			
			}
						
			ERServer.NORM.info("Closing connection");
			//tidy up
			out.close();
			in.close();
			data.close();

		} catch (Exception e) {
			ERServer.NORM.error("Error with connection: " + e.getMessage());
		}
		
	} //EOF run
	
} //EOF TCPServer
