using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;

using System.Text;
using System.Windows.Forms;

using System.Linq;

using System.Threading;
using System.Net.Sockets;
using System.Net;

namespace NetworkDiscovery
{
    public partial class Form_IpConfig : Form
    {
        bool dhcp = true;

        internal bool isChanged = false;

        protected Socket s = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
        public const int UDP_TX_PORT = 49049;   // порт передачи сообщений
        public const int UDP_RX_PORT = 49049;   // порт приема сообщений 
        protected UdpClient listener;
        public static List<IPAddress> MyIpList;
        protected const int delayTime = 500;
        private const int timeout = 5000;
        private List<String> messages = new List<String>();

        public string DeviceIP { get; private set; }
        public string SerialNo { get; private set; }

        public Form_IpConfig(string deviceIP, string serNo)
        {
            InitializeComponent();

            DeviceIP = deviceIP;
            SerialNo = serNo;

            textBox1.Text = DeviceIP;

            checkBox1.Checked = true;

            Thread ask = new Thread(this.StartListener);
            ask.Start();
            
        }

        //Кнопка "Применить"
        private void apply_button_click(object sender, EventArgs e)
        {
            if (!textBox1.ForeColor.Equals(Color.Green) || !textBox2.ForeColor.Equals(Color.Green) || !textBox3.ForeColor.Equals(Color.Green))
            {
                MessageBox.Show("Проверьте правильность настроек", "Неправильный формат данных",
                       MessageBoxButtons.OK, MessageBoxIcon.Error); return;
            }

            SendBroadcast("{" + "\"serno\":" + '"' + SerialNo + '"' + "," + "\"dhcp\":" + '"' + dhcp + '"' + "," + "\"ipaddress\":" + '"' + textBox1.Text + '"' + "," + "\"gateway\":" + '"' + textBox2.Text + '"' + ","
    + "\"mask\"" + ":" + '"' + textBox3.Text + '"' + "}");
            messages.Clear();

            isChanged = true;

            base.Close();

        }


        private void Button_Reset_Click(object sender, EventArgs e)
        {
            checkBox1.Checked = true;
            textBox1.Text = "192.168.1.2";
            textBox2.Text = "192.168.1.1";
            textBox3.Text = "255.255.255.0";
            dhcp = true;
        }


        protected void SendBroadcast(String message)
        {
            /*UdpClient client = new UdpClient();
            IPEndPoint ip = new IPEndPoint(IPAddress.Broadcast, UDP_TX_PORT);
            Byte[] bytes = Encoding.ASCII.GetBytes(message);
            try
            {
                client.Send(bytes, bytes.Length, ip);
            }
            catch (ThreadAbortException e)
            {
                MessageBox.Show("Ничего серьезного, попробуйте еще раз, но сли вы увидели данное сообщение то расскажите о нем разработчику", "Debug",
                    MessageBoxButtons.OK, MessageBoxIcon.Error);

            }
            catch (Exception e)
            {
                //MessageBox.Show("Проблемы с отправкой на порт: " + UDP_TX_PORT, "Порт отправки занят",
                //    MessageBoxButtons.OK, MessageBoxIcon.Error);
                MessageBox.Show("Порт занят, попробуйте еще раз", "Порт отправки занят",
                    MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
            finally
            {
                client.Close();
            }*/

            try
            {
                byte[] sendbuf = Encoding.ASCII.GetBytes(message);
                Socket s = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
                s.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.Broadcast, 1);
                IPEndPoint ep = new IPEndPoint(IPAddress.Broadcast, 49049);
                s.Connect(ep);
                s.SendTo(sendbuf, ep);
                s.Close();
/*                s.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.Broadcast, 1);
                s.EnableBroadcast = true;

                IPAddress broadcast = IPAddress.Broadcast;

                byte[] sendbuf = Encoding.ASCII.GetBytes(message);
                IPEndPoint ep = new IPEndPoint(broadcast, 49049);

                s.Bind(ep);

                s.Connect(ep);

                s.Send(sendbuf);*/
            }
            catch (Exception ex) { MessageBox.Show(ex.Message); }
        }

        private string GetBroadcastIP(string deviceIP)
        {
            string broad = String.Empty;
            string[] arr = deviceIP.Split('.');
            arr[0] = "255";
            arr[1] = "255";
            arr[2] = "255";
            arr[3] = "255";
            arr.ToList().ForEach(a => broad += a + '.');
            return broad.Remove(broad.Length - 1);
        }

        private void Sender()
        {
            try
            {
                while (true)
                {
                    string str = "{" + "\"serno\":" + '"' + SerialNo + '"' + "," + "\"dhcp\":" + '"' /*+ dhcp*/ + '"' + "," + "\"ipaddress\":" + '"' + '"' + "," + "\"gateway\":" + '"' + '"' + "," + "\"mask\"" + ":" + '"' + '"' + "}";
                    SendBroadcast(str);
                    Thread.Sleep(delayTime);
                }
            }
            catch (ThreadAbortException e)
            {
                Thread.ResetAbort();
                return;
            }
        }

