using System;
using System.Collections.Generic;
using System.Security.Cryptography;
using System.Linq;
using System.Text;

namespace WIN_CLIENT_RPI
{
    class ClientFunctions
    {
        static List<TcpClientSifrovany> conections= new List<TcpClientSifrovany>();
        static bool connected = false;
        static bool loged = false;
        static int conection_ID = -1;


        private static bool Check_Connection()
        {

            if (conection_ID == -1)
                for (int i = 0; i < conections.Count; i++)
                {
                    if (conections[i].Secured)
                    {
                        conection_ID = i;
                        return true;
                    }
                }
            if (conection_ID == -1)
            {
                Connect();
                return false;
            }
            return true;
        }

        public static bool Connect()
        {
            foreach (TcpClientSifrovany tcp in conections)
                tcp.Cancel();
            conections.Clear();

            if (connected == false)
            {
                conections.Add(new TcpClientSifrovany());
                //TODO skus všetky servery až kým sa nenájde správny
                //string str = Properties.Settings.Default.IPs[1];

                conections[0].Conect_nonbloking("127.0.0.1", 4444);
                connected = true;
                //client_sifrovany.BeginRead(sluzba);
                //conections[0].Cancel();
            }
            return true;
        }
        public static bool Login( string meno, string heslo)
        {
            if (!Check_Connection())
                return false;

            Byte[] sprava = new Byte[128];
            MD5 md5Hash = MD5.Create();
            string hashheslo = GetMd5Hash(md5Hash, heslo);
            ASCIIEncoding.UTF8.GetBytes(hashheslo).CopyTo(sprava, 60);
            ASCIIEncoding.UTF8.GetBytes(meno).CopyTo(sprava, 10);
            ASCIIEncoding.UTF8.GetBytes("C_LOG_USER").CopyTo(sprava, 0);
            conections[conection_ID].Write(sprava, 0, 92);

            conections[conection_ID].Read(sprava);
            var reply = ASCIIEncoding.UTF8.GetString(sprava, 0, 10);
            var result = ASCIIEncoding.UTF8.GetString(sprava, 10, 5);
            if (result == "TRUE.")
            {
                loged = true;
                return true;
            }
            if (result == "FALSE")
            {
                loged = false;
                return false;
            }
            conection_ID = -1;
            //throw new Exception("neprisla odpoved"); 
            return false;
        }
        public static bool Register(string meno, string heslo, string mail)
        {
            if (!Check_Connection())
                return false;

            Byte[] sprava = new Byte[256];
            MD5 md5Hash = MD5.Create();
            string hashheslo = GetMd5Hash(md5Hash, heslo);
            ASCIIEncoding.UTF8.GetBytes(mail).CopyTo(sprava, 92);
            ASCIIEncoding.UTF8.GetBytes(hashheslo).CopyTo(sprava, 60);
            ASCIIEncoding.UTF8.GetBytes(meno).CopyTo(sprava, 10);
            ASCIIEncoding.UTF8.GetBytes("C_ADD_USER").CopyTo(sprava, 0);
            conections[conection_ID].Write(sprava, 0, 142);

            conections[conection_ID].Read(sprava);
            var reply = ASCIIEncoding.UTF8.GetString(sprava, 0, 10);
            var result = ASCIIEncoding.UTF8.GetString(sprava, 10, 5);
            if (result == "TRUE.")
            {
                loged = true;
                return true;
            }
            if (result == "FALSE")
            {
                loged = false;
                return false;
            }
            conection_ID = -1;
            //throw new Exception("neprisla odpoved"); 
            return false;
        }
        public static bool ADD_Devi(UInt16 typ, UInt64 ID, string heslo)
        {
            if (!Check_Connection())
                return false;

            Byte[] sprava = new Byte[256];
            MD5 md5Hash = MD5.Create();
            string hashheslo = GetMd5Hash(md5Hash, heslo);
            ASCIIEncoding.UTF8.GetBytes("C_ADD_DEVI").CopyTo(sprava, 0);
            BitConverter.GetBytes(typ).CopyTo(sprava, 10);
            BitConverter.GetBytes(ID).CopyTo(sprava, 12);
            ASCIIEncoding.UTF8.GetBytes(hashheslo).CopyTo(sprava, 20);
            conections[conection_ID].Write(sprava, 0, 256);

            conections[conection_ID].Read(sprava);
            var reply = ASCIIEncoding.UTF8.GetString(sprava, 0, 10);
            var result = ASCIIEncoding.UTF8.GetString(sprava, 10, 5);
            if (result == "TRUE.")
            {
                //loged = true;
                return true;
            }
            if (result == "FALSE")
            {
                //loged = false;
                return false;
            }
            conection_ID = -1;
            //throw new Exception("neprisla odpoved");
            return false;
        }
        public static bool REM_Devi(UInt64 ID)
        {
            if (!Check_Connection())
                return false;

            Byte[] sprava = new Byte[256];
            ASCIIEncoding.UTF8.GetBytes("C_REM_DEVI").CopyTo(sprava, 0);
            BitConverter.GetBytes(ID).CopyTo(sprava, 12);

            conections[conection_ID].Write(sprava, 0, 32);
            conections[conection_ID].Read(sprava);

            var reply = ASCIIEncoding.UTF8.GetString(sprava, 0, 10);
            var result = ASCIIEncoding.UTF8.GetString(sprava, 10, 5);
            if (result == "TRUE.")
            {
                //loged = true;
                return true;
            }
            if (result == "FALSE")
            {
                //loged = false;
                return false;
            }
            conection_ID = -1;
            //throw new Exception("neprisla odpoved");
            return false;
        }
        public static byte[] GET_Devi (out int count)
        {
            count = 0;

            if (!Check_Connection())
                return null;

            Byte[] sprava = new Byte[32];
            ASCIIEncoding.UTF8.GetBytes("C_SHW_DEVI").CopyTo(sprava, 0);
            if (!conections[conection_ID].Write(sprava, 0, 32))
            {
                connected = false;
                conection_ID = -1;
                Connect();
                return null;
                
            };

            if (conections[conection_ID].Read(sprava)==-1)
            {
                connected = false;
            };
            count = BitConverter.ToUInt16(sprava, 0);
            if (count == 0)
                return null;

            byte[] vystup = new Byte[10 * count];
            if (count > 3)
            {
                Array.Copy(sprava, 2, vystup, 0, 30);
                int Size_of_array = (((count - 3) * 10 - 1) / 32 + 1) * 32;
                Byte[] pole = new Byte[Size_of_array];
                conections[conection_ID].Read(pole, Size_of_array);

                Array.Copy(pole, 0, vystup, 30, (count-3)*10);
            }
            else
                Array.Copy(sprava, 2, vystup, 0, count * 10);
            return vystup;         
        }
        public static string GET_Pass(UInt64 ID_DEVI)
        {
            if (!Check_Connection())
                return null;

            Byte[] sprava = new Byte[32];
            ASCIIEncoding.UTF8.GetBytes("C_GET_PASS").CopyTo(sprava, 0);
            BitConverter.GetBytes(ID_DEVI).CopyTo(sprava, 10);
            if (!conections[conection_ID].Write(sprava, 0, 32))
            {
                connected = false;
                conection_ID = -1;
                Connect();
                return null;

            };
            if (conections[conection_ID].Read(sprava) == -1)
            {
                connected = false;
            };
            return ASCIIEncoding.UTF8.GetString(sprava, 0, 32); ;
        }


