using System;
using System.Collections.Generic;
using System.Text;

using System.Threading;

using System.Xml;
using System.Xml.Serialization;
using System.IO;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.InteropServices;

using System.Net;
using System.Net.Sockets;
using Wayne.FDCPOSLibrary;
using Wayne.FDCPOSLibrary.Configuration;
using Wayne.OptInterface;
using Wayne.FDCPOSInterface.Configuration;


namespace Wayne.FDCPOSInterface
{
    using Microsoft.Extensions.DependencyInjection;
    using Microsoft.Extensions.Logging;
    using System.Linq;
    using System.Xml.Schema;


    public sealed class SchemasSG
    {
        private static readonly object instLock = new object();
        private static Dictionary<string, XmlSchemaSet> schemasSG;

        private static SchemasSG _instance;
        public static SchemasSG Instance
        {
            get
            {
                if (_instance == null)
                {
                    lock (instLock) // make it multithread safe
                    {
                        if (_instance == null)
                        {
                            _instance = new SchemasSG();

                        }
                    }
                }
                return _instance;

            }
        }
        public Dictionary<string, XmlSchemaSet> GetSchemas
        {
            get { return schemasSG; }

        }
        private SchemasSG()
        {
            schemasSG = new Dictionary<string, XmlSchemaSet>();

            // read schemas from resource files
            Assembly a = Assembly.GetExecutingAssembly();
            string name = a.GetName().Name;
            string sBasicTypeName = "SchemasSG.FDC_Basic_Types.xsd";
            Stream sBasicTypes = a.GetManifestResourceStream(name + "." + sBasicTypeName);
            XmlSchema sBasicTypesSchema = XmlSchema.Read(sBasicTypes, ValidationCallback);
            //FDCPOSManager.tracer.WriteLine("BasicTypes Name: " + name + "." + sBasicTypeName);

            foreach (string resource in a.GetManifestResourceNames())
            {

                if (resource.EndsWith(".xsd"))
                {
                    try
                    {
                        //FDCPOSManager.tracer.WriteLine("Schema Name: " + resource);
                        string shortName = resource.Substring(name.Length + 1);  // get rid of Assembly name
                        if (!sBasicTypeName.Equals(shortName))
                        {
                            shortName = shortName.Substring(shortName.IndexOf(".") + 1); // get rid of the folder name SchemasSG
                            shortName = shortName.Substring(0, shortName.Length - 4); // get rid of ".xsd"
                            //FDCPOSManager.tracer.WriteLine("schema name: " + shortName);

                            Stream s = Assembly.GetExecutingAssembly().GetManifestResourceStream(resource);
                            {
                                schemasSG[shortName] = new XmlSchemaSet();
                                schemasSG[shortName].Add(XmlSchema.Read(s, ValidationCallback));
                                schemasSG[shortName].Add(sBasicTypesSchema); // add this basic type to every node
                            }
                        }
                    }
                    catch (Exception ex)
                    {
                        //FDCPOSManager.tracer.WriteLine("Exception in Schemas! " + ex.Message);
                    }

                }
            }

        }

        static void ValidationCallback(object sender, ValidationEventArgs args)
        {
            //if (args.Severity == XmlSeverityType.Warning)
            //    FDCPOSManager.tracer.Write("WARNING: ");
            //else if (args.Severity == XmlSeverityType.Error)
            //    FDCPOSManager.tracer.Write("ERROR: ");

            //FDCPOSManager.tracer.WriteLine(args.Message);
        }

    }

    public class FdcClientTcpHandler : IDisposable
    {
        private bool disposed = false;
        //static NLog.Logger fdcSocketLogger = NLog.LogManager.LoadConfiguration("nlog.config").GetLogger("FdcServerSocket");
        private ILogger fdcSocketLogger;
        //= ServiceBuilder.Provider
        //.GetRequiredService<ILoggerFactory>().CreateLogger("FdcServerSocket");
        private MD5Crypter crypter = new MD5Crypter();

        /// <summary>
        /// ip:port, used for logging
        /// </summary>
        public string TcpClientEndPointString { get; private set; }

        private TcpClient tcpClient;
        public TcpClient TcpClient { get { return this.tcpClient; } }

        private FDCPOSManager fdcposManager;
        private FdcServerTcpHandler fdcServerTcpHandler;

        public string workstationID = "";
        public string applicationSender = "";

        /// <summary>
        /// fired on get tcp level error, mostly likely the tcp is broken
        /// </summary>
        public event EventHandler OnCommunicatingError;

        public FdcClientTcpHandler(FDCPOSManager _fdcposManager, FdcServerTcpHandler _fdcServerTcpHandler,
            TcpClient tcpClient, ILogger logger)
        {
            this.fdcposManager = _fdcposManager;
            this.fdcServerTcpHandler = _fdcServerTcpHandler;
            this.tcpClient = tcpClient;
            this.fdcSocketLogger = logger;
        }


        private void OnTcpClientDataRead(IAsyncResult ar)
        {
            NetworkStream networkStream;
            byte[] buffer = null;
            int readCount = 0;
            int previousReadCount = 0;
            Action<byte[], NetworkStream> callback = null;
            int expectingMsgLength = 0;
            try
            {
                //tuple is: ns, readBuffer, offset, readFullMsgCallback, expectingLengthToRead
                var parameter = (ar.AsyncState as Tuple<NetworkStream, byte[], int, Action<byte[], NetworkStream>, int>);
                networkStream = parameter.Item1;
                buffer = parameter.Item2;
                previousReadCount = parameter.Item3;
                callback = parameter.Item4;
                expectingMsgLength = parameter.Item5;

                readCount = networkStream.EndRead(ar);
                if (readCount == 0)
                    throw new Exception("tcp client received 0 count data which indicates the connection is broken, trigger disconnection");
            }
            catch (Exception eee)
            {
                fdcSocketLogger.LogError("EndRead Fdc client tcpClient NetworkStream exceptioned: " + eee
                    + "\r\n will treat as OnCommunicatingError, this client with its Ip and port: " + this.TcpClientEndPointString);
                this.OnCommunicatingError?.Invoke(this, null);
                return;
            }

            if ((readCount + previousReadCount) < expectingMsgLength)
            {
                try
                {
                    var _ = networkStream.BeginRead(buffer, (readCount + previousReadCount),
                        (expectingMsgLength - (readCount + previousReadCount)),
                        this.OnTcpClientDataRead,
                        new Tuple<NetworkStream, byte[], int, Action<byte[], NetworkStream>, int>(
                            networkStream, buffer, readCount + previousReadCount, callback, expectingMsgLength));
                }
                catch (Exception eee)
                {
                    fdcSocketLogger.LogError("Continue BeginRead Fdc client tcpClient NetworkStream exceptioned: " + eee
                        + "\r\n will treat as OnCommunicatingError, this client with its Ip and port: " + this.TcpClientEndPointString);
                    this.OnCommunicatingError?.Invoke(this, null);
                    return;
                }
            }
            else
            {
                try
                {
                    callback(buffer, networkStream);
                }
                catch (Exception xxx)
                {
                    fdcSocketLogger.LogError("Callback in OnTcpClientDataRead exceptioned: " + xxx
                        + "\r\n will ignore the error");
                }
            }
        }

        private void ProcessMessageHeader(byte[] headerBuffer, NetworkStream networkStream)
        {
            try
            {
                int msgBodyLength = FdcClientTcpHandler.getMsgLength(headerBuffer);
                if (this.fdcSocketLogger.IsEnabled(LogLevel.Debug))
                    this.fdcSocketLogger.LogDebug($"Received a msg with BodyLength: {msgBodyLength}, will further parsing...");
                if (msgBodyLength >= 19999) throw new ArgumentOutOfRangeException("MsgBodyLength: " + msgBodyLength + " is too big and unlikely a valid message");
                byte[] bodyBuffer = new byte[msgBodyLength];
                var r = networkStream.BeginRead(bodyBuffer, 0, msgBodyLength,
                        this.OnTcpClientDataRead,
                        //ns, readBuffer, offset, readFullMsgCallback, expectingLengthToRead
                        new Tuple<NetworkStream, byte[], int, Action<byte[], NetworkStream>, int>(
                            networkStream, bodyBuffer, 0,
                            (bodyBuffer, __) =>
                            {
                                this.ParseServiceRequestOrFdcMessageFromRaw(bodyBuffer, __, msgBodyLength, headerBuffer);
                                this.StartReadingDataFromClient();
                            },
                            msgBodyLength));
            }
            catch (Exception exxx)
            {
                fdcSocketLogger.LogError("BeginRead Fdc client tcpClient NetworkStream(ProcessMessageHeader) exceptioned: " + exxx
                    + "\r\n will treat as OnCommunicatingError, this client with its Ip and port: " + this.TcpClientEndPointString);
                this.OnCommunicatingError?.Invoke(this, null);
                return;
            }

        }

        private void ParseServiceRequestOrFdcMessageFromRaw(byte[] bodyBuffer, NetworkStream networkStream, int msgLength, byte[] headerBytes)
        {
            var message = Encoding.UTF8.GetString(bodyBuffer);
            if (fdcSocketLogger.IsEnabled(LogLevel.Trace))
            {
                // set a trace since the heartbeat msg is so frenquency and causing too much logging
                fdcSocketLogger.LogTrace($"Parsing ServiceRequest Or FdcMessage from raw incoming message: {message ?? ""}");
            }

            var result = OverallResult.Success;
            string sEndmsg = "";

            //no trailing spaces xml message
            string exactXmlMsgStr = "";
            int indexEndMsgSR = -1, indexEndFDCMsg = -1, indexEnd = -1;
            indexEndMsgSR = message.IndexOf("</ServiceRequest>");
            indexEndFDCMsg = message.IndexOf("</FDCMessage>");

            #region parse

            if (indexEndMsgSR >= 0 && indexEndFDCMsg >= 0)
            {
                indexEnd = System.Math.Min(indexEndMsgSR, indexEndFDCMsg);
                if (indexEndMsgSR < indexEndFDCMsg)
                {
                    sEndmsg = "</ServiceRequest>";
                    indexEndFDCMsg = -1;
                }
                else
                {
                    sEndmsg = "</FDCMessage>";
                    indexEndMsgSR = -1;
                }
            }
            else if (indexEndMsgSR >= 0 && indexEndFDCMsg < 0)
            {
                indexEnd = indexEndMsgSR;
                sEndmsg = "</ServiceRequest>";
            }
            else if (indexEndMsgSR < 0 && indexEndFDCMsg >= 0)
            {
                indexEnd = indexEndFDCMsg;
                sEndmsg = "</FDCMessage>";
            }
            else
                this.fdcSocketLogger.LogError("how a full MessageBody neither contains </ServiceRequest> nor </FDCMessage>, not a valid Fdc msg, will ignore it");

            #endregion

            if (indexEnd >= 0)
            {
                exactXmlMsgStr = message.Substring(0, indexEnd + sEndmsg.Length);
                message = message.Substring(indexEnd + sEndmsg.Length);
                if (fdcposManager.encryptedHeader)
                {
                    var hashingTarget = exactXmlMsgStr + MD5Crypter.passphrase;
                    if (!crypter.verifyMD5Hash(hashingTarget,
                        headerBytes.Skip(Define.HeaderLength).Take(Define.EncriptionLength).Select(h => h.ToString("x2")).Aggregate((acc, n) => acc + n)))
                    {
                        if (fdcSocketLogger.IsEnabled(LogLevel.Information))
                            fdcSocketLogger.LogInformation("verifyMD5Hash failed for msg from " + this.TcpClientEndPointString +
                                ", the computed&expecting hash string: " + crypter.getMD5Hash(hashingTarget) +
                                ", the hashing target(incomingMsg+passcode): \r\n" +
                                hashingTarget);
                        result = OverallResult.ValidationError;
                    }
                }

                if (exactXmlMsgStr.Length > 0)
                {
                    this.fdcServerTcpHandler.ReadRequest(this, exactXmlMsgStr, msgLength, (indexEndMsgSR > 0) ? true : false, ref result);
                }
            }
        }

        public void StartReadingDataFromClient()
        {
            if (this.tcpClient == null || !this.tcpClient.Connected) return;
            try
            {
                this.TcpClientEndPointString = ((IPEndPoint)(tcpClient.Client.RemoteEndPoint)).ToString();
            }
            catch { }

            try
            {
                NetworkStream networkStream = this.tcpClient.GetStream();
                var headerBuffer = new byte[Define.HeaderLength + Define.EncriptionLength];
                var _ = networkStream.BeginRead(headerBuffer, 0, (Define.HeaderLength + Define.EncriptionLength),
                        this.OnTcpClientDataRead,
                        //ns, readBuffer, offset, readFullMsgCallback, expectingLengthToRead
                        new Tuple<NetworkStream, byte[], int, Action<byte[], NetworkStream>, int>(
                            networkStream, headerBuffer, 0, this.ProcessMessageHeader, (Define.HeaderLength + Define.EncriptionLength)));
            }
            catch (Exception exxx)
            {
                fdcSocketLogger.LogError("Get or BeginRead Fdc client tcpClient NetworkStream exceptioned: " + exxx
                    + "\r\n will ignore this client");
                this.OnCommunicatingError?.Invoke(this, null);
                return;
            }
        }

        static public int getMsgLength(byte[] header)
        {
            int length = 0;
            for (int pos = 1; pos <= Define.HeaderLength; pos++)
            {
                length |= ((int)(header[pos - 1] << (Define.HeaderLength - pos) * 8));
            }
            return length;
        }

        public void Dispose()
        {
            try
            {
                this.disposed = true;
                this.tcpClient.Close();
            }
            catch { }
            finally { }
        }
    }

    public class FdcServerTcpHandler : IDisposable
    {
        private List<FdcClientTcpHandler> fdcClientTcpHandlers = new List<FdcClientTcpHandler>();
        //protected static NLog.Logger fdcSocketLogger = NLog.LogManager.LoadConfiguration("nlog.config").GetLogger("FdcServerSocket");
        protected ILogger fdcSocketLogger;// = ServiceBuilder.Provider.GetRequiredService<ILoggerFactory>().CreateLogger("FdcServerSocket");
        private bool disposed = false;
        protected FDCPOSManager fdcPosManager;
        protected TcpListener tcpListener;
        protected int iIPPort;
        private bool traceXML = false;

