using System;
using System.Net;
using System.Net.Sockets;
using System.Timers;
using System.Threading;
using System.Text;
using System.Collections;

namespace GameServer
{
    class cServer
    {
       
        public Hashtable hTable = new Hashtable();
        private Socket ServerSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
        private Socket ClientSocket;
        private System.Timers.Timer aTimer = new System.Timers.Timer();
        private int tID = 0;

        public void StartServer()
        {
            try
            {
                ServerSocket.Bind(new IPEndPoint(IPAddress.Parse("0.0.0.0"), Program.ConfigClass.Server_Port));
                ServerSocket.Listen(0);
                new cLog(C.MSG_SUCCESS, "GameServer started");
            }
            catch
            {
                new cLog(C.MSG_ERROR, "Starting Server on Port: " + Program.ConfigClass.Server_Port + " failed");
                Console.Read();
            }

            setTimer();
            Thread AcceptThread = new Thread(new ThreadStart(AcceptConnections));
            AcceptThread.Start();
            new cLog(C.MSG_INFO, "Waiting for Connections...");
        }

        private void AcceptConnections()
        {
            while (true)
            {
                ClientSocket = ServerSocket.Accept();
                Thread RecvThread = new Thread(new ThreadStart(RecvData));
                RecvThread.Start();
                Thread.Sleep(10);
            }
        }

        private void RecvData()
        {
            Socket cSocket = ClientSocket;
            byte[] RecvBytes = new Byte[1024];
            byte[] RecvPacket;
            Int32 RecvBytesLen = 0;

            tID++;
            Program.ConfigClass.CurrentPlayer++;
            cWRClient WRClient = new cWRClient(cSocket, tID);
            Program.WRServer.AddClient(WRClient);

            while (true)
            {
                try
                {
                    RecvBytesLen = cSocket.Receive(RecvBytes);

                    if (cSocket.Connected == true && RecvBytesLen > 0)
                    {
                        RecvPacket = new Byte[RecvBytesLen];
                        Array.Copy(RecvBytes, RecvPacket, RecvBytesLen);
                        WRClient.pHandler.Handle(Encoding.Default.GetString(RecvPacket), WRClient);



                        if (DateTime.Now.Second != WRClient.Second)
                        {
                            WRClient.Second = DateTime.Now.Second;
                            WRClient.Send(new SP_SpawnCount(WRClient));
                        }
                        
                    }
                }
                catch
                {
                    
                    WRClient.tTimer.Stop();
                    Program.WRServer.RemoveClient(WRClient);
                    Program.SQLClass.runSQL("UPDATE ACCOUNT_TBL SET online = '0' WHERE userID = '" + WRClient.getUserID().ToString() + "'");
                    Program.ConfigClass.CurrentPlayer--;
                    
                    WRClient = null;
                    break;
                }
            }
        }

        private void setTimer()
        {
            aTimer.Interval = 30000;
            aTimer.Elapsed += new System.Timers.ElapsedEventHandler(RefreshISC);
            aTimer.Start();
        }

        private void RefreshISC(Object myObject, EventArgs myEventArgs)
        {
            int oldV = Program.ConfigClass.CurrentPlayer;
            if (oldV != Program.ConfigClass.CurrentPlayer)
            { 
                Program.ISC.Client.Send(new SP_ISC_PLAYERUPDATE());
            }
        }

        public void SetUpHandlers()
        {
            addFunc(2288,  new CP_ISC_LOGIN_PACKET());
            addFunc(24832, new CP_WELCOME_PACKET());
            addFunc(25088, new CP_CHARACTER_INFO());
            addFunc(28673, new CP_CHANGE_CHANNEL());
            addFunc(29696, new CP_CHAT());
            addFunc(25600, new CP_PREMIUM_LEFT()); //Unknown Received Packet
            addFunc(28960, new CP_USER_LIST());
            addFunc(29970, new CP_CHANGE_WEAPON());
            addFunc(29440, new CP_CREATE_ROOM());
            addFunc(29504, new CP_LEAVE_ROOM());
            addFunc(29184, new CP_ROOM_LIST());
            addFunc(29456, new CP_JOIN_ROOM());
            addFunc(30000, new CP_CHANGE_ROOM_DATA());
            addFunc(29520, new CP_INVITE());
            addFunc(29505, new CP_ROOM_KICK());
            addFunc(30208, new CP_BUY_WEAPON());//habs schon mal rein gemacht :D
            addFunc(30032, new CP_UNKNOW());
        }

        private void addFunc(int OPC, object Function)
        {
            if (hTable.ContainsKey(OPC) == false)
            {
                hTable.Add(OPC, Function);
            }
            else
            {
                new cLog(C.MSG_ERROR, "Operation Code: " + OPC + " has already an Function!");
            }
        }
    }
}