        public static bool GET_Connected_to_RPi(UInt64 ID_DEVI,out string VID_PID_A,out string VID_PID_B)
        {
            VID_PID_A = null;
            VID_PID_B = null;

            if (!Check_Connection())
                return false;


            Byte[] sprava = new Byte[32];
            ASCIIEncoding.UTF8.GetBytes("C_R_PI_INF").CopyTo(sprava, 0);
            BitConverter.GetBytes(ID_DEVI).CopyTo(sprava, 10);
            if (!conections[conection_ID].Write(sprava, 0, 32))
            {
                connected = false;
                conection_ID = -1;
                Connect();
                return false;

            }
            System.Threading.Thread.Sleep(100);
            if (conections[conection_ID].Read(sprava) == -1)
            {
                connected = false;
            }
            string odpoved = ASCIIEncoding.UTF8.GetString(sprava, 10, 2);
       
            if (odpoved == "OK")
            {
                //TODO dorobiť desifrovanie dat (vidpid)
                VID_PID_A = ASCIIEncoding.UTF8.GetString(sprava, 13, 9);
                VID_PID_B = ASCIIEncoding.UTF8.GetString(sprava, 22, 9);
                return true;
            }
            return false; 
        }

        public static System.Net.IPAddress Connect_Server_Forvarding(UInt64 ID_DEVI)
        {
            if (!Check_Connection())
                return null;

            Byte[] sprava = new Byte[32];
            ASCIIEncoding.UTF8.GetBytes("C_CON_R_PI").CopyTo(sprava, 0);
            BitConverter.GetBytes(ID_DEVI).CopyTo(sprava, 10);
            if (!conections[conection_ID].Write(sprava, 0, 32))
            {
                connected = false;
                conection_ID = -1;
                Connect();
                return null;

            };
            if (conections[conection_ID].Read(sprava) == -1)
            {
                connected = false;
            };
            string odpoved = ASCIIEncoding.UTF8.GetString(sprava,10,2);
            if (odpoved=="OK")
            {
                return new System.Net.IPAddress(sprava.Skip(12).Take(4).ToArray()); 
            }
                return  null; 
        }

        static void sluzba(object o, EventArgs e)
        {
            TcpClientSifrovany.Receive rcv = (TcpClientSifrovany.Receive)o;
            string sprava = ASCIIEncoding.UTF8.GetString(rcv.mesage, 0, rcv.mesage_lenght);
            Console.WriteLine(sprava);
        }

        public static string GetMd5Hash(MD5 md5Hash, string input)
        {

            // Convert the input string to a byte array and compute the hash. 
            byte[] data = md5Hash.ComputeHash(Encoding.UTF8.GetBytes(input));

            // Create a new Stringbuilder to collect the bytes 
            // and create a string.
            StringBuilder sBuilder = new StringBuilder();

            // Loop through each byte of the hashed data  
            // and format each one as a hexadecimal string. 
            for (int i = 0; i < data.Length; i++)
            {
                sBuilder.Append(data[i].ToString("x2"));
            }

            // Return the hexadecimal string. 
            return sBuilder.ToString();
        }




    }
}
