using Dapper;
using EVCB_OCPP.Domain;
using EVCB_OCPP.Domain.Models.Database;
using EVCB_OCPP.Packet.Features;
using EVCB_OCPP.Packet.Messages;
using EVCB_OCPP.Packet.Messages.Basic;
using EVCB_OCPP.Packet.Messages.Core;
using EVCB_OCPP.Packet.Messages.RemoteTrigger;
using EVCB_OCPP.WSServer.Dto;
using EVCB_OCPP.WSServer.Helper;
using EVCB_OCPP.WSServer.Message;
using EVCB_OCPP.WSServer.Service;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using NLog;
using OCPPServer.Protocol;
using OCPPServer.SubProtocol;
using SuperSocket.SocketBase;
using SuperSocket.SocketBase.Config;
using System;
using System.Collections.Generic;
using System.Configuration;
using System.Data;
using System.Data.Entity;
using System.Data.SqlClient;
using System.Diagnostics;
using System.Linq;
using System.Security.Authentication;
using System.Threading;
using System.Threading.Tasks;
using System.Xml.Linq;


namespace EVCB_OCPP.WSServer
{
    public class DestroyRequest : IRequest
    {
        public string Action { get; set; }

        public bool TransactionRelated()
        {
            return false;
        }

        public bool Validate()
        {
            return true;
        }
    }
    internal class ProtalServer
    {
        static private ILogger logger = NLog.LogManager.GetCurrentClassLogger();
        private OuterHttpClient httpClient = new OuterHttpClient();
        private DateTime lastcheckdt = DateTime.UtcNow.AddSeconds(-20);
        private Dictionary<string, ClientData> clientDic = new Dictionary<string, ClientData>();
        private readonly Object _lockClientDic = new object();
        private readonly Object _lockConfirmPacketList = new object();
        private ProfileHandler profileHandler = new ProfileHandler();
        private List<NeedConfirmMessage> needConfirmPacketList = new List<NeedConfirmMessage>();
        private DateTime checkUpdateDt = DateTime.UtcNow;
        private DateTime _CheckFeeDt = DateTime.UtcNow;
        private DateTime _CheckWeatherDt = DateTime.UtcNow;
        private LoadingBalanceService _loadingBalanceService = new LoadingBalanceService();
        private Dictionary<string, TCCWeatherDto> TCCStationDic = new Dictionary<string, TCCWeatherDto>();

        private List<string> needConfirmActions = new List<string>()
        {
             "GetConfiguration",
             "ChangeConfiguration",
             "RemoteStartTransaction",
             "RemoteStopTransaction",
             "ChangeAvailability",
             "ClearCache",
             "DataTransfer",
             "Reset",
             "UnlockConnector",
             "TriggerMessage",
             "GetDiagnostics",
             "UpdateFirmware",
             "GetLocalListVersion",
             "SendLocalList",
             "SetChargingProfile",
             "ClearChargingProfile",
             "GetCompositeSchedule",
             "ReserveNow",
             "CancelReservation",
             "ExtendedTriggerMessage"
        };
        private List<Profile> profiles = new List<Profile>()
        {
             new CoreProfile(),
             new FirmwareManagementProfile(),
             new ReservationProfile(),
             new RemoteTriggerProfile(),
             new SmartChargingProfile(),
             new LocalAuthListManagementProfile(),
             new SecurityProfile(),
        };
        private CancellationTokenSource _cts = new CancellationTokenSource();
        private CancellationToken _ct;
        private string _ocpp20NetworkSetting = "";

        internal ProtalServer()
        {
            _ct = _cts.Token;
            WarmUpLog();
        }


        internal void Start()
        {

            if (!GlobalConfig.LoadAPPConfig())
            {
                Console.WriteLine("Please check App.Config setting .");
                return;
            }
            ReadTCCSetting();
            OpenNetwork();

            Task serverCommandTask = new Task(ServerMessageTrigger, _ct);
            serverCommandTask.Start();

            Task serverUpdateTask = new Task(ServerUpdateTrigger, _ct);
            serverUpdateTask.Start();

            Task serverSetFeeTask = new Task(ServerSetFeeTrigger, _ct);
            serverSetFeeTask.Start();

            Task serverWeatherNotificationTask = new Task(ServerWeatherNotificationTrigger, _ct);
            serverWeatherNotificationTask.Start();

            Task serverBeatTask = new Task(HeartBeatCheckTrigger, _ct);
            serverBeatTask.Start();

            Task serverHealthTask = new Task(HealthCheckTrigger, _ct);
            serverHealthTask.Start();

            var ocpp20NetworkSetting = new EVCB_OCPP20.Packet.Messages.SetNetworkProfileRequest()
            {
                ConfigurationSlot = 0,
                ConnectionData = new EVCB_OCPP20.Packet.DataTypes.NetworkConnectionProfileType()
                {
                    OcppVersion = EVCB_OCPP20.Packet.DataTypes.EnumTypes.OCPPVersionEnumType.OCPP20,
                    OcppTransport = EVCB_OCPP20.Packet.DataTypes.EnumTypes.OCPPTransportEnumType.JSON,
                    MessageTimeout = 30,
                    OcppCsmsUrl = "ws://ocpp.phihong.com.tw:5004",
                    OcppInterface = EVCB_OCPP20.Packet.DataTypes.EnumTypes.OCPPInterfaceEnumType.Wired0
                }

            };

            _ocpp20NetworkSetting = JsonConvert.SerializeObject(ocpp20NetworkSetting, Formatting.None);

            while (true)
            {
                var input = Console.ReadLine();

                switch (input.ToLower())
                {
                    case "stop":
                        Console.WriteLine("Command stop");
                        Stop();
                        break;

                    case "gc":
                        Console.WriteLine("Command GC");
                        GC.Collect();
                        break;

                    case "lc":
                        {
                            Console.WriteLine("Command List Clients");
                            Dictionary<string, ClientData> _copyClientDic = null;
                            lock (_lockClientDic)
                            {
                                _copyClientDic = new Dictionary<string, ClientData>(clientDic);

                            }
                            var list = _copyClientDic.Select(c => c.Value).ToList();
                            var locations = _copyClientDic.Where(x => !string.IsNullOrEmpty(x.Value.StationLocation)).Distinct().Select(x => x.Value.StationLocation).ToList();
                            int i = 1;
                            foreach (var c in list)
                            {
                                Console.WriteLine(i + ":" + c.ChargeBoxId + " " + c.SessionID);
                                i++;
                            }

                            foreach (var c in TCCStationDic)
                            {
                                Console.WriteLine(i + ":" + c.Key + "-" + c.Value.Temperature + "/" + c.Value.WeatherID);
                                i++;
                            }

                        }
                        break;
                    case "lcn":
                        {
                            Console.WriteLine("Command List Customer Name");
                            Dictionary<string, ClientData> _copyClientDic = null;
                            lock (_lockClientDic)
                            {
                                _copyClientDic = new Dictionary<string, ClientData>(clientDic);

                            }
                            var lcn = clientDic.Select(c => c.Value.CustomerName).Distinct().ToList();
                            int iLcn = 1;
                            foreach (var c in lcn)
                            {
                                Console.WriteLine(iLcn + ":" + c + ":" + clientDic.Where(z => z.Value.CustomerName == c).Count().ToString());
                                iLcn++;
                            }

                        }
                        break;
                    case "help":
                        Console.WriteLine("Command help!!");
                        Console.WriteLine("lcn : List Customer Name");
                        Console.WriteLine("gc : GC Collect");
                        Console.WriteLine("lc : List Clients");
                        Console.WriteLine("cls : clear console");
                        Console.WriteLine("silent : silent");
                        Console.WriteLine("show : show log");
                        // logger.Info("rcl : show Real Connection Limit");
                        break;
                    case "cls":
                        Console.WriteLine("Command clear");
                        Console.Clear();
                        break;

                    case "silent":
                        Console.WriteLine("Command silent");
                        var xe = XElement.Load("NLog.config");
                        var xns = xe.GetDefaultNamespace();
                        var minlevelattr = xe.Descendants(xns + "rules").Elements(xns + "logger")
                            .Where(c => c.Attribute("writeTo").Value.Equals("console")).Attributes("minlevel").FirstOrDefault();
                        if (minlevelattr != null)
                        {

                            minlevelattr.Value = "Warn";
                        }
                        xe.Save("NLog.config");
                        break;
                    case "show":
                        Console.WriteLine("Command show");
                        var xe1 = XElement.Load("NLog.config");
                        var xns1 = xe1.GetDefaultNamespace();
                        var minlevelattr1 = xe1.Descendants(xns1 + "rules").Elements(xns1 + "logger")
                            .Where(c => c.Attribute("writeTo").Value.Equals("console")).Attributes("minlevel").FirstOrDefault();
                        if (minlevelattr1 != null)
                        {

                            minlevelattr1.Value = "trace";
                        }
                        xe1.Save("NLog.config");
                        break;
                    case "rcl":
                        break;
                    default:
                        break;
                }
            }
        }

        internal void Stop()
        {
            if (_cts != null)
            {
                _cts.Cancel();
            }
        }

        private void CheckVersion(string chargeBoxId)
        {
            if (string.IsNullOrEmpty(chargeBoxId)) return;
            using (var db = new MainDBContext())
            {
                db.ServerMessage.Add(new ServerMessage()
                {
                    ChargeBoxId = chargeBoxId,
                    CreatedBy = "Server",
                    CreatedOn = DateTime.UtcNow,
                    OutAction = Actions.DataTransfer.ToString(),
                    OutRequest = JsonConvert.SerializeObject(
                          new DataTransferRequest()
                          {
                              messageId = "ID_FirmwareVersion",
                              vendorId = "Phihong Technology"

                          },
                          new JsonSerializerSettings() { NullValueHandling = NullValueHandling.Ignore, Formatting = Formatting.None }),
                    SerialNo = Guid.NewGuid().ToString(),
                    InMessage = string.Empty

                });

                db.SaveChanges();
            }

        }


