/// <summary>
        /// Process an incoming client
        /// </summary>
        /// <param name="state"></param>
        private static void ProcessTCPMessage(object state)
        {
            //Now, notify that we have a connection, let's create our stream reader around it, and retrieve our header
            TcpClient Conn      = (TcpClient)state;
            String    FileName  = "";
            DateTime  StartTime = DateTime.Now;

            //If our source IP address changes, notify the console
            IPAddress Address = ((IPEndPoint)Conn.Client.RemoteEndPoint).Address;

            if (Address.ToString() != MM_Server.LastTEDEAddress.ToString())
            {
                MM_Notification.WriteLine(ConsoleColor.Yellow, "TEDE: IP Source Address change detected: {0}, last {1}", Address, MM_Server.LastTEDEAddress);
            }
            MM_Server.LastTEDEAddress = Address;

            using (NetworkStream nRd = Conn.GetStream())
                using (StreamReader sRd = new StreamReader(nRd))
                    try
                    {
                        //Define our key variables
                        List <String>  OutList     = new List <string>();
                        bool           AtBeginning = true;
                        PropertyInfo[] HeaderInfo  = null;
                        DateTime       BatchId     = default(DateTime);
                        Type           TargetType  = null;

                        //Now, read in all of our lines of data, using reflection to store our data
                        String InLine;
                        while ((InLine = sRd.ReadLine()) != null)
                        {
                            if (InLine.StartsWith("#"))
                            {
                                String[] splStr = InLine.TrimStart('#').TrimEnd(',').Split(',');
                                MM_Server.LastTEDEUpdate = DateTime.Now;

                                //If we're at the beginning, process accordingly
                                if (AtBeginning)
                                {
                                    StartTime = DateTime.Now;
                                    //Pull in, and parse our first line.
                                    BatchId  = new DateTime(1970, 1, 1).AddSeconds(Convert.ToDouble(splStr[0]));
                                    FileName = splStr[1];
                                    if (!FileName.EndsWith(".csv", StringComparison.CurrentCultureIgnoreCase))
                                    {
                                        FileName += ".csv";
                                    }

                                    if (InputTypes.TryGetValue(FileName, out TargetType))
                                    {
                                        //Now that we have our first, line, build our outgoing list
                                        OutList.Clear();

                                        //Read our header
                                        String[] HeaderLine = sRd.ReadLine().TrimStart('#').Split(',');

                                        HeaderInfo = MM_Serialization.GetHeaderInfo(TargetType, HeaderLine);
                                        for (int a = 0; a < HeaderLine.Length; a++)
                                        {
                                            if (HeaderInfo[a] == null)
                                            {
                                                MM_Notification.WriteLine(ConsoleColor.Yellow, "Unknown variable {0} in {1}", HeaderLine[a], FileName);
                                            }
                                        }

                                        //Confirm all of our headers are present
                                        foreach (PropertyInfo pI in TargetType.GetProperties())
                                        {
                                            if (Array.FindIndex <String>(HeaderLine, T => T.Equals(pI.Name, StringComparison.CurrentCultureIgnoreCase)) == -1)
                                            {
                                                MM_Notification.WriteLine(ConsoleColor.Yellow, "Missing variable {0} ({1}) in {2} / {3}", pI.Name, pI.PropertyType.Name, TargetType.Name, FileName);
                                            }
                                        }
                                    }
                                    else
                                    {
                                        //Console.WriteLine("Rereading file " + FileName);
                                        sRd.ReadLine();
                                    }

                                    AtBeginning = false;
                                }
                                else
                                {
                                    DateTime EndTime = new DateTime(1970, 1, 1).AddSeconds(Convert.ToDouble(splStr[0]));
                                    if (EndTime != BatchId)
                                    {
                                        MM_Notification.WriteLine(ConsoleColor.Red, "Mismatch date on {0}: Start {1}, End {2}", FileName, BatchId, EndTime);
                                    }
                                    if (OutList != null)
                                    {
                                        ThreadPool.QueueUserWorkItem(new WaitCallback(ProcessData), new object[] { OutList.ToArray(), TargetType, HeaderInfo });
                                    }
                                    else
                                    {
                                        //MM_Notification.WriteLine(ConsoleColor.Yellow, "Ignore processing data from {0}.", FileName);
                                    }
                                    AtBeginning = true;
                                }
                            }
                            else if (OutList != null)
                            {
                                OutList.Add(InLine);
                            }
                        }
                    }
                    catch (Exception ex)
                    {
                        MM_Notification.WriteLine(ConsoleColor.Red, "Error reading {0} from {1}: {2}", FileName, Conn.Client.RemoteEndPoint, ex);
                    }
        }
        /// <summary>
        /// Process a stream, reading and parsing its content
        /// </summary>
        /// <param name="InLines"></param>
        /// <param name="FileName"></param>
        public static void ProcessStreamRead(StreamReader sRd, String FileName, Type TargetType, ref DateTime LatestBatchID)
        {
            //Now, parse our stream
            IList OutList = (IList)Activator.CreateInstance(typeof(List <>).MakeGenericType(TargetType));

            //Read our header
            String FirstLine = sRd.ReadLine().TrimStart('#').TrimEnd(',');

            String[] HeaderLine;
            Double   ProperDate;
            DateTime BatchId = DateTime.Now;

            if (Double.TryParse(FirstLine, out ProperDate))
            {
                BatchId    = new DateTime(1970, 1, 1).AddSeconds(ProperDate);
                HeaderLine = sRd.ReadLine().TrimStart('#').Split(',');
            }
            else
            {
                HeaderLine = FirstLine.Split(',');
            }

            if (BatchId < LatestBatchID)
            {
                MM_Notification.WriteLine(ConsoleColor.Red, "Aborting {0} Batch {1} because it's older than {1}", FileName, BatchId, LatestBatchID);
                return;
            }
            else
            {
                LatestBatchID = BatchId;
            }

            PropertyInfo[] HeaderInfo = MM_Serialization.GetHeaderInfo(TargetType, HeaderLine);
            for (int a = 0; a < HeaderLine.Length; a++)
            {
                if (HeaderInfo[a] == null)
                {
                    MM_Notification.WriteLine(ConsoleColor.Yellow, "Unknown variable {0} in {1}", HeaderLine[a], FileName);
                }
            }

            //Confirm all of our headers are present
            foreach (PropertyInfo pI in TargetType.GetProperties())
            {
                if (Array.FindIndex <String>(HeaderLine, T => T.Equals(pI.Name, StringComparison.CurrentCultureIgnoreCase)) == -1)
                {
                    MM_Notification.WriteLine(ConsoleColor.Yellow, "Missing variable {0} ({1}) in {2} / {3}", pI.Name, pI.PropertyType.Name, TargetType.Name, FileName);
                }
            }

            //Now, read in all of our lines of data, using reflection to store our data
            String InLine;

            while ((InLine = sRd.ReadLine()) != null)
            {
                if (InLine.StartsWith("#"))
                {
                    DateTime EndTime = new DateTime(1970, 1, 1).AddSeconds(Convert.ToDouble(InLine.TrimStart('#').TrimEnd(',')));
                    if (EndTime != BatchId)
                    {
                        MM_Notification.WriteLine(ConsoleColor.Red, "Mismatch date on {0}: Start {1}, End {2}", FileName, BatchId, EndTime);
                    }
                }
                else
                {
                    Object OutObj = MM_Serialization.Deserialize(HeaderInfo, InLine.Split(','), Activator.CreateInstance(TargetType));
                    //if (OutObj is MacomberMapCommunications.Messages.EMS.MM_BreakerSwitch_Data)
                    //{
                    //    MacomberMapCommunications.Messages.EMS.MM_BreakerSwitch_Data bs = (MacomberMapCommunications.Messages.EMS.MM_BreakerSwitch_Data)OutObj;
                    //    if (bs.TEID_CB == 118964)
                    //        MM_Notification.WriteLine(ConsoleColor.Magenta, "   TEID=" + bs.TEID_CB.ToString() + "    status=" + (bs.Open_CB ? "Open" : "Closed"));
                    //}
                    OutList.Add(OutObj);
                }
            }

            //Once our data are done, use the interprocess communication to update our data
            if (TargetType == typeof(MM_EMS_Command))
            {
                MM_Server.EMSCommands.Clear();
                foreach (Object obj in OutList)
                {
                    MM_Server.EMSCommands.Add((MM_EMS_Command)obj);
                }
            }
            else
            {
                MM_EMS_Data_Updater.ProcessUpdate(TargetType, (Array)OutList.GetType().GetMethod("ToArray").Invoke(OutList, null));
            }
            OutList.Clear();
            OutList = null;
        }