using System;
using System.Net.Sockets;
using System.Net;
using System.Collections;
using System.IO;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary;
using System.Threading;

namespace vclass.chat.server
{
	public class ChatServer:ChatStream
	{
		//Define the number of users per room
		//Set to 2 for easy testing
		const int DEFAULT_NUM_PER_ROOM=50;

		//Port Number to listen 
		private int port_no;
		//Number of Chat rooms
		private int num_room;
		//number of participants per chat room
		private int num_per_room;

		//One and only connection listener
		private TcpListener listener;

		//Collections to manage users and connections
		private Hashtable connections;
		private Hashtable[] roomusers;
		

		//2 parameters Constructor
		public ChatServer(int port_no,int num_room)
		{
			this.port_no =port_no;
			this.num_room=num_room;

		    //init num per room used for room assignment
			num_per_room=DEFAULT_NUM_PER_ROOM;

			//instantiate the connection listener
			listener=new TcpListener(IPAddress.Any,this.port_no);

			//get all the registered users from file
			// DeserializeChatUsers("users.bin");

			//init all the rooms
			roomusers=new Hashtable[num_room];
			for(int i=0;i<num_room;i++)
				roomusers[i]=new Hashtable();
			Console.WriteLine("before break ");

			//init connections
			connections=new Hashtable();


			Thread t=new Thread(new ThreadStart(HandleConnection));
			t.Start();

		}

		public void HandleConnection()
		{
			Listener.Start();

			while(true)
			{
				Console.WriteLine("Waiting for connection...");
				//get the connected client
				TcpClient client=Listener.AcceptTcpClient();
				//create a new socket helper to manage the connection
				SocketHelper sh=new SocketHelper(this,client);

				Console.WriteLine("Connected");
			}
		}
	


		

		public int ProposedNumUsersPerRoom
		{
			get
			{
				return num_per_room;
			}
			set
			{
				num_per_room=value;
			}
		}

		public int NumRoom
		{
			get
			{
				return num_room;
			}

			set
			{
				NumRoom=value;
			}

		}

		public int PortNo
		{
			get
			{
				return port_no;
			}

			set
			{
				PortNo=value;
			}
		}

		public TcpListener Listener
		{
			get
			{
				return listener;
			}

			set
			{
				listener=value;
			}

		}


		public Hashtable ClientConnections
		{
			get
			{
				return connections;
			}

			set
			{
				connections=value;
			}
		}


		public Hashtable[] RoomUsers
		{
			get
			{
				return roomusers;
			}
			set
			{
				roomusers=value;
			}
		}

		public int AssignRoom(string name)
		{
			for(int i=0;i<NumRoom;i++)
				if(RoomUsers[i].Count <ProposedNumUsersPerRoom)
				{
					AddRoomUser(RoomUsers[i],name);
					return i+1;
				}

			AddRoomUser(RoomUsers[0],name);
			return 1;
		}

		public void AddConnection(string index,TcpClient c)
		{
			connections.Add(index,c);
		}

		public void RemoveConnection(string index,TcpClient c)
		{
			connections.Remove(index);
		}

		public void AddRoomUser(System.Collections.Hashtable room, string index)
		{
			room.Add(index,index);
		}

		public void RemoveRoomUser(System.Collections.Hashtable room, string index)
		{
			room.Remove(index);
		}

		public void Broadcast(string msg, int room)
		{
			foreach(string s in RoomUsers[room-1].Keys)
			{
				TcpClient t=(TcpClient)connections[s];
				Write(t.GetStream(),msg);
			}
		}

		public void Broadcast(string s)
		{
			for(int i=0;i<NumRoom;i++)
			{
				Broadcast(s,i+1);
			}
		}

		public int FindUserRoom(string index)
		{
			for(int i=0;i<NumRoom;i++)
			 foreach(string  s in RoomUsers[i].Keys)
				 if(s==index)
					 return (i+1);


			return 0;
		}

	}
}