        private void CheckEVSEConfigure(string chargeBoxId)
        {
            if (string.IsNullOrEmpty(chargeBoxId)) return;
            using (var db = new MainDBContext())
            {
                db.ServerMessage.Add(new ServerMessage()
                {
                    ChargeBoxId = chargeBoxId,
                    CreatedBy = "Server",
                    CreatedOn = DateTime.UtcNow,
                    OutAction = Actions.GetConfiguration.ToString(),
                    OutRequest = JsonConvert.SerializeObject(
                            new GetConfigurationRequest()
                            {
                                key = new List<string>()

                            },
                            new JsonSerializerSettings() { NullValueHandling = NullValueHandling.Ignore, Formatting = Formatting.None }),
                    SerialNo = Guid.NewGuid().ToString(),
                    InMessage = string.Empty

                }); ;

                db.SaveChanges();

            }
        }


        #region 台泥


        private void ReadTCCSetting()
        {
            using (var db = new MainDBContext())
            {
                var info = db.Customer.Where(x => x.Id == new Guid("009E603C-79CD-4620-A2B8-D9349C0E8AD8")).Select(x => new { x.ApiUrl, x.ApiKey }).FirstOrDefault();
                GlobalConfig.TCC_API_URL = info.ApiUrl;
                GlobalConfig.TCC_SALTKEY = info.ApiKey;

            }
        }
        async private Task<TCCStationInfoDto> GetStationInfo(string machineId)
        {
            TCCStationInfoDto stationInfo = null;
            if (string.IsNullOrEmpty(machineId)) return stationInfo;
            using (SqlConnection conn = new SqlConnection(webConnectionString))
            {
                var parameters = new DynamicParameters();
                parameters.Add("@MachineId", machineId, DbType.String, ParameterDirection.Input);
                string sql = " SELECT CAST([Latitude] as DECIMAL(5,2)) Lat,CAST([Longitude] as DECIMAL(5, 2))  Long ,SUBSTRING([Address],1,3) as zipcode FROM[StationMachine]  left join [dbo].[Station]" +
               "  on[StationMachine].StationId = Station.[Id]  where StationMachine.MachineId=@MachineId; ";

                var result = await conn.QueryAsync<TCCStationInfoDto>(sql, parameters);
                stationInfo = result.FirstOrDefault();
            }

            return stationInfo;
        }
        #endregion

        private void OpenNetwork()
        {

            //載入OCPP Protocol
            var appServer = new OCPPWSServer(new List<OCPPSubProtocol>() { new OCPPSubProtocol(), new OCPPSubProtocol(" ocpp1.6"), new OCPPSubProtocol("ocpp2.0") });

            List<IListenerConfig> llistener = new List<IListenerConfig>();
            //System.Net.IPAddress.Any.ToString()
            // llistener.Add(new ListenerConfig { Ip = "", Port = Convert.ToInt32(wssserverPort), Backlog = 100, Security = serverSecurity });
            llistener.Add(new ListenerConfig { Ip = System.Net.IPAddress.Any.ToString(), Port = Convert.ToInt32(GlobalConfig.GetWS_Port()), Backlog = 100, Security = "None" });
            llistener.Add(new ListenerConfig { Ip = System.Net.IPAddress.Any.ToString(), Port = Convert.ToInt32(GlobalConfig.GetWSS_Port()), Backlog = 100, Security = SslProtocols.Tls12.ToString() });

            // llistener.Add(new ListenerConfig { Ip = System.Net.IPAddress.Any.ToString(), Port = Convert.ToInt32(GlobalConfig.GetWSS_Port()), Backlog = 100, Security = SslProtocols.Tls11.ToString() });
            var config = ConfigurationManager.GetSection("superSocket") as IConfigurationSource;
            ICertificateConfig Certificate = config.Servers.ElementAt(0).Certificate;
            IEnumerable<IListenerConfig> listeners = llistener;

            //設定server config
            var serverConfig = new ServerConfig
            {

                //Port = Convert.ToInt32(2012),
                //Ip = "172.17.40.13",
                MaxRequestLength = 204800,
                //Security = serverSecurity,
                Certificate = Certificate,
                Listeners = listeners,
                //  LogAllSocketException = true,
                KeepAliveTime = 10,
                // LogBasicSessionActivity = true


            };

            //Setup with listening port
            if (!appServer.Setup(serverConfig, logFactory: new OCPPLogFactory()))
            {
                Console.WriteLine("Failed to setup!");
                return;
            }

            appServer.NewSessionConnected += AppServer_NewSessionConnected;
            appServer.SessionClosed += AppServer_SessionClosed;


            //Try to start the appServer
            if (!appServer.Start())
            {
                Console.WriteLine("Failed to start!");
                Console.ReadKey();
                return;
            }
        }

        private void AppServer_SessionClosed(ClientData session, CloseReason value)
        {
            //  Console.WriteLine(session.RemoteEndPoint.Address);
            WriteMachineLog(session, string.Format("CloseReason: {0}", value), "Connection", "");
            RemoveClient(session);
            // close Connection
        }

        private void AppServer_NewSessionConnected(ClientData session)
        {
            Console.WriteLine("++++++++++++++++");
            try
            {
                lock (_lockClientDic)
                {
                    bool isNotSupported = session.SecWebSocketProtocol.Contains("ocpp1.6") ? false : session.SecWebSocketProtocol.Contains("ocpp2.0") ? false : true;
                    if (isNotSupported)
                    {
                        //logger.Debug(string.Format("ChargeBoxId:{0} SecWebSocketProtocol:{1} NotSupported", session.ChargeBoxId, session.SecWebSocketProtocol));
                        WriteMachineLog(session, string.Format("SecWebSocketProtocol:{0} NotSupported", session.SecWebSocketProtocol), "Connection", "");
                        return;
                    }
                    ClientData _removeClient = null;


                    clientDic.TryGetValue(session.ChargeBoxId, out _removeClient);
                    if (_removeClient != null)
                    {
                        WriteMachineLog(_removeClient, "Duplicate Logins", "Connection", "");
                        _removeClient.Close(CloseReason.ServerShutdown);
                        RemoveClient(_removeClient);
                    }

                    clientDic.Add(session.ChargeBoxId, session);
                    session.m_ReceiveData += new ClientData.OCPPClientDataEventHandler<ClientData, String>(ReceivedMessage);
                    // logger.Debug("------------New " + (session == null ? "Oops" : session.ChargeBoxId));
                    WriteMachineLog(session, "NewSessionConnected", "Connection", "");

                    using (var db = new MainDBContext())
                    {
                        var machine = db.Machine.Where(x => x.ChargeBoxId == session.ChargeBoxId).FirstOrDefault();
                        if (machine != null)
                        {
                            machine.ConnectionType = session.Origin.Contains("https") ? 2 : 1;
                            db.SaveChanges();
                        }
                    }


                    // CheckEVSEConfigure(session.ChargeBoxId);
                }
            }
            catch (Exception ex)
            {
                logger.Error(string.Format("NewSessionConnected Ex: {0}", ex.ToString()));
            }


        }

