using System;
using System.Collections;
using System.ComponentModel;
using System.Diagnostics;
using System.Net;
using System.Net.Sockets;
using System.Threading;

namespace ChatServer
{
	/// <summary>
	/// Summary description for Form1.
	/// </summary>
	public class ChatServer
	{
		/// <summary>
		/// Required designer variable.
		/// </summary>
		private int listenport = 5555;
		private TcpListener listener;
		private ArrayList clients;
		private Thread processor;
		private Socket clientsocket;
		private Thread clientservice;
		private EventLog myLog;
		private PerformanceCounter myCounter;


		public ChatServer()
		{
			listener = new TcpListener(listenport);
			myLog = new EventLog();
			myCounter=new PerformanceCounter("Chat Service Counters","UsersOnline",false);
			myCounter.RawValue=0;
			myLog.Source = "ChatService";
			clients = new ArrayList();
		}

		

		public void Start()
		{
			clients.Clear();
			processor = new Thread(new ThreadStart(StartListening));
			processor.Start();
			
		}

		public void Stop()
		{
			try
			{
				for(int n=0; n<clients.Count; n++)
				{
					Client cl = (Client)clients[n];
					SendToClient(cl, "QUIT|");
					cl.Sock.Close();
					cl.CLThread.Abort();
				}
				listener.Stop();
				if(processor != null)
					processor.Abort();
				clients.Clear();
			}
			catch (ThreadAbortException ex)
			{
				//如果是因为调用Abort引发的ThreadAbortException例外
				//则不处理
			}
			catch(Exception ex)
			{
				myLog.WriteEntry(ex.ToString(),EventLogEntryType.Error);
			}			
		}

		public void Suspend()
		{
			processor.Suspend();
		}

		public void Resume()
		{
			processor.Resume();
		}
	
		private void StartListening()
		{
			try
			{
				listener.Start();
				while (true) 
				{					
					Socket s = listener.AcceptSocket();
					clientsocket = s;
					clientservice = new Thread(new ThreadStart(ServiceClient));
					clientservice.Start();
				}
			}
			catch (ThreadAbortException ex)
			{
				//如果是因为调用Abort引发的ThreadAbortException例外
				//则不处理
			}
			catch(Exception ex)
			{
				myLog.WriteEntry(ex.ToString(),EventLogEntryType.Error);
			}
			
		}

		private void ServiceClient()
		{
			Socket client = clientsocket;
			bool keepalive = true;

			while (keepalive)
			{
				Byte[] buffer = new Byte[1024];
				client.Receive(buffer);
				string clientcommand = System.Text.Encoding.ASCII.GetString(buffer);

				string[] tokens = clientcommand.Split(new Char[]{'|'});
				Console.WriteLine(clientcommand);

				if (tokens[0] == "CONN")
				{
					for(int n=0; n<clients.Count; n++) {
						Client cl = (Client)clients[n];
						SendToClient(cl, "JOIN|" + tokens[1]);
					}
					EndPoint ep = client.RemoteEndPoint;
					Client c = new Client(tokens[1], ep, clientservice, client);
					clients.Add(c);
					string message = "LIST|" + GetChatterList() +"\r\n";
					SendToClient(c, message);
					myCounter.Increment();
				}
				if (tokens[0] == "CHAT")
				{
					for(int n=0; n<clients.Count; n++)
					{
						Client cl = (Client)clients[n];
						SendToClient(cl, clientcommand);
					}
				}
				if (tokens[0] == "PRIV") {
					string destclient = tokens[3];
					for(int n=0; n<clients.Count; n++) {
						Client cl = (Client)clients[n];
						if(cl.Name.CompareTo(tokens[3]) == 0)
							SendToClient(cl, clientcommand);
						if(cl.Name.CompareTo(tokens[1]) == 0)
							SendToClient(cl, clientcommand);
					}
				}
				if (tokens[0] == "GONE")
				{
					int remove = 0;
					bool found = false;
					int c = clients.Count;
					for(int n=0; n<c; n++)
					{
						Client cl = (Client)clients[n];
						SendToClient(cl, clientcommand);
						if(cl.Name.CompareTo(tokens[1]) == 0)
						{
							remove = n;
							found = true;
						}
					}
					if(found)
						clients.RemoveAt(remove);
					client.Close();
					keepalive = false;
					myCounter.Decrement();
				}
			} 
		}

		private void SendToClient(Client cl, string message)
		{
			try{
				byte[] buffer = System.Text.Encoding.ASCII.GetBytes(message.ToCharArray());
				cl.Sock.Send(buffer,buffer.Length,0);
			}
			catch(Exception ex){
				clients.Remove(cl);
				cl.Sock.Close();
				cl.CLThread.Abort();
				myCounter.Decrement();
			}
		}

		private string GetChatterList()
		{
			string chatters = "";
			for(int n=0; n<clients.Count; n++)
			{
				Client cl = (Client)clients[n];
				chatters += cl.Name;
				chatters += "|";
			}
			chatters.Trim(new char[]{'|'});
			return chatters;
		}
	}
}
