private bool SendPing(CClient client)
        {
            int lightsused = 0;

            lock (m_mutex)
            {
                //check if any light is used
                for (int i = 0; i < client.m_lights.Count; i++)
                {
                    if (client.m_lights[i].GetNrUsers() > 0)
                    {
                        lightsused = 1;
                        break; //if one light is used we have enough info
                    }
                }
            }

            CTcpData data = new CTcpData();

            data.SetData("ping " + lightsused + "\n");

            if (client.m_socket.Write(data) != true)
            {
                Util.Log(client.m_socket.GetError());
                return(false);
            }
            return(true);
        }
        private bool SendLights(CClient client)
        {
            CTcpData data = new CTcpData();

            //build up messages by appending to CTcpData
            data.SetData("lights " + client.m_lights.Count + "\n");

            for (int i = 0; i < client.m_lights.Count; i++)
            {
                data.SetData("light " + client.m_lights[i].Name + " ", true);

                data.SetData("scan ", true);
                data.SetData(client.m_lights[i].GetVscan()[0].ToString(Util.NumbersFormat) + " ", true);
                data.SetData(client.m_lights[i].GetVscan()[1].ToString(Util.NumbersFormat) + " ", true);
                data.SetData(client.m_lights[i].GetHscan()[0].ToString(Util.NumbersFormat) + " ", true);
                data.SetData(client.m_lights[i].GetHscan()[1].ToString(Util.NumbersFormat), true);
                data.SetData("\n", true);
            }

            if (client.m_socket.Write(data) != true)
            {
                Util.Log(client.m_socket.GetError());
                return(false);
            }
            return(true);
        }
        private bool ParseSync(CClient client)
        {
            List <CDevice> users = new List <CDevice>();

            lock (m_mutex)
            {
                //build up a list of devices using this client's input
                for (int i = 0; i < client.m_lights.Count; i++)
                {
                    users.AddRange(client.m_lights[i].GetAllUsers());
                    //for (int j = 0; j < client.m_lights[i].GetNrUsers(); j++)
                    //    users.Add(client.m_lights[i].GetUser(j));
                }
            }

            var distinctUsers = users.Distinct();

            //message all devices
            foreach (CDevice device in distinctUsers)
            {
                device.Sync();
            }

            return(true);
        }
        private bool ParseGet(CClient client, CMessage message)
        {
            CTcpData data = new CTcpData();
            string   messagekey;

            if (!Util.GetWord(ref message.message, out messagekey))
            {
                Util.LogError($"{client.m_socket.Address}:{client.m_socket.Port} sent gibberish");
                return(false);
            }

            if (messagekey == "version")
            {
                Util.Log($"{client.m_socket.Address}:{client.m_socket.Port} said get version");

                return(SendVersion(client));
            }
            else if (messagekey == "lights")
            {
                Util.Log($"{client.m_socket.Address}:{client.m_socket.Port} said get lights");

                return(SendLights(client));
            }
            else
            {
                Util.LogError($"{client.m_socket.Address}:{client.m_socket.Port} sent gibberish");
                return(false);
            }
        }
        private bool ParseMessage(CClient client, CMessage message)
        {
            CTcpData data = new CTcpData();
            string   messagekey;

            //an empty message is invalid
            if (!Util.GetWord(ref message.message, out messagekey))
            {
                Util.LogError($"{client.m_socket.Address}:{client.m_socket.Port} sent gibberish");
                return(false);
            }

            if (messagekey == "hello")
            {
                Util.Log($"{client.m_socket.Address}:{client.m_socket.Port} said hello");
                data.SetData("hello\n");
                if (client.m_socket.Write(data) != true)
                {
                    Util.Log(client.m_socket.GetError());
                    return(false);
                }

                lock (m_mutex)
                {
                    if (client.m_connecttime == -1)
                    {
                        client.m_connecttime = message.time;
                    }
                }
            }
            else if (messagekey == "ping")
            {
                return(SendPing(client));
            }
            else if (messagekey == "get")
            {
                return(ParseGet(client, message));
            }
            else if (messagekey == "set")
            {
                return(ParseSet(client, message));
            }
            else if (messagekey == "sync")
            {
                return(ParseSync(client));
            }
            else
            {
                Util.LogError($"{client.m_socket.Address}:{client.m_socket.Port} sent gibberish");
                return(false);
            }

            return(true);
        }
        private bool SendVersion(CClient client)
        {
            CTcpData data = new CTcpData();

            data.SetData("version " + ProtocolVersion.Version + "\n");

            if (client.m_socket.Write(data) != true)
            {
                Util.Log(client.m_socket.GetError());
                return(false);
            }
            return(true);
        }
 private void RemoveClient(CClient client)
 {
     lock (m_mutex)
     {
         //TODO: can use linq to remove the for loop/if statement
         for (int i = 0; i < m_clients.Count; i++)
         {
             if (m_clients[i].m_socket.GetSock() == client.m_socket.GetSock())
             {
                 Util.Log($"removing {m_clients[i].m_socket.Address}:{m_clients[i].m_socket.Port}");
                 m_clients[i].Dispose();
                 m_clients.RemoveAt(i);
                 return;
             }
         }
     }
 }
        private bool HandleMessages(CClient client)
        {
            if (client.m_messagequeue.GetRemainingDataSize() > CMessageQueue.MAXDATA) //client sent too much data
            {
                Util.LogError($"{client.m_socket.Address}:{client.m_socket.Port} sent too much data");
                return(false);
            }

            //loop until there are no more messages
            while (client.m_messagequeue.GetNrMessages() > 0)
            {
                CMessage message = client.m_messagequeue.GetMessage();
                if (!ParseMessage(client, message))
                {
                    return(false);
                }
            }
            return(true);
        }
        private void AddClient(CClient client)
        {
            //TODO: google this
            const int FD_SETSIZE = 100;

            lock (m_mutex)
            {
                if (m_clients.Count >= FD_SETSIZE) //maximum number of clients reached
                {
                    Util.LogError($"number of clients reached maximum {FD_SETSIZE}");
                    CTcpData data = new CTcpData();
                    data.SetData("full\n");
                    client.m_socket.Write(data);
                    client = null;
                    return;
                }

                //assign lights and put the pointer in the clients vector
                client.InitLights(m_lights);
                m_clients.Add(client);
            }
        }
        private bool ParseSet(CClient client, CMessage message)
        {
            string messagekey;

            if (!Util.GetWord(ref message.message, out messagekey))
            {
                Util.LogError($"{client.m_socket.Address}:{client.m_socket.Port} sent gibberish");
                return(false);
            }

            if (messagekey == "priority")
            {
                int    priority;
                string strpriority;
                if (!Util.GetWord(ref message.message, out strpriority) || !int.TryParse(strpriority, out priority))
                {
                    Util.LogError($"{client.m_socket.Address}:{client.m_socket.Port} sent gibberish");
                    return(false);
                }
                lock (m_mutex)
                {
                    client.SetPriority(priority);
                }

                Util.Log($"{client.m_socket.Address}:{client.m_socket.Port} priority set to {client.m_priority}");
            }
            else if (messagekey == "light")
            {
                return(ParseSetLight(client, message));
            }
            else
            {
                Util.LogError($"{client.m_socket.Address}:{client.m_socket.Port} sent gibberish");
                return(false);
            }
            return(true);
        }
        public void Process()
        {
            //open listening socket if it's not already
            if (!m_socket.IsOpen)
            {
                string liseningAddress = String.IsNullOrEmpty(m_address) ? "*" : m_address;
                Util.Log($"opening listening socket on {liseningAddress}:{m_port}");

                if (!m_socket.Open(m_address, m_port, 1000000))
                {
                    Util.LogError($"{m_socket.GetError()}");
                    m_socket.Close();
                }
            }

            //see if there's a socket we can read from
            IList <Socket> sockets = GetReadableFd();

            foreach (Socket sock in sockets)
            {
                if (sock == m_socket.GetSock()) //we can read from the listening socket
                {
                    CClient client  = new CClient();
                    bool    returnv = m_socket.Accept(client.m_socket);
                    if (returnv)
                    {
                        Util.Log($"{client.m_socket.Address}:{client.m_socket.Port} connected");
                        AddClient(client);
                    }
                    else
                    {
                        client.Dispose();
                        client = null;
                        Util.Log(m_socket.GetError());
                    }
                }
                else
                {
                    //get the client the sock fd belongs to
                    CClient client = GetClientFromSock(sock);
                    if (client == null) //guess it belongs to nobody
                    {
                        continue;
                    }

                    //try to read data from the client
                    CTcpData data    = new CTcpData();
                    bool     returnv = client.m_socket.Read(data);
                    if (!returnv)
                    { //socket broke probably
                        Util.Log(client.m_socket.GetError());
                        RemoveClient(client);
                        continue;
                    }

                    //add data to the messagequeue
                    client.m_messagequeue.AddData(data.GetData(), data.GetSize());

                    //check messages from the messaqueue and parse them, if it fails remove the client
                    if (!HandleMessages(client))
                    {
                        RemoveClient(client);
                    }
                }
            }
        }
        private bool ParseSetLight(CClient client, CMessage message)
        {
            string lightname;
            string lightkey;
            int    lightnr;

            if (!Util.GetWord(ref message.message, out lightname) || !Util.GetWord(ref message.message, out lightkey) || (lightnr = client.LightNameToInt(lightname)) == -1)
            {
                Util.LogError($"{client.m_socket.Address}:{client.m_socket.Port} sent gibberish");
                return(false);
            }

            if (lightkey == "rgb")
            {
                float[] rgb = new float[3];
                string  value;

                Util.ConvertFloatLocale(ref message.message); //workaround for locale mismatch (, and .)

                for (int i = 0; i < 3; i++)
                {
                    if (!Util.GetWord(ref message.message, out value) || !float.TryParse(value, out rgb[i]))
                    {
                        Util.LogError($"{client.m_socket.Address}:{client.m_socket.Port} sent gibberish");
                        return(false);
                    }
                }

                lock (m_mutex)
                {
                    client.m_lights[lightnr].SetRgb(rgb, message.time);
                }
            }
            else if (lightkey == "speed")
            {
                float  speed;
                string value;

                Util.ConvertFloatLocale(ref message.message); //workaround for locale mismatch (, and .)

                if (!Util.GetWord(ref message.message, out value) || !float.TryParse(value, out speed))
                {
                    Util.LogError($"{client.m_socket.Address}:{client.m_socket.Port} sent gibberish");
                    return(false);
                }

                lock (m_mutex)
                {
                    client.m_lights[lightnr].SetSpeed(speed);
                }
            }
            else if (lightkey == "interpolation")
            {
                bool   interpolation;
                string value;

                if (!Util.GetWord(ref message.message, out value) || !Util.StrToBool(value, out interpolation))
                {
                    Util.LogError($"{client.m_socket.Address}:{client.m_socket.Port} sent gibberish");
                    return(false);
                }

                lock (m_mutex)
                {
                    client.m_lights[lightnr].SetInterpolation(interpolation);
                }
            }
            else if (lightkey == "use")
            {
                bool   use;
                string value;

                if (!Util.GetWord(ref message.message, out value) || !Util.StrToBool(value, out use))
                {
                    Util.LogError($"{client.m_socket.Address}:{client.m_socket.Port} sent gibberish");
                    return(false);
                }

                lock (m_mutex)
                {
                    client.m_lights[lightnr].SetUse(use);
                }
            }
            else if (lightkey == "singlechange")
            {
                float  singlechange;
                string value;

                Util.ConvertFloatLocale(ref message.message); //workaround for locale mismatch (, and .)

                if (!Util.GetWord(ref message.message, out value) || !float.TryParse(value, out singlechange))
                {
                    Util.LogError($"{client.m_socket.Address}:{client.m_socket.Port} sent gibberish");
                    return(false);
                }

                lock (m_mutex)
                {
                    client.m_lights[lightnr].SetSingleChange(singlechange);
                }
            }
            else
            {
                Util.LogError($"{client.m_socket.Address}:{client.m_socket.Port} sent gibberish");
                return(false);
            }

            return(true);
        }