using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Text;
using System.Windows.Media;
using System.Threading.Tasks;
using System.Threading;

using System.Net;
using System.Net.Sockets;
using System.Net.NetworkInformation;



namespace VibrationExciterControl
{
    public class DevicesCollection
    {
        public string DeviceName { get; set; }
        public string DeviceIP { get; set; }
        public Brush color { get; set; }
    }

    
    class Comm
    {
        const string loginMsg = "GEconnect";
        const string statusMsg = "status";
        const string testDataNext = "GEtest next";
        const string testDataDone = "GEtest done";
        const string startTest = "GEstarttest";
        const string stopTest = "GEstoptest";
        const string startTestOk = "GEstarttest ok";
        const string startTestNok = "GEstarttest nok";
        const string takeControl = "GEopen";
        const string takeControlOk = "GEopen ok";
        const string takeControlNok = "GEopen nok";
        const int BROADCAST_PORT = 30303;
        const string BROADCAST_REQUEST = "Discovery: Who is out there?";

        public enum CONNECTION { CONNECTED, CHECKING_STATUS, CONTROLED_BY_3RD_SITE, NOT_CONNECTED, CONNECTION_LOST, ERROR };
        public enum TEST_TYPE
        {
            TEST_TYPE_NOTEST = 0,
            TEST_TYPE_STANDARD,
            TEST_TYPE_RESERVED,
            TEST_TYPE_SWEEP_TO_BACK,
            TEST_TYPE_HALF_SIN,
        };

        public struct STATE
        {
            public CONNECTION connection;
            public float inputVoltage;
            public int temperature;
            public bool voltge3V3Good;
            public bool voltage5VGood;
            public bool voltage12VGood;
            public bool generatorOn;
            public bool generatorReady;
            public bool overCurrent;
            public bool overHeat;
            public bool controlled;
            public bool searching;
            public bool searchCallback;
            public bool testMeasureData;
            public bool testComplete;
        };
        public ObservableCollection<DevicesCollection> devices;
        DevicesCollection devicesItem;

        // FIFO for sending messages
        volatile private ObservableCollection<Byte[]> messages;

        //callback to main windows
        public delegate void Del_Callback(STATE s);
        Del_Callback MWCallback;

        //current state
        public STATE state;
    
        
        Thread T_KeepConnection;
        Thread T_BroadcastSearch;
        Thread T_SendToServer;

        
        //waithandes are used to synchronize theads, timeouts and repeat periods
        private EventWaitHandle repeatRequest = new EventWaitHandle(false, EventResetMode.AutoReset);
        private EventWaitHandle repeatBroadcastSeacrh = new EventWaitHandle(false, EventResetMode.AutoReset);
        private EventWaitHandle sendToServerRoutine = new EventWaitHandle(false, EventResetMode.AutoReset);

        int sendToServerPeriod = -1;
        int repeatPeriod = -1;
        int repeatBroacastSearchPeriod = -1;


        UdpClient broadcastListen;
        UdpClient broadcastSend;

        UdpClient udpClient;

        UdpClient serverReceive;
        /// <summary>
        /// Initialize class
        /// </summary>
        /// <param name="MWCallback"> Delegate to callback function</param>
        public Comm(Del_Callback MWCallback )
        {
            this.MWCallback = MWCallback;
            devices = new ObservableCollection<DevicesCollection>();
            state.connection = CONNECTION.NOT_CONNECTED;
            state.inputVoltage = 0;
            state.voltge3V3Good = false;
            state.voltage5VGood = false;
            state.voltage12VGood = false;
            state.searching = false;

            T_KeepConnection = new Thread((ThreadStart)delegate { KeepConnection(); });
            T_KeepConnection.Name = "keep Connection up";
            T_KeepConnection.Start();

            T_BroadcastSearch = new Thread((ThreadStart)delegate { SendBroadcastTask(); });
            T_BroadcastSearch.Name = "Broadcast rearch";
            T_BroadcastSearch.Start();

            T_SendToServer = new Thread((ThreadStart)delegate { SendToServerRoutine(); });
            T_SendToServer.Name = "Send to serverRoutine";
            T_SendToServer.Start();

            //T_ReceiveFromServer = new Thread((ThreadStart)delegate { ReceiveFromServer1(); });
            //T_ReceiveFromServer.Name = "Receive from server";
            

            messages = new ObservableCollection<Byte[]>();
            //measuredData = new ObservableCollection<double[]>();
            
        }

        