        async private void ReceivedMessage(ClientData session, string rawdata)
        {
            try
            {
                BasicMessageHandler msgAnalyser = new BasicMessageHandler();
                MessageResult analysisResult = msgAnalyser.AnalysisReceiveData(session, rawdata);

                WriteMachineLog(session, rawdata,
                     string.Format("{0} {1}", string.IsNullOrEmpty(analysisResult.Action) ? "unknown" : analysisResult.Action, analysisResult.Id == 2 ? "Request" : (analysisResult.Id == 3 ? "Confirmation" : "Error")), analysisResult.Exception == null ? "" : analysisResult.Exception.Message);

                if (session.ResetSecurityProfile)
                {
                    logger.Error(string.Format("[{0}] ChargeBoxId:{1} ResetSecurityProfile", DateTime.UtcNow, session.ChargeBoxId));
                    RemoveClient(session);
                    return;
                }


                if (!analysisResult.Success)
                {
                    //解析RawData就發生錯誤
                    if (!string.IsNullOrEmpty(analysisResult.CallErrorMsg))
                    {
                        Send(session, analysisResult.CallErrorMsg, string.Format("{0} {1}", analysisResult.Action, "Error"));
                    }
                    else
                    {
                        if (analysisResult.Message == null)
                        {
                            string replyMsg = BasicMessageHandler.GenerateCallError(analysisResult.UUID, OCPPErrorCodes.InternalError, OCPPErrorDescription.InternalError);
                            string errorMsg = string.Empty;
                            if (analysisResult.Exception != null)
                            {
                                errorMsg = analysisResult.Exception.ToString();
                            }

                            Send(session, replyMsg, string.Format("{0} {1}", "unknown", "Error"), "EVSE's sent essage has parsed Failed. ");
                        }
                        else
                        {
                            BaseMessage _baseMsg = analysisResult.Message as BaseMessage;


                            string replyMsg = BasicMessageHandler.GenerateCallError(_baseMsg.Id, OCPPErrorCodes.InternalError, OCPPErrorDescription.InternalError);
                            string errorMsg = string.Empty;
                            if (analysisResult.Exception != null)
                            {
                                errorMsg = analysisResult.Exception.ToString();
                            }

                            Send(session, replyMsg, string.Format("{0} {1}", analysisResult.Action, "Error"), errorMsg);
                        }

                    }
                }
                else
                {



                    //if (session.ISOCPP20 && !(analysisResult.Action != Actions.BootNotification.ToString() || analysisResult.Action != Actions.Heartbeat.ToString()))
                    //{
                    //    Send(session, "Backend doesn't support this message.", string.Format("{0} {1}", analysisResult.Action, "Error"));
                    //    return;
                    //}
                    switch (analysisResult.Id)
                    {
                        case BasicMessageHandler.TYPENUMBER_CALL:
                            {
                                if (!session.ISOCPP20)
                                {
                                    Actions action = Convertor.GetAction(analysisResult.Action);
                                    ProcessRequestMessage(analysisResult, session, action);
                                }
                                else
                                {
                                    EVCB_OCPP20.Packet.Features.Actions action = Convertor.GetActionby20(analysisResult.Action);
                                    MessageResult result = new MessageResult() { Success = true };
                                    //ocpp20 處理
                                    switch (action)
                                    {

                                        case EVCB_OCPP20.Packet.Features.Actions.BootNotification:
                                            {
                                                EVCB_OCPP20.Packet.Messages.BootNotificationRequest _request = (EVCB_OCPP20.Packet.Messages.IRequest)analysisResult.Message as EVCB_OCPP20.Packet.Messages.BootNotificationRequest;

                                                var confirm = new EVCB_OCPP20.Packet.Messages.BootNotificationResponse() { CurrentTime = DateTime.UtcNow, Interval = 180, Status = EVCB_OCPP20.Packet.DataTypes.EnumTypes.RegistrationStatusEnumType.Pending };

                                                result.Message = confirm;
                                                result.Success = true;

                                                string response = BasicMessageHandler.GenerateConfirmationofOCPP20(analysisResult.UUID, (EVCB_OCPP20.Packet.Messages.IConfirmation)result.Message);
                                                Send(session, response, string.Format("{0} {1}", analysisResult.Action, "Response"), result.Exception == null ? string.Empty : result.Exception.ToString());


                                                var request = new EVCB_OCPP20.Packet.Messages.SetNetworkProfileRequest()
                                                {
                                                    ConfigurationSlot = 1,
                                                    ConnectionData = new EVCB_OCPP20.Packet.DataTypes.NetworkConnectionProfileType()
                                                    {
                                                        OcppVersion = EVCB_OCPP20.Packet.DataTypes.EnumTypes.OCPPVersionEnumType.OCPP20,
                                                        OcppTransport = EVCB_OCPP20.Packet.DataTypes.EnumTypes.OCPPTransportEnumType.JSON,
                                                        MessageTimeout = 30,
                                                        OcppCsmsUrl = "ws://ocpp.phihong.com.tw:5004",
                                                        OcppInterface = EVCB_OCPP20.Packet.DataTypes.EnumTypes.OCPPInterfaceEnumType.Wired0
                                                    }

                                                };
                                                var uuid = session.queue20.store(request);
                                                string requestText = BasicMessageHandler.GenerateRequestofOCPP20(uuid, "SetNetworkProfile", request);
                                                Send(session, requestText, "SetNetworkProfile");

                                            }
                                            break;
                                        default:
                                            {
                                                logger.Error(string.Format("We don't implement messagetype:{0} of raw data :{1} by {2}", analysisResult.Id, rawdata, session.ChargeBoxId));
                                            }
                                            break;
                                    }

                                }


                            }
                            break;
                        case BasicMessageHandler.TYPENUMBER_CALLRESULT:
                            {
                                if (!session.ISOCPP20)
                                {
                                    Actions action = Convertor.GetAction(analysisResult.Action);
                                    ProcessConfirmationMessage(analysisResult, session, action);
                                }
                                else
                                {
                                    EVCB_OCPP20.Packet.Features.Actions action = Convertor.GetActionby20(analysisResult.Action);
                                    MessageResult result = new MessageResult() { Success = true };
                                    //ocpp20 處理
                                    switch (action)
                                    {

                                        case EVCB_OCPP20.Packet.Features.Actions.SetNetworkProfile:
                                            {
                                                EVCB_OCPP20.Packet.Messages.SetNetworkProfileResponse response = (EVCB_OCPP20.Packet.Messages.IConfirmation)analysisResult.Message as EVCB_OCPP20.Packet.Messages.SetNetworkProfileResponse;

                                                if (response.Status == EVCB_OCPP20.Packet.DataTypes.EnumTypes.SetNetworkProfileStatusEnumType.Accepted)
                                                {
                                                    var request = new EVCB_OCPP20.Packet.Messages.SetVariablesRequest()
                                                    {
                                                        SetVariableData = new List<EVCB_OCPP20.Packet.DataTypes.SetVariableDataType>()
                                                         {
                                                              new EVCB_OCPP20.Packet.DataTypes.SetVariableDataType()
                                                              {
                                                                    Component=new EVCB_OCPP20.Packet.DataTypes.ComponentType()
                                                                    {
                                                                         Name="OCPPCommCtrlr",

                                                                    },
                                                                     AttributeType= EVCB_OCPP20.Packet.DataTypes.EnumTypes.AttributeEnumType.Actual,
                                                                     AttributeValue= JsonConvert.SerializeObject(new List<int>(){ 1 }),
                                                                     Variable=new EVCB_OCPP20.Packet.DataTypes.VariableType()
                                                                    {
                                                                            Name="NetworkConfigurationPriority",

                                                                    }


                                                              }
                                                         }

                                                    };
                                                    var uuid = session.queue20.store(request);
                                                    string requestText = BasicMessageHandler.GenerateRequestofOCPP20(uuid, "SetVariables", request);
                                                    Send(session, requestText, "SetVariables");
                                                }

                                            }
                                            break;
                                        case EVCB_OCPP20.Packet.Features.Actions.SetVariables:
                                            {
                                                EVCB_OCPP20.Packet.Messages.SetVariablesResponse response = (EVCB_OCPP20.Packet.Messages.IConfirmation)analysisResult.Message as EVCB_OCPP20.Packet.Messages.SetVariablesResponse;

                                                if (response.SetVariableResult[0].AttributeStatus == EVCB_OCPP20.Packet.DataTypes.EnumTypes.SetVariableStatusEnumType.RebootRequired)
                                                {
                                                    var request = new EVCB_OCPP20.Packet.Messages.ResetRequest()
                                                    {
                                                        Type = EVCB_OCPP20.Packet.DataTypes.EnumTypes.ResetEnumType.OnIdle

                                                    };
                                                    var uuid = session.queue20.store(request);
                                                    string requestText = BasicMessageHandler.GenerateRequestofOCPP20(uuid, "Reset", request);
                                                    Send(session, requestText, "Reset");

                                                }
                                            }
                                            break;
                                        default:
                                            {
                                                logger.Error(string.Format("We don't implement messagetype:{0} of raw data :{1} by {2}", analysisResult.Id, rawdata, session.ChargeBoxId));
                                            }
                                            break;
                                    }
                                }

                            }
                            break;
                        case BasicMessageHandler.TYPENUMBER_CALLERROR:
                            {
                                //只處理 丟出Request 收到Error的訊息                              
                                if (analysisResult.Success && analysisResult.Message != null)
                                {
                                    Actions action = Convertor.GetAction(analysisResult.Action);
                                    ProcessErrorMessage(analysisResult, session, action);
                                }

                            }
                            break;
                        default:
                            {
                                logger.Error(string.Format("Can't analyze messagetype:{0} of raw data :{1} by {2}", analysisResult.Id, rawdata, session.ChargeBoxId));
                            }
                            break;

                    }
                }

                await Task.Delay(10);
            }
            catch (Exception ex)
            {


                if (ex.InnerException != null)
                {
                    logger.Error(string.Format("{0} **Inner Exception :{1} ", session.ChargeBoxId + rawdata, ex.ToString()));


                }
                else
                {
                    logger.Error(string.Format("{0} **Exception :{1} ", session.ChargeBoxId, ex.ToString()));
                }
            }


        }



