/// <summary>
        /// Salva i dati ricevuti nella tabella dei dati "raw"
        /// </summary>
        /// <param name="packets">Lista dei pacchetti da salvare</param>
        /// <param name="ipAddress">Ip del dispositivo che ha catturato i pacchetti</param>
        public void saveReceivedData(PacketsInfo packets, IPAddress ipAddress)
        {
            if (packets.listPacketInfo.Count == 0)
            {
                return;
            }

            StringBuilder query = new StringBuilder("");

            query.Append("INSERT INTO [dbo].[Packets] (SourceAddress, SSID, signalStrength, hashCode, timestamp_packet, device) VALUES ");
            foreach (PacketInfo packet in packets.listPacketInfo)
            {
                query.Append("('" + packet.sourceAddress + "',");
                query.Append("'" + packet.SSID + "',");
                query.Append(packet.signalStrength + ",");
                query.Append("'" + packet.hashCode + "',");
                query.Append(packet.timestamp * 1000 + ","); //*1000 per passare dai secondi ai millisecondi
                query.Append("'" + ipAddress.ToString() + "'),");
            }
            query.Remove(query.Length - 1, 1); //elimino l'ultima virgola

            int queryResult = runInsertDelete(query.ToString(), null);

            if (queryResult == packets.listPacketInfo.Count)
            {
                Utils.logMessage(this.ToString(), Utils.LogCategory.Info, "INSERT in Packets effettuata con successo");
            }
            else
            {
                Utils.logMessage(this.ToString(), Utils.LogCategory.Info, "INSERT in Packets fallita");
                return;
            }


            updateAssembled();
        }
        ///<summary>metodo che gestisce la connessione socket con un rilevatore</summary>
        ///<exception cref = "SnifferAppSocketException">Eccezione lanciata in caso di errore su una operazione sul socket</exception>
        public void gestioneDevice(TcpClient client)
        {
            IPEndPoint    remoteIpEndPoint = null;
            Device        device;
            NetworkStream stream = client.GetStream();

            stream.ReadTimeout  = 120000; //timeout in lettura in millis
            stream.WriteTimeout = 15000;  //timeout in scrittura in millis

            try {
                remoteIpEndPoint = client.Client.RemoteEndPoint as IPEndPoint;
            } catch (Exception e) {
                string message = "Errore nel riconoscere il socket remoto";
                Utils.logMessage(this.ToString(), Utils.LogCategory.Error, message);
                throw new SnifferAppSocketException(message, e);
            }

            //verifico che non scattino timeout sulla connessione socket
            try {
                //verifico se il dispositivo con quell'IP era già connesso (l'IP del dispositivo era contentuto già nella lstConfDevices)
                if (ConfDevice.lstConfDevices.TryGetValue(remoteIpEndPoint.Address.ToString(), out device))
                {
                    //il dispositivo era gia configurato
                    Utils.logMessage(this.ToString(), Utils.LogCategory.Info, "RECONNECTED with device: " + remoteIpEndPoint.Address.ToString());
                }
                else
                {
                    //se non era già configurato aspetto l'evento di Configurazione dall'interfaccia grafica
                    Utils.logMessage(this.ToString(), Utils.LogCategory.Info, "CONNECTED with device: " + remoteIpEndPoint.Address.ToString());

                    //event per gestire la sincronizzazione con il thread della GUI
                    ManualResetEvent deviceConfEvent = new ManualResetEvent(false);
                    //aggiungo il dispositivo (con il rispettivo Event) nella lista dei dispositivi non configurati
                    NoConfDevice.lstNoConfDevices.TryAdd(remoteIpEndPoint.Address.ToString(), deviceConfEvent);
                    //delegato per gestire la variazione della lista dei device da configurare
                    NoConfDevice.OnLstNoConfDevicesChanged(this, EventArgs.Empty);

                    //mi risveglio quando dalla GUI è richiesta la configurazione del dispositivo o si vuole inviare al rilevatore il segnale "IDENTIFICA"
                    bool isSignalled = false;
                    while (!isSignalled && !stopThreadElaboration)
                    {
                        isSignalled = deviceConfEvent.WaitOne(TimeSpan.FromSeconds(20));
                    }

                    //mi sono risvegliato dall'evento ma il thread deve fermarsi
                    if (stopThreadElaboration)
                    {
                        //chiudo il client TCP
                        client.Close();
                        Utils.logMessage(this.ToString(), Utils.LogCategory.Info, "Socket chiuso");
                        return;
                    }

                    do
                    {
                        //controllo se il device è stato eliminato dalla lista dei device non configurati
                        if (!NoConfDevice.lstNoConfDevices.TryGetValue(remoteIpEndPoint.Address.ToString(), out deviceConfEvent))
                        {
                            //il device è stato configurato
                            break;
                        }
                        else
                        {
                            //il device non è stato configurato e quindi il thread si è risvegliato per richiedere un "IDENTIFICA"
                            Utils.sendMessage(stream, remoteIpEndPoint, "IDENTIFICA");

                            deviceConfEvent.Reset();

                            //come su, volutare se realizzare un wrapper sull'evento
                            isSignalled = false;
                            while (!isSignalled && !stopThreadElaboration)
                            {
                                isSignalled = deviceConfEvent.WaitOne(TimeSpan.FromSeconds(20));
                            }

                            //mi sono risvegliato dall'evento ma il thread deve fermarsi
                            if (stopThreadElaboration)
                            {
                                //chiudo il client TCP
                                client.Close();
                                Utils.logMessage(this.ToString(), Utils.LogCategory.Info, "Socket chiuso");
                                return;
                            }
                        }
                    } while (true);
                }

                //incremento il numero di socket associati al device
                //non faccio il check se il device c'è nella lista perchè in questo punto del codice c'è sicuramente
                ConfDevice.lstConfDevices.TryGetValue(remoteIpEndPoint.Address.ToString(), out device);
                device.openSocket = device.openSocket + 1;
                ConfDevice.lstConfDevices.AddOrUpdate(device.ipAddress, device, (k, v) => v);
                Utils.logMessage(this.ToString(), Utils.LogCategory.Info, "Socket aperti con " + remoteIpEndPoint.Address.ToString() + ": " + device.openSocket);

                string messageReceived;
                //count per triggerare la sincronizzazione dei clock tra il server e il rilevatore
                int countSyncTimestamp = 0;

                //ciclo fin quando non viene invocato il metodo stop in attesa di messaggi da parte dei rilevatori
                while (!stopThreadElaboration)
                {
                    //se il count è a 0 eseguo la sincronizzazione
                    if (countSyncTimestamp == 0)
                    {
                        //invio il messaggio per iniziare la sincronizzazione
                        Utils.sendMessage(stream, remoteIpEndPoint, "SYNC_CLOCK");
                        messageReceived = Utils.receiveMessage(stream, remoteIpEndPoint);

                        //posso ricevere SYNC_CLOCK_START (devo sincronizzare) o SYNC_CLOCK_STOP (sincronizzazione terminata)
                        while (messageReceived == "SYNC_CLOCK_START")
                        {
                            //invio il segnale di sincronizzazione
                            Utils.syncClock(client.Client);
                            messageReceived = Utils.receiveMessage(stream, remoteIpEndPoint);
                        }
                        //resetto il count; sincronizzo i timestamp ogni 50 interazioni
                        countSyncTimestamp = 50;
                    }

                    //invio messaggio per indicare che può iniziare l'invio dei dati
                    Utils.sendMessage(stream, remoteIpEndPoint, "START_SEND");

                    //attendo il JSON dal rilevatore con i pacchetti catturati dall'ultima interazione
                    messageReceived = Utils.receiveMessage(stream, remoteIpEndPoint);

                    PacketsInfo packetsInfo = null;

                    try {
                        //deserializzazione del JSON ricevuto
                        packetsInfo = Newtonsoft.Json.JsonConvert.DeserializeObject <PacketsInfo>(messageReceived);
                    } catch (Exception) {
                        Utils.logMessage(this.ToString(), Utils.LogCategory.Warning, "Errore nella deserializzazione del messaggio JSON. Il messaggio verrà scartato");
                    }
                    //controllo che ci siano messaggi e che ci siano almeno 2 device configurati
                    if (packetsInfo != null && packetsInfo.listPacketInfo.Count > 0 && ConfDevice.lstConfDevices.Count >= 2)
                    {
                        //salvo i dati nella tabella raw del DB
                        dbManager.saveReceivedData(packetsInfo, remoteIpEndPoint.Address);
                    }

                    Utils.logMessage(this.ToString(), Utils.LogCategory.Info, "Device: " + remoteIpEndPoint.Address.ToString() + " -- Numero pacchetti ricevuti: " + packetsInfo.listPacketInfo.Count);

                    //decremento il contatore per la sincronizzazione dei timestamp
                    countSyncTimestamp--;
                }
            } catch (SnifferAppSocketTimeoutException e) {
                Utils.logMessage(this.ToString(), Utils.LogCategory.Warning, "Device:" + remoteIpEndPoint.Address.ToString() + " -- " + e.Message);
            }

            //chiudo il client TCP
            stream.Close();
            client.Close();
            Utils.logMessage(this.ToString(), Utils.LogCategory.Info, "Socket con " + remoteIpEndPoint.Address.ToString() + " chiuso");

            //decremento il numero di socket aperti sul device
            ConfDevice.lstConfDevices.TryGetValue(remoteIpEndPoint.Address.ToString(), out device);
            device.openSocket = device.openSocket - 1;
            ConfDevice.lstConfDevices.AddOrUpdate(device.ipAddress, device, (k, v) => v);
            Utils.logMessage(this.ToString(), Utils.LogCategory.Info, "Socket aperti con " + remoteIpEndPoint.Address.ToString() + ": " + device.openSocket);

            //se il numero di socket aperti è zero devo togliere il device dalla lista dei configurati
            if (device.openSocket <= 0 && !stopThreadElaboration)
            {
                ConfDevice.lstConfDevices.TryRemove(remoteIpEndPoint.Address.ToString(), out device);
                Utils.logMessage(this.ToString(), Utils.LogCategory.Info, "Device " + remoteIpEndPoint.Address.ToString() + " eliminato dalla lista dei device configurati");
                ConfDevice.OnLstConfDevicesChanged(this, EventArgs.Empty);
            }
        }