        /// <summary>
        /// Connects to server, and cretes UDP server for incomming measure data
        /// </summary>
        /// <param name="ipstring"></param>
        /// <param name="port"></param>
        public void ConnectToServer(string ipstring, int port)
        {
            IPAddress ip;
            int localport;
            IPAddress.TryParse(ipstring, out ip);

            if (udpClient == null)
            {
                udpClient = new UdpClient();
                
                udpClient.Connect(ip, port);
                localport = ((IPEndPoint)udpClient.Client.LocalEndPoint).Port;

                //check if port (localPort is free to use), if not close connection and open new one with different localPort
                bool alreadyinuse = (from p in System.Net.NetworkInformation.IPGlobalProperties.GetIPGlobalProperties().GetActiveUdpListeners() where p.Port == (localport - 1) select p).Count() == 1;
                
                while (alreadyinuse == true)
                {
                    udpClient.Close();
                    udpClient = new UdpClient();
                    udpClient.Connect(ip, port);
                    localport = ((IPEndPoint)udpClient.Client.LocalEndPoint).Port;
                    alreadyinuse = (from p in System.Net.NetworkInformation.IPGlobalProperties.GetIPGlobalProperties().GetActiveUdpListeners() where p.Port == (localport - 1) select p).Count() == 1;
                }

                udpClient.BeginReceive(new AsyncCallback(ReceiveFromServer), udpClient);
                //T_ReceiveFromServer.Start();
                
            }
            localport = ((IPEndPoint)udpClient.Client.LocalEndPoint).Port;
            StartServer(localport - 1);
            //SendMessageToServer(loginMsg);
            state.connection = CONNECTION.NOT_CONNECTED;
            repeatPeriod = 200;
            repeatRequest.Set();

        }


        /// <summary>
        /// takes control over generator
        /// </summary>
        public void TakeControl()
        {
            if (state.connection == CONNECTION.CHECKING_STATUS)
            {
                SendMessageToServer(takeControl);
            }
            
        }

        int connectionLostCounter;
        bool stopConnection = false;
        bool stopConnection2 = false;

        /// <summary>
        /// keeps connection alive by cecking state of device
        /// </summary>
        void KeepConnection()
        {
            while(true)
            {
                repeatRequest.WaitOne(repeatPeriod);
                if (stopConnection == false)
                {
                    SendMessageToServer(loginMsg);
                }
                
                connectionLostCounter++;
                if (connectionLostCounter>4)
                {
                    connectionLostCounter = 0;
                    ConnectionLost();

                    repeatPeriod = -1;
                    if (MWCallback != null)
                    {
                        MWCallback(state);
                    }
                    
                }
            }
        }

        private void ConnectionLost()
        {
            
            state.inputVoltage = 0;
            state.temperature = 0;
            state.voltage12VGood = false;
            state.voltage5VGood = false;
            state.voltge3V3Good = false;
            state.generatorOn = false;
            state.generatorReady = false;
            state.overCurrent = false;
            state.overHeat = false;
            stopConnection = false;
            stopConnection2 = true;
            messageAcked = true;
            sending = false;
            messages.Clear();
        }

        /// <summary>
        /// Stops connection
        /// </summary>
        public void StopConnection()
        {
            state.connection = CONNECTION.CONNECTION_LOST;
            messageAcked = true;
            stopConnection = true;
            stopConnection2 = true;
            connectionLostCounter = 5;      //make function KeepConnection believe that connection lost
            messages.Clear();               //clear any remaining messages
            repeatRequest.Set();
        }

        /// <summary>
        /// terminates all threads, its called upon application closing
        /// </summary>
        public void TerminateThreads()
        {
            T_KeepConnection.Abort();
            T_BroadcastSearch.Abort();
            T_SendToServer.Abort();
            if (udpClient != null)
            {
                udpClient.Close();
            }
            
        }