        async private void ProcessRequestMessage(MessageResult analysisResult, ClientData session, Actions action)
        {
            BasicMessageHandler msgAnalyser = new BasicMessageHandler();
            if (!session.IsCheckIn && action != Actions.BootNotification)
            {
                string response = BasicMessageHandler.GenerateCallError(analysisResult.UUID, OCPPErrorCodes.GenericError, OCPPErrorDescription.NotChecked);
                Send(session, response, string.Format("{0} {1}", analysisResult.Action, "Error"));
            }
            else
            {
                var profileName = profiles.Where(x => x.IsExisted(analysisResult.Action)).Select(x => x.Name).FirstOrDefault();
                switch (profileName)
                {
                    case "Core":
                        {

                            var replyResult = await profileHandler.ExecuteCoreRequest(action, session, (IRequest)analysisResult.Message).ConfigureAwait(false);
                            if (replyResult.Success)
                            {
                                string response = BasicMessageHandler.GenerateConfirmation(analysisResult.UUID, (IConfirmation)replyResult.Message);


                                Send(session, response, string.Format("{0} {1}", analysisResult.Action, "Confirmation"), replyResult.Exception == null ? string.Empty : replyResult.Exception.ToString());

                                if (action == Actions.BootNotification && replyResult.Message is BootNotificationConfirmation)
                                {
                                    if (((BootNotificationConfirmation)replyResult.Message).status == Packet.Messages.SubTypes.RegistrationStatus.Accepted)
                                    {
                                        session.IsCheckIn = true;
                                        CheckVersion(session.ChargeBoxId);
                                        CheckEVSEConfigure(session.ChargeBoxId);

                                        if (session.CustomerId == new Guid("009E603C-79CD-4620-A2B8-D9349C0E8AD8"))
                                        {

                                            var stationInfo = await GetStationInfo(session.MachineId);
                                            if (stationInfo != null)
                                            {
                                                session.StationLocation = string.Format("{0},{1}", stationInfo.Lat, stationInfo.Long);
                                                session.StationName = stationInfo.ZipCode;
                                            }
                                            using (var db = new MainDBContext())
                                            {
                                                db.ServerMessage.Add(new ServerMessage()
                                                {
                                                    ChargeBoxId = session.ChargeBoxId,
                                                    CreatedBy = "Server",
                                                    CreatedOn = DateTime.UtcNow,
                                                    OutAction = Actions.DataTransfer.ToString(),
                                                    OutRequest = JsonConvert.SerializeObject(
                                                          new DataTransferRequest()
                                                          {
                                                              messageId = "ID_Station_Location",
                                                              vendorId = "Phihong Technology",
                                                              data = JsonConvert.SerializeObject(new { stationName = session.StationName })

                                                          },
                                                          new JsonSerializerSettings() { NullValueHandling = NullValueHandling.Ignore, Formatting = Formatting.None }),
                                                    SerialNo = Guid.NewGuid().ToString(),
                                                    InMessage = string.Empty

                                                });


                                                db.ServerMessage.Add(new ServerMessage()
                                                {
                                                    ChargeBoxId = session.ChargeBoxId,
                                                    CreatedBy = "Server",
                                                    CreatedOn = DateTime.UtcNow,
                                                    OutAction = Actions.ChangeConfiguration.ToString(),
                                                    OutRequest = JsonConvert.SerializeObject(
                                                         new ChangeConfigurationRequest()
                                                         {
                                                             key = "TimeOffset",
                                                             value = "+08:00"

                                                         },
                                                         new JsonSerializerSettings() { NullValueHandling = NullValueHandling.Ignore, Formatting = Formatting.None }),
                                                    SerialNo = Guid.NewGuid().ToString(),
                                                    InMessage = string.Empty

                                                });


                                                if (!TCCStationDic.ContainsKey(session.StationLocation))
                                                {

                                                    _CheckWeatherDt = DateTime.UtcNow.AddDays(-1);
                                                }
                                                else
                                                {

                                                    db.ServerMessage.Add(new ServerMessage()
                                                    {
                                                        ChargeBoxId = session.ChargeBoxId,
                                                        CreatedBy = "Server",
                                                        CreatedOn = DateTime.UtcNow,
                                                        OutAction = Actions.DataTransfer.ToString(),
                                                        OutRequest = JsonConvert.SerializeObject(
                                                        new DataTransferRequest()
                                                        {
                                                            messageId = "ID_Weather_Info",
                                                            vendorId = "Phihong Technology",
                                                            data = JsonConvert.SerializeObject(
                                                                new
                                                                {
                                                                    weatherId = TCCStationDic[session.StationLocation].WeatherID,
                                                                    Temperature = TCCStationDic[session.StationLocation].Temperature
                                                                })
                                                        },
                                                        new JsonSerializerSettings() { NullValueHandling = NullValueHandling.Ignore, Formatting = Formatting.None }),
                                                        SerialNo = Guid.NewGuid().ToString(),
                                                        InMessage = string.Empty

                                                    });

                                                }


                                                db.SaveChanges();


                                            }

                                        }




                                    }
                                    else
                                    {
                                        using (var db = new MainDBContext())
                                        {
                                            var machine = db.Machine.Where(x => x.ChargeBoxId == session.ChargeBoxId).FirstOrDefault();
                                            if (machine != null)
                                            {
                                                if (machine.ConnectorType.Contains("6") || machine.ConnectorType.Contains("7") || machine.ConnectorType.Contains("8") || machine.ConnectorType.Contains("9"))
                                                {
                                                    session.IsAC = false;
                                                }
                                                machine.ConnectionType = session.Origin.Contains("https") ? 2 : 1;
                                                db.SaveChanges();
                                            }
                                        }

                                        await SetDefaultFee(session);
                                    }
                                }


                                if (action == Actions.StartTransaction && session.CustomerId == new Guid("009E603C-79CD-4620-A2B8-D9349C0E8AD8") && replyResult.Message is StartTransactionConfirmation)
                                {

                                    StartTransactionConfirmation confirm = (StartTransactionConfirmation)replyResult.Message;
                                    StartTransactionRequest request = (StartTransactionRequest)analysisResult.Message;
                                    using (var db = new MainDBContext())
                                    {
                                        db.ServerMessage.Add(new ServerMessage()
                                        {
                                            ChargeBoxId = session.ChargeBoxId,
                                            CreatedBy = "Server",
                                            CreatedOn = DateTime.UtcNow.AddMinutes(1),
                                            OutAction = Actions.DataTransfer.ToString(),
                                            OutRequest = JsonConvert.SerializeObject(
                                                    new DataTransferRequest()
                                                    {
                                                        messageId = "ID_GetTxUserInfo",
                                                        vendorId = "Phihong Technology",
                                                        data = JsonConvert.SerializeObject(new { txId = confirm.transactionId, ConnectorId = request.connectorId })
                                                    },
                                                    new JsonSerializerSettings() { NullValueHandling = NullValueHandling.Ignore, Formatting = Formatting.None }),
                                            SerialNo = Guid.NewGuid().ToString(),
                                            InMessage = string.Empty

                                        });

                                        db.SaveChanges();
                                    }
                                }

                            }
                            else
                            {
                                string response = BasicMessageHandler.GenerateCallError(analysisResult.UUID, OCPPErrorCodes.InternalError, OCPPErrorDescription.InternalError);
                                string errorMsg = replyResult.Exception != null ? replyResult.Exception.ToString() : string.Empty;

                                Send(session, response, string.Format("{0} {1}", analysisResult.Action, "Error"), errorMsg);
                            }

                            if (action == Actions.StartTransaction)
                            {
                                var stationId = _loadingBalanceService.GetStationIdByMachineId(session.MachineId);
                                var _powerDic = _loadingBalanceService.GetSettingPower(stationId, session.MachineId);
                                if (_powerDic != null)
                                {
                                    foreach (var kv in _powerDic)
                                    {
                                        try
                                        {
                                            string chargeBoxId = string.Empty;
                                            //set profile
                                            lock (_lockClientDic)
                                            {
                                                chargeBoxId = clientDic.Where(x => x.Value.MachineId == kv.Key).Select(x => x.Value.ChargeBoxId).FirstOrDefault();
                                            }

                                            if (chargeBoxId != null && kv.Value.HasValue)
                                            {
                                                profileHandler.SetChargingProfile(chargeBoxId, kv.Value.Value, Packet.Messages.SubTypes.ChargingRateUnitType.W);
                                            }
                                        }
                                        catch (Exception ex)
                                        {
                                            logger.Error(string.Format("Set Profile Exception: {0}", ex.ToString()));
                                        }

                                    }
                                }
                            }

                            if (action == Actions.StopTransaction)
                            {
                                var stationId = _loadingBalanceService.GetStationIdByMachineId(session.MachineId);
                                if (_loadingBalanceService.IsNeedtoCancelSetting(stationId, session.MachineId, session.ChargeBoxId))
                                {
                                    //Clear  current profile    
                                    profileHandler.ClearChargingProfile(session.ChargeBoxId);

                                    var _powerDic = _loadingBalanceService.GetRerangeSettingPower(stationId);
                                    if (_powerDic != null)
                                    {
                                        foreach (var kv in _powerDic)
                                        {
                                            try
                                            {
                                                string chargeBoxId = string.Empty;
                                                //set profile
                                                lock (_lockClientDic)
                                                {
                                                    chargeBoxId = clientDic.Where(x => x.Value.MachineId == kv.Key).Select(x => x.Value.ChargeBoxId).FirstOrDefault();
                                                }

                                                if (chargeBoxId != null && kv.Value.HasValue)
                                                {
                                                    profileHandler.SetChargingProfile(chargeBoxId, kv.Value.Value, Packet.Messages.SubTypes.ChargingRateUnitType.W);
                                                }
                                            }
                                            catch (Exception ex)
                                            {
                                                logger.Error(string.Format("Set Profile Exception: {0}", ex.ToString()));
                                            }

                                        }
                                    }

                                }

                            }

                        }
                        break;
                    case "FirmwareManagement":
                        {
                            var replyResult = profileHandler.ExecuteFirmwareManagementRequest(action, session, (IRequest)analysisResult.Message);
                            if (replyResult.Success)
                            {
                                string response = BasicMessageHandler.GenerateConfirmation(analysisResult.UUID, (IConfirmation)replyResult.Message);
                                Send(session, response, string.Format("{0} {1}", analysisResult.Action, "Confirmation", replyResult.Exception == null ? string.Empty : replyResult.Exception.ToString()));

                            }
                            else
                            {
                                string response = BasicMessageHandler.GenerateCallError(analysisResult.UUID, OCPPErrorCodes.InternalError, OCPPErrorDescription.InternalError);
                                string errorMsg = replyResult.Exception != null ? replyResult.Exception.ToString() : string.Empty;

                                Send(session, response, string.Format("{0} {1}", analysisResult.Action, "Error"), errorMsg);
                            }

                        }
                        break;
                    case "Security":
                        {
                            var replyResult = profileHandler.ExecuteSecurityRequest(action, session, (IRequest)analysisResult.Message);
                            if (replyResult.Success)
                            {
                                string response = BasicMessageHandler.GenerateConfirmation(analysisResult.UUID, (IConfirmation)replyResult.Message);
                                Send(session, response, string.Format("{0} {1}", analysisResult.Action, "Confirmation", replyResult.Exception == null ? string.Empty : replyResult.Exception.ToString()));

                            }
                            else
                            {
                                string response = BasicMessageHandler.GenerateCallError(analysisResult.UUID, OCPPErrorCodes.InternalError, OCPPErrorDescription.InternalError);
                                string errorMsg = replyResult.Exception != null ? replyResult.Exception.ToString() : string.Empty;

                                Send(session, response, string.Format("{0} {1}", analysisResult.Action, "Error"), errorMsg);
                            }
                        }
                        break;
                    default:
                        {
                            string replyMsg = BasicMessageHandler.GenerateCallError(analysisResult.UUID, OCPPErrorCodes.InternalError, OCPPErrorDescription.InternalError);
                            string errorMsg = string.Format("Couldn't find action name: {0} of profile", action);
                            Send(session, replyMsg, string.Format("{0} {1}", analysisResult.Action, "Error"), errorMsg);
                        }
                        break;

                }
            }
        }

