/*
Netlib v2.0
Server
By Sam
*/
using System;
using System.Net;
using System.Net.Sockets;
using System.Text;

public class Netlib_v2_0
{
    public static void Main()
    {
        byte[] data = new byte[1024];
        IPEndPoint ipep = new IPEndPoint(IPAddress.Any, 3388);
        UdpClient newsock = new UdpClient(ipep);
        IPEndPoint sender = new IPEndPoint(IPAddress.Any, 0);

        int num_of_ids = 100;
        int num_of_amws = 1000;

        string[] id_names = new string[num_of_ids];
        string[] id_data = new string[num_of_ids];
        int id_num = 0;

        IPEndPoint[,] amw = new IPEndPoint[num_of_ids, num_of_amws];
        string[] amw_id = new string[num_of_ids];
        int[] amw_ips = new int[num_of_ids];
        int amw_num = 0;
        string MainString;
        string mode;
        string id;
        string text;
        int toSearchInt = 0;
        int toSearchFound = 0;
        int toSearchFound2 = 0;
        int toSearchFound3 = 0;
        int toSearchFound4 = 0;
        string toSend;

        Console.WriteLine("Netlib v2.0 Ready.");



        while (true)
        {
        begining: //had to use labels, while loops were complicated and
            //local variables mode,id,text did not exist (?)
            try
            {
                data = newsock.Receive(ref sender);
            }
            catch (Exception ex)
            {
                //An exception has happened!
                //Now, after this happens to
                //one IP and port, it will
                //CONTINUE to error, but will
                //still work...
                ////System.Console.WriteLine(ex.ToString());
                ex = null;
                goto begining;
            }
            ////System.Console.WriteLine("From "+sender.ToString());
            MainString = Encoding.ASCII.GetString(data, 0, data.Length);
            if (MainString.Length < 4)
            {
                //System.Console.WriteLine("error:length");
                goto begining;
            }
            int check1 = MainString.IndexOf(":");
            if (check1 != 1)
            {
                //System.Console.WriteLine("error: first colon");
                goto begining;
            }
            mode = MainString.Substring(0, 1);
            MainString = MainString.Remove(0, 2);
            int check2 = MainString.IndexOf(":");
            if (check2 == -1)
            {
                //System.Console.WriteLine("error: second colon");
                goto begining;
            }
            id = MainString.Substring(0, check2);
            if (id == "")
            {
                //System.Console.WriteLine("error:id");
                goto begining;
            }
            MainString = MainString.Remove(0, check2 + 1);
            text = MainString;
            //mode, id, and text are now available
            if (mode == "w" || mode == "a") //write id
            {
                toSearchInt = 0;
                toSearchFound = 0;
                foreach (string num in id_names)
                {
                    if (num == null)
                        break;
                    if (num == id)
                    {
                        if (mode == "w")
                        {
                            id_data[toSearchInt] = text;
                        }
                        if (mode == "a")
                        {
                            id_data[toSearchInt] = id_data[toSearchInt] + text;
                        }
                        //System.Console.WriteLine("ID: " + id + " modified with mode: " + mode);
                        toSearchFound = 1;
                        break;
                    }
                    toSearchInt++;

                }
                if (toSearchFound == 0) //id was not found
                {
                    id_data[id_num] = text;
                    id_names[id_num] = id;
                    id_num++;
                    //System.Console.WriteLine("ID: " + id + " added with mode: " + mode);
                }


                //-----
                //send all AMWs
                //-----

                toSearchInt = 0;
                foreach (string num in amw_id) //search amw_id[] for id given
                {
                    if (num == null)
                        break;
                    if (num == id) //if found
                    {
                        for (int a = 0; a <= num_of_amws - 1; a++) //search all IPs in AMW...
                        {
                            if (amw[toSearchInt, a] == null)
                            {
                                break;
                            }

                            if (amw[toSearchInt, a].ToString() != sender.ToString())
                            {
                                toSend = id + ":" + text;
                                data = Encoding.ASCII.GetBytes(toSend);
                                newsock.Send(data, data.Length, amw[toSearchInt, a]);
                                //System.Console.WriteLine("AMW: sent id " + id + " to " + amw[toSearchInt, a].ToString());
                            }
                        }
                        break;
                    }
                    toSearchInt++;
                }

                if (id_names[num_of_ids - 1] != null)
                {
                    Console.WriteLine("Reseting IDs...");
                    //Reset all data...
                    id_names = new string[num_of_ids];
                    id_data = new string[num_of_ids];
                    id_num = 0;

                    amw = new IPEndPoint[num_of_ids, 500];
                    amw_id = new string[num_of_ids];
                    amw_ips = new int[num_of_ids];
                    amw_num = 0;
                }


            }
            if (mode == "g") //get id
            {
                toSearchInt = 0;
                toSearchFound = 0;
                foreach (string num in id_names)
                {
                    if (num == null)
                        break;
                    if (num == id)
                    {
                        toSend = id_names[toSearchInt] + ":" + id_data[toSearchInt];
                        data = Encoding.ASCII.GetBytes(toSend);
                        newsock.Send(data, data.Length, sender);
                        //System.Console.WriteLine("ID: " + id + " sent with mode: " + mode);
                        toSearchFound = 1;
                        break;
                    }
                    toSearchInt++;

                }
                if (toSearchFound == 0) //id was not found
                {
                    /*
                    toSend = id + ":error_missing_id";
                    data = Encoding.ASCII.GetBytes(toSend);
                    newsock.Send(data, data.Length, sender);*/
                    //System.Console.WriteLine("ID: " + id + " requested; missing");
                }
            }
            if (mode == "r") //add AMW
            {
                toSearchInt = 0;
                toSearchFound = 0;
                toSearchFound2 = 0;
                toSearchFound3 = 0;
                toSearchFound4 = 0;
                foreach (string num in amw_id) //search amw_id[] for id given
                {
                    if (num == null)
                    {
                        toSearchFound4 = 1;
                        break;
                    }
                    if (num == id) //if found
                    {
                        for (int a = 0; a <= num_of_amws - 1; a++) //search to see if IP exists...
                        {
                            if (amw[toSearchInt, a] == null)
                            {
                                toSearchFound3 = 1;
                                break;
                            }
                            if (amw[toSearchInt, a].ToString() == sender.ToString())
                            {
                                toSearchFound2 = 1;
                                //System.Console.WriteLine("AMW already exists with id " + id + " for sender " + sender.ToString());
                                break;
                            }
                        }
                        if (toSearchFound2 == 0 && amw_ips[toSearchInt] == num_of_amws - 1) //need to add, but its full! So...erase
                        {
                            Console.WriteLine("Reseting IPs in AMW for id " + id);
                            for (int a = 0; a <= num_of_amws - 1; a++)
                                amw[toSearchInt, a] = null;
                            amw_ips[toSearchInt] = 0;
                        }
                        if (toSearchFound2 == 0) //if sender not found, add IPEndPoint sender
                        {
                            amw[toSearchInt, amw_ips[toSearchInt]] = sender;
                            amw_ips[toSearchInt]++;
                            //System.Console.WriteLine("AMW ip added with id " + id + " for sender " + sender.ToString());
                            amw_num++;
                        }
                        toSearchFound = 1;
                        break;
                    }
                    toSearchInt++;

                }
                if (toSearchFound == 0 && toSearchFound4 == 0) //AMWs are full, and need to add, clear all entrys
                {
                    Console.WriteLine("AMWs are full, reseting...");
                    amw = new IPEndPoint[num_of_ids, num_of_amws];
                    amw_id = new string[num_of_ids];
                    amw_ips = new int[num_of_ids];
                    amw_num = 0;
                }
                if (toSearchFound == 0) //if entry id isnt even there
                {
                    amw_id[amw_num] = id;
                    amw[amw_num, 0] = sender; //add entry
                    amw_ips[amw_num] = 1;
                    amw_num++;
                    //System.Console.WriteLine("AMW entry added for id " + id + " with sender " + sender.ToString());
                }
            }

            if (mode == "u") //delete AMW
            {
                toSearchInt = 0;
                toSearchFound = 0;
                toSearchFound2 = 0;
                foreach (string num in amw_id) //search amw_id[] for id given
                {
                    if (num == null)
                        break;
                    if (num == id) //if found
                    {
                        for (int a = 0; a <= num_of_amws - 1; a++) //search to see if IP exists...
                        {
                            if (amw[toSearchInt, a] == null)
                                break;
                            if (amw[toSearchInt, a].ToString() == sender.ToString()) //found IP!
                            {
                                toSearchFound2 = a;
                                for (int b = toSearchFound2; b <= num_of_amws - 2; b++) //re-sort all data
                                {
                                    amw[toSearchInt, b] = amw[toSearchInt, b + 1];
                                }
                                amw[toSearchInt, num_of_amws - 1] = null;
                                amw_ips[toSearchInt]--;
                                //System.Console.WriteLine("AMW: removed sender " + sender.ToString() + " from id " + id);
                                break;
                            }
                        }
                        break;
                    }
                    toSearchInt++;

                }
            }



            //Console.WriteLine(Encoding.ASCII.GetString(data, 0, data.Length));
            //newsock.Send(data, data.Length, sender);
        }
    }
}