        //int messageIndex;
        System.Diagnostics.Stopwatch stopky;

        volatile int indexOfSentMessages;
        volatile int indexOfReceivedMessages;
        Byte[] message;
        volatile bool messageAcked = true;
        volatile bool sending = false;
        int notAckedCnt;

        /// <summary>
        /// routine to send datagrams, keeps track of retrasmisson, 
        /// ensures that no duplicate packtes are read in generator by adding message index
        /// </summary>
        void SendToServerRoutine()
        {
            bool msTST = true;
            while (true)
            {
                sendToServerRoutine.WaitOne(sendToServerPeriod);
                sendToServerPeriod = 20;

                System.Windows.Application.Current.Dispatcher.Invoke((Action)delegate
                {
                    msTST = messageAcked;
                    
                });

                if (messageAcked == true)
                {
                    notAckedCnt = 0;
                    if (messages.Count > 0)
                    {
                        if (messages[0] != null)
                        {
                            message = new Byte[messages[0].Length + 2];
                            Array.Copy(messages[0], 0, message, 2, messages[0].Length);
                            messages.RemoveAt(0);  //remove first message
                            messageAcked = false;
                            indexOfSentMessages++;

                        }
                        else
                        {
                            messages.RemoveAt(0);  //remove first message
                            continue;
                        }
                        
                    }
                    else
                    {
                        sending = false;
                        sendToServerPeriod = -1;
                        continue;
                    }
                    //sendToServerPeriod = 10;

                }
                else
                {
                    notAckedCnt++;
                    if (notAckedCnt > 5)
                    {
                        notAckedCnt = 0;
                        StopConnection();
                        sendToServerPeriod = -1;

                        continue;
                    }
                }

                if ((message != null) && (state.connection != CONNECTION.CONNECTION_LOST))
                {
                    message[0] = (Byte)((indexOfSentMessages >> 8) & 0xFF);
                    message[1] = (Byte)(indexOfSentMessages & 0xFF);


                    udpClient.Send(message, message.Length);

                }
                
            }
        }



        /// <summary>
        /// Adds message to FIFO, and start trasmission if there is no transission running
        /// </summary>
        /// <param name="message"></param>
        /// <returns></returns>
        public bool SendMessageToServer(string message)
        {
            Byte[] dataToSend = new Byte[message.Length];

            dataToSend = Encoding.ASCII.GetBytes(message);

            if (udpClient != null)
            {

                messages.Add(dataToSend);
                if (sending == false)
                {
                    sending = true;
                    sendToServerRoutine.Set();
                }

                return true;
            }
            else
            {
                return false;
            }
        }
        public bool SendMessageToServer(Byte[] message)
        {

            if (udpClient != null)
            {
                messages.Add(message);
                if (sending == false)
                {
                    sending = true;
                    sendToServerRoutine.Set();
                }
                
                return true;
            }
            else
            {
                return false;
            }
        }


        /// <summary>
        /// stops test
        /// </summary>
        public void StopTest()
        {
            SendMessageToServer(stopTest);
        }