        async private void ProcessConfirmationMessage(MessageResult analysisResult, ClientData session, Actions action)
        {

            BasicMessageHandler msgAnalyser = new BasicMessageHandler();
            if (ReConfirmMessage(analysisResult))
            {
                var profileName = profiles.Where(x => x.IsExisted(analysisResult.Action)).Select(x => x.Name).FirstOrDefault();
                MessageResult confirmResult = null;
                switch (profileName)
                {
                    case "Core":
                        {
                            confirmResult = await profileHandler.ExecuteCoreConfirm(action, session, (IConfirmation)analysisResult.Message, analysisResult.RequestId);
                        }
                        break;
                    case "FirmwareManagement":
                        {
                            confirmResult = profileHandler.ExecuteFirmwareManagementConfirm(action, session, (IConfirmation)analysisResult.Message, analysisResult.RequestId);
                        }
                        break;
                    case "RemoteTrigger":
                        {
                            confirmResult = profileHandler.ExecuteRemoteTriggerConfirm(action, session, (IConfirmation)analysisResult.Message, analysisResult.RequestId);
                        }
                        break;
                    case "Reservation":
                        {
                            confirmResult = profileHandler.ExecuteReservationConfirm(action, session, (IConfirmation)analysisResult.Message, analysisResult.RequestId);
                        }
                        break;
                    case "LocalAuthListManagement":
                        {
                            confirmResult = profileHandler.ExecuteLocalAuthListManagementConfirm(action, session, (IConfirmation)analysisResult.Message, analysisResult.RequestId);
                        }
                        break;
                    case "SmartCharging":
                        {
                            confirmResult = profileHandler.ExecuteSmartChargingConfirm(action, session, (IConfirmation)analysisResult.Message, analysisResult.RequestId);
                        }
                        break;
                    case "Security":
                        {
                            confirmResult = profileHandler.ExecuteSecurityConfirm(action, session, (IConfirmation)analysisResult.Message, analysisResult.RequestId);
                        }
                        break;
                    default:
                        {
                            string replyMsg = BasicMessageHandler.GenerateCallError(analysisResult.UUID, OCPPErrorCodes.InternalError, OCPPErrorDescription.InternalError);
                            string errorMsg = string.Format("Couldn't find action name: {0} of profile", action);
                            Send(session, replyMsg, string.Format("{0} {1}", analysisResult.Action, "Error"), errorMsg);
                        }
                        break;

                }

                if (confirmResult == null || !confirmResult.Success)
                {
                    logger.Error(string.Format("Action:{0} MessageId:{1}  ExecuteConfirm Error:{2} ",
                        analysisResult.Action, analysisResult.UUID, confirmResult.Exception.ToString()));
                }
            }
            else
            {
                string replyMsg = BasicMessageHandler.GenerateCallError(analysisResult.UUID, OCPPErrorCodes.InternalError, OCPPErrorDescription.InternalError);
                string errorMsg = string.Format("Action:{0} MessageId:{1}  didn't exist in confirm message", analysisResult.Action, analysisResult.UUID);
                Send(session, replyMsg, string.Format("{0} {1}", analysisResult.Action, "Error"), errorMsg);
            }
        }

        private void ProcessErrorMessage(MessageResult analysisResult, ClientData session, Actions action)
        {
            BasicMessageHandler msgAnalyser = new BasicMessageHandler();
            if (ReConfirmMessage(analysisResult))
            {
                var profileName = profiles.Where(x => x.IsExisted(analysisResult.Action)).Select(x => x.Name).FirstOrDefault();
                switch (profileName)
                {
                    case "Core":
                        {
                            profileHandler.ReceivedCoreError(action, analysisResult.ReceivedErrorCode, session, analysisResult.RequestId);
                        }
                        break;
                    case "FirmwareManagement":
                        {
                            profileHandler.ReceivedFirmwareManagementError(action, analysisResult.ReceivedErrorCode, session, analysisResult.RequestId);
                        }
                        break;
                    case "RemoteTrigger":
                        {
                            profileHandler.ReceivedRemoteTriggerError(action, analysisResult.ReceivedErrorCode, session, analysisResult.RequestId);
                        }
                        break;
                    case "Reservation":
                        {
                            profileHandler.ExecuteReservationError(action, analysisResult.ReceivedErrorCode, session, analysisResult.RequestId);
                        }
                        break;
                    case "LocalAuthListManagement":
                        {
                            profileHandler.ReceivedLocalAuthListManagementError(action, analysisResult.ReceivedErrorCode, session, analysisResult.RequestId);
                        }
                        break;
                    case "SmartCharging":
                        {
                            profileHandler.ReceivedSmartChargingError(action, analysisResult.ReceivedErrorCode, session, analysisResult.RequestId);
                        }
                        break;
                    default:
                        {
                            string replyMsg = BasicMessageHandler.GenerateCallError(analysisResult.UUID, OCPPErrorCodes.InternalError, OCPPErrorDescription.InternalError);
                            string errorMsg = string.Format("Couldn't find action name: {0} of profile", action);
                            Send(session, replyMsg, string.Format("{0} {1}", analysisResult.Action, "Error"), errorMsg);
                        }
                        break;

                }
            }
            else
            {
                string replyMsg = BasicMessageHandler.GenerateCallError(analysisResult.UUID, OCPPErrorCodes.InternalError, OCPPErrorDescription.InternalError);
                string errorMsg = string.Format("Action:{0} MessageId:{1}  didn't exist in confirm message", analysisResult.Action, analysisResult.UUID);
                Send(session, replyMsg, string.Format("{0} {1}", analysisResult.Action, "Error"), errorMsg);


            }
        }


        private void Send(ClientData session, string msg, string messageType, string errorMsg = "")
        {
            try
            {

                if (session != null)
                {
                    WriteMachineLog(session, msg, messageType, errorMsg, true);
                    session.Send(msg);
                }

            }
            catch (Exception ex)
            {
                logger.Error(string.Format("Send Ex:{0}", ex.ToString()));
            }


        }

        async private void ServerUpdateTrigger()
        {
            for (; ; )
            {
                if (_ct.IsCancellationRequested)
                {
                    break;
                }

                var min_Interval = (DateTime.UtcNow - checkUpdateDt).TotalMinutes;
                if (min_Interval > 3)
                {
                    BasicMessageHandler msgAnalyser = new BasicMessageHandler();
                    Dictionary<string, ClientData> _copyClientDic = null;
                    lock (_lockClientDic)
                    {
                        _copyClientDic = new Dictionary<string, ClientData>(clientDic);

                    }
                    checkUpdateDt = DateTime.UtcNow;
                    using (var db = new MainDBContext())
                    {
                        //var needUpdateChargers = db.Machine.Where(x => x.FW_AssignedMachineVersionId.HasValue == true &&
                        //    x.FW_AssignedMachineVersionId != x.FW_VersionReport && x.Online == true)
                        //    .Select(x => new { x.Id, x.ChargeBoxId, x.FW_AssignedMachineVersionId }).ToList();

                        var needUpdateChargers = db.Machine.Where(x => x.FW_AssignedVersion.HasValue == true &&
                          x.FW_AssignedVersion != x.FW_VersionReport && x.Online == true)
                          .Select(x => x.ChargeBoxId).AsNoTracking().ToList();

                        foreach (var chargeBoxId in needUpdateChargers)
                        {
                            try
                            {


                                ClientData session;
                                if (_copyClientDic.TryGetValue(chargeBoxId, out session))
                                {

                                    string requestId = Guid.NewGuid().ToString();
                                    // using (var db = new MainDBContext())

                                    if (session.IsCheckIn && !session.ISOCPP20)
                                    {

                                        var _request = new TriggerMessageRequest()
                                        {
                                            requestedMessage = Packet.Messages.SubTypes.MessageTrigger.FirmwareStatusNotification
                                        };

                                        var uuid = session.queue.store(_request);
                                        string rawRequest = BasicMessageHandler.GenerateRequest(uuid, _request.Action, _request);
                                        Send(session, rawRequest, string.Format("{0} {1}", _request.Action, "Request"), "");

                                        #region OCTT   ,測試韌體更新方式
                                        //--------------------> OCTT   ,測試韌體更新方式
                                        //{
                                        //    var machine = db.Machine.Where(x => x.FW_AssignedMachineVersionId.HasValue == true &&
                                        //        x.FW_AssignedMachineVersionId != x.FW_VersionReport && x.ChargeBoxId == session.ChargeBoxId)
                                        //        .Select(x => new { x.Id, x.FW_AssignedMachineVersionId }).FirstOrDefault();

                                        //    if (machine != null)
                                        //    {
                                        //        var mv = db.MachineVersion.Include(c => c.PublishVersion)
                                        //         .Include(c => c.PublishVersion.PublishVersionFiles)
                                        //         .Include(c => c.PublishVersion.PublishVersionFiles.Select(z => z.UploadFile))
                                        //         .Where(c => c.Id == machine.FW_AssignedMachineVersionId.Value).First();

                                        //        string downloadUrl = mv.PublishVersion.PublishVersionFiles.FirstOrDefault().UploadFile.FileUrl;

                                        //        var _updateFWrequest = new UpdateFirmwareRequest()
                                        //        {
                                        //            location = new Uri(downloadUrl),
                                        //            retries = 3,
                                        //            retrieveDate = DateTime.UtcNow,
                                        //            retryInterval = 10
                                        //        };
                                        //        db.MachineOperateRecord.Add(new MachineOperateRecord()
                                        //        {
                                        //            CreatedOn = DateTime.UtcNow,
                                        //            ChargeBoxId = session.ChargeBoxId,
                                        //            SerialNo = requestId,
                                        //            RequestContent = JsonConvert.SerializeObject(_updateFWrequest, new JsonSerializerSettings() { NullValueHandling = NullValueHandling.Ignore, Formatting = Formatting.None }),
                                        //            EVSE_Status = 0,
                                        //            EVSE_Value = "Fw Version:" + machine.FW_AssignedMachineVersionId,
                                        //            Status = 0,
                                        //            RequestType = 0,

                                        //        });

                                        //        db.ServerMessage.Add(new ServerMessage()
                                        //        {
                                        //            ChargeBoxId = session.ChargeBoxId,
                                        //            CreatedBy = "Server",
                                        //            CreatedOn = DateTime.UtcNow,
                                        //            OutAction = _updateFWrequest.Action.ToString(),
                                        //            OutRequest = JsonConvert.SerializeObject(_updateFWrequest, new JsonSerializerSettings() { NullValueHandling = NullValueHandling.Ignore, Formatting = Formatting.None }),
                                        //            SerialNo = requestId,
                                        //            InMessage = string.Empty

                                        //        });

                                        //        db.SaveChanges();

                                        //    }

                                        //}
                                        #endregion
                                    }



                                }


                            }
                            catch (Exception ex)
                            {
                                logger.Error(string.Format("serverUpdateTrigger ChargeBoxId:{0}  Ex:{1}", chargeBoxId, ex.ToString()));
                            }
                        }
                    }
                    await Task.Delay(1000);
                    //  Thread.CurrentThread.Join(1000);
                }
            }
        }
        string webConnectionString = ConfigurationManager.ConnectionStrings["WebDBContext"].ConnectionString;