        public FDCPOSInterfaceServer FdcPosInterface { get; set; }

        public int IPPort
        {
            get { return iIPPort; }
            set { iIPPort = value; }
        }

        public FdcServerTcpHandler(FDCPOSManager _fdcPosManager, int _iIPPort, ILogger logger)
        {
            this.fdcSocketLogger = logger;
            fdcPosManager = _fdcPosManager;
            iIPPort = _iIPPort;
        }

        public bool StartListening()
        {
            try
            {
                this.tcpListener = new TcpListener(IPAddress.Any, iIPPort);
                this.tcpListener.Start();
                var _ = this.tcpListener.BeginAcceptTcpClient(this.OnTcpClientAccepted, null);
                this.fdcSocketLogger.LogInformation("FdcServerTcpHandler is listening on port: " + iIPPort);
                return true;
            }
            catch (Exception exxx)
            {
                fdcSocketLogger.LogError("Listening port: " + iIPPort + " exceptioned: " + exxx
                    + "\r\n will QUIT listening");
                throw;
            }
        }

        private void OnTcpClientAccepted(IAsyncResult ar)
        {
            TcpClient tcpClient = null;
            try
            {
                tcpClient = this.tcpListener.EndAcceptTcpClient(ar);
                this.fdcSocketLogger.LogDebug("A Tcp client: " + ((IPEndPoint)(tcpClient.Client.RemoteEndPoint)).ToString() + " has connected in...");
            }
            catch (Exception exxx)
            {
                fdcSocketLogger.LogError($"TcpListener EndAcceptTcpClient exceptioned: {exxx.ToString() + Environment.NewLine}will continue listening(depends on is app shuting down)");
                return;
            }
            finally
            {
                if (!this.disposed)
                    tcpListener.BeginAcceptTcpClient(this.OnTcpClientAccepted, null);
            }

            var fdcClientTcpHandler = new FdcClientTcpHandler(fdcPosManager, this, tcpClient, this.fdcSocketLogger);
            fdcClientTcpHandler.OnCommunicatingError += (s, e) =>
            {

                #region clean up

                fdcClientTcpHandler.Dispose();
                string fdcClientId = FDCPOSClient.getClientID(fdcClientTcpHandler.workstationID, fdcClientTcpHandler.applicationSender);
                try
                {
                    if (this.fdcPosManager.fdcClientList.ContainsKey(fdcClientId))
                    {
                        fdcSocketLogger.LogInformation(string.Format("Cleaning up existed FdcClient '{0}' which from remote: {1}",
                            fdcClientId,
                            fdcClientTcpHandler.TcpClientEndPointString));
                        this.fdcPosManager.DisconnectClient(this.fdcPosManager.fdcClientList[fdcClientId]);
                    }
                }
                catch (Exception eeee)
                {
                    fdcSocketLogger.LogInformation(string.Format("Cleaning up existed FdcClient '{0}', from remote: {1} exceptioned: \r\n {2}",
                        fdcClientId,
                        fdcClientTcpHandler.TcpClientEndPointString,
                        eeee));
                }

                #endregion

            };
            fdcClientTcpHandler.StartReadingDataFromClient();
            this.fdcClientTcpHandlers.Add(fdcClientTcpHandler);
        }