        /// <summary>
        /// Sets new test, sends data of test, and schedule start of test
        /// </summary>
        /// <param name="testType"></param>
        /// <param name="fdata"></param>
        /// <param name="length"></param>
        public void SetTest(TEST_TYPE testType, UInt32[] fdata, int length)
        {
            string setTeststring = "GEsettest ";
            int totalLength = length;

            Byte[] setTestMessage;// = new Byte[setTeststring.Length + 2];

            setTestMessage = Encoding.ASCII.GetBytes(setTeststring);
            Array.Resize(ref setTestMessage, setTestMessage.Count() + 3);

            setTestMessage[setTeststring.Length] = (Byte)(testType);
            setTestMessage[setTeststring.Length+1] = (Byte)((length >> 8) & 0xFF);
            setTestMessage[setTeststring.Length+2] = (Byte)((length) & 0xFF);
            SendMessageToServer(setTestMessage);

            string testDatastring = "GEtest ";
            int lengthOfdataMessage;
            int dataStart;
            int sourceDataEnd = 0;


            Byte[] testMessage;

            while (totalLength > 0)
            {

                testMessage = Encoding.ASCII.GetBytes(testDatastring);
                
                dataStart = testDatastring.Length + 2;

                int testDataMessageIndex = 0;
                if (totalLength > 50)
	            {
		            lengthOfdataMessage = 50;
	            }
                else
	            {
                    lengthOfdataMessage = totalLength;
	            }
                Array.Resize(ref testMessage, testMessage.Count() + 4 * lengthOfdataMessage + 2);

                testMessage[testDatastring.Length] = (Byte)((lengthOfdataMessage>>8) & 0xFF);
                testMessage[testDatastring.Length + 1] = (Byte)(lengthOfdataMessage & 0xFF);
                for (int i = 0; i < lengthOfdataMessage; i++)
                {
                    testMessage[dataStart + testDataMessageIndex++] = (Byte)((fdata[sourceDataEnd + i] >> 0) & 0xFF);
                    testMessage[dataStart + testDataMessageIndex++] = (Byte)((fdata[sourceDataEnd + i] >> 8) & 0xFF);
                    testMessage[dataStart + testDataMessageIndex++] = (Byte)((fdata[sourceDataEnd + i] >> 16) & 0xFF);
                    testMessage[dataStart + testDataMessageIndex++] = (Byte)((fdata[sourceDataEnd + i] >> 24) & 0xFF);
                }
                SendMessageToServer(testMessage);
                //messages.Add(testMessage);
                totalLength -= 50;
                sourceDataEnd += 50;
            }




        }


        /// <summary>
        /// receives data from server, responses to commands
        /// </summary>
        /// <param name="ar"></param>
        void ReceiveFromServer(IAsyncResult ar)
        {
            UdpClient c = (UdpClient)ar.AsyncState;
            int statusIndex;

            //IPEndPoint wantedIpEndPoint = (IPEndPoint)((UdpState)(ar.AsyncState)).e;
            IPEndPoint receivedIpEndPoint = new IPEndPoint(IPAddress.Any, 0);

            try
            {
                Byte[] receiveBytes = c.EndReceive(ar, ref receivedIpEndPoint);

                if (state.connection != CONNECTION.CONNECTION_LOST)
                {
                    indexOfReceivedMessages = (receiveBytes[0] << 8) | receiveBytes[1];
                    
                    if (indexOfReceivedMessages == indexOfSentMessages)
                    {
                        if (T_SendToServer.ThreadState == ThreadState.WaitSleepJoin)
                        {
                            messageAcked = true;
                            //sendToServerRoutine.Set();   
                        }
                    }
                    string s = Encoding.ASCII.GetString(receiveBytes);
                    statusIndex = s.IndexOf(statusMsg);


                    if (StringCheck(s, loginMsg))
                    {
                        if (state.connection != CONNECTION.CONNECTED )
                        {
                            state.connection = CONNECTION.CHECKING_STATUS;
                        }
                        
                        connectionLostCounter = 0;

                        if (receiveBytes.Count() >= 21)
                        {
                            if (statusIndex != -1)
                            {
                                statusIndex += statusMsg.Length + 1;
                            }
                            state.inputVoltage = (receiveBytes[statusIndex + 1] * 256 + receiveBytes[statusIndex]) / 100F;
                            state.temperature = receiveBytes[statusIndex + 2];
                            state.voltge3V3Good = ((receiveBytes[statusIndex + 3] & 0x01) == 0x01);
                            state.voltage5VGood = ((receiveBytes[statusIndex + 3] & 0x02) == 0x02);
                            state.voltage12VGood = ((receiveBytes[statusIndex + 3] & 0x04) == 0x04);
                            state.generatorOn = ((receiveBytes[statusIndex + 3] & 0x08) == 0x08);
                            state.generatorReady = ((receiveBytes[statusIndex + 3] & 0x10) == 0x10);
                            state.overCurrent = ((receiveBytes[statusIndex + 3] & 0x20) == 0x20);
                            state.overHeat = ((receiveBytes[statusIndex + 3] & 0x40) == 0x40);
                            state.controlled = ((receiveBytes[statusIndex + 3] & 0x80) == 0x80);
                        }
                    }
                    else if (StringCheck(s, takeControlOk))
                    {
                        state.connection = CONNECTION.CONNECTED;
                    }
                    else if (StringCheck(s, takeControlNok))
                    {
                        state.connection = CONNECTION.CONTROLED_BY_3RD_SITE;
                    }
                    else if (StringCheck(s, testDataDone))
                    {
                        SendMessageToServer(startTest);
                    }





                    if (MWCallback != null)
                    {
                        MWCallback(state);
                    }

                }

                // Restart listening for udp data packages
                c.BeginReceive(new AsyncCallback(ReceiveFromServer), ar.AsyncState);

            }
            catch (Exception ex)
            {
                if (ex is ObjectDisposedException || ex is SocketException)
                {
                    //System.Windows.MessageBox.Show("a");
                    //Log it as a trace here
                    return;
                }
                throw;
            }
            if (messageAcked)
            {
                sendToServerRoutine.Set();
            }

        }


