/// <summary>Performing the necessary operations when entering the automatic mode.</summary>
        /// <param name="url">Streaming URL.</param>
        /// <returns>.</returns>
        private static LiveVideoControlResult ProcessAutomaticMode(string url)
        {
            LogManager.WriteLog(
                TraceType.INFO,
                "Entering automatic mode",
                "PIS.Ground.LiveVideoControl.LiveVideoControlService.ProcessAutomaticMode",
                null,
                EventIdEnum.LiveVideoControl);

            LiveVideoControlResult result = new LiveVideoControlResult();

            result.RequestId  = Guid.Empty;
            result.ResultCode = LiveVideoControlErrorEnum.InternalError;

            // Starting a background process to send start commands to the trains that have the
            // desired status
            DelegateAutomaticModeBackgroundProcessing handler = SendStartStreamingCommandToProperStatusElements;

            handler.BeginInvoke(url, handler.EndInvoke, null);

            result.Url        = url;
            result.ResultCode = LiveVideoControlErrorEnum.RequestAccepted;

            return(result);
        }
        /// <summary>Command to select the automatic or manual starting mode for the video streaming.
        ///          If the specified URL is empty or null, manual mode is selected.
        ///          Otherwise, automatic mode is selected</summary>
        /// <param name="sessionId">Identifier for the session.</param>
        /// <param name="url">URL of the stream to be used in automatic mode.</param>
        /// <returns>Return statement of the request (Success, failed,...) with URL and request id.</returns>
        LiveVideoControlResult ILiveVideoControlService.ChangeCommandMode(Guid sessionId, string url)
        {
            LiveVideoControlResult result = new LiveVideoControlResult();

            result.RequestId  = Guid.Empty;
            result.ResultCode = LiveVideoControlErrorEnum.InternalError;

            if (_sessionManager.IsSessionValid(sessionId))
            {
                // Checking if the specified url contains an non empty string
                if (string.IsNullOrEmpty(url) || url.Trim().Length == 0)
                {
                    // If empty url, it means we want to clear the automatic mode
                    if (ClearAutomaticMode())
                    {
                        // Notify all clients that we are entering the manual mode
                        LiveVideoControlService.SendNotificationToGroundApp(
                            Guid.Empty,
                            PIS.Ground.GroundCore.AppGround.NotificationIdEnum.LiveVideoControlManualMode,
                            null);
                    }
                    result.ResultCode = LiveVideoControlErrorEnum.RequestAccepted;
                }
                else
                {
                    // If non empty url, it means we want to enter the automatic mode
                    lock (_automaticModeLock)
                    {
                        if (SetAutomaticMode(url))
                        {
                            // Send notifications and start commands
                            result = ProcessAutomaticMode(url);

                            // If the command failed, restore the manual mode
                            if (result.ResultCode != LiveVideoControlErrorEnum.RequestAccepted)
                            {
                                ClearAutomaticMode();
                            }
                        }
                        else
                        {
                            // We are already in automatic mode. Get the current url used.
                            string currentAutomaticURL;
                            GetAutomaticMode(out currentAutomaticURL);
                            result.Url        = currentAutomaticURL;
                            result.ResultCode = LiveVideoControlErrorEnum.AutomaticModeActivated;
                        }
                    }
                }
            }
            else
            {
                result.ResultCode = LiveVideoControlErrorEnum.InvalidSessionId;
            }

            return(result);
        }
        /// <summary>Command to determine the current command mode.</summary>
        /// <param name="sessionId">Identifier for the session.</param>
        /// <returns>Null if manual mode, streaming URL if automatic mode</returns>
        LiveVideoControlResult ILiveVideoControlService.GetCommandMode(Guid sessionId)
        {
            LiveVideoControlResult result = new LiveVideoControlResult();

            result.RequestId  = Guid.Empty;
            result.ResultCode = LiveVideoControlErrorEnum.InternalError;
            result.Url        = null;

            if (_sessionManager.IsSessionValid(sessionId))
            {
                string url;
                GetAutomaticMode(out url);
                result.Url        = url;
                result.ResultCode = LiveVideoControlErrorEnum.RequestAccepted;
            }
            else
            {
                result.ResultCode = LiveVideoControlErrorEnum.InvalidSessionId;
            }

            return(result);
        }
        /// <summary>
        /// LiveVideoControlService Web service method "StartVideoStreamingCommand" that sends a
        /// scheduled message to addressee.
        /// </summary>
        /// <param name="sessionId">The session identifier.</param>
        /// <param name="targetAddress">Addressee information.</param>
        /// <param name="url">The request timeout.</param>
        /// <returns>Response <see cref="LiveVideoControlResult"/>.</returns>
        LiveVideoControlResult ILiveVideoControlService.StartVideoStreamingCommand(
            Guid sessionId,
            TargetAddressType targetAddress,
            string url)
        {
            LiveVideoControlResult result = new LiveVideoControlResult();

            result.RequestId  = Guid.Empty;
            result.ResultCode = LiveVideoControlErrorEnum.RequestAccepted;

            string automaticModeURL;

            if (_sessionManager.IsSessionValid(sessionId))
            {
                if (GetAutomaticMode(out automaticModeURL) == false)
                {
                    _dicVideoHistory[targetAddress]            = url;
                    _dicVideoHistorySentService[targetAddress] = null;

                    result = SendStartStreamingCommand(
                        sessionId,
                        targetAddress,
                        url
                        );
                }
                else
                {
                    result.Url        = automaticModeURL;
                    result.ResultCode = LiveVideoControlErrorEnum.AutomaticModeActivated;
                }
            }
            else
            {
                result.ResultCode = LiveVideoControlErrorEnum.InvalidSessionId;
            }

            return(result);
        }
        /// <summary>
        /// LiveVideoControlService Web service method "StopVideoStreamingCommand" that cancels all
        /// predefined and free-text messages at addressee.
        /// </summary>
        /// <param name="sessionId">The session identifier.</param>
        /// <param name="targetAddress">Addressee information.</param>
        /// <returns>Response <see cref="LiveVideoControlResult"/>.</returns>
        LiveVideoControlResult ILiveVideoControlService.StopVideoStreamingCommand(
            Guid sessionId,
            TargetAddressType targetAddress)
        {
            LiveVideoControlResult result = new LiveVideoControlResult();

            result.RequestId  = Guid.Empty;
            result.ResultCode = LiveVideoControlErrorEnum.RequestAccepted;

            _dicVideoHistory.Remove(targetAddress);
            _dicVideoHistorySentService.Remove(targetAddress);

            if (_sessionManager.IsSessionValid(sessionId))
            {
                string automaticModeURL;

                if (GetAutomaticMode(out automaticModeURL) == false)
                {
                    Guid   requestId = Guid.Empty;
                    string error     = _sessionManager.GenerateRequestID(sessionId, out requestId);

                    if (requestId != Guid.Empty)
                    {
                        ElementList <AvailableElementData> elements;
                        T2GManagerErrorEnum rqstResult = _t2gManager.GetAvailableElementDataByTargetAddress(targetAddress, out elements);
                        switch (rqstResult)
                        {
                        case T2GManagerErrorEnum.eSuccess:
                        {
                            List <RequestContext> newRequests = new List <RequestContext>();
                            foreach (AvailableElementData element in elements)
                            {
                                LiveVideoControlService.SendNotificationToGroundApp(requestId, PIS.Ground.GroundCore.AppGround.NotificationIdEnum.LiveVideoControlDistributionProcessing, element.ElementNumber);

                                ProcessStopVideoStreamingCommandRequestContext request = new ProcessStopVideoStreamingCommandRequestContext(
                                    element.ElementNumber,
                                    requestId,
                                    sessionId);

                                newRequests.Add(request);
                            }

                            _requestProcessor.AddRequestRange(newRequests);
                            result.RequestId  = requestId;
                            result.ResultCode = LiveVideoControlErrorEnum.RequestAccepted;
                        }

                        break;

                        case T2GManagerErrorEnum.eT2GServerOffline:
                            result.ResultCode = LiveVideoControlErrorEnum.T2GServerOffline;
                            break;

                        case T2GManagerErrorEnum.eElementNotFound:
                            result.ResultCode = LiveVideoControlService.GetInvalidTargetAddressResponse(targetAddress);
                            break;

                        default:
                            break;
                        }
                    }
                    else
                    {
                        LogManager.WriteLog(TraceType.ERROR, error, "PIS.Ground.LiveVideoControl.LiveVideoControlService.StopVideoStreamingCommand", null, EventIdEnum.LiveVideoControl);
                        result.ResultCode = LiveVideoControlErrorEnum.InvalidRequestID;
                    }
                }
                else
                {
                    result.Url        = automaticModeURL;
                    result.ResultCode = LiveVideoControlErrorEnum.AutomaticModeActivated;
                }
            }
            else
            {
                result.ResultCode = LiveVideoControlErrorEnum.InvalidSessionId;
            }

            return(result);
        }
        /// <summary>Sends a start streaming command.</summary>
        /// <param name="sessionId">The session identifier.</param>
        /// <param name="targetAddress">Addressee information.</param>
        /// <param name="url">The streaming URL to be used.</param>
        /// <returns>Response <see cref="LiveVideoControlElementListResult"/>.</returns>
        private static LiveVideoControlResult SendStartStreamingCommand(
            Guid sessionId,
            TargetAddressType targetAddress,
            string url)
        {
            LiveVideoControlResult result = new LiveVideoControlResult();

            result.RequestId  = Guid.Empty;
            result.ResultCode = LiveVideoControlErrorEnum.InternalError;
            Guid   requestId = Guid.Empty;
            string error;

            if (sessionId != Guid.Empty)
            {
                error = _sessionManager.GenerateRequestID(sessionId, out requestId);
            }
            else
            {
                error = _sessionManager.GenerateRequestID(out requestId);
            }

            if (requestId != Guid.Empty)
            {
                ElementList <AvailableElementData> elements;
                T2GManagerErrorEnum rqstResult = _t2gManager.GetAvailableElementDataByTargetAddress(targetAddress, out elements);

                switch (rqstResult)
                {
                case T2GManagerErrorEnum.eSuccess:
                    Guid notificationRequestId        = requestId;
                    List <RequestContext> newRequests = new List <RequestContext>();
                    foreach (AvailableElementData element in elements)
                    {
                        if (_dicVideoHistorySentService.ContainsKey(targetAddress))
                        {
                            ServiceInfo availableService;
                            if (_t2gManager.GetAvailableServiceData(element.ElementNumber, (int)eServiceID.eSrvSIF_LiveVideoControlServer, out availableService) == T2GManagerErrorEnum.eSuccess)
                            {
                                _dicVideoHistorySentService[targetAddress] = availableService;
                            }
                        }

                        LiveVideoControlService.SendNotificationToGroundApp(requestId, PIS.Ground.GroundCore.AppGround.NotificationIdEnum.LiveVideoControlDistributionProcessing, element.ElementNumber);
                        ProcessStartVideoStreamingCommandRequestContext request = new ProcessStartVideoStreamingCommandRequestContext(
                            element.ElementNumber,
                            requestId,
                            sessionId,
                            url);

                        newRequests.Add(request);
                    }

                    _requestProcessor.AddRequestRange(newRequests);
                    result.RequestId  = requestId;
                    result.ResultCode = LiveVideoControlErrorEnum.RequestAccepted;
                    break;

                case T2GManagerErrorEnum.eT2GServerOffline:
                    LogManager.WriteLog(TraceType.ERROR, "T2G Offline", "PIS.Ground.LiveVideoControl.LiveVideoControlService.SendStartStreamingCommand", null, EventIdEnum.LiveVideoControl);
                    result.ResultCode = LiveVideoControlErrorEnum.T2GServerOffline;
                    break;

                case T2GManagerErrorEnum.eElementNotFound:
                    LogManager.WriteLog(TraceType.ERROR, "Element not found", "PIS.Ground.LiveVideoControl.LiveVideoControlService.SendStartStreamingCommand", null, EventIdEnum.LiveVideoControl);
                    result.ResultCode = LiveVideoControlService.GetInvalidTargetAddressResponse(targetAddress);
                    break;

                default:
                    LogManager.WriteLog(TraceType.ERROR, "Problem looking for an element. T2GClient returned: " + rqstResult.ToString(),
                                        "PIS.Ground.LiveVideoControl.LiveVideoControlService.SendStartStreamingCommand", null, EventIdEnum.LiveVideoControl);
                    result.ResultCode = LiveVideoControlErrorEnum.InternalError;
                    break;
                }
            }
            else
            {
                LogManager.WriteLog(TraceType.ERROR, error, "PIS.Ground.LiveVideoControl.LiveVideoControlService.SendStartStreamingCommand", null, EventIdEnum.LiveVideoControl);
                result.ResultCode = LiveVideoControlErrorEnum.InvalidRequestID;
            }

            return(result);
        }
        /// <summary>
        /// Callback called when Element Online state changes (signaled by the T2G Client).
        /// </summary>
        /// <param name="sender">Source of the event.</param>
        /// <param name="args">Event information to send to registered event handlers.</param>
        public static void OnElementInfoChanged(object sender, ElementEventArgs args)
        {
            if (args != null &&
                args.SystemInformation != null &&
                args.SystemInformation.IsOnline == true &&
                args.SystemInformation.PisMission != null &&
                args.SystemInformation.PisMission.MissionState == MissionStateEnum.MI)
            {
                // Will be called multiple times for the same train.
                // Some sort of debouncing will be welcome in a future revision
                // to prevent multiple notifications to the console(s)

                if (string.IsNullOrEmpty(args.SystemInformation.SystemId) == false)
                {
                    TargetAddressType target = new TargetAddressType();
                    target.Type = AddressTypeEnum.Element;
                    target.Id   = args.SystemInformation.SystemId;

                    string automaticModeUrl;
                    if (GetAutomaticMode(out automaticModeUrl) == true)
                    {
                        LogManager.WriteLog(
                            TraceType.INFO,
                            "Automatically starting streaming on newly detected train: " + args.SystemInformation.SystemId,
                            "PIS.Ground.LiveVideoControl.LiveVideoControlService.OnElementInfoChanged",
                            null,
                            EventIdEnum.LiveVideoControl);

                        LiveVideoControlResult result =
                            SendStartStreamingCommand(Guid.Empty, target, automaticModeUrl);

                        if (result.ResultCode != LiveVideoControlErrorEnum.RequestAccepted)
                        {
                            LogManager.WriteLog(TraceType.ERROR,
                                                "Problem sending a start command with url "
                                                + automaticModeUrl
                                                + " to train "
                                                + target.Id
                                                + ". Error: "
                                                + result.ResultCode.ToString(),

                                                "PIS.Ground.LiveVideoControl.LiveVideoControlService.OnElementInfoChanged",
                                                null, EventIdEnum.LiveVideoControl);
                        }
                    }
                    else
                    {
                        // Manual Mode, resend the latest Start command if available
                        ServiceInfo lastSentService;
                        if (_dicVideoHistory.ContainsKey(target) && _dicVideoHistorySentService.TryGetValue(target, out lastSentService))
                        {
                            ServiceInfo foundService = (args.SystemInformation.ServiceList != null) ? args.SystemInformation.ServiceList.FirstOrDefault(s => s.ServiceId == (ushort)eServiceID.eSrvSIF_LiveVideoControlServer && s.IsAvailable): null;
                            bool        lServiceLiveVideoControlServerAvailable = foundService != null;

                            // If service is not available, force the sent status to value false.
                            if (!lServiceLiveVideoControlServerAvailable && lastSentService != null)
                            {
                                _dicVideoHistorySentService[target] = null;
                            }

                            // Avoiding sending multiple start notifications.
                            // The LiveVideoService have to be online
                            if (lServiceLiveVideoControlServerAvailable == true && (lastSentService == null || !foundService.Equals(lastSentService)))
                            {
                                LogManager.WriteLog(
                                    TraceType.INFO,
                                    "Re-starting streaming on newly detected train: " + args.SystemInformation.SystemId,
                                    "PIS.Ground.LiveVideoControl.LiveVideoControlService.OnElementInfoChanged",
                                    null,
                                    EventIdEnum.LiveVideoControl);

                                LiveVideoControlResult result =
                                    SendStartStreamingCommand(Guid.Empty, target, _dicVideoHistory[target]);

                                // Setting the flag that the start command was already sent
                                _dicVideoHistorySentService[target] = foundService;

                                if (result.ResultCode != LiveVideoControlErrorEnum.RequestAccepted)
                                {
                                    LogManager.WriteLog(TraceType.ERROR,
                                                        "Problem sending a start command with url "
                                                        + _dicVideoHistory[target]
                                                        + " to train "
                                                        + target.Id
                                                        + ". Error: "
                                                        + result.ResultCode.ToString(),

                                                        "PIS.Ground.LiveVideoControl.LiveVideoControlService.OnElementInfoChanged",
                                                        null, EventIdEnum.LiveVideoControl);
                                }
                            }
                        }
                    }
                }
            }
        }