        public string ReadRequest(FdcClientTcpHandler fdcClientTcpHandler, string message, int msglength,
            bool isServiceRequest, ref OverallResult result)
        {
            OverallResult extresult = result;
            ErrorCode iFDCStatus = (int)ErrorCode.ERRCD_OK;
            int requestId = -1;
            string requestType = (isServiceRequest) ? GetRequestType(message) : GetMessageType(message);
            string applicationSender = GetApplicationSender(message);
            string workstationId = GetWorkstationID(message);

            if (string.IsNullOrEmpty(requestType))
            {
                fdcSocketLogger.LogInformation(string.Format("Client with applicationSender={0}, workstationId={1} is " +
                               "sending in a message that Fcc resolved an empty or null requestType from it, unlikely an valid format message:{2}{3}",
                               applicationSender, workstationId, Environment.NewLine, (message ?? "")));
                result = OverallResult.NoData;
                iFDCStatus = ErrorCode.ERRCD_BADVAL;
                ((FDCPOSInterfaceServerManager)this.fdcPosManager).fdcPosInterface.messages.SendErrorResponse(requestType, workstationId, applicationSender, requestId, iFDCStatus, result.ToString());
                return requestType;
            }
            try
            {
                //FDCPOSManager.tracer.WriteLine(string.Format("init requestType='{0}'", requestType));
                if (fdcSocketLogger.IsEnabled(LogLevel.Trace))
                    fdcSocketLogger.LogTrace($"Parsed the incoming Request, requestType: {requestType ?? ""}, applicationSender: {applicationSender ?? ""}, workstationId: {workstationId ?? ""}, message: {Environment.NewLine} {message ?? ""}");
                if (fdcSocketLogger.IsEnabled(LogLevel.Debug))
                    if (requestType != "POSHeartBeat")
                        fdcSocketLogger.LogTrace($"Parsed the incoming Request, requestType: {requestType ?? ""}, applicationSender: {applicationSender ?? ""}, workstationId: {workstationId ?? ""}, message: {Environment.NewLine} {message ?? ""}");

                if (requestType != "LogOn")
                {
                    if (!this.fdcPosManager.fdcClientList.ContainsKey(FDCPOSClient.getClientID(workstationId, applicationSender)))
                    {
                        FDCPOSClient fdcposClient = new FDCPOSClient(fdcPosManager, null, this.fdcSocketLogger);
                        fdcposClient.workstationID = workstationId;
                        fdcposClient.applicationSender = applicationSender;
                        IPEndPoint endpoint = (IPEndPoint)(fdcClientTcpHandler.TcpClient.Client.RemoteEndPoint);
                        string sIPAddress = endpoint.Address.ToString();
                        fdcposClient.sIPAddress = sIPAddress;
                        fdcposClient.FdcClientTcpHandler = fdcClientTcpHandler;
                        fdcposClient.connected = true;
                        fdcposClient.socketChannelResponse = fdcClientTcpHandler.TcpClient;
                        fdcClientTcpHandler.workstationID = workstationId;
                        fdcClientTcpHandler.applicationSender = applicationSender;
                        fdcPosManager.fdcClientList.Add(FDCPOSClient.getClientID(workstationId, applicationSender), fdcposClient);

                        if (this.fdcSocketLogger.IsEnabled(LogLevel.Debug))
                            this.fdcSocketLogger.LogDebug(string.Format("Unknown Client with appSender={0}, wId={1} is " +
                                "sending Request(type={2}) in without log on, Will response: AuthentificationError",
                                applicationSender, workstationId, requestType));
                        result = OverallResult.AuthentificationError;
                        iFDCStatus = ErrorCode.ERRCD_COMMERR;
                        ((FDCPOSInterfaceServerManager)this.fdcPosManager).fdcPosInterface.messages.SendErrorResponse(requestType, workstationId, applicationSender, requestId, iFDCStatus, result.ToString());
                        fdcPosManager.fdcClientList.Remove(FDCPOSClient.getClientID(workstationId, applicationSender));
                        return requestType;
                    }

                    if (result == OverallResult.Success && extresult == OverallResult.Success)
                    {
                        fdcPosManager.fdcClientList[FDCPOSClient.getClientID(workstationId, applicationSender)].heartbeat.StopClientDisconnectionTimer();
                    }
                }

                if (requestType == "POSHeartBeat")
                {
                    if (fdcSocketLogger.IsEnabled(LogLevel.Debug))
                        this.fdcSocketLogger.LogDebug(string.Format("Received a POSHeartBeat from applicationSender: {0}, workstationId: {1}", (applicationSender ?? ""), (workstationId ?? "")));
                    //    if (isServiceRequest)
                    //    {
                    //        ServiceRequestHeartbeat sr = Deserialize<ServiceRequestHeartbeat>(myString, ref result);
                    //        if (!this.fdcposManager.tcpClientList.ContainsKey(FDCPOSClient.getClientID(sr.WorkstationID, sr.ApplicationSender)))
                    //            result = OverallResult.AuthentificationError;
                    //        if (sr != null && result == OverallResult.Success && extresult == OverallResult.Success)
                    //        {
                    //            fdcposManager.tcpClientList[FDCPOSClient.getClientID(sr.WorkstationID, sr.ApplicationSender)].heartbeat.ResetDisconnectionTimeout();
                    //        }
                    //    }
                    //    else
                    //    {
                    //        FDCMessageFDCHeartbeat sr = Deserialize<FDCMessageFDCHeartbeat>(myString, ref result);
                    //        if (!this.fdcposManager.tcpClientList.ContainsKey(FDCPOSClient.getClientID(sr.WorkstationID, sr.ApplicationSender)))
                    //            result = OverallResult.AuthentificationError;
                    //        if (sr != null && result == OverallResult.Success && extresult == OverallResult.Success)
                    //        {
                    //            fdcposManager.tcpClientList[FDCPOSClient.getClientID(sr.WorkstationID, sr.ApplicationSender)].heartbeat.ResetDisconnectionTimeout();
                    //        }
                    //    }
                }
                else if (requestType == "LogOn")
                {
                    ServiceRequestLogOn sr = Deserialize<ServiceRequestLogOn>(message, ref result);
                    if (sr != null)
                    {
                        requestId = sr.RequestIDNumber;

                        if (sr.POSdata.GetLength(0) == 0)
                            result = OverallResult.MissingMandatoryData;
                        else
                        {
                            int iResponsePort = Convert.ToInt32(sr.POSdata[0].ResponsePort);
                            if (iResponsePort == 0)
                                iResponsePort = this.IPPort;
                            int iUnsolicitedPort = Convert.ToInt32(sr.POSdata[0].UnsolicitedPort);
                            if (iUnsolicitedPort == 0)
                                iUnsolicitedPort = this.IPPort;
                            fdcSocketLogger.LogInformation(string.Format("Client with WorkstationId: {0}, ApplicationSender: {1}, InterfaceVersion: {2} from {3} is logging on",
                                sr.WorkstationID,
                                sr.ApplicationSender,
                                (sr.POSdata?.FirstOrDefault()?.interfaceVersion ?? ""),
                                ((IPEndPoint)(fdcClientTcpHandler.TcpClient.Client.RemoteEndPoint)).ToString()
                                ));
                            if (sr.POSdata[0].interfaceVersion != null)
                            {
                                //FDCPOSManager.tracer.WriteLine(string.Format("sr.POSdata[0].interfaceVersion='{0}'", sr.POSdata[0].interfaceVersion));
                                if (sr.POSdata[0].interfaceVersion == "00.07")
                                    FDCGlobal.ProtocolVersion = FDCVersion.V0007;
                                else if (sr.POSdata[0].interfaceVersion == "00.05")
                                    FDCGlobal.ProtocolVersion = FDCVersion.V0005;
                                else if (sr.POSdata[0].interfaceVersion == "00.03")
                                    FDCGlobal.ProtocolVersion = FDCVersion.V0003;
                                //FDCPOSManager.tracer.WriteLine(string.Format("interfaceVersion set"));

                            }
                            //FDCPOSManager.tracer.WriteLine(string.Format("this.fdcposManager.forecourtConfiguration={0}", this.fdcposManager.forecourtConfiguration));
                            //FDCPOSManager.tracer.WriteLine(string.Format("test={0}", sr.POSdata[0].ValidationInfo != null && (this.fdcposManager.forecourtConfiguration != "Q8-DENMARK" && this.fdcposManager.forecourtConfiguration != "WINCOR")));
                            if (sr.POSdata[0].ValidationInfo != null && (this.fdcPosManager.forecourtConfiguration != "Q8-DENMARK" && this.fdcPosManager.forecourtConfiguration != "WINCOR"))
                            {
                                string filename = "", version = "", ssigncheck = "", CRC = "", binaryCRC = "", versionCRC = "", addInfo = "";
                                string softsealfilename = "", softsealversion = "", binarysoftsealCRC = "", versionsoftsealCRC = "";
                                bool signaturecheck = false, softsealadded = false;
                                DESCrypter crypter = new DESCrypter();

                                try
                                {
                                    Monitor.Enter(fdcPosManager);
                                    foreach (byte[] validationInfoElem in sr.POSdata[0].ValidationInfo)
                                    {
                                        byte[] data = crypter.Decrypt(validationInfoElem);
                                        if (data != null && data.Length > 0)
                                        {
                                            signaturecheck = false;

                                            string s = System.Text.Encoding.UTF8.GetString(data, 0, data.GetLength(0));
                                            //FDCPOSManager.tracer.WriteLine(string.Format("validation string='{0}'", s));
                                            filename = s.Substring(0, s.IndexOf("###"));
                                            //FDCPOSManager.tracer.WriteLine(string.Format("filename='{0}'", filename));
                                            s = s.Substring(s.IndexOf("###") + 3);
                                            version = s.Substring(0, s.IndexOf("###"));
                                            //FDCPOSManager.tracer.WriteLine(string.Format("version='{0}'", version));
                                            s = s.Substring(s.IndexOf("###") + 3);
                                            ssigncheck = s.Substring(0, s.IndexOf("###"));
                                            //FDCPOSManager.tracer.WriteLine(string.Format("ssigncheck='{0}'", ssigncheck));
                                            signaturecheck = (ssigncheck == "1") ? true : false;
                                            s = s.Substring(s.IndexOf("###") + 3);
                                            CRC = s.Substring(0, s.IndexOf("###"));
                                            if (CRC.IndexOf("-") >= 0)
                                            {
                                                binaryCRC = CRC.Substring(0, CRC.IndexOf("-"));
                                                versionCRC = CRC.Substring(CRC.IndexOf("-") + 1);
                                            }
                                            else
                                                versionCRC = CRC;
                                            //FDCPOSManager.tracer.WriteLine(string.Format("binaryCRC='{0}', versionCRC'{1}'", binaryCRC, versionCRC));
                                            s = s.Substring(s.IndexOf("###") + 3);
                                            softsealfilename = s.Substring(0, s.IndexOf("###"));
                                            //FDCPOSManager.tracer.WriteLine(string.Format("softsealfilename='{0}'", softsealfilename));
                                            s = s.Substring(s.IndexOf("###") + 3);
                                            softsealversion = s.Substring(0, s.IndexOf("###"));
                                            //FDCPOSManager.tracer.WriteLine(string.Format("softsealversion='{0}'", softsealversion));
                                            s = s.Substring(s.IndexOf("###") + 3);
                                            if (s.IndexOf("###") == -1)
                                                CRC = s;
                                            else
                                            {
                                                CRC = s.Substring(0, s.IndexOf("###"));
                                                s = s.Substring(s.IndexOf("###") + 3);
                                                addInfo = s;
                                            }
                                            if (CRC.IndexOf("-") >= 0)
                                            {
                                                binarysoftsealCRC = CRC.Substring(0, CRC.IndexOf("-"));
                                                versionsoftsealCRC = CRC.Substring(CRC.IndexOf("-") + 1);
                                            }
                                            else
                                                versionsoftsealCRC = CRC;
                                            //FDCPOSManager.tracer.WriteLine(string.Format("binarysoftsealCRC='{0}', versionsoftsealCRC'{1}'", binarysoftsealCRC, versionsoftsealCRC));

                                            if (softsealfilename != "" && !softsealadded)
                                            {
                                                //FDCPOSManager.tracer.WriteLine(string.Format("validate add file='{0}', version={1}", softsealfilename, softsealversion));
                                                this.FdcPosInterface.ValidateSealAddReq(softsealfilename.Substring(softsealfilename.LastIndexOf('\\') + 1), softsealversion, (((FDCPOSInterfaceServerManager)this.fdcPosManager).certificate == certificateType.MID) ? binarysoftsealCRC : versionsoftsealCRC, "");
                                                softsealadded = true;
                                            }
                                            if (signaturecheck)
                                            {
                                                //FDCPOSManager.tracer.WriteLine(string.Format("validate add file='{0}', version={1}", filename, version));
                                                this.FdcPosInterface.ValidateSealAddReq(filename.Substring(filename.LastIndexOf('\\') + 1), version, (((FDCPOSInterfaceServerManager)this.fdcPosManager).certificate == certificateType.MID) ? binaryCRC : versionCRC, addInfo);
                                            }
                                            else
                                            {
                                                //FDCPOSManager.tracer.WriteLine(string.Format("signature failed file='{0}', version={1}", filename, version));
                                                result = OverallResult.AuthentificationError;
                                                break;
                                            }
                                        }
                                        else
                                        {
                                            //FDCPOSManager.tracer.WriteLine(string.Format("error decrypting"));
                                            result = OverallResult.AuthentificationError;
                                            break;
                                        }
                                    }
                                    if (result == OverallResult.Success)
                                    {
                                        if (!this.FdcPosInterface.ValidateSealEndReq(true))
                                        {
                                            //FDCPOSManager.tracer.WriteLine(string.Format("error on seal validation"));
                                            result = OverallResult.AuthentificationError;
                                        }
                                    }
                                    else
                                    {
                                        //FDCPOSManager.tracer.WriteLine(string.Format("reset seal validation info"));
                                        this.FdcPosInterface.ValidateSealEndReq(false);
                                    }
                                }
                                catch (Exception ex)
                                {
                                    //FDCPOSManager.tracer.WriteLine(string.Format("LogOn Validation Info Exception! " + ex.Message));
                                    result = OverallResult.AuthentificationError;
                                }
                                finally
                                {
                                    Monitor.Exit(fdcPosManager);
                                }
                            }
                            else
                            {
                                if (this.fdcPosManager.forecourtConfiguration != "Q8-DENMARK" && this.fdcPosManager.forecourtConfiguration != "WINCOR")
                                {
                                    fdcSocketLogger.LogInformation("configuration is not Q8 and is not WINCOR - AuthorizationInfo must not be null - AuthentificationError !");
                                    //FDCPOSManager.tracer.WriteLine(string.Format("configuration is not Q8 and is not WINCOR - AuthorizationInfo must not be null - AuthentificationError !"));
                                    result = OverallResult.AuthentificationError;
                                }
                            }

                            IPEndPoint endpoint = (IPEndPoint)(fdcClientTcpHandler.TcpClient.Client.RemoteEndPoint);
                            string sIPAddress = endpoint.Address.ToString();

                            if (result == OverallResult.Success && extresult == OverallResult.Success)
                            {
                                //FDCPOSManager.tracer.WriteLine(string.Format("PortA='{0}', PortB='{1}', PortC='{2}'",
                                //this.IPPort, iResponsePort, iUnsolicitedPort));
                                //fdcSocketLogger.LogInformation(string.Format("PortA='{0}', PortB='{1}', PortC='{2}', in Logon", this.IPPort, iResponsePort, iUnsolicitedPort));
                                Messages.HeartbeatCallback heartbeatCallback = new Messages.HeartbeatCallback(this.FdcPosInterface.messages.Heartbeat);
                                bool enteredmonitor = false;
                                try
                                {
                                    Monitor.Enter(fdcPosManager.fdcClientList);
                                    enteredmonitor = true;
                                    if (!fdcPosManager.fdcClientList.ContainsKey(FDCPOSClient.getClientID(sr.WorkstationID, sr.ApplicationSender)))
                                    {
                                        //FDCPOSManager.tracer.WriteLine(string.Format("Client not found - adding"));
                                        fdcSocketLogger.LogInformation("Client: " + FDCPOSClient.getClientID(sr.WorkstationID, sr.ApplicationSender)
                                            + " not found in TcpClientList("
                                            + (fdcPosManager.fdcClientList.Keys.Any() ?
                                                fdcPosManager.fdcClientList.Keys.Select(k => k ?? "null").Aggregate((n, acc) => n + ", " + acc)
                                                    : "Empty yet")
                                            + ") - will adding in, in LogOn");
                                        FDCPOSClient fdcposClient = null;
                                        string posInfo;
                                        if (sr.POSdata[0].posInfo != null) // && sr.POSdata[0].posInfo != "")
                                        {
                                            posInfo = UTF8Encoding.UTF8.GetString(sr.POSdata[0].posInfo, 0, sr.POSdata[0].posInfo.GetLength(0));
                                            POSType posType = FDCPOSClient.GetType(posInfo);
                                            if (posType == POSType.IXTerminal)
                                            {
                                                fdcposClient = new FDCPOSClientIX(fdcPosManager, heartbeatCallback, posInfo);
                                            }
                                            else if (posType == POSType.Generic)
                                            {
                                                fdcposClient = new FDCPOSClient(fdcPosManager, heartbeatCallback, this.fdcSocketLogger);
                                            }
                                        }
                                        else
                                            fdcposClient = new FDCPOSClient(fdcPosManager, heartbeatCallback, this.fdcSocketLogger);
                                        fdcposClient.workstationID = sr.WorkstationID;
                                        fdcposClient.applicationSender = sr.ApplicationSender;
                                        fdcposClient.sIPAddress = sIPAddress;
                                        fdcposClient.FdcClientTcpHandler = fdcClientTcpHandler;
                                        fdcClientTcpHandler.workstationID = sr.WorkstationID;
                                        fdcClientTcpHandler.applicationSender = sr.ApplicationSender;
                                        fdcPosManager.fdcClientList.Add(FDCPOSClient.getClientID(sr.WorkstationID, sr.ApplicationSender), fdcposClient);
                                        fdcSocketLogger.LogInformation("      Client: " + FDCPOSClient.getClientID(sr.WorkstationID, sr.ApplicationSender) + " is added in TcpClientList");
                                        Monitor.Exit(fdcPosManager.fdcClientList);
                                        enteredmonitor = false;
                                        this.FdcPosInterface.LogOnReq(sr.WorkstationID, sr.ApplicationSender, sr.RequestIDNumber, iResponsePort, iUnsolicitedPort, (int)(FDCGlobal.ProtocolVersion));
                                    }
                                    else if (!fdcPosManager.fdcClientList[FDCPOSClient.getClientID(sr.WorkstationID, sr.ApplicationSender)].logon &&
                                        fdcPosManager.fdcClientList[FDCPOSClient.getClientID(sr.WorkstationID, sr.ApplicationSender)].sIPAddress == sIPAddress)
                                    {
                                        //FDCPOSManager.tracer.WriteLine(string.Format("Client found but not logged - logging"));
                                        fdcSocketLogger.LogInformation("Client: " + FDCPOSClient.getClientID(sr.WorkstationID, sr.ApplicationSender) + " is found in TcpClientList but not logged on - will set to LoggedOn, in LogOn");
                                        FDCPOSClient fdcposClient = fdcPosManager.fdcClientList[FDCPOSClient.getClientID(sr.WorkstationID, sr.ApplicationSender)];
                                        fdcposClient.logon = true;
                                        fdcposClient.FdcClientTcpHandler = fdcClientTcpHandler;
                                        Monitor.Exit(fdcPosManager.fdcClientList);
                                        enteredmonitor = false;
                                        this.FdcPosInterface.LogOnReq(sr.WorkstationID, sr.ApplicationSender, sr.RequestIDNumber, iResponsePort, iUnsolicitedPort, (int)(FDCGlobal.ProtocolVersion));
                                    }
                                    else
                                    {
                                        //FDCPOSManager.tracer.WriteLine(string.Format("Client already logged (!?)"));
                                        fdcSocketLogger.LogInformation("Client: " + FDCPOSClient.getClientID(sr.WorkstationID, sr.ApplicationSender) + " already logged on, why log on again (!?), give it an Error, in LogOn");
                                        Monitor.Exit(fdcPosManager.fdcClientList);
                                        enteredmonitor = false;
                                        FDCPOSClient tempTCPClient = new FDCPOSClient(fdcPosManager, heartbeatCallback, this.fdcSocketLogger);
                                        tempTCPClient.sIPAddress = sIPAddress;
                                        tempTCPClient.FdcClientTcpHandler = fdcClientTcpHandler;
                                        this.FdcPosInterface.messages.LogOn(sr.WorkstationID, sr.ApplicationSender, sr.RequestIDNumber, iResponsePort, iUnsolicitedPort, (int)(FDCPOSLibrary.ErrorCode.ERRCD_NOPERM), Convert.ToString(FDCPOSLibrary.OverallResult.AuthentificationError), tempTCPClient);
                                    }
                                }
                                catch (Exception ex)
                                {
                                    fdcSocketLogger.LogError("LogOn Exceptioned: " + ex);
                                    if (enteredmonitor)
                                    {
                                        Monitor.Exit(fdcPosManager.fdcClientList);
                                    }
                                    //FDCPOSManager.tracer.WriteLine(string.Format("LogOn Exception! " + ex.Message));
                                    FDCPOSClient tempTCPClient = new FDCPOSClient(fdcPosManager, heartbeatCallback, this.fdcSocketLogger);
                                    tempTCPClient.sIPAddress = sIPAddress;
                                    tempTCPClient.FdcClientTcpHandler = fdcClientTcpHandler;
                                    this.FdcPosInterface.messages.LogOn(sr.WorkstationID, sr.ApplicationSender, sr.RequestIDNumber, iResponsePort, iUnsolicitedPort, (int)FDCPOSLibrary.ErrorCode.ERRCD_NOPERM, Convert.ToString(FDCPOSLibrary.OverallResult.AuthentificationError), tempTCPClient);
                                    return requestType;
                                }
                            }
                            else
                            {
                                //FDCPOSManager.tracer.WriteLine(string.Format("LogOn extresult={0}, result={1} ", extresult, result));
                                FDCPOSClient tempTCPClient = new FDCPOSClient(fdcPosManager, null, this.fdcSocketLogger);
                                tempTCPClient.sIPAddress = sIPAddress;
                                tempTCPClient.FdcClientTcpHandler = fdcClientTcpHandler;
                                this.FdcPosInterface.messages.LogOn(sr.WorkstationID, sr.ApplicationSender, sr.RequestIDNumber, iResponsePort, iUnsolicitedPort, (int)FDCPOSLibrary.ErrorCode.ERRCD_COMMERR, (result != OverallResult.Success) ? Convert.ToString(result) : Convert.ToString(extresult), tempTCPClient);
                                return requestType;
                            }
                        }
                    }
                }
                else if (requestType == "LogOff")
                {
                    ServiceRequestLogOff sr = Deserialize<ServiceRequestLogOff>(message, ref result);
                    if (sr != null)
                    {
                        requestId = sr.RequestIDNumber;
                        if (result == OverallResult.Success && extresult == OverallResult.Success)
                        {
                            FdcPosInterface.LogOffReq(sr.WorkstationID, sr.ApplicationSender, sr.RequestIDNumber);
                        }
                    }
                }
                else if (requestType == "VersionInfo")
                {
                    ServiceRequestVersionInfo sr = Deserialize<ServiceRequestVersionInfo>(message, ref result);
                    if (sr != null)
                    {
                        requestId = sr.RequestIDNumber;
                        if (result == OverallResult.Success && extresult == OverallResult.Success)
                        {
                            this.FdcPosInterface.VersionInfoReq(sr.WorkstationID, sr.ApplicationSender, sr.RequestIDNumber);
                        }
                    }
                }
                else if (requestType == "StartForecourt")
                {
                    ServiceRequestStartForecourt sr = Deserialize<ServiceRequestStartForecourt>(message, ref result);
                    if (sr != null)
                    {
                        requestId = sr.RequestIDNumber;
                        if (result == OverallResult.Success && extresult == OverallResult.Success)
                        {
                            this.FdcPosInterface.StartForecourtReq(sr.WorkstationID, sr.ApplicationSender, sr.RequestIDNumber);
                        }
                    }
                }
                else if (requestType == "StopForecourt")
                {
                    ServiceRequestStopForecourt sr = Deserialize<ServiceRequestStopForecourt>(message, ref result);
                    if (sr != null)
                    {
                        requestId = sr.RequestIDNumber;
                        if (result == OverallResult.Success && extresult == OverallResult.Success)
                        {
                            bool emergencyStop = (sr.POSdata[0].EmergencyStop != null && sr.POSdata[0].EmergencyStop.ToUpper() == "NO") ? emergencyStop = false : emergencyStop = true;
                            this.FdcPosInterface.StopForecourtReq(sr.WorkstationID, sr.ApplicationSender, sr.RequestIDNumber, emergencyStop);
                        }
                    }
                }
                else if (requestType == "GetCurrentFuellingStatus")
                {
                    ServiceRequestGetCurrentFuellingStatus sr = Deserialize<ServiceRequestGetCurrentFuellingStatus>(message, ref result);
                    if (sr != null)
                    {
                        requestId = sr.RequestIDNumber;
                        if (sr.POSdata.GetLength(0) == 0 || sr.POSdata[0].DeviceClass == null || sr.POSdata[0].DeviceClass.DeviceID == "")
                            result = OverallResult.MissingMandatoryData;
                        if (result == OverallResult.Success && extresult == OverallResult.Success)
                        {
                            this.FdcPosInterface.GetCurrentFuellingStatusReq(sr.WorkstationID, sr.ApplicationSender, sr.RequestIDNumber,
                                                                (sr.POSdata[0].DeviceClass.DeviceID == "*") ? -1 : Convert.ToInt32(sr.POSdata[0].DeviceClass.DeviceID));
                        }
                    }
                }
                else if (requestType == "GetFuelPointTotals")
                {
                    ServiceRequestGetFuelPointTotals sr = Deserialize<ServiceRequestGetFuelPointTotals>(message, ref result);
                    if (sr != null)
                    {
                        requestId = sr.RequestIDNumber;
                        if (sr.POSdata.GetLength(0) == 0 || sr.POSdata[0].DeviceClass == null || sr.POSdata[0].DeviceClass.DeviceID == "" || sr.POSdata[0].DeviceClass.NozzleNo == "")
                            result = OverallResult.MissingMandatoryData;
                        if (result == OverallResult.Success && extresult == OverallResult.Success)
                        {
                            this.FdcPosInterface.GetFuelPointTotalsReq(sr.WorkstationID, sr.ApplicationSender, sr.RequestIDNumber,
                                                                (sr.POSdata[0].DeviceClass.DeviceID == "*") ? -1 : Convert.ToInt32(sr.POSdata[0].DeviceClass.DeviceID),
                                                                (sr.POSdata[0].DeviceClass.NozzleNo == "*") ? -1 : Convert.ToInt32(sr.POSdata[0].DeviceClass.NozzleNo));
                        }
                    }
                }
                else if (requestType == "GetTotals")
                {
                    ServiceRequestGetTotals sr = Deserialize<ServiceRequestGetTotals>(message, ref result);
                    if (sr != null)
                    {
                        requestId = sr.RequestIDNumber;
                        if (sr.POSdata.GetLength(0) == 0 || sr.POSdata[0].DeviceClass == null || sr.POSdata[0].DeviceClass.DeviceID == "" || sr.POSdata[0].DeviceClass.NozzleNo == "")
                            result = OverallResult.MissingMandatoryData;
                        if (result == OverallResult.Success && extresult == OverallResult.Success)
                        {
                            this.FdcPosInterface.GetFuelPointTotalsReq(sr.WorkstationID, sr.ApplicationSender, sr.RequestIDNumber,
                                                                (sr.POSdata[0].DeviceClass.DeviceID == "*") ? -1 : Convert.ToInt32(sr.POSdata[0].DeviceClass.DeviceID),
                                                                (sr.POSdata[0].DeviceClass.NozzleNo == "*") ? -1 : Convert.ToInt32(sr.POSdata[0].DeviceClass.NozzleNo));
                        }
                    }
                }
                else if (requestType == "GetDeviceState")
                {
                    ServiceRequestGetDeviceState sr = Deserialize<ServiceRequestGetDeviceState>(message, ref result);
                    if (sr != null)
                    {
                        requestId = sr.RequestIDNumber;
                        if (sr.POSdata.GetLength(0) == 0 || sr.POSdata[0].DeviceClass == null || sr.POSdata[0].DeviceClass.DeviceID == "")
                            result = OverallResult.MissingMandatoryData;
                        if (result == OverallResult.Success && extresult == OverallResult.Success)
                        {
                            this.FdcPosInterface.GetDeviceStateReq(sr.WorkstationID, sr.ApplicationSender, sr.RequestIDNumber,
                                                                sr.POSdata[0].DeviceClass.Type,
                                                                (sr.POSdata[0].DeviceClass.DeviceID == "*") ? -1 : Convert.ToInt32(sr.POSdata[0].DeviceClass.DeviceID));
                        }
                    }
                }
                else if (requestType == "GetFPState")
                {
                    ServiceRequestGetFPState sr = Deserialize<ServiceRequestGetFPState>(message, ref result);
                    if (sr != null)
                    {
                        requestId = sr.RequestIDNumber;
                        if (sr.POSdata.GetLength(0) == 0 || sr.POSdata[0].DeviceClass == null || sr.POSdata[0].DeviceClass.DeviceID == "")
                            result = OverallResult.MissingMandatoryData;
                        if (result == OverallResult.Success && extresult == OverallResult.Success)
                        {
                            this.FdcPosInterface.GetDeviceStateReq(sr.WorkstationID, sr.ApplicationSender, sr.RequestIDNumber,
                                                                sr.POSdata[0].DeviceClass.Type,
                                                                (sr.POSdata[0].DeviceClass.DeviceID == "*") ? -1 : Convert.ToInt32(sr.POSdata[0].DeviceClass.DeviceID));
                        }
                    }
                }
                else if (requestType == "TerminateFuelling")
                {
                    ServiceRequestTerminateFuelling sr = Deserialize<ServiceRequestTerminateFuelling>(message, ref result);
                    if (sr != null)
                    {
                        requestId = sr.RequestIDNumber;
                        if (sr.POSdata.GetLength(0) == 0 || sr.POSdata[0].DeviceClass == null || sr.POSdata[0].DeviceClass.DeviceID == "")
                            result = OverallResult.MissingMandatoryData;
                        if (result == OverallResult.Success && extresult == OverallResult.Success)
                        {
                            this.FdcPosInterface.TerminateFuellingReq(sr.WorkstationID, sr.ApplicationSender, sr.RequestIDNumber,
                                                                (sr.POSdata[0].DeviceClass.DeviceID == "*") ? -1 : Convert.ToInt32(sr.POSdata[0].DeviceClass.DeviceID));
                        }
                    }
                }
                else if (requestType == "AuthoriseFuelPoint")
                {
                    ServiceRequestAuthoriseFuelPoint sr = Deserialize<ServiceRequestAuthoriseFuelPoint>(message, ref result);
                    if (sr != null)
                    {
                        requestId = sr.RequestIDNumber;
                        if (sr.POSdata.GetLength(0) == 0)
                            result = OverallResult.MissingMandatoryData;
                        if (result == OverallResult.Success && extresult == OverallResult.Success)
                        {
                            string products = "";
                            int mode = -1;
                            if (sr.POSdata[0].DeviceClass == null || sr.POSdata[0].DeviceClass.DeviceID == "")
                            {
                                //FDCPOSManager.tracer.WriteLine("'device' missing");
                                result = OverallResult.MissingMandatoryData;
                            }
                            else
                            {
                                //Decimal MaxTrxVolume = 0, MaxTrxAmount = 0;
                                ////FDCPOSManager.tracer.WriteLine(string.Format("products.GetLength={0}", sr.POSdata[0].DeviceClass.products.GetLength(0)));
                                //FDCPOSManager.tracer.WriteLine(string.Format("fuelmode={0}, mode={1}", sr.POSdata[0].DeviceClass.FuelMode, (sr.POSdata[0].DeviceClass.FuelMode != null) ? sr.POSdata[0].DeviceClass.FuelMode.ModeNo : null));
                                if (sr.POSdata[0].DeviceClass.FuelMode != null && sr.POSdata[0].DeviceClass.FuelMode.ModeNo != null && sr.POSdata[0].DeviceClass.FuelMode.ModeNo != "")
                                    mode = Convert.ToInt32(sr.POSdata[0].DeviceClass.FuelMode.ModeNo);
                                if (FDCGlobal.ProtocolVersion == FDCVersion.V0003)
                                {
                                    if (sr.POSdata[0].DeviceClass.Products != null && sr.POSdata[0].DeviceClass.Products.ProductNo != null &&
                                        sr.POSdata[0].DeviceClass.Products.ProductNo.GetLength(0) > 0)
                                    {
                                        foreach (string product in sr.POSdata[0].DeviceClass.Products.ProductNo)
                                        {
                                            //FDCPOSManager.tracer.WriteLine(string.Format("ProductNo='{0}', products='{0}'", product, products));
                                            ////FDCPOSManager.tracer.WriteLine(string.Format("ProductNo='{0}', products='{0}'", product.ProductNo, products));
                                            products += product + ";";
                                        }
                                    }
                                }
                                else if (FDCGlobal.ProtocolVersion == FDCVersion.V0005)
                                {
                                    if (sr.POSdata[0].DeviceClass.ReleasedProducts != null && sr.POSdata[0].DeviceClass.ReleasedProducts.ProductNo != null &&
                                        sr.POSdata[0].DeviceClass.ReleasedProducts.ProductNo.GetLength(0) > 0)
                                    {
                                        foreach (string product in sr.POSdata[0].DeviceClass.ReleasedProducts.ProductNo)
                                        {
                                            //FDCPOSManager.tracer.WriteLine(string.Format("ProductNo='{0}'", product));
                                            products += product + ";";
                                        }
                                    }
                                }
                                else
                                {
                                    if (sr.POSdata[0].DeviceClass.ReleasedProducts != null && sr.POSdata[0].DeviceClass.ReleasedProducts.Product != null &&
                                        sr.POSdata[0].DeviceClass.ReleasedProducts.Product.GetLength(0) > 0)
                                    {
                                        foreach (ProductElementClass product in sr.POSdata[0].DeviceClass.ReleasedProducts.Product)
                                        {
                                            //FDCPOSManager.tracer.WriteLine(string.Format("ProductNo='{0}'", product.ProductNo, products));
                                            products += product.ProductNo + ";";
                                        }
                                    }
                                }

                                this.FdcPosInterface.AuthoriseFuelPointReq(sr.WorkstationID,
                                    sr.ApplicationSender,
                                    sr.RequestIDNumber,
                                    (sr.POSdata[0].DeviceClass.ReleaseToken != null) ? sr.POSdata[0].DeviceClass.ReleaseToken : "",
                                    (sr.POSdata[0].DeviceClass.FuellingType == "") ? 0 : Convert.ToInt32(sr.POSdata[0].DeviceClass.FuellingType),
                                    (sr.POSdata[0].DeviceClass.DeviceID == "*") ? -1 : Convert.ToInt32(sr.POSdata[0].DeviceClass.DeviceID),
                                    (sr.POSdata[0].DeviceClass.ReservingDeviceId == "") ? 0 : Convert.ToInt32(sr.POSdata[0].DeviceClass.ReservingDeviceId),
                                    FDCConvert.ToDecimal(sr.POSdata[0].DeviceClass.MaxTrxAmount), FDCConvert.ToDecimal(sr.POSdata[0].DeviceClass.MaxTrxVolume),
                                    products, mode,
                                    (sr.POSdata[0].DeviceClass.LockFuelSaleTrx != null && sr.POSdata[0].DeviceClass.LockFuelSaleTrx.ToUpper() == "TRUE") ? true : false, sr.POSdata[0].DeviceClass.PayType);
                            }
                        }
                    }
                }
                else if (requestType == "ChangeFuelMode")
                {
                    ServiceRequestChangeFuelMode sr = Deserialize<ServiceRequestChangeFuelMode>(message, ref result);
                    string mode = "";
                    if (sr != null)
                    {
                        requestId = sr.RequestIDNumber;
                        if (sr.POSdata.GetLength(0) == 0 || sr.POSdata[0].DeviceClass == null)
                            result = OverallResult.MissingMandatoryData;
                        if (result == OverallResult.Success && extresult == OverallResult.Success)
                        {
                            if (sr.POSdata[0].DeviceClass.Length > 1)
                            {
                                foreach (ServiceRequestDeviceClassChangeFuelMode deviceClass in sr.POSdata[0].DeviceClass)
                                {
                                    mode = "";
                                    if (deviceClass != null)
                                    {
                                        if (FDCGlobal.ProtocolVersion == FDCVersion.V0003)
                                        {
                                            if (deviceClass.ModeNo != null) mode = deviceClass.ModeNo;
                                        }
                                        else
                                        {
                                            if (deviceClass.FuelMode != null && deviceClass.FuelMode.ModeNo != null) mode = deviceClass.FuelMode.ModeNo;
                                        }
                                        //FDCPOSManager.tracer.WriteLine(string.Format("DeviceID={0}, ModeNo={1}", deviceClass.DeviceID, mode));
                                        if (mode != "")
                                            this.FdcPosInterface.ChangeFuelModeAddReq(sr.WorkstationID, sr.ApplicationSender, sr.RequestIDNumber, deviceClass.Type,
                                                                    (deviceClass.DeviceID == "*") ? -1 : Convert.ToInt32(deviceClass.DeviceID), Convert.ToInt32(mode));
                                    }
                                }
                                this.FdcPosInterface.ChangeFuelModeEndReq(sr.WorkstationID, sr.ApplicationSender, sr.RequestIDNumber);
                            }
                            else
                            {
                                if (FDCGlobal.ProtocolVersion == FDCVersion.V0003)
                                {
                                    if (sr.POSdata[0].DeviceClass[0].ModeNo != null) mode = sr.POSdata[0].DeviceClass[0].ModeNo;
                                }
                                else
                                {
                                    if (sr.POSdata[0].DeviceClass[0].FuelMode != null && sr.POSdata[0].DeviceClass[0].FuelMode.ModeNo != null) mode = sr.POSdata[0].DeviceClass[0].FuelMode.ModeNo;
                                }
                                if (mode == "")
                                    result = OverallResult.MissingMandatoryData;
                                this.FdcPosInterface.ChangeFuelModeReq(sr.WorkstationID, sr.ApplicationSender, sr.RequestIDNumber, sr.POSdata[0].DeviceClass[0].Type,
                                                                    (sr.POSdata[0].DeviceClass[0].DeviceID == "*") ? -1 : Convert.ToInt32(sr.POSdata[0].DeviceClass[0].DeviceID),
                                                                    Convert.ToInt32(mode));
                            }
                        }
                    }
                }
                else if (requestType == "ChangeFuelPrice")
                {
                    ServiceRequestChangeFuelPrice sr = Deserialize<ServiceRequestChangeFuelPrice>(message, ref result);
                    if (sr != null)
                    {
                        requestId = sr.RequestIDNumber;
                        if (sr.POSdata.GetLength(0) == 0 || sr.POSdata[0].Product == null)
                            result = OverallResult.MissingMandatoryData;
                        //FDCPOSManager.tracer.WriteLineIf(FDCPOSManager.tracer.CheckTraceLevel(3), string.Format("result=" + result));
                        if (result == OverallResult.Success && extresult == OverallResult.Success)
                        {
                            string overallRes = OverallResult.Success.ToString();
                            if (sr.POSdata[0].Product != null)
                            {
                                string formattedString = "";
                                //double oldPrice;
                                string sModeNo = "", sPriceNew = "", effectiveDateTime = "";
                                foreach (ServiceRequestProductChangeFuelPrice product in sr.POSdata[0].Product)
                                {
                                    if (product == null) continue;
                                    sModeNo = "";
                                    sPriceNew = "";
                                    effectiveDateTime = "";
                                    if (FDCGlobal.ProtocolVersion == FDCVersion.V0003)
                                    {
                                        sModeNo = (product.ModeNo != null) ? product.ModeNo : "";
                                        sPriceNew = (product.PriceNew != null) ? product.PriceNew : "";
                                        effectiveDateTime = (product.EffectiveDateTime != null) ? product.EffectiveDateTime : "";

                                        string localresult = OverallResult.Success.ToString();
                                        if (product.ProductNo != null && product.ProductNo != "" && sPriceNew != "" && sModeNo != "")
                                        {
                                            //localresult = this.FdcPosInterface.ChangeFuelPriceAddReq(sr.WorkstationID, sr.ApplicationSender, sr.RequestIDNumber, Convert.ToInt32(product.ProductNo), FDCConvert.ToDecimal(product.PriceNew), Convert.ToInt32(product.ModeNo), out oldPrice);
                                            formattedString = formattedString + product.ProductNo + ";" + sPriceNew + ";" + sModeNo + ";" + effectiveDateTime + "!";
                                        }
                                        else
                                        {
                                            localresult = OverallResult.Failure.ToString();
                                        }
                                        if (localresult != OverallResult.Success.ToString() && overallRes == OverallResult.Success.ToString())
                                            overallRes = OverallResult.Failure.ToString();
                                        else if (localresult == OverallResult.Success.ToString() && overallRes == OverallResult.Failure.ToString())
                                            overallRes = OverallResult.PartialFailure.ToString();
                                        //FDCPOSManager.tracer.WriteLine(string.Format("localresult={0}, overallRes={1}", localresult, overallRes));
                                        //this.FdcPosInterface.messages.ChangeFuelPriceAdd(sr.WorkstationID, sr.ApplicationSender, sr.RequestIDNumber, Convert.ToInt32(product.ProductNo), FDCConvert.ToDecimal(product.PriceNew), Convert.ToInt32(product.ModeNo), Convert.ToDecimal(oldPrice));
                                    }
                                    else
                                    {
                                        if (product.FuelMode != null)
                                        {
                                            /* the Schema said the FuleMode only can contain a single fule price change item!!!!!!!!!*/
                                            foreach (ServiceRequestFuelModeChangeFuelPrice fuelMode in product.FuelMode)
                                            {
                                                if (fuelMode == null) continue;
                                                sModeNo = (fuelMode.ModeNo != null) ? fuelMode.ModeNo : "";
                                                sPriceNew = (fuelMode.PriceNew != null) ? fuelMode.PriceNew : "";
                                                effectiveDateTime = (fuelMode.EffectiveDateTime != null) ? fuelMode.EffectiveDateTime : "";

                                                string localresult = OverallResult.Success.ToString();
                                                if (product.ProductNo != null && product.ProductNo != "" && sPriceNew != "" && sModeNo != "")
                                                {
                                                    //localresult = this.FdcPosInterface.ChangeFuelPriceAddReq(sr.WorkstationID, sr.ApplicationSender, sr.RequestIDNumber, Convert.ToInt32(product.ProductNo), FDCConvert.ToDecimal(product.PriceNew), Convert.ToInt32(product.ModeNo), out oldPrice);
                                                    formattedString = formattedString + product.ProductNo + ";" + sPriceNew + ";" + sModeNo + ";" + effectiveDateTime + "!";
                                                }
                                                else
                                                {
                                                    localresult = OverallResult.Failure.ToString();
                                                }
                                                if (localresult != OverallResult.Success.ToString() && overallRes == OverallResult.Success.ToString())
                                                    overallRes = OverallResult.Failure.ToString();
                                                else if (localresult == OverallResult.Success.ToString() && overallRes == OverallResult.Failure.ToString())
                                                    overallRes = OverallResult.PartialFailure.ToString();
                                                //FDCPOSManager.tracer.WriteLine(string.Format("localresult={0}, overallRes={1}, product.ProductNo={2}, fuelMode.PriceNew={3}, fuelMode.ModeNo={4}", localresult, overallRes, product.ProductNo, fuelMode.PriceNew, fuelMode.ModeNo));
                                                //this.FdcPosInterface.messages.ChangeFuelPriceAdd(sr.WorkstationID, sr.ApplicationSender, sr.RequestIDNumber, Convert.ToInt32(product.ProductNo), FDCConvert.ToDecimal(product.PriceNew), Convert.ToInt32(product.ModeNo), Convert.ToDecimal(oldPrice));
                                            }
                                        }
                                    }
                                }
                                //this.FdcPosInterface.ChangeFuelPriceEndReq(sr.WorkstationID, sr.ApplicationSender, sr.RequestIDNumber);
                                string outresult = this.FdcPosInterface.ChangeFuelPriceInStringReq(sr.WorkstationID, sr.ApplicationSender, sr.RequestIDNumber, formattedString);
                                if (string.IsNullOrEmpty(outresult)) overallRes = OverallResult.Failure.ToString();
                                string item, sProd, sPriceOld;
                                while (outresult != "")
                                {
                                    if (outresult.IndexOf('!') >= 0)
                                    {
                                        item = outresult.Substring(0, outresult.IndexOf('!'));

                                        sProd = item.Substring(0, item.IndexOf(';'));
                                        item = item.Substring(item.IndexOf(';') + 1);
                                        sPriceNew = item.Substring(0, item.IndexOf(';'));
                                        item = item.Substring(item.IndexOf(';') + 1);
                                        sModeNo = item.Substring(0, item.IndexOf(';'));
                                        item = item.Substring(item.IndexOf(';') + 1);
                                        sPriceOld = item.Substring(0, item.IndexOf(';'));
                                        effectiveDateTime = item.Substring(item.IndexOf(';') + 1);

                                        outresult = outresult.Substring(outresult.IndexOf('!') + 1);

                                        // pricenew and priceold always is formatted with '.' as decimal separator
                                        sPriceNew = sPriceNew.Replace(".", FDCConvert.DecimalSeparator);
                                        sPriceOld = sPriceOld.Replace(".", FDCConvert.DecimalSeparator);
                                        Decimal pricenew = FDCConvert.ToDecimal(sPriceNew), priceold = FDCConvert.ToDecimal(sPriceOld);
                                        //FDCPOSManager.tracer.WriteLine(string.Format("prod={0}, mode={1}, newprice={2}, effectiveDateTime={3}, oldprice={4}", sProd, sModeNo, sPriceNew, effectiveDateTime, sPriceOld));

                                        this.FdcPosInterface.messages.ChangeFuelPriceAdd(sr.WorkstationID, sr.ApplicationSender, sr.RequestIDNumber, Convert.ToInt32(sProd), pricenew, Convert.ToInt32(sModeNo), effectiveDateTime, priceold);
                                    }
                                }
                            }
                            else
                                overallRes = OverallResult.MissingMandatoryData.ToString();
                            this.FdcPosInterface.messages.ChangeFuelPriceSend(sr.WorkstationID, sr.ApplicationSender, sr.RequestIDNumber, (int)ErrorCode.ERRCD_OK, overallRes);
                        }
                    }
                }
                else if (requestType == "LockFuelSaleTrx")
                {
                    ServiceRequestLockFuelSaleTrx sr = Deserialize<ServiceRequestLockFuelSaleTrx>(message, ref result);
                    if (sr != null)
                    {
                        string transactionNo = (sr.POSdata[0].DeviceClass.TransactionNo != null) ? sr.POSdata[0].DeviceClass.TransactionNo : ((sr.POSdata[0].DeviceClass.TransactionSeqNo != null) ? sr.POSdata[0].DeviceClass.TransactionSeqNo : "");
                        string releaseToken = (sr.POSdata[0].DeviceClass.ReleaseToken != null) ? sr.POSdata[0].DeviceClass.ReleaseToken : "";
                        requestId = sr.RequestIDNumber;
                        if (sr.POSdata.GetLength(0) == 0 || sr.POSdata[0].DeviceClass == null || sr.POSdata[0].DeviceClass.DeviceID == "" || transactionNo == "")
                            result = OverallResult.MissingMandatoryData;
                        if (result == OverallResult.Success && extresult == OverallResult.Success)
                        {
                            this.FdcPosInterface.LockFuelSaleTrxReq(sr.WorkstationID, sr.ApplicationSender, sr.RequestIDNumber,
                                                                (sr.POSdata[0].DeviceClass.DeviceID == "*") ? -1 : Convert.ToInt32(sr.POSdata[0].DeviceClass.DeviceID),
                                                                Convert.ToInt32(transactionNo), releaseToken);
                        }
                    }
                }
                else if (requestType == "UnlockFuelSaleTrx")
                {
                    ServiceRequestUnlockFuelSaleTrx sr = Deserialize<ServiceRequestUnlockFuelSaleTrx>(message, ref result);
                    if (sr != null)
                    {
                        string transactionNo = (sr.POSdata[0].DeviceClass.TransactionNo != null) ? sr.POSdata[0].DeviceClass.TransactionNo : ((sr.POSdata[0].DeviceClass.TransactionSeqNo != null) ? sr.POSdata[0].DeviceClass.TransactionSeqNo : "");
                        string releaseToken = (sr.POSdata[0].DeviceClass.ReleaseToken != null) ? sr.POSdata[0].DeviceClass.ReleaseToken : "";
                        requestId = sr.RequestIDNumber;
                        if (sr.POSdata.GetLength(0) == 0 || sr.POSdata[0].DeviceClass == null || sr.POSdata[0].DeviceClass.DeviceID == "" || transactionNo == "")
                            result = OverallResult.MissingMandatoryData;
                        if (result == OverallResult.Success && extresult == OverallResult.Success)
                        {
                            this.FdcPosInterface.UnlockFuelSaleTrxReq(sr.WorkstationID, sr.ApplicationSender, sr.RequestIDNumber,
                                                                (sr.POSdata[0].DeviceClass.DeviceID == "*") ? -1 : Convert.ToInt32(sr.POSdata[0].DeviceClass.DeviceID),
                                                                Convert.ToInt32(transactionNo), releaseToken);
                        }
                    }
                }
                else if (requestType == "ClearFuelSaleTrx")
                {
                    ServiceRequestClearFuelSaleTrx sr = Deserialize<ServiceRequestClearFuelSaleTrx>(message, ref result);
                    if (sr != null)
                    {
                        string transactionNo = (sr.POSdata[0].DeviceClass.TransactionNo != null) ? sr.POSdata[0].DeviceClass.TransactionNo : ((sr.POSdata[0].DeviceClass.TransactionSeqNo != null) ? sr.POSdata[0].DeviceClass.TransactionSeqNo : "");
                        string releaseToken = (sr.POSdata[0].DeviceClass.ReleaseToken != null) ? sr.POSdata[0].DeviceClass.ReleaseToken : "";
                        requestId = sr.RequestIDNumber;
                        if (sr.POSdata.GetLength(0) == 0 || sr.POSdata[0].DeviceClass == null || sr.POSdata[0].DeviceClass.DeviceID == "" || transactionNo == "")
                            result = OverallResult.MissingMandatoryData;
                        if (result == OverallResult.Success && extresult == OverallResult.Success)
                        {
                            this.FdcPosInterface.ClearFuelSaleTrxReq(sr.WorkstationID, sr.ApplicationSender, sr.RequestIDNumber,
                                                                (sr.POSdata[0].DeviceClass.DeviceID == "*") ? -1 : Convert.ToInt32(sr.POSdata[0].DeviceClass.DeviceID),
                                                                Convert.ToInt32(transactionNo), releaseToken);
                        }
                    }
                }
                else if (requestType == "GetAvailableFuelSaleTrxs")
                {
                    ServiceRequestGetAvailableFuelSaleTrxs sr = Deserialize<ServiceRequestGetAvailableFuelSaleTrxs>(message, ref result);
                    if (sr != null)
                    {
                        requestId = sr.RequestIDNumber;
                        if (sr.POSdata.GetLength(0) == 0 || sr.POSdata[0].DeviceClass == null || sr.POSdata[0].DeviceClass.DeviceID == "")
                            result = OverallResult.MissingMandatoryData;
                        if (result == OverallResult.Success && extresult == OverallResult.Success)
                        {
                            this.FdcPosInterface.GetAvailableFuelSaleTrxsReq(sr.WorkstationID, sr.ApplicationSender, sr.RequestIDNumber,
                                                                (sr.POSdata[0].DeviceClass.DeviceID == "*") ? -1 : Convert.ToInt32(sr.POSdata[0].DeviceClass.DeviceID));
                        }
                    }
                }
                else if (requestType == "GetFuelSaleTrxDetails")
                {
                    ServiceRequestGetFuelSaleTrxDetails sr = Deserialize<ServiceRequestGetFuelSaleTrxDetails>(message, ref result);
                    if (sr != null)
                    {
                        string transactionNo = (sr.POSdata[0].DeviceClass.TransactionNo != null) ? sr.POSdata[0].DeviceClass.TransactionNo : ((sr.POSdata[0].DeviceClass.TransactionSeqNo != null) ? sr.POSdata[0].DeviceClass.TransactionSeqNo : "");
                        string releaseToken = (sr.POSdata[0].DeviceClass.ReleaseToken != null) ? sr.POSdata[0].DeviceClass.ReleaseToken : "";
                        requestId = sr.RequestIDNumber;
                        if (sr.POSdata.GetLength(0) == 0 || sr.POSdata[0].DeviceClass == null || sr.POSdata[0].DeviceClass.DeviceID == "" || (transactionNo == "" && releaseToken == ""))
                            result = OverallResult.MissingMandatoryData;
                        if (result == OverallResult.Success && extresult == OverallResult.Success)
                        {
                            this.FdcPosInterface.GetFuelSaleTrxDetailsReq(sr.WorkstationID, sr.ApplicationSender, sr.RequestIDNumber,
                                                                (sr.POSdata[0].DeviceClass.DeviceID == "*") ? -1 : Convert.ToInt32(sr.POSdata[0].DeviceClass.DeviceID),
                                                                (transactionNo == "*") ? -1 : Convert.ToInt32(transactionNo),
                                                                releaseToken);
                        }
                    }
                }
                else if (requestType == "GetProductTable")
                {
                    ServiceRequestGetProductTable sr = Deserialize<ServiceRequestGetProductTable>(message, ref result);
                    if (sr != null)
                    {
                        requestId = sr.RequestIDNumber;
                        if (result == OverallResult.Success && extresult == OverallResult.Success)
                        {
                            this.FdcPosInterface.GetProductTableReq(sr.WorkstationID, sr.ApplicationSender, sr.RequestIDNumber);
                        }
                    }
                }
                else if (requestType == "GetModeTable")
                {
                    ServiceRequestGetModeTable sr = Deserialize<ServiceRequestGetModeTable>(message, ref result);
                    if (sr != null)
                    {
                        requestId = sr.RequestIDNumber;
                        if (result == OverallResult.Success && extresult == OverallResult.Success)
                        {
                            this.FdcPosInterface.GetModeTableReq(sr.WorkstationID, sr.ApplicationSender, sr.RequestIDNumber);
                        }
                    }
                }
                else if (requestType == "GetFuelMode")
                {
                    ServiceRequestGetFuelMode sr = Deserialize<ServiceRequestGetFuelMode>(message, ref result);
                    if (sr != null)
                    {
                        requestId = sr.RequestIDNumber;
                        if (sr.POSdata.GetLength(0) == 0 || sr.POSdata[0].DeviceClass == null || sr.POSdata[0].DeviceClass.DeviceID == "")
                            result = OverallResult.MissingMandatoryData;
                        if (result == OverallResult.Success && extresult == OverallResult.Success)
                        {
                            this.FdcPosInterface.GetFuelModeReq(sr.WorkstationID, sr.ApplicationSender, sr.RequestIDNumber, sr.POSdata[0].DeviceClass.Type,
                                                                (sr.POSdata[0].DeviceClass.DeviceID == "*") ? -1 : Convert.ToInt32(sr.POSdata[0].DeviceClass.DeviceID));
                        }
                    }
                }
                else if (requestType == "GetConfiguration")
                {
                    Messages.bWholeConfiguration = true;
                    ServiceRequestGetConfiguration sr = Deserialize<ServiceRequestGetConfiguration>(message, ref result);
                    if (sr != null)
                    {
                        requestId = sr.RequestIDNumber;
                        if (result == OverallResult.Success && extresult == OverallResult.Success)
                        {
                            this.FdcPosInterface.GetConfigurationReq(sr.WorkstationID, sr.ApplicationSender, sr.RequestIDNumber, "");
                        }
                    }
                }
                else if (requestType == "GetDSPConfiguration")
                {
                    Messages.bWholeConfiguration = false;
                    ServiceRequestGetDSPConfiguration sr = Deserialize<ServiceRequestGetDSPConfiguration>(message, ref result);
                    if (sr != null)
                    {
                        requestId = sr.RequestIDNumber;
                        if (result == OverallResult.Success && extresult == OverallResult.Success)
                        {
                            this.FdcPosInterface.GetConfigurationReq(sr.WorkstationID, sr.ApplicationSender, sr.RequestIDNumber, DeviceType.DT_FuelDispenser);
                        }
                    }
                }
                else if (requestType == "GetTLGConfiguration")
                {
                    Messages.bWholeConfiguration = false;
                    ServiceRequestGetTLGConfiguration sr = Deserialize<ServiceRequestGetTLGConfiguration>(message, ref result);
                    if (sr != null)
                    {
                        requestId = sr.RequestIDNumber;
                        if (result == OverallResult.Success && extresult == OverallResult.Success)
                        {
                            this.FdcPosInterface.GetConfigurationReq(sr.WorkstationID, sr.ApplicationSender, sr.RequestIDNumber, DeviceType.DT_TankLevelGauge);
                        }
                    }
                }
                else if (requestType == "GetPPConfiguration")
                {
                    Messages.bWholeConfiguration = false;
                    ServiceRequestGetPPConfiguration sr = Deserialize<ServiceRequestGetPPConfiguration>(message, ref result);
                    if (sr != null)
                    {
                        requestId = sr.RequestIDNumber;
                        if (result == OverallResult.Success && extresult == OverallResult.Success)
                        {
                            this.FdcPosInterface.GetConfigurationReq(sr.WorkstationID, sr.ApplicationSender, sr.RequestIDNumber, DeviceType.DT_PricePole);
                        }
                    }
                }
                else if (requestType == "SetConfiguration")
                {
                    ServiceRequestSetConfiguration sr = Deserialize<ServiceRequestSetConfiguration>(message, ref result);
                    if (sr != null)
                    {
                        requestId = sr.RequestIDNumber;
                        if (result == OverallResult.Success && extresult == OverallResult.Success)
                        {
                            this.FdcPosInterface.SetConfigurationReq(sr);
                        }
                    }
                }
                else if (requestType == "LockNozzle")
                {
                    ServiceRequestLockNozzle sr = Deserialize<ServiceRequestLockNozzle>(message, ref result);
                    if (sr != null)
                    {
                        requestId = sr.RequestIDNumber;
                        if (sr.POSdata.GetLength(0) == 0 || sr.POSdata[0].DeviceClass == null || sr.POSdata[0].DeviceClass.DeviceID == "" ||
                            sr.POSdata[0].DeviceClass.NozzleNo == "")
                            result = OverallResult.MissingMandatoryData;
                        if (result == OverallResult.Success && extresult == OverallResult.Success)
                        {
                            this.FdcPosInterface.LockNozzleReq(sr.WorkstationID, sr.ApplicationSender, sr.RequestIDNumber,
                                                                Convert.ToInt32(sr.POSdata[0].DeviceClass.DeviceID),
                                                                (sr.POSdata[0].DeviceClass.NozzleNo == "*") ? -1 : Convert.ToInt32(sr.POSdata[0].DeviceClass.NozzleNo));
                        }
                    }
                }
                else if (requestType == "UnlockNozzle")
                {
                    ServiceRequestUnlockNozzle sr = Deserialize<ServiceRequestUnlockNozzle>(message, ref result);
                    if (sr != null)
                    {
                        requestId = sr.RequestIDNumber;
                        if (sr.POSdata.GetLength(0) == 0 || sr.POSdata[0].DeviceClass == null || sr.POSdata[0].DeviceClass.DeviceID == "" ||
                            sr.POSdata[0].DeviceClass.NozzleNo == "")
                            result = OverallResult.MissingMandatoryData;
                        if (result == OverallResult.Success && extresult == OverallResult.Success)
                        {
                            this.FdcPosInterface.UnlockNozzleReq(sr.WorkstationID, sr.ApplicationSender, sr.RequestIDNumber,
                                                                Convert.ToInt32(sr.POSdata[0].DeviceClass.DeviceID),
                                                                (sr.POSdata[0].DeviceClass.NozzleNo == "*") ? -1 : Convert.ToInt32(sr.POSdata[0].DeviceClass.NozzleNo));
                        }
                    }
                }
                else if (requestType == "GetCountrySettings")
                {
                    ServiceRequestGetCountrySettings sr = Deserialize<ServiceRequestGetCountrySettings>(message, ref result);
                    if (sr != null)
                    {
                        requestId = sr.RequestIDNumber;
                        if (result == OverallResult.Success && extresult == OverallResult.Success)
                        {
                            this.FdcPosInterface.GetCountrySettingsReq(sr.WorkstationID, sr.ApplicationSender, sr.RequestIDNumber);
                        }
                    }
                }
                else if (requestType == "GetDSPLimits")
                {
                    ServiceRequestGetDSPLimits sr = Deserialize<ServiceRequestGetDSPLimits>(message, ref result);
                    if (sr != null)
                    {
                        requestId = sr.RequestIDNumber;
                        if (sr.POSdata.GetLength(0) == 0 || sr.POSdata[0].DeviceClass == null || sr.POSdata[0].DeviceClass.DeviceID == "")
                            result = OverallResult.MissingMandatoryData;
                        if (result == OverallResult.Success && extresult == OverallResult.Success)
                        {
                            this.FdcPosInterface.GetDSPLimitsReq(sr.WorkstationID, sr.ApplicationSender, sr.RequestIDNumber,
                                                                (sr.POSdata[0].DeviceClass.DeviceID == "*") ? -1 : Convert.ToInt32(sr.POSdata[0].DeviceClass.DeviceID));
                        }
                    }
                }
                else if (requestType == "ChangeDSPLimits")
                {
                    ServiceRequestChangeDSPLimits sr = Deserialize<ServiceRequestChangeDSPLimits>(message, ref result);
                    if (sr != null)
                    {
                        requestId = sr.RequestIDNumber;
                        if (sr.POSdata.GetLength(0) == 0 || sr.POSdata[0].DeviceClass == null || sr.POSdata[0].DeviceClass.DeviceID == "" ||
                            (FDCGlobal.ProtocolVersion > FDCVersion.V0003 && (sr.POSdata[0].DeviceClass.Product == null || sr.POSdata[0].DeviceClass.Product.FuelMode == null)))
                            result = OverallResult.MissingMandatoryData;
                        if (result == OverallResult.Success && extresult == OverallResult.Success)
                        {
                            int mode = 0, productNo = 0;
                            Decimal maxTrxAmount = -1, maxTrxVolume = -1;
                            if (FDCGlobal.ProtocolVersion == FDCVersion.V0003)
                            {
                                productNo = Convert.ToInt32(sr.POSdata[0].DeviceClass.ProductNo);
                                mode = Convert.ToInt32(sr.POSdata[0].DeviceClass.ModeNo);
                                maxTrxAmount = FDCConvert.ToDecimal(sr.POSdata[0].DeviceClass.MaxTrxAmount);
                                maxTrxVolume = FDCConvert.ToDecimal(sr.POSdata[0].DeviceClass.MaxTrxVolume);
                            }
                            else
                            {
                                productNo = Convert.ToInt32(sr.POSdata[0].DeviceClass.Product.ProductNo);
                                mode = Convert.ToInt32(sr.POSdata[0].DeviceClass.Product.FuelMode.ModeNo);
                                maxTrxAmount = FDCConvert.ToDecimal(sr.POSdata[0].DeviceClass.Product.FuelMode.MaxTrxAmount);
                                maxTrxVolume = FDCConvert.ToDecimal(sr.POSdata[0].DeviceClass.Product.FuelMode.MaxTrxVolume);
                            }
                            this.FdcPosInterface.ChangeDSPLimitsReq(sr.WorkstationID, sr.ApplicationSender, sr.RequestIDNumber,
                                        (sr.POSdata[0].DeviceClass.DeviceID == "*") ? -1 : Convert.ToInt32(sr.POSdata[0].DeviceClass.DeviceID),
                                        productNo,
                                        mode, maxTrxAmount, maxTrxVolume);
                        }
                    }
                }
                else if (requestType == "SuspendFuelling")
                {
                    ServiceRequestSuspendFuelling sr = Deserialize<ServiceRequestSuspendFuelling>(message, ref result);
                    if (sr != null)
                    {
                        requestId = sr.RequestIDNumber;
                        if (sr.POSdata.GetLength(0) == 0 || sr.POSdata[0].DeviceClass == null || sr.POSdata[0].DeviceClass.DeviceID == "")
                            result = OverallResult.MissingMandatoryData;
                        if (result == OverallResult.Success && extresult == OverallResult.Success)
                        {
                            this.FdcPosInterface.SuspendFuellingReq(sr.WorkstationID, sr.ApplicationSender, sr.RequestIDNumber,
                                                                (sr.POSdata[0].DeviceClass.DeviceID == "*") ? -1 : Convert.ToInt32(sr.POSdata[0].DeviceClass.DeviceID));
                        }
                    }
                }
                else if (requestType == "ResumeFuelling")
                {
                    ServiceRequestResumeFuelling sr = Deserialize<ServiceRequestResumeFuelling>(message, ref result);
                    if (sr != null)
                    {
                        requestId = sr.RequestIDNumber;
                        if (sr.POSdata.GetLength(0) == 0 || sr.POSdata[0].DeviceClass == null || sr.POSdata[0].DeviceClass.DeviceID == "")
                            result = OverallResult.MissingMandatoryData;
                        if (result == OverallResult.Success && extresult == OverallResult.Success)
                        {
                            this.FdcPosInterface.ResumeFuellingReq(sr.WorkstationID, sr.ApplicationSender, sr.RequestIDNumber,
                                                                (sr.POSdata[0].DeviceClass.DeviceID == "*") ? -1 : Convert.ToInt32(sr.POSdata[0].DeviceClass.DeviceID));
                        }
                    }
                }
                else if (requestType == "LockTank")
                {
                    ServiceRequestLockTank sr = Deserialize<ServiceRequestLockTank>(message, ref result);
                    if (sr != null)
                    {
                        requestId = sr.RequestIDNumber;
                        if (sr.POSdata.GetLength(0) == 0 || sr.POSdata[0].DeviceClass == null || sr.POSdata[0].DeviceClass.DeviceID == "" ||
                            sr.POSdata[0].DeviceClass.TankNo == "")
                            result = OverallResult.MissingMandatoryData;
                        if (result == OverallResult.Success && extresult == OverallResult.Success)
                        {
                            this.FdcPosInterface.LockTankReq(sr.WorkstationID, sr.ApplicationSender, sr.RequestIDNumber,
                                                                Convert.ToInt32(sr.POSdata[0].DeviceClass.DeviceID),
                                                                Convert.ToInt32(sr.POSdata[0].DeviceClass.TankNo));
                        }
                    }
                }
                else if (requestType == "UnlockTank")
                {
                    ServiceRequestUnlockTank sr = Deserialize<ServiceRequestUnlockTank>(message, ref result);
                    if (sr != null)
                    {
                        requestId = sr.RequestIDNumber;
                        if (sr.POSdata.GetLength(0) == 0 || sr.POSdata[0].DeviceClass == null || sr.POSdata[0].DeviceClass.DeviceID == "" ||
                            sr.POSdata[0].DeviceClass.TankNo == "")
                            result = OverallResult.MissingMandatoryData;
                        if (result == OverallResult.Success && extresult == OverallResult.Success)
                        {
                            this.FdcPosInterface.UnlockTankReq(sr.WorkstationID, sr.ApplicationSender, sr.RequestIDNumber,
                                                                Convert.ToInt32(sr.POSdata[0].DeviceClass.DeviceID),
                                                                Convert.ToInt32(sr.POSdata[0].DeviceClass.TankNo));
                        }
                    }
                }
                else if (requestType == "GetTankData")
                {
                    ServiceRequestGetTankData sr = Deserialize<ServiceRequestGetTankData>(message, ref result);
                    if (sr != null)
                    {
                        requestId = sr.RequestIDNumber;
                        if (sr.POSdata.GetLength(0) == 0 || sr.POSdata[0].DeviceClass == null || sr.POSdata[0].DeviceClass.DeviceID == "" ||
                            sr.POSdata[0].DeviceClass.TankNo == "")
                            result = OverallResult.MissingMandatoryData;
                        if (result == OverallResult.Success && extresult == OverallResult.Success)
                        {
                            this.FdcPosInterface.GetTankDataReq(sr.WorkstationID, sr.ApplicationSender, sr.RequestIDNumber,
                                                                (sr.POSdata[0].DeviceClass.DeviceID == "*") ? -1 : Convert.ToInt32(sr.POSdata[0].DeviceClass.DeviceID),
                                                                (sr.POSdata[0].DeviceClass.TankNo == "*") ? -1 : Convert.ToInt32(sr.POSdata[0].DeviceClass.TankNo));
                        }
                    }
                }
                else if (requestType == "ReserveFuelPoint")
                {
                    ServiceRequestReserveFuelPoint sr = Deserialize<ServiceRequestReserveFuelPoint>(message, ref result);
                    if (sr != null)
                    {
                        requestId = sr.RequestIDNumber;
                        if (sr.POSdata.GetLength(0) == 0 || sr.POSdata[0].DeviceClass == null || sr.POSdata[0].DeviceClass.DeviceID == "")
                            result = OverallResult.MissingMandatoryData;
                        if (result == OverallResult.Success && extresult == OverallResult.Success)
                        {
                            this.FdcPosInterface.ReserveFuelPointReq(sr.WorkstationID, sr.ApplicationSender, sr.RequestIDNumber,
                                                                Convert.ToInt32(sr.POSdata[0].DeviceClass.DeviceID));
                        }
                    }
                }
                else if (requestType == "FreeFuelPoint")
                {
                    ServiceRequestFreeFuelPoint sr = Deserialize<ServiceRequestFreeFuelPoint>(message, ref result);
                    if (sr != null)
                    {
                        requestId = sr.RequestIDNumber;
                        if (sr.POSdata.GetLength(0) == 0 || sr.POSdata[0].DeviceClass == null || sr.POSdata[0].DeviceClass.DeviceID == "")
                            result = OverallResult.MissingMandatoryData;
                        if (result == OverallResult.Success && extresult == OverallResult.Success)
                        {
                            this.FdcPosInterface.FreeFuelPointReq(sr.WorkstationID, sr.ApplicationSender, sr.RequestIDNumber,
                                                                Convert.ToInt32(sr.POSdata[0].DeviceClass.DeviceID));
                        }
                    }
                }
                else if (requestType == "StartFuelPointTest")
                {
                    ServiceRequestStartFuelPointTest sr = Deserialize<ServiceRequestStartFuelPointTest>(message, ref result);
                    if (sr != null)
                    {
                        requestId = sr.RequestIDNumber;
                        if (sr.POSdata.GetLength(0) == 0 || sr.POSdata[0].DeviceClass == null || sr.POSdata[0].DeviceClass.DeviceID == "")
                            result = OverallResult.MissingMandatoryData;
                        if (result == OverallResult.Success && extresult == OverallResult.Success)
                        {
                            this.FdcPosInterface.StartFuelPointTestReq(sr.WorkstationID, sr.ApplicationSender, sr.RequestIDNumber,
                                                                Convert.ToInt32(sr.POSdata[0].DeviceClass.DeviceID));
                        }
                    }
                }
                else if (requestType == "EndFuelPointTest")
                {
                    ServiceRequestEndFuelPointTest sr = Deserialize<ServiceRequestEndFuelPointTest>(message, ref result);
                    if (sr != null)
                    {
                        requestId = sr.RequestIDNumber;
                        if (sr.POSdata.GetLength(0) == 0 || sr.POSdata[0].DeviceClass == null || sr.POSdata[0].DeviceClass.DeviceID == "")
                            result = OverallResult.MissingMandatoryData;
                        if (result == OverallResult.Success && extresult == OverallResult.Success)
                        {
                            this.FdcPosInterface.EndFuelPointTestReq(sr.WorkstationID, sr.ApplicationSender, sr.RequestIDNumber,
                                                                Convert.ToInt32(sr.POSdata[0].DeviceClass.DeviceID));
                        }
                    }
                }
                else if (requestType == "SetDeviceAlarm")
                {
                    ServiceRequestSetDeviceAlarm sr = Deserialize<ServiceRequestSetDeviceAlarm>(message, ref result);
                    if (sr != null)
                    {
                        requestId = sr.RequestIDNumber;
                        if (sr.POSdata.GetLength(0) == 0 || sr.POSdata[0].DeviceClass == null || sr.POSdata[0].DeviceClass.DeviceID == "")
                            result = OverallResult.MissingMandatoryData;
                        if (result == OverallResult.Success && extresult == OverallResult.Success)
                        {
                            this.FdcPosInterface.SetDeviceAlarmReq(sr.WorkstationID, sr.ApplicationSender, sr.RequestIDNumber,
                                                                sr.POSdata[0].DeviceClass.Type,
                                                                Convert.ToInt32(sr.POSdata[0].DeviceClass.DeviceID),
                                                                Convert.ToInt32(sr.POSdata[0].DeviceClass.AlarmMsg[0].Number),
                                                                sr.POSdata[0].DeviceClass.AlarmMsg[0].Text);
                        }
                    }
                }
                else if (requestType == "OpenFuelPoint")
                {
                    ServiceRequestOpenFuelPoint sr = Deserialize<ServiceRequestOpenFuelPoint>(message, ref result);
                    if (sr != null)
                    {
                        requestId = sr.RequestIDNumber;
                        if (sr.POSdata.GetLength(0) == 0 || sr.POSdata[0].DeviceClass == null || sr.POSdata[0].DeviceClass.DeviceID == "")
                            result = OverallResult.MissingMandatoryData;
                        if (result == OverallResult.Success && extresult == OverallResult.Success)
                        {
                            this.FdcPosInterface.OpenFuelPointReq(sr.WorkstationID, sr.ApplicationSender, sr.RequestIDNumber,
                                                                (sr.POSdata[0].DeviceClass.DeviceID == "*") ? -1 : Convert.ToInt32(sr.POSdata[0].DeviceClass.DeviceID));
                        }
                    }
                }
                else if (requestType == "OpenDevice")
                {
                    ServiceRequestOpenDevice sr = Deserialize<ServiceRequestOpenDevice>(message, ref result);
                    if (sr != null)
                    {
                        requestId = sr.RequestIDNumber;
                        if (sr.POSdata.GetLength(0) == 0 || sr.POSdata[0].DeviceClass == null || sr.POSdata[0].DeviceClass.DeviceID == "")
                            result = OverallResult.MissingMandatoryData;
                        if (result == OverallResult.Success && extresult == OverallResult.Success)
                        {
                            this.FdcPosInterface.OpenFuelPointReq(sr.WorkstationID, sr.ApplicationSender, sr.RequestIDNumber,
                                                                (sr.POSdata[0].DeviceClass.DeviceID == "*") ? -1 : Convert.ToInt32(sr.POSdata[0].DeviceClass.DeviceID));
                        }
                    }
                }
                else if (requestType == "CloseFuelPoint")
                {
                    ServiceRequestCloseFuelPoint sr = Deserialize<ServiceRequestCloseFuelPoint>(message, ref result);
                    if (sr != null)
                    {
                        requestId = sr.RequestIDNumber;
                        if (sr.POSdata.GetLength(0) == 0 || sr.POSdata[0].DeviceClass == null || sr.POSdata[0].DeviceClass.DeviceID == "")
                            result = OverallResult.MissingMandatoryData;
                        if (result == OverallResult.Success && extresult == OverallResult.Success)
                        {
                            this.FdcPosInterface.CloseFuelPointReq(sr.WorkstationID, sr.ApplicationSender, sr.RequestIDNumber,
                                                                (sr.POSdata[0].DeviceClass.DeviceID == "*") ? -1 : Convert.ToInt32(sr.POSdata[0].DeviceClass.DeviceID));
                        }
                    }
                }
                else if (requestType == "CloseDevice")
                {
                    ServiceRequestCloseDevice sr = Deserialize<ServiceRequestCloseDevice>(message, ref result);
                    if (sr != null)
                    {
                        requestId = sr.RequestIDNumber;
                        if (sr.POSdata.GetLength(0) == 0 || sr.POSdata[0].DeviceClass == null || sr.POSdata[0].DeviceClass.DeviceID == "")
                            result = OverallResult.MissingMandatoryData;
                        if (result == OverallResult.Success && extresult == OverallResult.Success)
                        {
                            this.FdcPosInterface.CloseFuelPointReq(sr.WorkstationID, sr.ApplicationSender, sr.RequestIDNumber,
                                                                (sr.POSdata[0].DeviceClass.DeviceID == "*") ? -1 : Convert.ToInt32(sr.POSdata[0].DeviceClass.DeviceID));
                        }
                    }
                }
                else if (requestType == "OPTAdd")
                {
                    ServiceRequestOPTAdd sr = Deserialize<ServiceRequestOPTAdd>(message, ref result);
                    if (sr != null)
                    {
                        requestId = sr.RequestIDNumber;
                        if (sr.POSdata.GetLength(0) == 0 || sr.POSdata[0].DeviceClass == null || sr.POSdata[0].DeviceClass.DeviceID == "")
                            result = OverallResult.MissingMandatoryData;
                        if (result == OverallResult.Success && extresult == OverallResult.Success)
                        {
                            if (sr.POSdata[0].DeviceClass.serialPort != null && sr.POSdata[0].DeviceClass.serialPort.Port.Length > 0)
                                //OptInterfaceServer.optInterfaceServer.
                                this.FdcPosInterface.AddSerialPortReq(sr.WorkstationID, sr.ApplicationSender, sr.RequestIDNumber,
                                                                    sr.POSdata[0].DeviceClass.Type, Convert.ToInt32(sr.POSdata[0].DeviceClass.DeviceID), Convert.ToInt32(sr.POSdata[0].DeviceClass.serialPort.Port),
                                                                    Convert.ToInt32(sr.POSdata[0].DeviceClass.serialPort.BaudRate), Convert.ToInt32(sr.POSdata[0].DeviceClass.serialPort.DataBit), Convert.ToInt32(sr.POSdata[0].DeviceClass.serialPort.StopBit), Convert.ToInt32(sr.POSdata[0].DeviceClass.serialPort.Parity));
                            else if (sr.POSdata[0].DeviceClass.tcp != null && sr.POSdata[0].DeviceClass.tcp.Port.Length > 0)
                                //OptInterfaceServer.optInterfaceServer.
                                this.FdcPosInterface.AddTCPReq(sr.WorkstationID, sr.ApplicationSender, sr.RequestIDNumber,
                                                                    sr.POSdata[0].DeviceClass.Type, Convert.ToInt32(sr.POSdata[0].DeviceClass.DeviceID),
                                                                    sr.POSdata[0].DeviceClass.tcp.Address, Convert.ToInt32(sr.POSdata[0].DeviceClass.tcp.Port));
                        }
                    }
                }
                else if (requestType == "OPTRemove")
                {
                    ServiceRequestOPTRemove sr = Deserialize<ServiceRequestOPTRemove>(message, ref result);
                    if (sr != null)
                    {
                        requestId = sr.RequestIDNumber;
                        if (sr.POSdata.GetLength(0) == 0 || sr.POSdata[0].DeviceClass == null || sr.POSdata[0].DeviceClass.DeviceID == "")
                            result = OverallResult.MissingMandatoryData;
                        if (result == OverallResult.Success && extresult == OverallResult.Success)
                        {
                            this.FdcPosInterface.RemoveReq(sr.WorkstationID, sr.ApplicationSender, sr.RequestIDNumber,
                                                                sr.POSdata[0].DeviceClass.Type, Convert.ToInt32(sr.POSdata[0].DeviceClass.DeviceID));
                        }
                    }
                }
                else if (requestType == "OPTWrite")
                {
                    ServiceRequestOPTWrite sr = Deserialize<ServiceRequestOPTWrite>(message, ref result);
                    if (sr != null)
                    {
                        requestId = sr.RequestIDNumber;
                        if (sr.POSdata.GetLength(0) == 0 || sr.POSdata[0].DeviceClass == null || sr.POSdata[0].DeviceClass.DeviceID == "")
                            result = OverallResult.MissingMandatoryData;
                        if (result == OverallResult.Success && extresult == OverallResult.Success)
                        {
                            this.FdcPosInterface.WriteReq(sr.WorkstationID, sr.ApplicationSender, sr.RequestIDNumber,
                                                                sr.POSdata[0].DeviceClass.Type, Convert.ToInt32(sr.POSdata[0].DeviceClass.DeviceID),
                                                                sr.POSdata[0].DeviceClass.Message);
                        }
                    }
                }
                else if (requestType == "GenericTypelessMessage")
                {
                    ServiceRequestGenericTypelessMessage sr = Deserialize<ServiceRequestGenericTypelessMessage>(message, ref result);
                    if (sr != null)
                    {
                        requestId = sr.RequestIDNumber;
                        if (result == OverallResult.Success && extresult == OverallResult.Success)
                        {
                            this.FdcPosInterface.GenericTypelessMessageReq(sr.WorkstationID, sr.ApplicationSender, sr.RequestIDNumber, sr.POSdata[0].Message);
                        }
                    }
                }
                else
                {
                    fdcSocketLogger.LogInformation(string.Format("Client with applicationSender={0}, workstationId={1} is " +
                            "sending in an unknown requestType: {2} message, Will response: ParsingError",
                            applicationSender, workstationId, requestType));
                    result = OverallResult.ParsingError;
                }
            }
            catch (Exception ex)
            {
                result = OverallResult.Failure;
                fdcSocketLogger.LogError("ReadRequest(requestType: " + (requestType ?? "") + ") from Fdc client(wId: "
                    + (workstationId ?? "") + ",appSender: " + (applicationSender ?? "") + ") exceptioned: \r\n" + ex);
                //FDCPOSManager.tracer.WriteLine(string.Format("Exception! requestType='{0}': {1}", requestType, ex.Message));
            }

            if (result != OverallResult.Success || extresult != OverallResult.Success)
            {
                ((FDCPOSInterfaceServerManager)this.fdcPosManager).fdcPosInterface.messages
                    .SendErrorResponse(requestType, workstationId, applicationSender, requestId,
                        (extresult != OverallResult.Success) ? ErrorCode.ERRCD_COMMERR : ErrorCode.ERRCD_BADVAL,
                        result.ToString());
            }
            else
            {
                if (fdcPosManager.fdcClientList.TryGetValue(FDCPOSClient.getClientID(workstationId, applicationSender), out FDCPOSClient cachedFdcPosClient))
                    cachedFdcPosClient.heartbeat.StartClientDisconnectionTimer();
            }
            //FDCPOSManager.tracer.WriteLine(string.Format("end requestType='{0}'", requestType));
            return requestType;
        }