        /// <summary>
        /// Checks 2 strings
        /// </summary>
        /// <param name="stringToCheck"></param>
        /// <param name="refString"></param>
        /// <returns></returns>
        bool StringCheck(string stringToCheck, string refString)
        {
            if (stringToCheck.Length >= refString.Length + 2)
	        {
                string aa = stringToCheck.Substring(2, refString.Length);
                return (aa == refString);
	        }
            return false;
        }


        /// <summary>
        /// starts UDP server
        /// </summary>
        /// <param name="port"></param>
        public void StartServer(int port)
        {
            if (serverReceive == null)
            {
                serverReceive = new UdpClient(port);
                serverReceive.BeginReceive(new AsyncCallback(ServerReceive), serverReceive);
                //SendMessageToServer("GEopen");
            }
            else
            {
                serverReceive.Close();
                serverReceive = new UdpClient(port);
                serverReceive.BeginReceive(new AsyncCallback(ServerReceive), serverReceive);
                //SendMessageToServer("GEopen");
            }
            stopConnection2 = false;
        }

        private volatile int testTimeProgress;
        public int GetTestTimeProgress()
        {
            return testTimeProgress;
        }
        private double[] measuredData;
        public double[] GetMeasuredData()
        {
            //double[] mData = measuredData[0];
            //measuredData.RemoveAt(0);
            return measuredData;
            
        }

        /// <summary>
        /// Receives data from server
        /// </summary>
        /// <param name="ar"></param>
        void ServerReceive(IAsyncResult ar)
        {
            UdpClient c = (UdpClient)ar.AsyncState;
            IPEndPoint remoteEndPoint = new IPEndPoint(IPAddress.Any,0);

            try
            {
                Byte[] bytes = c.EndReceive(ar, ref remoteEndPoint);

                if (stopConnection2 == false)
                {
                    c.BeginReceive(new AsyncCallback(ServerReceive), serverReceive);
                    c.BeginSend(Encoding.ASCII.GetBytes("ack"), 3, remoteEndPoint, new AsyncCallback(DataSent), c);
                }

                if (bytes[2] == 0)
                {
                    testTimeProgress = (int)bytes[3] << 8 | bytes[4]-1;
                    //double[] measuredData = new double[120];
                    measuredData = new double[120];

                    for (int i = 0; i < 120; i++)
                    {
                        if (bytes[5 + i] >= 0x80)
                        {
                            measuredData[i] = -1.8868*(double)(((Byte)~bytes[5 + i]) + 1);
                        }
                        else
                        {
                            measuredData[i] = 1.8868*(double)bytes[5 + i] ;
                        }
                    
                    }
                    state.testMeasureData = true;
                    MWCallback(state);
                    state.testMeasureData = false;

                }
                else
                {
                    if (StringCheck(Encoding.ASCII.GetString(bytes),"GEtestcomplete") == true)
                    {
                        state.testComplete = true;
                        MWCallback(state);
                        state.testComplete = false;

                    }
                }
                //this.measuredData.Add(measuredData);
                
            }
            catch (Exception ex)
            {
                if (ex is ObjectDisposedException || ex is SocketException)
                {
                    //System.Windows.MessageBox.Show("a");
                    //Log it as a trace here
                    return;
                }
                throw;
            }

        }