        public static bool CheckPortFree(int nPortNum)
        {
            bool bCheckResult = true;
            Socket s = null;

            try
            {
                s = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
                s.Bind(new IPEndPoint(IPAddress.Loopback, nPortNum));

            }


            catch (Exception e)
            {
                MessageBox.Show("Порт занят сторонним приложением", "Порт Занят",
                    MessageBoxButtons.OK, MessageBoxIcon.Error);
                bCheckResult = false;


            }
            finally
            {
                s.Close();
            }


            return bCheckResult;
        }

        protected static List<IPAddress> GetMyIpList()
        {
            List<IPAddress> MyIpList = new List<IPAddress>();
            String strHostName = Dns.GetHostName();
            IPHostEntry iphostentry = Dns.GetHostEntry(strHostName);
            foreach (IPAddress ipaddress in iphostentry.AddressList)
            {
                MyIpList.Add(ipaddress);
            }
            return MyIpList;
        }

        private void StartListener()
        {
            Thread.Sleep(500);
            Thread sender = new Thread(this.Sender);
            sender.Start();
            try
            {
                if (CheckPortFree(UDP_RX_PORT))
                    listener = new UdpClient(UDP_RX_PORT);
                else return;
                IPEndPoint groupEP = new IPEndPoint(IPAddress.Any, UDP_RX_PORT);

                MyIpList = GetMyIpList();

                DateTime startTime = DateTime.Now;


                while (true)
                {


                    if (listener.Available > 0)
                    {
                        byte[] bytes = listener.Receive(ref groupEP);

                        if ((!MyIpList.Contains(groupEP.Address))
                            && (Encoding.UTF8.GetString(bytes, 0, bytes.Length).StartsWith("{" + "\"serno\":" + '"' + SerialNo + '"')))
                        {
                            messages.Add(Encoding.UTF8.GetString(bytes, 0, bytes.Length));
                            Invoke((Action)(() => SetParams()));
                            break;
                        }
                    }

                    if (DateTime.Now.Subtract(startTime) >= new TimeSpan(0, 0, 0, 0, timeout))// функция выполняется в течении трех секунд
                    {
                        MessageBox.Show("Сетевые параметры этого устройства не были получены, попробуйте еще раз", "Настройки не получены",
                         MessageBoxButtons.OK, MessageBoxIcon.Error);

                        break;
                    }
                }
            }
            catch (Exception e)
            {
                MessageBox.Show(e.Message + "\n In listener");
            }
            finally
            {
                sender.Abort();
                listener.Close();


            }
        }

        private void SetParams()
        {
            if (messages.Count > 0)
            {
                Dictionary<string, string> dict = new Dictionary<string, string>();
                try
                {
                    dict = GetDictFromJson(messages[0]);

                    checkBox1.Checked = dhcp = dict["dhcp"].ToLower().Equals("true") ? true : false;
                    textBox1.Text = dict["ipaddress"];
                    textBox2.Text = dict["gateway"];
                    textBox3.Text = dict["mask"];
                }
                catch
                {
                    MessageBox.Show("Ошибка при парсинге JSON"); 
                    return;
                }

                //string recievedMessage = String.Empty;
                //string str1 = //(string)recievedMessage["dhcp"];
                //if (String.Equals(str1, "True"))
                //{
                //    dhcp = true;
                //}
                //else
                //{
                //    dhcp = false;
                //}
                //checkBox1.Checked = dhcp;
                //textBox1.Text = (string)recievedMessage["ipaddress"];
                //textBox2.Text = (string)recievedMessage["gateway"];
                //textBox3.Text = (string)recievedMessage["mask"];

            }
        }

        private Dictionary<string, string> GetDictFromJson(string jsonText)
        {
            return jsonText
                .Replace('"', ' ')
                .Split(new char[] { ',', '{', '}' }, StringSplitOptions.RemoveEmptyEntries)
                .ToDictionary(
                    s => s.Split(':')[0].Trim().ToLower(),
                    s => s.Split(':')[1].Trim().ToLower());
        }

        private void checkBox1_CheckedChanged(object sender, EventArgs e)
        {
            if (checkBox1.Checked)
            {
                textBox1.ReadOnly = true;
                textBox2.ReadOnly = true;
                textBox3.ReadOnly = true;
                dhcp = true;
            }
            else
            {
                textBox1.ReadOnly = false;
                textBox2.ReadOnly = false;
                textBox3.ReadOnly = false;
                dhcp = false;
            }



        }

        void textBox_TextChanged_Verify(object sender, EventArgs e)
        {
            TextBox textBox = sender as TextBox;

            textBox.ForeColor = IsIpAddress(textBox.Text) ? Color.Green : Color.Red;
        }

        static bool IsIpAddress(string Address)
        {
            System.Text.RegularExpressions.Regex IpMatch =
                new System.Text.RegularExpressions.Regex(@"^(25[0-5]|2[0-4][0-9]|[0-1][0-9]{2}|[0-9]{2}|[0-9])(\.(25[0-5]|2[0-4][0-9]|[0-1][0-9]{2}|[0-9]{2}|[0-9])){3}$");

            return IpMatch.IsMatch(Address);
        }

    }
}
