using System;
using System.Net.Sockets;
using XYNetSocketLib;
using System.Xml;
using System.Collections;
using System.IO;

namespace vclass.network.server
{
	/// <summary>
	/// This class is used on server-side. It accepts clients and manages the interaction of clients.
	/// </summary>
	/// 
	/// Author: yavuz
	/// created: 18/03/05
	/// last update: 
	
	public class ClassServer
	{
		private XYNetSocketLib.XYNetServer vcServer = null;
		private int serverPort;
		private int minThreads;
		private int maxThreads;
		private ArrayList clients = new ArrayList();

		public ClassServer()
		{
			//The server runs on port 3232.
			//minimum # of threads is 1
			//maximum # of threads is 10
			
			//TODO: These will be read from the configuration file
			//Configuration will be handled with the System.Configuration class

			serverPort = 3232;
			minThreads = 1;
			maxThreads = 10;

			vcServer = new XYNetSocketLib.XYNetServer("", serverPort, minThreads, maxThreads);
			// set event handlers
			vcServer.SetConnectionFilter(
				new ConnectionFilterDelegate(this.ConnectionFilter));
			vcServer.SetExceptionHandler(
				new ExceptionHandlerDelegate(this.ExceptionHandler));
			vcServer.SetStringInputHandler(
				new StringInputHandlerDelegate(this.StringInputHandler));
			vcServer.SetBinaryInputHandler(new BinaryInputHandlerDelegate(this.BinaryInputHandler));
		}

		private void BinaryInputHandler(string sRemoteAddress,
			int nRemotePort, Byte[] sData){
			System.Console.Out.WriteLine("Server: " + sRemoteAddress + ":" +
				nRemotePort.ToString() + " " + sData.Length + " bytes received");
			FileStream fileStream = File.Create("C:/server-file.jpg");
			try
			{
				fileStream.Write(sData, 0, sData.Length);
				fileStream.Close();
				broadcastBinaryData(sData);
			}
			catch(Exception e){
				Console.WriteLine("Server exception st " + e.StackTrace + " msg " + e.Message + " src " + e.Source);
			}
		}

		public void start(){
			vcServer.StartServer();
		}

		public void stop(){
			vcServer.StopServer();
		}

		private void ExceptionHandler(Exception oBug)
		{
			//TODO: write these to an Exception File!

			System.Console.Out.WriteLine("Error at server: " + oBug.Message + " " + oBug.StackTrace);
		}
		private void ConnectionFilter(string sRemoteAddress,
			int nRemotePort, Socket sock)
		{
			//TODO: write to log file!
			System.Console.Out.WriteLine("Accept " + sRemoteAddress + ":" +
				nRemotePort.ToString());
			//TODO: inform others about new connection...
			clients.Add(new ClientInfo(sRemoteAddress, nRemotePort, sock));
		}

		private void StringInputHandler(string sRemoteAddress,
			int nRemotePort, string sData)
		{
			//TODO: Write to log file!
			System.Console.Out.WriteLine("Server: " + sRemoteAddress + ":" +
				nRemotePort.ToString());
//			System.Console.Out.WriteLine("   " + sData);
			XmlDocument doc = new XmlDocument();
//			Console.WriteLine("Server got: " + sData);
			doc.LoadXml(sData);
			String action = doc.DocumentElement.LocalName;
			Console.WriteLine("Server action: " + action);
			if(action.Equals("authentication"))
			{
				//TODO: Check for password
				int accessRight = 1;
				String response = "<authenticationResponse>" + accessRight.ToString() + "</authenticationResponse>";
				vcServer.SendStringData(sRemoteAddress, nRemotePort, response);
			}
			else if(action.Equals("applicationSharing")){
				Console.WriteLine("server:sharing application...");
				broadcastString(sData);
			}
		}

		private void broadcastString(String broadcastString){
			int clientCount = vcServer.GetClientCount();
			
			for(int i = 0;i < clientCount;i++){
				ClientInfo c = (ClientInfo)clients[i];
								try
								{
									vcServer.SendStringData(c.getAddress(), c.getPort(), broadcastString);
								}
								catch(Exception exce){
									Console.WriteLine("broadcast error: " + exce.StackTrace);
								}
			}
		}

		private void broadcastBinaryData(byte[] broadcastData)
		{
			int clientCount = vcServer.GetClientCount();
			
			for(int i = 0;i < clientCount;i++)
			{
				ClientInfo c = (ClientInfo)clients[i];
				try
				{
					vcServer.SendBinaryData(c.getAddress(), c.getPort(), broadcastData);
				}
				catch(Exception excep)
				{
					Console.WriteLine("broadcast binary error: " + excep.StackTrace);
				}
			}
		}

		private void broadcastApplication(byte[] applicationData){
			int clientCount = vcServer.GetClientCount();
			Console.WriteLine(clientCount + " client(s) connected");
			for(int i = 0;i < clientCount;i++)
			{
				ClientInfo c = (ClientInfo)clients[i];
				Console.WriteLine("broadcasting " + c.getAddress() + " " + c.getPort());
/*				try
				{
					vcServer.SendBinaryData(c.getAddress(), c.getPort(), applicationData);
				}
				catch(Exception exce){
					Console.WriteLine("broadcast error: " + exce.StackTrace);
				}
*/			}
		}
	}
}