        /// <summary>
        /// ends transmisson of ack to UDP client in generator
        /// </summary>
        /// <param name="ar"></param>
        void DataSent(IAsyncResult ar)
        {
            UdpClient c = (UdpClient)ar.AsyncState;
            c.EndSend(ar);
        }




        /// <summary>
        /// starts listent to broadcasted datagrams
        /// </summary>
        public void StartBroadcastListening()
        {
            broadcastListen = new UdpClient(new IPEndPoint(IPAddress.Any, BROADCAST_PORT));
            //UdpState stateBroadcast;
            //stateBroadcast = new UdpState(broadcastListen, brc);

            broadcastListen.BeginReceive(new AsyncCallback(BroadcastDataReceived), broadcastListen);
        }

        /// <summary>
        /// pauses listening
        /// </summary>
        void PauseBrouadCastListening()
        {
            System.Windows.Application.Current.Dispatcher.Invoke((Action)delegate
            {
                broadcastListen.Close();
            });           
        }

        /// <summary>
        /// resumes listenning
        /// </summary>
        void ResumeBroadcastListeneing()
        {
            broadcastListen = new UdpClient(new IPEndPoint(IPAddress.Any, 30303));
            broadcastListen.BeginReceive(new AsyncCallback(BroadcastDataReceived), broadcastListen);
        }



        IPAddress localInterfaceIP;
        public void SendBroadcastSearchReq1(string sLocalIP)
        {

            IPAddress localIP;
            if (IPAddress.TryParse(sLocalIP, out localIP))
            {
                localInterfaceIP = localIP;
                repeatBroacastSearchPeriod = 1000;
                state.searching = true;
                repeatBroadcastSeacrh.Set();
            }
            devices.Clear();
        }


        /// <summary>
        /// Sends query to connected generator, every second 11 times
        /// </summary>
        public void SendBroadcastTask()
        {
            int stopCounter = 0;
            while(true)
            {
                repeatBroadcastSeacrh.WaitOne(repeatBroacastSearchPeriod);
                if (stopCounter++ > 9)
                {
                    repeatBroacastSearchPeriod = -1;
                    stopCounter = 0;
                    state.searching = false;
                    MWCallbackSearch();
                    continue;
                }
                MWCallbackSearch();

                UdpClient client = new UdpClient();
                IPAddress tempIP;
                IPAddress.TryParse("255.255.255.255", out tempIP);
                Byte[] bytes = Encoding.ASCII.GetBytes(BROADCAST_REQUEST);

                IPEndPoint localtest = new IPEndPoint(localInterfaceIP, BROADCAST_PORT);

                //

                PauseBrouadCastListening();
                broadcastSend = new UdpClient(localtest);
                //broadcastSend = new UdpClient(30303);
                broadcastSend.Connect(tempIP, BROADCAST_PORT);
                broadcastSend.EnableBroadcast = true;

                broadcastSend.Send(bytes, bytes.Length);
                broadcastSend.Close();
                ResumeBroadcastListeneing();

            }
        }

        private void MWCallbackSearch()
        {
            state.searchCallback = true;
            MWCallback(state);
            state.searchCallback = false;
        }



        public void SendBroadcastSearchReq(string message, int port, string sLocalIP)
        {
            UdpClient client = new UdpClient();
            IPAddress tempIP;
            IPAddress.TryParse("255.255.255.255", out tempIP);
            Byte[] bytes = Encoding.ASCII.GetBytes(message);

            devices.Clear();
            PauseBrouadCastListening();

            IPAddress localIP;
            if (IPAddress.TryParse(sLocalIP, out localIP))
            {
                IPEndPoint localtest = new IPEndPoint(localIP, 30303);
                broadcastSend = new UdpClient(localtest);
                //broadcastSend = new UdpClient(30303);
                broadcastSend.Connect(tempIP, port);
                broadcastSend.EnableBroadcast = true;
                broadcastSend.BeginSend(bytes, bytes.Length, new AsyncCallback(BroadcastDataSent), broadcastSend);
            }
            
        }