        async private void ServerMessageTrigger()
        {
            for (; ; )
            {
                if (_ct.IsCancellationRequested)
                {
                    break;
                }

                try
                {
                    RemoveConfirmMessage();
                    BasicMessageHandler msgAnalyser = new BasicMessageHandler();
                    using (var db = new MainDBContext())
                    {
                        DateTime startDt = DateTime.UtcNow.AddSeconds(-30);
                        DateTime dt = new DateTime(1991, 1, 1);
                        DateTime currentTime = DateTime.UtcNow;
                        var commandList = db.ServerMessage.Where(c => c.ReceivedOn == dt && c.UpdatedOn == dt && c.CreatedOn >= startDt && c.CreatedOn <= currentTime).AsNoTracking().ToList();


                        //處理主機傳送的有指令
                        var cmdMachineList = commandList.Select(c => c.ChargeBoxId).Distinct().ToList();
                        if (commandList.Count > 0)
                        {
                            // Console.WriteLine(string.Format("Now:{0} commandList Count:{1} ", DateTime.UtcNow.ToString("yyyy/MM/dd HH:mm:ss"), commandList.Count));
                        }
                        var resendList = GetResendMessage();
                        foreach (var resendItem in resendList)
                        {
                            ClientData session;
                            if (clientDic.TryGetValue(resendItem.ChargePointSerialNumber, out session))
                            {
                                if (resendItem.SentTimes > 0 && DateTime.UtcNow.Subtract(resendItem.SentOn).TotalSeconds > 1)
                                {
                                    resendItem.SentTimes--;
                                    resendItem.SentOn = DateTime.UtcNow;
                                    Send(session, resendItem.SentMessage, string.Format("{0} {1}", resendItem.SentAction, "Request"), "");
                                }

                            }

                        }
                        foreach (var charger_SN in cmdMachineList)
                        {
                            ClientData session;
                            string uuid = string.Empty;
                            if (clientDic.TryGetValue(charger_SN, out session))
                            {
                                //logger.Debug(string.Format("charger_SN:{0} startDt:{1} CreatedOn:{2}", charger_SN, startDt.ToString("yyyy/MM/dd HH:mm:ss"), DateTime.UtcNow.ToString("yyyy/MM/dd HH:mm:ss")));

                                if (session.IsCheckIn && !session.ISOCPP20)
                                {
                                    string rawRequest = string.Empty;

                                    var cmdList = commandList.Where(c => c.ChargeBoxId == charger_SN).ToList();

                                    foreach (var item in cmdList)
                                    {
                                        IRequest request = null;
                                        Actions action = Actions.None;
                                        Enum.TryParse(item.OutAction, out action);
                                        Type _RequestType = null;

                                        for (int i = 0; i < profiles.Count; i++)
                                        {
                                            var feature = profiles[i].GetFeaturebyAction(item.OutAction);

                                            if (feature != null)
                                            {
                                                _RequestType = feature.GetRequestType();
                                                break;
                                            }
                                        }

                                        if (_RequestType != null && item.CreatedBy != "Destroyer")
                                        {
                                            request = JsonConvert.DeserializeObject(item.OutRequest, _RequestType) as IRequest;
                                            uuid = session.queue.store(request);
                                            rawRequest = BasicMessageHandler.GenerateRequest(uuid, item.OutAction, request);
                                            Send(session, rawRequest, string.Format("{0} {1}", action, "Request"), "");
                                        }


                                        if (item.CreatedBy == "Destroyer")
                                        {

                                            if (_RequestType != null)
                                            {
                                                request = Activator.CreateInstance(_RequestType) as IRequest;
                                                uuid = session.queue.store(request);
                                                rawRequest = BasicMessageHandler.GenerateDestroyRequest(uuid, item.OutAction, item.OutRequest);
                                                Send(session, rawRequest, string.Format("{0} {1}", action, "Request"), "");

                                            }
                                            else
                                            {

                                                rawRequest = BasicMessageHandler.GenerateDestroyRequest(Guid.NewGuid().ToString(), item.OutAction, item.OutRequest);
                                                Send(session, rawRequest, string.Format("{0} {1}", action, "Request"), "");

                                            }
                                        }

                                        AddConfirmMessage(charger_SN, item.Id, item.SerialNo, item.OutAction, uuid, item.CreatedBy, rawRequest);

                                        #region 更新資料表單一欄位
                                        var _UpdatedItem = new ServerMessage() { Id = item.Id, UpdatedOn = DateTime.UtcNow };
                                        db.Configuration.AutoDetectChangesEnabled = false;//自動呼叫DetectChanges()比對所有的entry集合的每一個屬性Properties的新舊值
                                        db.Configuration.ValidateOnSaveEnabled = false;// 因為Entity有些欄位必填，若不避開會有Validate錯誤
                                                                                       // var _UpdatedItem = db.ServerMessage.Where(x => x.Id == item.Id).FirstOrDefault();
                                        db.ServerMessage.Attach(_UpdatedItem);
                                        _UpdatedItem.UpdatedOn = DateTime.UtcNow;
                                        db.Entry(_UpdatedItem).Property(x => x.UpdatedOn).IsModified = true;// 可以直接使用這方式強制某欄位要更新，只是查詢集合耗效能而己

                                        db.SaveChanges();

                                        #endregion

                                        await Task.Delay(100);

                                    }
                                }
                            }
                        }

                    }

                    await Task.Delay(500);

                }
                catch (Exception ex)
                {
                    logger.Error(string.Format("ServerMessageTrigger  Ex:{0}", ex.ToString()));
                }
            }
        }


        async private void HeartBeatCheckTrigger()
        {
            for (; ; )
            {
                if (_ct.IsCancellationRequested)
                {
                    break;
                }

                try
                {
                    if (DateTime.UtcNow.Subtract(lastcheckdt).TotalSeconds > 30)
                    {
                        lastcheckdt = DateTime.UtcNow;
                        Stopwatch watch = new Stopwatch();
                        Dictionary<string, ClientData> _copyClientDic = null;
                        lock (_lockClientDic)
                        {
                            _copyClientDic = new Dictionary<string, ClientData>(clientDic);
                        }

                        var cdt = DateTime.UtcNow;
                        var clients = _copyClientDic.Where(x => x.Value.LastActiveTime > cdt.AddSeconds(-120)).Select(x => x.Value).ToList();

                        watch.Start();
                        foreach (var session in clients)
                        {
                            using (var db = new MainDBContext())
                            {
                                var machine = new Machine() { Id = session.MachineId };
                                if (machine != null)
                                {
                                    db.Configuration.AutoDetectChangesEnabled = false;
                                    db.Configuration.ValidateOnSaveEnabled = false;
                                    db.Machine.Attach(machine);
                                    machine.HeartbeatUpdatedOn = DateTime.UtcNow;
                                    machine.ConnectionType = session.UriScheme.Equals("wss") ? 2 : 1;
                                    db.Entry(machine).Property(x => x.HeartbeatUpdatedOn).IsModified = true;
                                    db.Entry(machine).Property(x => x.ConnectionType).IsModified = true;
                                    await db.SaveChangesAsync();
                                }

                            }
                        }
                        watch.Stop();
                        if (watch.ElapsedMilliseconds / 1000 > 5)
                        {
                            logger.Fatal("Update HeartBeatCheckTrigger cost " + watch.ElapsedMilliseconds / 1000 + " seconds.");
                        }
                    }


                    await Task.Delay(10000);
                }
                catch (Exception ex)
                {
                    Console.WriteLine("***********************************************************");
                    logger.Error(string.Format("HeartBeatCheckTrigger  Ex:{0}", ex.ToString()));
                }

            }
        }