        #region misc

        protected string GetRequestType(string myString)
        {
            return GetElemValue("RequestType", myString);
        }

        protected string GetMessageType(string myString)
        {
            return GetElemValue("MessageType", myString);
        }

        protected string GetApplicationSender(string myString)
        {
            return GetElemValue("ApplicationSender", myString); ;
        }

        protected string GetWorkstationID(string myString)
        {
            return GetElemValue("WorkstationID", myString); ;
        }

        protected string GetElemValue(string field, string myString)
        {
            // TODO
            string value = "";
            try
            {
                if (myString.IndexOf(field) >= 0)
                {
                    myString = myString.Substring(myString.IndexOf(field));
                    myString = myString.Substring(myString.IndexOf('\"') + 1);
                    value = myString.Substring(0, myString.IndexOf('\"'));
                }
            }
            catch (Exception ex)
            {
                fdcSocketLogger.LogError("GetElemValue exceptioned: " + ex.ToString());
                //FDCPOSManager.tracer.WriteLine("Exception!" + ex.Message);
            }
            return value;
        }

        #endregion

        #region Deserialize

        public T Deserialize<T>(string xmlString, ref OverallResult result)
        {
            if (string.IsNullOrEmpty(xmlString))
                throw new ArgumentNullException("Target string for Deserialize must not null or empty");
            // Create an instance of the XmlSerializer class;
            // specify the type of object to be deserialized.
            result = OverallResult.Success;

            //===========================
            Exception firstException = null;


            System.Xml.Schema.XmlSchemaSet smSet;

            SchemasSG sgmInst = SchemasSG.Instance;
            if (sgmInst.GetSchemas.ContainsKey((typeof(T).Name)))
            {
                smSet = sgmInst.GetSchemas[typeof(T).Name];
            }
            else
            {
                smSet = null;
            }
            if (smSet != null)
            {
                var settings = new XmlReaderSettings
                {
                    Schemas = smSet,
                    CheckCharacters = true,
                    IgnoreComments = true,
                    IgnoreProcessingInstructions = true,
                    IgnoreWhitespace = true,
                    MaxCharactersInDocument = 999999, // most xml files have 450 characters, if this increases, we need to enlarge the number
                    ValidationType = ValidationType.Schema,
                    ValidationFlags =
                        XmlSchemaValidationFlags.ProcessIdentityConstraints |
                        XmlSchemaValidationFlags.ReportValidationWarnings
                };
                settings.ValidationEventHandler +=
                    delegate (object sender, ValidationEventArgs args)
                    {
                        if (args.Severity == XmlSeverityType.Warning)
                        {
                            //Console.WriteLine("Warning: " + args.Message);
                            fdcSocketLogger.LogInformation("XmlSchema Validation has a Warning : " + (args.Message ?? "")
                                + Environment.NewLine + (args.Exception?.ToString() ?? "")
                                + Environment.NewLine + xmlString);
                        }
                        else
                        {
                            if (firstException == null)
                            {
                                firstException = args.Exception;
                            }

                            fdcSocketLogger.LogError("XmlSchema Validation has an ERROR: " + (args.Message ?? "")
                                + Environment.NewLine + (args.Exception?.ToString() ?? "")
                                + Environment.NewLine + xmlString);
                            //Console.WriteLine("Exception: " + args.Exception.ToString());
                            //FDCPOSManager.tracer.WriteLine("Exception: " + args.Exception.ToString());
                        }
                    };

                //======================================
                T sr = default(T);

                try
                {
                    using (var tempStream = new System.IO.StringReader(xmlString))
                    {
                        using (var reader = XmlReader.Create(tempStream, settings))
                        {
                            XmlSerializer serializer = new XmlSerializer(typeof(T));
                            serializer.UnknownNode += new XmlNodeEventHandler((_, n) =>
                            {
                                //the target object may miss to defined a Property?
                                fdcSocketLogger.LogInformation("XmlSerializer read an Unknown Node with Name: " + (n.Name ?? "") + ", text: " + (n.Text ?? "")
                                    + System.Environment.NewLine + xmlString);
                            });
                            serializer.UnknownAttribute += new XmlAttributeEventHandler((_, e) =>
                            {
                                //the target object may miss to defined a Property?
                                System.Xml.XmlAttribute attr = e.Attr;
                                fdcSocketLogger.LogInformation("XmlSerializer read an Unknown Attr with Name: " + (attr.Name ?? "") + ", value: " + (attr.Value ?? "")
                                    + System.Environment.NewLine + xmlString);
                            });
                            sr = (T)serializer.Deserialize(reader);
                        }
                    }

                    if (firstException != null)
                        throw firstException;
                }
                catch (Exception ex)
                {
                    result = OverallResult.ParsingError;
                    //FDCPOSManager.tracer.WriteLine("Exception! " + ex.Message);
                    fdcSocketLogger.LogError("Deserialize<T>(string ,ref OverallResult) exceptioned for string: " + Environment.NewLine + xmlString
                                + Environment.NewLine + "exception detail: " + ex);
                }

                return sr;
            }
            else
            {
                result = OverallResult.ParsingError;
                return default(T);
            }

        } // end of Deserialize