        /// <summary>
        /// sends broadcast, ask if any generators are in the network
        /// </summary>
        /// <param name="ar"></param>
        private void BroadcastDataSent(IAsyncResult ar)
        {
            int sentbytes;
            
            System.Windows.Application.Current.Dispatcher.Invoke((Action)delegate
            {
            
                UdpClient c = (UdpClient)ar.AsyncState;
                sentbytes = c.EndSend(ar);

                c.Close();
                ResumeBroadcastListeneing();
            });
        }

        /// <summary>
        /// receives broadcasted data
        /// </summary>
        /// <param name="ar"></param>
        private void BroadcastDataReceived(IAsyncResult ar)
        {
            UdpClient c = (UdpClient)ar.AsyncState;
            
            //IPEndPoint wantedIpEndPoint = (IPEndPoint)((UdpState)(ar.AsyncState)).e;
            IPEndPoint receivedIpEndPoint = new IPEndPoint(IPAddress.Any, 0);
            try
            {
                Byte[] receiveBytes = c.EndReceive(ar, ref receivedIpEndPoint);
                string ipremote;

                ipremote = receivedIpEndPoint.Address.ToString();

                Byte[] iprem = new Byte[ipremote.Length];

                iprem = Encoding.ASCII.GetBytes(ipremote);
                int startIndex = receiveBytes.Count();


                int indexOfStartName = Array.IndexOf(receiveBytes, (Byte)4);
                int indexOfEndName = Array.IndexOf(receiveBytes, (Byte)5);
                if ((indexOfStartName) > 0 && (indexOfEndName > 0))
                {
                    UpdateDeviceList(Encoding.ASCII.GetString(receiveBytes, indexOfStartName+1, indexOfEndName - indexOfStartName -3), ipremote);
                }

                Array.Resize(ref receiveBytes, receiveBytes.Length + ipremote.Length);
                Array.Copy(iprem, 0, receiveBytes, startIndex, ipremote.Length);

                // Check sender
                bool isRightHost = true;
                //bool isRightHost = (wantedIpEndPoint.Address.Equals(receivedIpEndPoint.Address)) || wantedIpEndPoint.Address.Equals(IPAddress.Any);
                //bool isRightPort = (wantedIpEndPoint.Port == receivedIpEndPoint.Port) || wantedIpEndPoint.Port == 0;
                //if (isRightHost && isRightPort)
                if (isRightHost)
                {

                    // Convert data to ASCII and print in console
                    //string receivedText = ASCIIEncoding.ASCII.GetString(receiveBytes);
                    //Console.Write(receivedText);
                }

                // Restart listening for udp data packages
                c.BeginReceive(new AsyncCallback(BroadcastDataReceived), ar.AsyncState);
            }
            catch (Exception ex)
            {
                if (ex is ObjectDisposedException || ex is SocketException)
                {
                    //System.Windows.MessageBox.Show("a");
                    //Log it as a trace here
                    return;
                }
            }
        }

        /// <summary>
        /// update list of devices, that were found by search function
        /// </summary>
        /// <param name="DeviceName"></param>
        /// <param name="ip"></param>
        void UpdateDeviceList( string DeviceName, string ip)
        {
            bool inTheList = false;

            for (int i = 0; i < devices.Count; i++)
			{
                //System.Windows.Application.Current.Dispatcher.Invoke((Action)delegate
                //{          
                    if (devices[i].DeviceName == DeviceName)
                    {
                        inTheList = true;
                    }
                //});
			}

            if (inTheList == false)
            {
                devicesItem = new DevicesCollection();
                devicesItem.DeviceName = DeviceName;
                devicesItem.DeviceIP = ip;
                devicesItem.color = Brushes.Black;
                
                System.Windows.Application.Current.Dispatcher.Invoke((Action)delegate
                {
                    devices.Add(devicesItem);
                });

            }            
        }

        /// <summary>
        /// gets devide IP from list
        /// </summary>
        /// <param name="index"></param>
        /// <returns></returns>
        public string GetDeviceIP(int index)
        {
            if (index < devices.Count && index >= 0)
            {
                return devices[index].DeviceIP;
            }
            return null;
        }

        public int GetDeviceCount()
        {
            return devices.Count();
        }


    }
}