        async private void ServerWeatherNotificationTrigger()
        {
            for (; ; )
            {
                if (_ct.IsCancellationRequested)
                {
                    break;
                }

                var min_Interval = (DateTime.UtcNow - _CheckWeatherDt).TotalMinutes;

                if (min_Interval > 30)
                {
                    // Console.WriteLine("in...............ServerWeatherNotificationTrigger");
                    BasicMessageHandler msgAnalyser = new BasicMessageHandler();
                    Dictionary<string, ClientData> _copyClientDic = null;
                    lock (_lockClientDic)
                    {
                        _copyClientDic = new Dictionary<string, ClientData>(clientDic);

                    }
                    _CheckWeatherDt = DateTime.UtcNow;

                    var locations = _copyClientDic.Where(x => !string.IsNullOrEmpty(x.Value.StationLocation)).Distinct().Select(x => x.Value.StationLocation).ToList();

                    // Console.WriteLine("in...............ServerWeatherNotificationTrigger");
                    foreach (var location in locations)
                    {

                        try
                        {   //query weather
                            var httpResult = await httpClient.GetWeather("https://api.weatherapi.com/v1/current.json?key=874346abc0874e69a9423510222201&q=" + location, null, null);

                            string temp = "17";
                            string weather_code = "1183";
                            if (httpResult.Status == System.Net.HttpStatusCode.OK)
                            {
                                try
                                {
                                    var jsonResult = JsonConvert.DeserializeObject(httpResult.Response) as JObject;
                                    temp = jsonResult["current"]["temp_c"].ToString();
                                    weather_code = jsonResult["current"]["condition"]["code"].ToString();


                                }
                                catch (Exception ex)
                                {
                                    ;
                                }

                            }

                            #region 台泥氣象Mapping
                            switch (weather_code)
                            {
                                case "1000":
                                    weather_code = "1";
                                    break;
                                case "1003":
                                case "1006":
                                case "1009":
                                    weather_code = "2";
                                    break;
                                case "1063":
                                case "1072":
                                case "1150":
                                case "1153":
                                case "1168":
                                case "1171":
                                case "1180":
                                case "1183":
                                case "1186":
                                case "1189":
                                case "1192":
                                case "1195":
                                case "1198":
                                case "1201":
                                case "1237":
                                case "1240":
                                case "1243":
                                case "1246":
                                case "1261":
                                case "1264":
                                    weather_code = "3";
                                    break;
                                case "1087":
                                case "1273":
                                case "1276":
                                case "1279":
                                case "1282":
                                    weather_code = "4";
                                    break;
                                case "1066":
                                case "1069":
                                case "1114":
                                case "1117":
                                case "1204":
                                case "1207":
                                case "1210":
                                case "1213":
                                case "1216":
                                case "1219":
                                case "1222":
                                case "1225":
                                case "1249":
                                case "1252":
                                case "1255":
                                case "1258":
                                    weather_code = "5";
                                    break;
                                case "1030":
                                case "1135":
                                case "1147":
                                    weather_code = "2";
                                    break;
                                default:
                                    weather_code = "2";
                                    break;
                            }
                            #endregion


                            if (TCCStationDic.ContainsKey(location))
                            {
                                TCCStationDic[location].Temperature = (int)double.Parse(temp);
                                TCCStationDic[location].WeatherID = int.Parse(weather_code);
                            }
                            else
                            {
                                TCCStationDic.Add(location, new TCCWeatherDto() { WeatherID = int.Parse(weather_code), Temperature = (int)double.Parse(temp) });
                            }

                        }
                        catch (Exception ex)
                        {
                            logger.Error(string.Format("ServerWeatherNotificationTrigger ChargeBoxId:{0}  Ex:{1}", location, ex.ToString()));
                        }
                    }

                    var clients = _copyClientDic.Where(x => x.Value.CustomerId == new Guid("009E603C-79CD-4620-A2B8-D9349C0E8AD8")).
                    Select(x => new { ChargeBoxId = x.Value.ChargeBoxId, StationLocation = x.Value.StationLocation }).ToList();

                    using (var db = new MainDBContext())
                    {

                        foreach (var client in clients)
                        {
                            try
                            {
                                if (string.IsNullOrEmpty(client.StationLocation))
                                {
                                    Console.WriteLine(client.StationLocation + " is empty");
                                    continue;
                                }


                                if (TCCStationDic.ContainsKey(client.StationLocation))
                                {
                                    db.ServerMessage.Add(new ServerMessage()
                                    {
                                        ChargeBoxId = client.ChargeBoxId,
                                        CreatedBy = "Server",
                                        CreatedOn = DateTime.UtcNow,
                                        OutAction = Actions.DataTransfer.ToString(),
                                        OutRequest = JsonConvert.SerializeObject(
                                                           new DataTransferRequest()
                                                           {
                                                               messageId = "ID_Weather_Info",
                                                               vendorId = "Phihong Technology",
                                                               data = JsonConvert.SerializeObject(
                                                                   new
                                                                   {
                                                                       weatherId = TCCStationDic[client.StationLocation].WeatherID,
                                                                       Temperature = TCCStationDic[client.StationLocation].Temperature
                                                                   })
                                                           },
                                                           new JsonSerializerSettings() { NullValueHandling = NullValueHandling.Ignore, Formatting = Formatting.None }),
                                        SerialNo = Guid.NewGuid().ToString(),
                                        InMessage = string.Empty

                                    });

                                    await db.SaveChangesAsync();
                                }
                            }
                            catch (Exception ex)
                            {
                                logger.Error(string.Format("ServerWeatherNotificationTrigger ChargeBoxId:{0}  Ex:{1}", client.ChargeBoxId, ex.ToString()));
                            }


                        }
                    }

                }
                await Task.Delay(1000);
            }
        }

        async private void ServerSetFeeTrigger()
        {
            for (; ; )
            {
                if (_ct.IsCancellationRequested)
                {
                    break;
                }

                var min_Interval = (DateTime.UtcNow - _CheckFeeDt).TotalMinutes;
                if (min_Interval > 1)
                {
                    BasicMessageHandler msgAnalyser = new BasicMessageHandler();
                    Dictionary<string, ClientData> _copyClientDic = null;
                    lock (_lockClientDic)
                    {
                        _copyClientDic = new Dictionary<string, ClientData>(clientDic);

                    }
                    _CheckFeeDt = DateTime.UtcNow;
                    foreach (var item in _copyClientDic)
                    {
                        try
                        {
                            ClientData session = item.Value;
                            if (session.IsCheckIn)
                            {

                                string displayPriceText = await SetDefaultFee(session);
                                if (!string.IsNullOrEmpty(displayPriceText) && displayPriceText != session.DisplayPrice)
                                {
                                    clientDic[item.Key].DisplayPrice = displayPriceText;

                                    using (var db = new MainDBContext())
                                    {
                                        db.ServerMessage.Add(new ServerMessage()
                                        {
                                            ChargeBoxId = session.ChargeBoxId,
                                            CreatedBy = "Server",
                                            CreatedOn = DateTime.UtcNow,
                                            OutAction = Actions.ChangeConfiguration.ToString(),
                                            OutRequest = JsonConvert.SerializeObject(
                                                    new ChangeConfigurationRequest()
                                                    {
                                                        key = "DefaultPrice",
                                                        value = clientDic[item.Key].DisplayPrice
                                                    },
                                                    new JsonSerializerSettings() { NullValueHandling = NullValueHandling.Ignore, Formatting = Formatting.None }),
                                            SerialNo = Guid.NewGuid().ToString(),
                                            InMessage = string.Empty

                                        }); ;

                                        if (session.CustomerId == new Guid("10C7F5BD-C89A-4E2A-8611-B617E0B41A73"))
                                        {
                                            db.ServerMessage.Add(new ServerMessage()
                                            {
                                                ChargeBoxId = session.ChargeBoxId,
                                                CreatedBy = "Server",
                                                CreatedOn = DateTime.UtcNow,
                                                OutAction = Actions.ChangeConfiguration.ToString(),
                                                OutRequest = JsonConvert.SerializeObject(
                                                   new ChangeConfigurationRequest()
                                                   {
                                                       key = "ConnectionTimeOut",
                                                       value = "120"
                                                   },
                                                   new JsonSerializerSettings() { NullValueHandling = NullValueHandling.Ignore, Formatting = Formatting.None }),
                                                SerialNo = Guid.NewGuid().ToString(),
                                                InMessage = string.Empty

                                            });
                                            db.ServerMessage.Add(new ServerMessage()
                                            {
                                                ChargeBoxId = session.ChargeBoxId,
                                                CreatedBy = "Server",
                                                CreatedOn = DateTime.UtcNow,
                                                OutAction = Actions.ChangeConfiguration.ToString(),
                                                OutRequest = JsonConvert.SerializeObject(
                                                   new ChangeConfigurationRequest()
                                                   {
                                                       key = "MeterValueSampleInterval",
                                                       value = "3"
                                                   },
                                                   new JsonSerializerSettings() { NullValueHandling = NullValueHandling.Ignore, Formatting = Formatting.None }),
                                                SerialNo = Guid.NewGuid().ToString(),
                                                InMessage = string.Empty

                                            });
                                        }

                                        await db.SaveChangesAsync();

                                    }
                                }
                            }

                        }
                        catch (Exception ex)
                        {
                            logger.Error(string.Format("ServerSetFeeTrigger ChargeBoxId:{0}  Ex:{1}", item.Key, ex.ToString()));
                        }
                    }
                }
                await Task.Delay(1000);
            }
        }