        #endregion

        /// <summary>
        /// 4 bytes Length(16 bytes hash excluded) + 16 bytes hash + UTF8 encoded xml content
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="sr"></param>
        /// <param name="enableHashHeader">if false, will set 0 for all 16 bytes</param>
        /// <returns>string is the serialized Message xml string</returns>
        public static Tuple<byte[], string> SerializeFdcMessageToNetworkBytes<T>(T sr, bool enableHashHeader)
        {
            var xmlMsgBodyMemStream = new MemoryStream();
            XmlSerializer serializer = new XmlSerializer(typeof(T));
            serializer.Serialize(xmlMsgBodyMemStream, (T)sr);
            xmlMsgBodyMemStream.Position = 0;
            string xmlBodyStr = "";
            byte[] xmlBodyBytes = null;
            using (StreamReader _ = new StreamReader(xmlMsgBodyMemStream, Encoding.UTF8))
            {
                xmlBodyStr = _.ReadToEnd();
                xmlBodyBytes = Encoding.UTF8.GetBytes(xmlBodyStr);
            }

            #region msg header, 4 bytes of msg body length

            byte[] lengthBytes = new byte[Define.HeaderLength];
            lengthBytes[3] = (byte)(xmlBodyBytes.Length & 0x000000FF);
            lengthBytes[2] = (byte)((xmlBodyBytes.Length & 0x0000FF00) / Math.Pow(2, 8));
            lengthBytes[1] = (byte)((xmlBodyBytes.Length & 0x00FF0000) / Math.Pow(2, 16));
            lengthBytes[0] = (byte)((xmlBodyBytes.Length & 0xFF000000) / Math.Pow(2, 24));

            #endregion

            #region msg encription Bytes, 16 bytes

            var hashBytes = new byte[Define.EncriptionLength];
            if (enableHashHeader)
            {
                MD5Crypter crypter = new MD5Crypter();
                byte[] hashingbytes = new byte[xmlBodyBytes.Length + crypter.getPassphrase().Length];
                Array.Copy(xmlBodyBytes, hashingbytes, xmlBodyBytes.Length);
                Array.Copy(crypter.getPassphrase(), 0, hashingbytes, xmlBodyBytes.Length, crypter.getPassphrase().Length);
                hashBytes = crypter.ComputeHash(hashingbytes);
            }
            else
            {
                for (int i = 0; i < Define.EncriptionLength; i++)
                    hashBytes[i] = 0;
            }

            #endregion

            // 3 parts concat.
            var finalBytes = lengthBytes.Concat(hashBytes).Concat(xmlBodyBytes).ToArray();
            return new Tuple<byte[], string>(finalBytes, xmlBodyStr);
        }

        public bool SendResponse<T>(FDCPOSClient fdcPosClient, T sr)
        {
            try
            {
                if (fdcPosClient == null)
                {
                    fdcSocketLogger.LogInformation("SendResponse, client is NULL!");
                    //FDCPOSManager.tracer.WriteLine(string.Format("client is NULL!"));
                    return false;
                }

                if (!fdcPosClient.connected)
                {
                    fdcSocketLogger.LogInformation(string.Format("client '{0}' NOT connected, will skip send this response", fdcPosClient.sID));
                    //FDCPOSManager.tracer.WriteLine(string.Format("client '{0}' NOT connected", fdcposClient.sID));
                    return false;
                }

                Interlocked.Increment(ref FDCPOSManager.messageIdCounter);

                var result = SerializeFdcMessageToNetworkBytes(sr, this.fdcPosManager.encryptedHeader);

                if (result.Item1.Length >= 19999999)
                    fdcSocketLogger.LogInformation("SendResponse " + typeof(T).Name
                        + ", rawBytes Length: " + result.Item1.Length + " excceed normal value, will send anyway");

                lock (fdcPosClient)
                {
                    if (fdcSocketLogger.IsEnabled(LogLevel.Debug))
                        fdcSocketLogger.LogDebug("Will Send Fdc Response(full message include header bytes count: " + result.Item1.Length + "): "
                            + sr.GetType().Name + ", content:\r\n"
                            + result.Item2
                            + "\r\n to client(wId: " + (fdcPosClient.workstationID ?? "")
                            + ", appSender: " + (fdcPosClient.applicationSender ?? "") + ")");
                    var networkStream = fdcPosClient.socketChannelResponse.GetStream();
                    networkStream.Write(result.Item1);
                    if (fdcSocketLogger.IsEnabled(LogLevel.Debug))
                    {
                        fdcSocketLogger.LogDebug("  done send Fdc Response: " + sr.GetType().Name);
                    }
                }

                try
                {
                    if (false && traceXML)
                    {
                        //DateTime now = DateTime.Now;
                        //string sdate = now.Day.ToString() + "-" + now.Month.ToString() + "-";
                        //System.IO.StreamWriter testwriter = new StreamWriter(SINPConfigurazione.TracePath + sdate + "xmlServerResponse.xml", true);
                        //serializer.Serialize(testwriter, sr);
                        //testwriter.Close();
                    }
                }
                catch (Exception Ex)
                {
                    fdcSocketLogger.LogError(string.Format("Exception tracing xml file: {0}", Ex.Message));
                    //FDCPOSManager.tracer.WriteLine(string.Format("Exception tracing xml file: {0}", Ex.Message));
                }
            }
            catch (Exception ex)
            {
                fdcSocketLogger.LogError("SendResponse " + typeof(T).Name + " to client: " + fdcPosClient.sID
                    + " Exceptioned: " + ex
                    + System.Environment.NewLine + "Will disconect this client");
                fdcPosClient.Dispose();
                this.fdcPosManager.DisconnectClient(fdcPosClient);
                return false;
            }

            return true;
        }

        public void Dispose()
        {
            try
            {
                this.disposed = true;
                this.fdcSocketLogger.LogError($"FdcServerTcpHandler is on stopping, and will Dispose all fdcClientTcpHandlers(total: {this.fdcClientTcpHandlers.Count}) as well... ");
                this.tcpListener.Stop();
                this.fdcClientTcpHandlers.ForEach(c => { try { c.Dispose(); } catch { } });
                this.fdcClientTcpHandlers.Clear();
            }
            finally
            {
            }
        }
    }
}