        async private Task<string> SetDefaultFee(ClientData client)
        {
            string displayPriceText = string.Empty;
            string charingPriceText = string.Empty;

            if (string.IsNullOrEmpty(client.ChargeBoxId)) return displayPriceText;

            using (SqlConnection conn = new SqlConnection(webConnectionString))
            {
                try
                {


                    var parameters = new DynamicParameters();
                    parameters.Add("@MachineId", client.MachineId, DbType.String, ParameterDirection.Input);
                    string displayPricestrSql = "";
                    string strSql = "";

                    if (client.IsAC)
                    {
                        displayPricestrSql = "   SELECT  [AC_BillingMethod] as BillingMethod,[AC_FeeName] as FeeName,[AC_Fee] as ChargingFeebyHour" +
                    "  ,[AC_ParkingFee] as ParkingFee, [Currency]  FROM[StationMachine]  left join[dbo].[Station]" +
                    "  on[StationMachine].StationId = Station.[Id]  where StationMachine.MachineId=@MachineId and Station.IsBilling=1; ";

                        strSql = " SELECT CAST( [StartTime] as varchar(5)) StartTime,CAST( [EndTime] as varchar(5)) EndTime,[Fee]  FROM[StationMachine]  left join [dbo].[StationFee]" +
                       " on[StationMachine].StationId = StationFee.StationId  where StationMachine.MachineId =@MachineId and StationFee.IsAC=1; ";
                    }
                    else
                    {
                        displayPricestrSql = "   SELECT  [DC_BillingMethod] as BillingMethod,[DC_FeeName] as FeeName,[DC_Fee] as ChargingFeebyHour" +
                   "  ,[DC_ParkingFee] as ParkingFee, [Currency]  FROM[StationMachine]  left join[dbo].[Station]" +
                   "  on[StationMachine].StationId = Station.[Id]  where StationMachine.MachineId=@MachineId and Station.IsBilling=1; ";

                        strSql = " SELECT CAST( [StartTime] as varchar(5)) StartTime,CAST( [EndTime] as varchar(5)) EndTime,[Fee]  FROM[StationMachine]  left join [dbo].[StationFee]" +
                       " on[StationMachine].StationId = StationFee.StationId  where StationMachine.MachineId =@MachineId and StationFee.IsAC=0; ";

                    }
                    var result = await conn.QueryAsync<StationFee>(displayPricestrSql, parameters);
                    if (result.Count() == 0)
                    {
                        return string.Empty;
                    }
                    var stationPrice = result.First();

                    if (stationPrice.BillingMethod == 1)
                    {
                        var chargingPriceResult = await conn.QueryAsync<ChargingPrice>(strSql, parameters);
                        client.ChargingPrices = chargingPriceResult.ToList();
                        if (string.IsNullOrEmpty(client.ChargingPrices[0].StartTime))
                        {
                            client.ChargingPrices = new List<ChargingPrice>();
                        }
                    }

                    displayPriceText = stationPrice.FeeName;
                    client.BillingMethod = stationPrice.BillingMethod;
                    client.Currency = stationPrice.Currency;
                    client.ChargingFeebyHour = stationPrice.ChargingFeebyHour;
                    client.ParkingFee = stationPrice.ParkingFee;
                    client.IsBilling = true;
                }
                catch (Exception ex)
                {
                    logger.Error(ex.ToString());
                }
            }

            return displayPriceText;
        }

        async private void HealthCheckTrigger()
        {
            for (; ; )
            {
                if (_ct.IsCancellationRequested)
                {
                    break;
                }

                try
                {
                    Dictionary<string, ClientData> _copyClientDic = null;
                    lock (_lockClientDic)
                    {
                        _copyClientDic = new Dictionary<string, ClientData>(clientDic);
                    }

                    var removeClients = _copyClientDic.Where(x => x.Value.LastActiveTime < DateTime.UtcNow.AddSeconds(-300)).Select(x => x.Value).ToList();

                    foreach (var session in removeClients)
                    {

                        Console.WriteLine(string.Format("Server forced to shut down ChargeBox ({0}: LastActiveTime{1})", session.ChargeBoxId, session.LastActiveTime));
                        RemoveClient(session);
                    }

                    await Task.Delay(60000);
                }
                catch (Exception ex)
                {
                    logger.Error(string.Format("HealthAlarmTrigger  Ex:{0}", ex.ToString()));
                }

            }
        }


        private List<NeedConfirmMessage> GetResendMessage()
        {
            List<NeedConfirmMessage> sendMessages = new List<NeedConfirmMessage>();
            lock (_lockConfirmPacketList)
            {
                sendMessages = needConfirmPacketList.Where(x => x.SentTimes > 1 && x.CreatedBy == "Server").ToList();

            }

            return sendMessages;
        }

        private void AddConfirmMessage(string chargePointSerialNumber, int table_id, string requestId, string action, string msg_id, string createdBy, string sendMessage)
        {
            NeedConfirmMessage _needConfirmMsg = new NeedConfirmMessage();
            _needConfirmMsg.Id = table_id;
            _needConfirmMsg.SentAction = action;
            _needConfirmMsg.SentOn = DateTime.UtcNow;
            _needConfirmMsg.SentTimes = 4;
            _needConfirmMsg.ChargePointSerialNumber = chargePointSerialNumber;
            _needConfirmMsg.RequestId = requestId;
            _needConfirmMsg.SentUniqueId = msg_id;
            _needConfirmMsg.CreatedBy = createdBy;
            _needConfirmMsg.SentMessage = sendMessage;

            if (needConfirmActions.Contains(action))
            {

                lock (_lockConfirmPacketList)
                {
                    needConfirmPacketList.Add(_needConfirmMsg);
                }
            }
        }

        private void RemoveConfirmMessage()
        {
            var before10Mins = DateTime.UtcNow.AddMinutes(-10);
            lock (_lockConfirmPacketList)
            {
                var removeList = needConfirmPacketList.Where(x => x.SentTimes == 0 || x.SentOn < before10Mins).ToList();
                foreach (var item in removeList)
                {
                    needConfirmPacketList.Remove(item);
                }               
            }
        }

        private bool ReConfirmMessage(MessageResult analysisResult)
        {
            bool confirmed = false;
            if (needConfirmActions.Contains(analysisResult.Action))
            {

                NeedConfirmMessage foundRequest = null;
                lock (_lockConfirmPacketList)
                {
                    foundRequest = needConfirmPacketList.Where(x => x.SentUniqueId == analysisResult.UUID).FirstOrDefault();
                }

                if (foundRequest != null && foundRequest.Id > 0)
                {
                    foundRequest.SentTimes = 0;
                    foundRequest.SentInterval = 0;
                    analysisResult.RequestId = foundRequest.RequestId;

                    using (var db = new MainDBContext())
                    {
                        var sc = db.ServerMessage.Where(x => x.Id == foundRequest.Id).FirstOrDefault();
                        sc.InMessage = JsonConvert.SerializeObject(analysisResult.Message, Formatting.None);
                        sc.ReceivedOn = DateTime.UtcNow;
                        db.SaveChanges();
                        //  Console.WriteLine(string.Format("Now:{0} ServerMessage Id:{1} ", DateTime.UtcNow.ToString("yyyy/MM/dd HH:mm:ss"), foundRequest.Id));

                    }
                    confirmed = true;



                }
                else if (analysisResult.Action == Actions.TriggerMessage.ToString())
                {
                    confirmed = true;
                }
                else
                {
                    logger.Error(string.Format("Received no record Action:{0} MessageId:{1} ", analysisResult.Action, analysisResult.UUID));
                }
            }

            return confirmed;
        }




        private void RemoveClient(ClientData session)
        {


            if (session != null)
            {

                logger.Trace("RemoveClient[" + session.ChargeBoxId + "]");
                if (session.Connected)
                {
                    session.Close(CloseReason.ServerShutdown);
                }
                RemoveClientDic(session);
                try
                {
                    session.m_ReceiveData -= new ClientData.OCPPClientDataEventHandler<ClientData, String>(ReceivedMessage);
                    // session.Close(CloseReason.ServerShutdown);

                }
                catch (Exception ex)
                {
                    //logger.Warn("Close client socket error!!");
                    logger.Warn(string.Format("Close client socket error!! {0} Msg:{1}", session.ChargeBoxId, ex.Message));
                }

                if (session != null)
                {
                    session = null;
                }

            }
        }

        private void RemoveClientDic(ClientData session)
        {
            if (!string.IsNullOrEmpty(session.ChargeBoxId))
            {
                lock (_lockClientDic)
                {

                    if (clientDic.ContainsKey(session.ChargeBoxId))
                    {
                        if (clientDic[session.ChargeBoxId].SessionID == session.SessionID)
                        {
                            logger.Debug(String.Format("ChargeBoxId:{0} Remove SessionId:{1} Removed SessionId:{2}", session.ChargeBoxId, session.SessionID, clientDic[session.ChargeBoxId].SessionID));

                            clientDic.Remove(session.ChargeBoxId);
                            logger.Trace("RemoveClient ContainsKey " + session.ChargeBoxId);
                        }

                    }
                }
            }

        }

        private void WarmUpLog()
        {

            using (var log = new ConnectionLogDBContext())
            {
                log.MachineConnectionLog.ToList();
            }
        }

        private void WriteMachineLog(ClientData clientData, string data, string messageType, string errorMsg = "", bool isSent = false)
        {
            try
            {

                if (clientData == null || string.IsNullOrEmpty(data)) return;

                if (clientData.ChargeBoxId == null)
                {
                    logger.Fatal(clientData.Path + "]********************session ChargeBoxId null sessionId=" + clientData.SessionID);
                }
                using (var db = new ConnectionLogDBContext())
                {
                    string sp = "[dbo].[uspInsertMachineConnectionLog] @CreatedOn," +
                          "@ChargeBoxId,@MessageType,@Data,@Msg,@IsSent,@EVSEEndPoint,@Session";
                    var dd = DateTime.UtcNow;
                    SqlParameter[] parameter =
                    {
                      new SqlParameter("CreatedOn",dd),
                      new SqlParameter("ChargeBoxId",clientData.ChargeBoxId==null?"unknown":clientData.ChargeBoxId.Replace("'","''")),
                      new SqlParameter("MessageType",messageType.Replace("'","''")),
                      new SqlParameter("Data",data.Replace("'","''")),
                      new SqlParameter("Msg",errorMsg.Replace("'","''")),
                      new  SqlParameter("IsSent",isSent),
                      new  SqlParameter("EVSEEndPoint",clientData.RemoteEndPoint==null?"123":clientData.RemoteEndPoint.ToString()),
                      new  SqlParameter("Session",clientData.SessionID==null?"123":clientData.SessionID)
               };

                    db.Database.ExecuteSqlCommand(sp, parameter);
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.ToString());
            }


        }
    }
}