// COPYRIGHT 2020 by the Open Rails project.
// 
// This file is part of Open Rails.
// 
// Open Rails is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// 
// Open Rails is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
// 
// You should have received a copy of the GNU General Public License
// along with Open Rails.  If not, see <http://www.gnu.org/licenses/>.

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using Orts.Common;
using ORTS.Common;
// using Orts.Formats.Msts;
using ORTS.Scripting.Api;
using Orts.Simulation.Physics;
using Orts.Simulation.Signalling;
using Orts.Simulation.RollingStocks;
using Orts.Simulation.RollingStocks.SubSystems;


namespace ORTS.Scripting.Script
{
    public class TCS_SCMT_IT : TrainControlSystem
    {
        enum CCS
        {
            SCMT,        // I SCMT
        }

        enum SSBSTATE
        {
            Off,
            ReadyToOn,
            On
        }


        enum MonitorState
        {
            Disabled,
            StandBy,
            Alarm,
            Emergency,
            ReadyToReset
        }

        enum TCSCommandEvent
        {
            None,
            AccendiSpegniSSB,
            None1,
            Pulsante_RF,
            Pulsante_SCMT,
            Pulsante_Man,
            Pulsante_RSC,
            Pulsante_SR,
            Visualizz_Pulsante_RF,
            Splash,
            Vigilante,
            Visualizz_Pulsante_RSC,
            Pulsante_Debug,
            Ripetizioni_estese,
            Pulsante_Dati,
            Pulsante_OK,
            Luce_blu_tacho,
            Luce_rossa_tacho,
            SR,
            Attivazione_SR,
            NextSignalAspect1,
            NextSignalAspect2,
            NextSignalAspect3,
            NextSignalSpeed,
            MaxSpeed,
            TargetSpeed,
            Pulsante_Pre,
            Pulsante_Ric,
            Approccio10,
            Visualizz_Pulsante_SCMT,			   
			Visualizz_GuastoATerra,		
			Visualizz_GuastoATerraRSC,
        }

        enum RSCSTATE
        {
            Inactive,
            WaitingAck,
            Active,
            AckMissed,
            WaitingShutdown,
            ActivationRequested,
			Disabled,
			Decision,
        }

        enum PRERICONOSCIMENTOSTATE
        {
            Invalid,
            Inactive,
            WaitingRic,
            WaitingRicEnd,
            WaitingPre,
            Timer12secOn,
            PreActive,
            Active,
            AckMissed,
            Timer12secExpired
        }

        enum RSCCODE
        {
            C270SS,
            C270S,
            C270,
            C180S,
            C180,
            C120S,
            C120,
            C75,
            SR,
            AC,
            None
        }

        enum SCMTSTATE
        {
            Off,
            Autotest,
            Manovra,
            IntroduzioneDatiOManovra,
            IntroduzioneDati,
            Predisposizione,
            Active,
            ActiveAndRSC,
            EsclusioneRequestedFromPred,
            EsclusoFromPred,
            ReinclusioneFromPred,
            EsclusioneRequestedFromActive,
            EsclusoFromActive,
            ReinclusioneFromActive,

            StandByReinclusoFromActive,
        }

        enum ATTIVAZIONESR
        {
            Inactive,
            Timer12SOn,
            SignalPassed,
        }

        enum AUTOTESTPHASE
        {
            FirstBraking,
            WaitFirstRelease,
            SecondBraking,
            WaitSecondRelease,
            PulsanteSCMT,
            PulsanteMan,
            PulsanteRSC,
            PulsanteSR,
            PulsanteDebug,
            PulsantePre,
            PulsanteRic,
            PulsanteRF,
            Beep,
            ThirdBraking,
            WaitThirdRelease,
            FourthBraking,
            WaitFourthRelease,
            FinalWait,
        }

        float[] SCMTAutotestTimerDelayS = new float[] { 1.0f, 3.0f, 1.0f, 3.0f, 0.3f, 0.3f, 0.3f, 0.3f, 0.3f, 0.3f, 0.3f, 0.3f, 1.0f, 3.0f, 1.0f, 3.0f, 1.0f, 5.0f };



        enum SIGNALFILESTYPE
        {
            SerriniBaldi,
            PriviteraBono
        }

        // Train parameters
        bool SCMTMonitor;                                 // SCMT
        bool RSCMonitor;

        string[] NoRSCStations = new string[] { "Milano Centrale", "Roma Termini", "Firenze S. Maria Novella", "Firenze SMN", "Torino Porta Nuova",
        "Genova P.Principe" };

        // Corrispondenze fra Dati segnali e codici RSC e Aspect per visualizzazione
        // per linee con VMax >= 250 NextSignalAspect(0), NextSignalAspect(1), NextSignalAspect(2), NextSignalAspect(3) == CLEAR_2 -> Cod. 270**
        // per linee con VMax >= 180 NextSignalAspect(0), NextSignalAspect(1), NextSignalAspect(2) == CLEAR_2 -> Cod. 270*
        // per le altre linee NextSignalAspect(0), NextSignalAspect(1) == CLEAR_2 -> Cod. 270
        // NextSignalAspect(0) == CLEAR_2 e senza vmax o == Restricting e vmax = 120 -> Cod. 180
        // NextSignalAspect(0) == CLEAR_2 e vmax 100, NextSignalAspect(0) == APPROACH_3 e vmax 60, NextSignalAspect(0) == APPROACH_2 e vmax 60 o vmax30,
        // NextSignalAspect(0) == APPROACH_1 e vmax30 --> Cod. 120
        // NextSignalAspect(0) == STOP --> Cod. 75
        // Rimangono 2 codici disponibili
        // Corrispondenze fra codici RSC e Aspect per visualizzazione
        // Cod. 270** Clear_2
        // Cod. 270* Clear_1
        // Cod. 270 Approach_3
        // Cod. 180 Approach_2
        // Cod. 120 Approach_1 --> genera PRERIC
        // Cod. 75 Stop

        float Debug;     //Debug mode, shows various debug values on the SCMT display    

        bool AutodetectSignalFilesType = true;
        SIGNALFILESTYPE SignalFilesType = SIGNALFILESTYPE.SerriniBaldi;
        bool HeavyFreightTrain;                             // MA train only
        float SafeDecelerationMpS2;                         // Gamma
        SSBSTATE SSBState = SSBSTATE.On;

        // SCMT (Sistema Controllo Marcia Treno)
        // Parameters
        bool SCMTAppliesCutsPower = true;
        float SCMTTrainSpeedLimitKpH;                        // VT
        float SCMTTrainLengthM;                              // L
        const float SCMTDelayBeforeEmergencyBrakingS = 5f;   // Tx
        float SCMTDelayBeforeBrakingEstablishedS;            // Tbo
        float SCMTOverspeedDownThresholdKpH = 5f;
        float SCMTAutopilotOverspeedDownThresholdKpH = 3f;
        float SCMTActualOverspeedDownThreshold = 5f;
        float AttivazioneSRTimerDelayS = 12f;
        bool Autopilot = false;
        float AutopilotTimerDelayS = 1.5f;
        float AutopilotButtonPressTimerDelayS = 0.7f;
        bool circuitBreakerOpened = false;

        // Variables
        bool SCMTEmergencyBraking = false;
        float SCMTWarningTimerDelayS = 3f;
        Timer SCMTWarningTimer;
        bool ExternalEmergencyBraking = false;
        bool normalSignalPassed = false;
        bool prericSignalPassed = false;
        bool distanceSignalPassed = false;
        bool infoSignalPassed = false;
        float normalSignalDistanceM;
        float PreviousSignalDistanceM = 0f;
        float distanceSignalDistanceM;
        float PreviousDistanceSignalDistanceM = 0f;
        float infoSignalDistanceM;
        float PreviousInfoSignalDistanceM = 0;
        string infoSignalMainHeadSignalType = "";
        string PreviousInfoSignalMainHeadSignalType = "";
        Aspect SCMTNextSignalAspect = Aspect.Stop;
        int UpdateCount;
        float nextSignalSpeedLimitKpH;
        Aspect nextSignalAspect = Aspect.None;
        Aspect previousSignalAspect = Aspect.None;
        float currentPostSpeedLimitKpH;
        bool ColdStart = true;
        bool[] TCSButtonPressed = new bool[32];
        bool[] TCSButtonReleased = new bool[32];
        SCMTSTATE SCMTState = SCMTSTATE.Active;
        bool SCMTSpad = false;
        TRAIN_CONTROL ControlMode;
        float SpeedKpH;
        ATTIVAZIONESR AttivazioneSR = ATTIVAZIONESR.Inactive;
        Timer AttivazioneSRTimer;
        Timer AutopilotTimer;
        Timer AutopilotButtonPressTimer;
        Timer SCMTAutotestTimer;
		Timer EsclusioneSCMTTimer;	
        Timer EsclusioneRSCTimer;		
        AUTOTESTPHASE AutotestPhase = AUTOTESTPHASE.FirstBraking;
        bool nextNormalSignalAspectWasAtStop = false;
        float SCMTVelocitaRilascio = 30f;

        SignalFeatures genericSignalFeatures;

        struct InternalSignalFeatures
        {
            public string MainHeadSignalTypeName;
            public Aspect Aspect;
            public float DistanceM;
            public float SpeedLimitMpS;
            public float AltitudeM;
        }

        float SCMTCurrentSignalSpeedLimitKpH;
        float SCMTNextSignalSpeedLimitKpH;
        float SCMTSignalTargetSpeedKpH;
        float SCMTSignalTargetDistanceM;
        float SCMTDeclivity = 0f;                            // i

        float SCMTCurrentSpeedPostSpeedLimitKpH;
        float SCMTNextSpeedPostSpeedLimitKpH;
        float SCMTSpeedPostTargetSpeedKpH;
        float SCMTSpeedPostTargetDistanceM;

        float SCMTCurrentAlertSpeedKpH;
        float SCMTCurrentEBSpeedKpH;
        float SCMTNextAlertSpeedKpH;
        float SCMTNextEBSpeedKpH;

        float SCMTSignalEmergencySpeedCurveKpH;
        float SCMTSignalAlertSpeedCurveKpH;
        float SCMTSpeedPostEmergencySpeedCurveKpH;
        float SCMTSpeedPostAlertSpeedCurveKpH;

        bool EmergencyBrakingRequest;
        bool FullBrakingRequest;
        bool PowerCutRequest;
        bool DynamicBrakingRequest;

        // RSC
        // Params
        float RSCMaxSignalSpeedCode180KpH = 115f;
        float RSCMaxSignalSpeedCode180StarKpH = 150f;
        float RSCMaxSignalSpeedCode270KpH = 180f;
        float RSCMaxSignalSpeedCode270StarKpH = 230f;
        float RSCMaxSignalSpeedCode270DoubleStarKpH = 250f;
        float RSCMinimumLengthWithoutSwitchesM = 1000f;
        float RSCNextDivergingSwitchMaxDistanceM = 300f;
        float RSCPrericonoscimentoTimerDelayS = 12f;
        float RSCCodeConfirmationDelayS = 4f;

        // Variables
        float RSCNextSignalAllowedSpeedKpH;
        RSCCODE RSCCode = RSCCODE.None;
        RSCCODE RSCPreviousCode = RSCCODE.None;
        RSCCODE RSCTempNewCode = RSCCODE.None;
        RSCSTATE RSCState = RSCSTATE.Inactive;
        bool RSCFirstRun = true;
        PRERICONOSCIMENTOSTATE RSCPrericonoscimentoState;
        Timer RSCPrericonoscimentoTimer;
        Timer RSCPrericonoscimento1Timer;
        Timer RSCCodeConfirmationTimer;
        Timer RSCCodeConfirmation1Timer;
        Timer RSCManualActivationTimer;									   
        Timer RSCCheckACFinitaTimer;
        float nextDivergingSwitchDistanceM;
        float RSCMinimumLengthM = 1000f;
        bool RSCFirstCodeReceived = true;
        bool NoRSCZone = false;
        bool RSCPresent = false;
        float RSCMaxTrailingDivergingSwitchDistanceM = 1000f;
        float RemainingLengthM = 0f;
        float OldRemainingLengthM = -1f;
        bool RSCPIPassed = false;
        float IntervalDistanceM = 0f;
        bool RSCForceCod = false;
        bool RSCForceCod9 = false;
        bool RSCForceNoCod = false;
        bool RSCEndsThisSection = false;
        bool RSCEndsNextSection = false;
        bool RSCEndsNextNextSection = false;
        bool RSCEndsNextNextNextSection = false;
        int[] incIndex = new int[3];
        int RequiredNormalSignals = 3;

        SignalFeatures[] NormalSignals = new SignalFeatures[7];
        SignalFeatures[] VirtualSignals = new SignalFeatures[7];
        SignalFeatures[] InfoSignals = new SignalFeatures[10];
        InternalSignalFeatures[] TrueNormalSignals = new InternalSignalFeatures[7];

        // MSTS TCS emulation

        float EmergencyStopMonitorTimeLimitS = 66f;
        float EmergencyStopAlarmTimeLimitS = 60f;
        float EmergencyStopPenaltyTimeLimitS = 0f;
        float EmergencyStopCriticalLevelMpS = 0f;
        float EmergencyStopResetLevelMpS = 0f;
        bool EmergencyStopAppliesFullBrake = true;
        bool EmergencyStopAppliesEmergencyBrake;
        bool EmergencyStopAppliesCutsPower;
        bool EmergencyStopAppliesShutsDownEngine;

        float VigilanceMonitorTimeLimitS = 66f;
        float VigilanceAlarmTimeLimitS = 60f;
        float VigilancePenaltyTimeLimitS = 0f;
        float VigilanceCriticalLevelMpS = 0f;
        float VigilanceResetLevelMpS = 0f;
        bool VigilanceAppliesFullBrake = true;
        bool VigilanceAppliesEmergencyBrake;
        bool VigilanceAppliesCutsPower;
        bool VigilanceAppliesShutsDownEngine;
        bool VigilanceResetOnZeroSpeed = true;
        bool VigilanceResetOnDirectionNeutral;
        bool VigilanceResetOnResetButton;
        bool VigilanceRestartOnControlsMoved;

        Timer VigilanceEmergencyTimer;
        Timer VigilancePenaltyTimer;

        MonitorState VigilanceMonitorState;
        MonitorState SCMTOverspeedMonitorState;

        float VigilanceAlarmTimeoutS;


        bool VigilanceMonitor = false;
        bool SCMTOverspeedMonitor = false;
        bool EmergencyStopMonitor = false;

        public TCS_SCMT_IT() { }

        public bool ResetButtonPressed { get; private set; }

        public bool VigilanceSystemEnabled
        {
            get
            {
                bool enabled = true;

                enabled &= IsAlerterEnabled();

                if (VigilanceMonitor)
                {
                    if (VigilanceResetOnDirectionNeutral)
                    {
                        enabled &= CurrentDirection() != Direction.N;
                    }
                }

                return enabled;
            }
        }

        public bool VigilanceReset
        {
            get
            {
                bool vigilanceReset = true;

                if (VigilanceMonitor)
                {
                    if (VigilanceResetOnDirectionNeutral)
                    {
                        vigilanceReset &= CurrentDirection() == Direction.N;
                    }

                    if (VigilanceResetOnZeroSpeed)
                    {
                        vigilanceReset &= SpeedMpS() < 0.1f;
                    }

                    if (VigilanceResetOnResetButton)
                    {
                        vigilanceReset &= ResetButtonPressed;
                    }
                }

                return vigilanceReset;
            }
        }

        public bool SpeedControlSystemEnabled
        {
            get
            {
                bool enabled = true;

                enabled &= IsSpeedControlEnabled();

                return enabled;
            }
        }

        public bool SCMTOverspeed
        {
            get
            {
                bool overspeed = false;

                if (SCMTOverspeedMonitor)
                {
                    overspeed |= SpeedKpH > SCMTSignalEmergencySpeedCurveKpH;
                    overspeed |= SpeedKpH > SCMTSpeedPostEmergencySpeedCurveKpH;


                }
                return overspeed;
            }
        }

        public bool SCMTOverspeedWarning
        {
            get
            {
                bool overspeedWarning = false;

                if (SCMTOverspeedMonitor)
                {
                    overspeedWarning |= SpeedKpH > SCMTSignalAlertSpeedCurveKpH;
                    overspeedWarning |= SpeedKpH > SCMTSpeedPostAlertSpeedCurveKpH;
                }
                return overspeedWarning;
            }
        }

        public bool SCMTOverspeedReadyToReset
        {
            get
            {
                bool overspeedReset = true;

                if (SCMTOverspeedMonitor)
                {
                    overspeedReset &= SpeedKpH < SCMTSignalAlertSpeedCurveKpH - SCMTActualOverspeedDownThreshold || SpeedKpH < 0.36f;
                    overspeedReset &= SpeedKpH < SCMTSpeedPostAlertSpeedCurveKpH - SCMTActualOverspeedDownThreshold || SpeedKpH < 0.36f;
                }
                return overspeedReset;
            }
        }

        public bool SCMTOverspeedWarningReset
        {
            get
            {
                bool overspeedWarningReset = true;

                if (SCMTOverspeedMonitor)
                {
                    overspeedWarningReset &= SpeedKpH < SCMTSignalAlertSpeedCurveKpH - SCMTActualOverspeedDownThreshold || SpeedKpH < 0.36f;
                    overspeedWarningReset &= SpeedKpH < SCMTSpeedPostAlertSpeedCurveKpH - SCMTActualOverspeedDownThreshold || SpeedKpH < 0.36f;
                    overspeedWarningReset |= SCMTOverspeed;
                }
                return overspeedWarningReset;
            }
        }

        public override void Initialize()
        {
            // General section
            SCMTMonitor = GetBoolParameter("General", "SCMTMonitor", false);
            VigilanceMonitor = GetBoolParameter("General", "VigilanceMonitor", false);
            EmergencyStopMonitor = GetBoolParameter("General", "EmergencyStopMonitor", false);
            SCMTOverspeedMonitor = GetBoolParameter("General", "SCMTOverspeedMonitor", false);
            RSCMonitor = GetBoolParameter("General", "RSCMonitor", false);
            AutodetectSignalFilesType = GetBoolParameter("General", "AutodetectSignalFilesType", true);
            SignalFilesType = (SIGNALFILESTYPE)GetIntParameter("General", "SignalFilesType", 0);
            HeavyFreightTrain = GetBoolParameter("General", "HeavyFreightTrain", false);
            SafeDecelerationMpS2 = GetFloatParameter("General", "SafeDecelerationMpS2", 0.7f);

            // SCMT section
            SCMTWarningTimerDelayS = GetFloatParameter("SCMT", "WarningTimerDelayS", 3f);
            SCMTAppliesCutsPower = GetBoolParameter("SCMT", "AppliesCutsPower", SCMTAppliesCutsPower);
            SCMTDeclivity = GetFloatParameter("SCMT", "DeclivityPerMille", 0f) / 1000f;

            // RSC section
            RSCMaxSignalSpeedCode180KpH = GetFloatParameter("RSC", "MaxSignalSpeedCode180KpH", RSCMaxSignalSpeedCode180KpH);
            RSCMinimumLengthWithoutSwitchesM = GetFloatParameter("RSC", "MinimumLengthWithoutSwitchesM", RSCMinimumLengthWithoutSwitchesM);
            RSCMinimumLengthWithoutSwitchesM = GetFloatParameter("RSC", "MinimumLengthWithoutSwitchesM", RSCMinimumLengthWithoutSwitchesM);
            RSCCodeConfirmationDelayS = GetFloatParameter("RSC", "CodeConfirmationDelayS", RSCCodeConfirmationDelayS);

            // MSTS TCS Emulation of .eng parameters

            // Vigilance monitor
            EmergencyStopMonitorTimeLimitS = GetFloatParameter("EmergencyStopMonitor", "MonitorTimeLimitS", EmergencyStopMonitorTimeLimitS);
            EmergencyStopAlarmTimeLimitS = GetFloatParameter("EmergencyStopMonitor", "AlarmTimeLimitS", EmergencyStopAlarmTimeLimitS);
            EmergencyStopPenaltyTimeLimitS = GetFloatParameter("EmergencyStopMonitor", "PenaltyTimeLimitS", EmergencyStopPenaltyTimeLimitS);
            EmergencyStopCriticalLevelMpS = GetFloatParameter("EmergencyStopMonitor", "CriticalLevelMpS", EmergencyStopCriticalLevelMpS);
            EmergencyStopResetLevelMpS = GetFloatParameter("EmergencyStopMonitor", "ResetLevelMpS", EmergencyStopResetLevelMpS);
            EmergencyStopAppliesFullBrake = GetBoolParameter("EmergencyStopMonitor", "AppliesFullBrake", EmergencyStopAppliesFullBrake);
            EmergencyStopAppliesEmergencyBrake = GetBoolParameter("EmergencyStopMonitor", "AppliesEmergencyBrake", EmergencyStopAppliesEmergencyBrake);
            EmergencyStopAppliesCutsPower = GetBoolParameter("EmergencyStopMonitor", "AppliesCutsPower", EmergencyStopAppliesCutsPower);
            EmergencyStopAppliesShutsDownEngine = GetBoolParameter("EmergencyStopMonitor", "AppliesShutsDownEngine", EmergencyStopAppliesShutsDownEngine);

            VigilanceMonitorTimeLimitS = GetFloatParameter("VigilanceMonitor", "MonitorTimeLimitS", VigilanceMonitorTimeLimitS);
            VigilanceAlarmTimeLimitS = GetFloatParameter("VigilanceMonitor", "AlarmTimeLimitS", VigilanceAlarmTimeLimitS);
            VigilancePenaltyTimeLimitS = GetFloatParameter("VigilanceMonitor", "PenaltyTimeLimitS", VigilancePenaltyTimeLimitS);
            VigilanceCriticalLevelMpS = GetFloatParameter("VigilanceMonitor", "CriticalLevelMpS", VigilanceCriticalLevelMpS);
            VigilanceResetLevelMpS = GetFloatParameter("VigilanceMonitor", "ResetLevelMpS", VigilanceResetLevelMpS);
            VigilanceAppliesFullBrake = GetBoolParameter("VigilanceMonitor", "AppliesFullBrake", VigilanceAppliesFullBrake);
            VigilanceAppliesEmergencyBrake = GetBoolParameter("VigilanceMonitor", "AppliesEmergencyBrake", VigilanceAppliesEmergencyBrake);
            VigilanceAppliesCutsPower = GetBoolParameter("VigilanceMonitor", "AppliesCutsPower", VigilanceAppliesCutsPower);
            VigilanceAppliesShutsDownEngine = GetBoolParameter("VigilanceMonitor", "AppliesShutsDownEngine", VigilanceAppliesShutsDownEngine);
            VigilanceResetOnDirectionNeutral = GetBoolParameter("VigilanceMonitor", "ResetOnDirectionNeutral", VigilanceResetOnDirectionNeutral);
            VigilanceResetOnZeroSpeed = GetBoolParameter("VigilanceMonitor", "ResetOnZeroSpeed", VigilanceResetOnZeroSpeed);
            VigilanceResetOnResetButton = GetBoolParameter("VigilanceMonitor", "ResetOnResetButton", VigilanceResetOnResetButton);
            VigilanceRestartOnControlsMoved = GetBoolParameter("VigilanceMonitor", "RestartOnControlsMoved", VigilanceRestartOnControlsMoved);


            // Initialize customized TCS command strings
            var i = 0;
            foreach (string TCSControlString in Enum.GetNames(typeof(TCSCommandEvent)))
            {
                if (TCSControlString == "None") continue;
                //               SetCustomizedTCSControlString(TCSControlString);
                SetCustomizedCabviewControlName(i, TCSControlString);
                i++;
            }

            // Variables initialization
            AttivazioneSRTimer = new Timer(this);
            AttivazioneSRTimer.Setup(AttivazioneSRTimerDelayS);
            SCMTWarningTimer = new Timer(this);
            SCMTWarningTimer.Setup(SCMTWarningTimerDelayS);
            RSCPrericonoscimento1Timer = new Timer(this);
            RSCPrericonoscimento1Timer.Setup(RSCCodeConfirmationDelayS);
            RSCPrericonoscimentoTimer = new Timer(this);
            RSCPrericonoscimentoTimer.Setup(RSCPrericonoscimentoTimerDelayS);
            RSCCodeConfirmationTimer = new Timer(this);
            RSCCodeConfirmationTimer.Setup(RSCCodeConfirmationDelayS);
            RSCCodeConfirmation1Timer = new Timer(this);
            RSCCodeConfirmation1Timer.Setup(RSCCodeConfirmationDelayS);
			RSCManualActivationTimer = new Timer(this);
            RSCManualActivationTimer.Setup(3.5f);										   																														
            RSCCheckACFinitaTimer = new Timer(this);
            RSCCheckACFinitaTimer.Setup(RSCCodeConfirmationDelayS);
            AutopilotTimer = new Timer(this);
            AutopilotTimer.Setup(AutopilotTimerDelayS);
            AutopilotButtonPressTimer = new Timer(this);
            AutopilotButtonPressTimer.Setup(AutopilotButtonPressTimerDelayS);
            SCMTAutotestTimer = new Timer(this);
            SCMTAutotestTimer.Setup(SCMTAutotestTimerDelayS[0]);

			EsclusioneSCMTTimer = new Timer(this);
            EsclusioneSCMTTimer.Setup(3f);

            EsclusioneRSCTimer = new Timer(this);
            EsclusioneRSCTimer.Setup (6f);									  
            // Variables initialization
            SCMTCurrentSignalSpeedLimitKpH = SCMTTrainSpeedLimitKpH;
            SCMTNextSignalSpeedLimitKpH = SCMTTrainSpeedLimitKpH;
            SCMTSignalTargetSpeedKpH = SCMTTrainSpeedLimitKpH;
            SCMTSignalTargetDistanceM = 0f;

            SCMTCurrentSpeedPostSpeedLimitKpH = SCMTTrainSpeedLimitKpH;
            SCMTNextSpeedPostSpeedLimitKpH = SCMTTrainSpeedLimitKpH;
            SCMTSpeedPostTargetSpeedKpH = SCMTTrainSpeedLimitKpH;
            SCMTSpeedPostTargetDistanceM = 0f;

            SCMTCurrentAlertSpeedKpH = 3f;
            SCMTCurrentEBSpeedKpH = 5f;
            SCMTNextAlertSpeedKpH = 3f;
            SCMTNextEBSpeedKpH = 5f;

            SetCabDisplayControl((int)(TCSCommandEvent.Splash) - 1, (int)SCMTSTATE.Off);

            Activated = true;

            InitializeMSTSTCSEmulation();
        }

        protected void InitializeMSTSTCSEmulation()
        {
            {
                VigilanceEmergencyTimer = new Timer(this);
                VigilancePenaltyTimer = new Timer(this);

                if (VigilanceMonitor)
                {
                    if (VigilanceMonitorTimeLimitS > VigilanceAlarmTimeLimitS)
                        VigilanceAlarmTimeoutS = VigilanceMonitorTimeLimitS - VigilanceAlarmTimeLimitS;
                    VigilanceEmergencyTimer.Setup(VigilanceAlarmTimeoutS);
                    VigilancePenaltyTimer.Setup(VigilancePenaltyTimeLimitS);
                }
            }
        }

        public override void Update()
        {
            SpeedKpH = MpS.ToKpH(SpeedMpS());
            // At startup not all variables are already available
            if (UpdateCount < 2)
            {
                SetCabDisplayControl((int)(TCSCommandEvent.Splash) - 1, (int)SCMTSTATE.Off);
                UpdateCount++;
                return;
            }
            if (UpdateCount == 2)
            {
                FirstUpdateInitializations();
                UpdateCount++;
                return;
            }

            if (IsTrainControlEnabled() || Autopilot)
            {
                UpdateSSBState();
                UpdateSCMTState();
            }
            if (RSCState == RSCSTATE.Active)
                SetCabDisplayControl((int)(TCSCommandEvent.Splash) - 1, (int)SCMTSTATE.ActiveAndRSC);
            else
                SetCabDisplayControl((int)(TCSCommandEvent.Splash) - 1, (int)SCMTState);

            
            if (SCMTState == SCMTSTATE.EsclusioneRequestedFromPred || SCMTState == SCMTSTATE.EsclusoFromPred || SCMTState == SCMTSTATE.ReinclusioneFromPred
                || (SCMTState == SCMTSTATE.EsclusioneRequestedFromActive && RSCState != RSCSTATE.Active)
                || (SCMTState == SCMTSTATE.EsclusoFromActive && RSCState != RSCSTATE.Active)
                || (SCMTState == SCMTSTATE.ReinclusioneFromActive && RSCState != RSCSTATE.Active)
                || (SCMTState == SCMTSTATE.StandByReinclusoFromActive && RSCState != RSCSTATE.Active)) //in questi stati
                SetCabDisplayControl((int)(TCSCommandEvent.Splash) - 1, (int)SCMTSTATE.Active); //fa rimanere scmt active e non mette la rsc


            if (SCMTState != SCMTSTATE.Autotest)
            {
                SetCabDisplayControl((int)(TCSCommandEvent.Visualizz_Pulsante_SCMT) - 1, (SCMTState == SCMTSTATE.Active || SCMTState == SCMTSTATE.EsclusioneRequestedFromActive) ? 1 : 0); 
                SetCabDisplayControl((int)(TCSCommandEvent.Visualizz_Pulsante_RSC) - 1, RSCState == RSCSTATE.Active ? 1 : RSCState == RSCSTATE.Inactive ? 0 : 2);
            }

            if (SCMTState != SCMTSTATE.Off && SCMTState != SCMTSTATE.Autotest &&
                SCMTState != SCMTSTATE.IntroduzioneDatiOManovra && SCMTState != SCMTSTATE.IntroduzioneDati)
            {

                if (TCSButtonPressed[(int)(TCSCommandEvent.Pulsante_Debug)])
                {
                    Debug = Debug == 0 ? 1 : 0;
                }
                SetCabDisplayControl((int)(TCSCommandEvent.Pulsante_Debug) - 1, Debug == 1 ? 1 : 0);


                UpdateSignal();
                UpdateInputs();
                Autopilot = IsAutopiloted();

                if (IsTrainControlEnabled() || Autopilot)
                {
                    SetCabDisplayControl((int)(TCSCommandEvent.Attivazione_SR) - 1, AttivazioneSR == ATTIVAZIONESR.SignalPassed ? 1 : 0);
					/* togliere riga*/																   
                    SetCabDisplayControl((int)(TCSCommandEvent.Vigilante) - 1, VigilanceMonitorState == MonitorState.Emergency ? 1 : 0);

                    SCMTActualOverspeedDownThreshold = Autopilot ? SCMTAutopilotOverspeedDownThresholdKpH : SCMTOverspeedDownThresholdKpH;

                if (SCMTState == SCMTSTATE.Active || SCMTState == SCMTSTATE.Predisposizione || RSCState == RSCSTATE.Active)
                    {
                        UpdateAttivazioneSR();
                    }
                    if (SCMTState == SCMTSTATE.Active)
                    {
                        SetCabDisplayControl((int)(TCSCommandEvent.Approccio10) - 1, SCMTVelocitaRilascio == 10f && SCMTNextSignalSpeedLimitKpH == 0 ? 1 : 0);
                    }
                    CheckSPAD();
                    if (SCMTState != SCMTSTATE.Manovra)
                    {
                        if (RSCState == RSCSTATE.Active)
                            CheckNoRSCZone();
                        if (RSCMonitor) UpdateRSCState();
                        if (RSCState == RSCSTATE.Active)
                            UpdateRSC();
                    }
                    UpdateLuceBlu();
                    if (AutopilotButtonPressTimer.Triggered)
                    {
                        TriggerSoundPenalty2();
                        AutopilotButtonPressTimer.Stop();
                    }
                    if ((normalSignalPassed) && SCMTState != SCMTSTATE.Active && SCMTState != SCMTSTATE.Manovra && SCMTState != SCMTSTATE.EsclusoFromActive && SCMTState != SCMTSTATE.EsclusoFromPred)
                    {
                        SCMTState = SCMTSTATE.Active;
                        TriggerSoundInfo1();
                    }
                    if (SCMTState == SCMTSTATE.Active || SCMTState == SCMTSTATE.Predisposizione || SCMTState == SCMTSTATE.Manovra)
                    {
                        UpdateSCMT();
                    }
                    if (VigilanceMonitor)
                        UpdateVigilance();
                    UpdateSCMTOverspeedMonitor();
                    bool EmergencyBrakingRequest = false;
                    bool FullBrakingRequest = false;
                    bool PowerCutRequest = false;
                    bool DynamicBrakingRequest = false;
                    if (VigilanceMonitor)
                    {
                        if (VigilanceAppliesEmergencyBrake)
                            EmergencyBrakingRequest |= (VigilanceMonitorState == MonitorState.Emergency);
                        else if (VigilanceAppliesFullBrake)
                            FullBrakingRequest |= (VigilanceMonitorState == MonitorState.Emergency);

                        if (VigilanceAppliesCutsPower)
                            PowerCutRequest |= (VigilanceMonitorState == MonitorState.Emergency);
                    }

                    if (SCMTOverspeedMonitor)
                    {
                        EmergencyBrakingRequest |= (SCMTOverspeedMonitorState == MonitorState.Emergency || SCMTOverspeedMonitorState == MonitorState.ReadyToReset);
                        PowerCutRequest |= (SCMTOverspeedMonitorState == MonitorState.Emergency || SCMTOverspeedMonitorState == MonitorState.ReadyToReset ||
                            SCMTOverspeedMonitorState == MonitorState.Alarm);
                        DynamicBrakingRequest |= SCMTOverspeedMonitorState == MonitorState.Alarm;
                    }

                    if (EmergencyStopMonitor)
                    {
                        if (EmergencyStopAppliesEmergencyBrake)
                            EmergencyBrakingRequest |= ExternalEmergencyBraking;
                        else if (EmergencyStopAppliesFullBrake)
                            FullBrakingRequest |= ExternalEmergencyBraking;

                        if (EmergencyStopAppliesCutsPower)
                            PowerCutRequest |= ExternalEmergencyBraking;
                    }
                    EmergencyBrakingRequest |= SCMTEmergencyBraking;

                    if (SCMTMonitor)
                        if (SCMTAppliesCutsPower)
                            PowerCutRequest |= SCMTEmergencyBraking;

                    if (EmergencyBrakingRequest && Math.Abs(SpeedKpH) < 0.36f)
                    {
                        SetCabDisplayControl((int)(TCSCommandEvent.Visualizz_Pulsante_RF) - 1, 1);
                    }
                    if (TCSButtonPressed[(int)(TCSCommandEvent.Pulsante_RF)] && EmergencyBrakingRequest == true)
                    {
                        if (Math.Abs(SpeedKpH) < 0.36f)
                        {
                            SCMTEmergencyBraking = false;
                            VigilanceMonitorState = MonitorState.Disabled;
                            TriggerSoundWarning2();
                            TriggerSoundAlert2();
                            SetCabDisplayControl((int)(TCSCommandEvent.Visualizz_Pulsante_RF) - 1, 0);
                            if (RSCState == RSCSTATE.AckMissed)
                            {
                                RSCState = RSCSTATE.WaitingAck;
                                TriggerSoundWarning1();
                                SCMTWarningTimer.Start();
                            }

                            if (SCMTSpad)
                            {
                                ControlMode = GetControlMode();
                                SetCabDisplayControl((int)(TCSCommandEvent.SR) - 1, 0);
                            }
                            if (RSCState == RSCSTATE.WaitingShutdown)
                            {
                                RSCState = RSCSTATE.Inactive;
                                RSCPreviousCode = RSCCODE.None;
                                RSCFirstRun = false;
                                RSCPrericonoscimentoState = PRERICONOSCIMENTOSTATE.Invalid;
                                RSCFirstCodeReceived = false;
                            }
                        }
                        SetCabDisplayControl((int)(TCSCommandEvent.Pulsante_Ric) - 1, 0);
                        SetCabDisplayControl((int)(TCSCommandEvent.Pulsante_Pre) - 1, 0);
                        if (RSCPrericonoscimentoState == PRERICONOSCIMENTOSTATE.AckMissed) RSCPrericonoscimentoState = PRERICONOSCIMENTOSTATE.Active;
                        else if (RSCPrericonoscimentoState == PRERICONOSCIMENTOSTATE.Timer12secExpired)
                        {
                            SetCabDisplayControl((int)(TCSCommandEvent.Pulsante_Pre) - 1, 1);
                            RSCPrericonoscimentoState = PRERICONOSCIMENTOSTATE.WaitingPre;
                        }
                    }


                    if (TCSButtonReleased[(int)(TCSCommandEvent.Pulsante_RF)])
                    {
                        TriggerSoundPenalty2();
                        if (SCMTSpad)
                        {
                            if (ControlMode != TRAIN_CONTROL.EXPLORER)
                                RequestToggleManualMode();
                            SCMTSpad = false;
                            RSCCode = RSCCODE.None;
                        }
                    }

                    //               EmergencyBrakingRequest = RSOEmergencyBraking || VACMAEmergencyBraking || ExternalEmergencyBraking;
                    SetEmergencyBrake(EmergencyBrakingRequest);
                    SetFullBrake(!EmergencyBrakingRequest && FullBrakingRequest);
                    SetTractionAuthorization((!DoesBrakeCutPower() || LocomotiveBrakeCylinderPressureBar() < BrakeCutsPowerAtBrakeCylinderPressureBar()) && !PowerCutRequest);
                    SetFullDynamicBrake(DynamicBrakingRequest);

                    SetPenaltyApplicationDisplay(IsBrakeEmergency() || IsBrakeFullService());

                    // Update monitoring status
                    // Following might be used for ETCS
                    /*               if (SpeedKpH > CurrentSpeedLimitKpH)
                                   {
                                       if (SCMTOverspeedMonitor && (OverspeedAppliesEmergencyBrake || OverspeedAppliesFullBrake))
                                           Status = MonitoringStatus.Intervention;
                                       else
                                           Status = MonitoringStatus.Warning;
                                   }
                                   else if (NextSpeedLimitKpH < CurrentSpeedLimitKpH && SpeedKpH > NextSpeedLimitKpH)
                                   {
                                       if (Deceleration(SpeedMpS(), MpS.FromKpH(NextSpeedLimitKpH), NextSignalDistanceM(0)) > 0.7f)
                                           Status = MonitoringStatus.Overspeed;
                                       else
                                           Status = MonitoringStatus.Indication;
                                   }
                                   else
                                       Status = MonitoringStatus.Normal; 
                                   SetMonitoringStatus(Status);*/

                }
            }
            else if (SCMTState == SCMTSTATE.Autotest)
                UpdateSCMTAutotest();
            for (int i = 0; i < TCSButtonPressed.Length; i++)
            {
                TCSButtonPressed[i] = false;
            }
            if (TCSButtonReleased[(int)(TCSCommandEvent.Pulsante_RF)])
            {
                TCSButtonReleased[(int)(TCSCommandEvent.Pulsante_RF)] = false;
            }
        }

        // First Update Initializations

        protected void FirstUpdateInitializations()
        {
            // Do it here because before Train is not defined
            SCMTTrainSpeedLimitKpH = GetFloatParameter("SCMT", "TrainSpeedLimitKpH", MpS.ToKpH(TrainMaxSpeedMpS()));
            if (ColdStart)
            {
                SCMTState = (!IsColdStart() && !DoesStartFromTerminalStation() && SCMTMonitor ||
                    SpeedMpS() > 0f) ? SCMTSTATE.Active : SCMTSTATE.Off;
                SSBState = SCMTState == SCMTSTATE.Off ? SSBSTATE.Off : SSBSTATE.On;
                if (DoesStartFromTerminalStation())
                {
                    NoRSCZone = true;
                    RSCPresent = false;
                }
            }
            if (!RSCPresent && !NoRSCZone) CheckRSCPresent();
            if (ColdStart)
            {
                RSCState = !IsColdStart() && !DoesStartFromTerminalStation() && RSCMonitor && RSCPresent ? RSCSTATE.Active : RSCSTATE.Inactive;
                RSCFirstRun = RSCState == RSCSTATE.Active && IsColdStart();
            }
            if (RSCState == RSCSTATE.Active)
                SetCabDisplayControl((int)(TCSCommandEvent.Splash) - 1, (int)SCMTSTATE.ActiveAndRSC);
            else
                SetCabDisplayControl((int)(TCSCommandEvent.Splash) - 1, (int)SCMTState);
            SetCabDisplayControl((int)(TCSCommandEvent.Ripetizioni_estese) - 1, 11 - (int)RSCCODE.C75);

            distanceSignalDistanceM = NextDistanceSignalDistanceM();
            normalSignalDistanceM = NextSignalDistanceM(0);
            infoSignalDistanceM = NextGenericSignalDistanceM("INFO");
            normalSignalPassed = false;
            distanceSignalPassed = false;
            if (normalSignalDistanceM > 0)
            {
                if (normalSignalDistanceM != float.MaxValue && AutodetectSignalFilesType)
                    SignalFilesType = DoesNextNormalSignalHaveRepeaterHead() ? SIGNALFILESTYPE.SerriniBaldi : SIGNALFILESTYPE.PriviteraBono;
                UpdateParams();
            }
            if (RSCState == RSCSTATE.Active)
                SetCabDisplayControl((int)(TCSCommandEvent.Ripetizioni_estese) - 1, 11 - (int)RSCCode);
        }

        public void UpdateInputs()
        {
        }

        void UpdateVigilance()
        {
            switch (VigilanceMonitorState)
            {
                case MonitorState.Disabled:
                    if (VigilanceSystemEnabled && SpeedKpH < 0.36f)
                    {
                        VigilanceMonitorState = MonitorState.StandBy;
                    }
                    break;

                case MonitorState.StandBy:
                    if (!VigilanceSystemEnabled)
                    {
                        VigilanceMonitorState = MonitorState.Disabled;
                    }
                    else
                    {
                        if (SpeedKpH > 2.5f)
                        {
                            VigilanceMonitorState = MonitorState.Alarm;
                            TriggerGenericSound(Event.GenericEvent1);
                        }

                        if (VigilanceEmergencyTimer.Started)
                        {
                            VigilanceEmergencyTimer.Stop();
                            TriggerSoundAlert2();
                        }
                    }
                    break;

                case MonitorState.Alarm:
                    if (!VigilanceSystemEnabled)
                    {
                        VigilanceMonitorState = MonitorState.Disabled;
                    }
                    else
                    {
                        if (!VigilanceEmergencyTimer.Started)
                        {
                            VigilanceEmergencyTimer.Start();
                            if (Autopilot) AutopilotTimer.Start();
                        }
                        if (VigilanceEmergencyTimer.Started && (ResetButtonPressed || AutopilotTimer.Triggered))
                        {
                            VigilanceEmergencyTimer.Stop();
                            AutopilotTimer.Stop();
                            TriggerSoundAlert2();
                            VigilanceMonitorState = MonitorState.Disabled;
                        }
                        if (VigilanceEmergencyTimer.Triggered)
                        {
                            VigilanceEmergencyTimer.Stop();
                            TriggerSoundAlert2();
                            TriggerSoundWarning1();
                            SetCabDisplayControl((int)(TCSCommandEvent.Visualizz_Pulsante_RF) - 1, 2);
                            VigilanceMonitorState = MonitorState.Emergency;
                        }
                    }
                    break;

                case MonitorState.Emergency:
                    break;
            }

            SetVigilanceAlarmDisplay(VigilanceMonitorState == MonitorState.Alarm);
            SetVigilanceEmergencyDisplay(VigilanceMonitorState == MonitorState.Emergency);
        }

        void UpdateSCMTOverspeedMonitor()
        {
            switch (SCMTOverspeedMonitorState)
            {
                case MonitorState.Disabled:
                    if (SpeedControlSystemEnabled)
                    {
                        SCMTOverspeedMonitorState = MonitorState.StandBy;
                    }
                    break;

                case MonitorState.StandBy:
                    if (!SpeedControlSystemEnabled)
                    {
                        SCMTOverspeedMonitorState = MonitorState.Disabled;
                    }
                    else
                    {
                        if (SCMTOverspeed)
                        {
                            TriggerSoundInfo2();
                            SetCabDisplayControl((int)(TCSCommandEvent.Visualizz_Pulsante_RF) - 1, 2);
                            SetCabDisplayControl((int)(TCSCommandEvent.Luce_rossa_tacho) - 1, 2);
                            SCMTOverspeedMonitorState = MonitorState.Emergency;
                        }
                        else if (SCMTOverspeedWarning)
                        {
                            TriggerSoundPenalty1();
                            SetCabDisplayControl((int)(TCSCommandEvent.Luce_rossa_tacho) - 1, 1);
                            SCMTOverspeedMonitorState = MonitorState.Alarm;
                        }

                    }
                    break;
                case MonitorState.Alarm:
                    if (SCMTOverspeed)
                    {
                        TriggerSoundAlert2();
                        TriggerSoundInfo2();
                        SetCabDisplayControl((int)(TCSCommandEvent.Visualizz_Pulsante_RF) - 1, 2);
                        SetCabDisplayControl((int)(TCSCommandEvent.Luce_rossa_tacho) - 1, 2);
                        SCMTOverspeedMonitorState = MonitorState.Emergency;
                    }
                    else if (SCMTOverspeedReadyToReset)
                    {
                        SetCabDisplayControl((int)(TCSCommandEvent.Luce_rossa_tacho) - 1, 0);
                        SCMTOverspeedMonitorState = MonitorState.StandBy;
                        TriggerSoundAlert2();
                    }
                    break;
                case MonitorState.Emergency:
                    if (SCMTOverspeedReadyToReset)
                    {
                        SetCabDisplayControl((int)(TCSCommandEvent.Visualizz_Pulsante_RF) - 1, 1);
                        SCMTOverspeedMonitorState = MonitorState.ReadyToReset;
                        if (Autopilot) AutopilotTimer.Start();
                    }
                    break;
                case MonitorState.ReadyToReset:
                    if (TCSButtonPressed[(int)(TCSCommandEvent.Pulsante_RF)] || Autopilot && AutopilotTimer.Triggered)
                    {
                        AutopilotTimer.Stop();
                        AutopilotButtonPressTimer.Start();
                        SetCabDisplayControl((int)(TCSCommandEvent.Visualizz_Pulsante_RF) - 1, 0);
                        SetCabDisplayControl((int)(TCSCommandEvent.Luce_rossa_tacho) - 1, 0);
                        SCMTOverspeedMonitorState = MonitorState.StandBy;
                        TriggerSoundWarning2();
                        TriggerSoundAlert2();
                    }
                    else
                    {

                    }
                    break;
            }
        }

        public override void SetEmergency(bool emergency)
        {
            ExternalEmergencyBraking = emergency;
        }

        protected void UpdateSSBState()
        {
            switch (SSBState)
            {
                case SSBSTATE.ReadyToOn:
                    if (TCSButtonPressed[(int)(TCSCommandEvent.AccendiSpegniSSB)] && SCMTState == SCMTSTATE.Off)
                    {
                        SCMTAutotestTimer.Setup(2);
                        SCMTAutotestTimer.Start();
                        SSBState = SSBSTATE.On;
                        TriggerSoundSystemActivate();
                    }
                    break;
                case SSBSTATE.On:
                    if (TCSButtonPressed[(int)(TCSCommandEvent.AccendiSpegniSSB)])
                    {
                        SCMTState = SCMTSTATE.Off;
                        RSCState = RSCSTATE.Inactive;
                        SSBState = SSBSTATE.ReadyToOn;
                        TriggerSoundSystemDeactivate();
                    }
                    if (circuitBreakerOpened)
                    {
                        TriggerSoundSystemDeactivate();
                    }
                    break;
            }
            if (TCSButtonReleased[(int)(TCSCommandEvent.AccendiSpegniSSB)])
                TCSButtonReleased[(int)(TCSCommandEvent.AccendiSpegniSSB)] = false;
            circuitBreakerOpened = false;
        }


        protected void UpdateSCMTState()
        {
            switch (SCMTState)
            {
                case SCMTSTATE.Off:
                    if (SCMTAutotestTimer.Triggered)
                    {
                        SCMTAutotestTimer.Stop();
                        SCMTState = SCMTSTATE.Autotest;
                        AutotestPhase = AUTOTESTPHASE.FirstBraking;
                        SCMTAutotestTimer.Setup(SCMTAutotestTimerDelayS[0]);
                    }
                    break;
                case SCMTSTATE.Manovra:
                    if (TCSButtonPressed[(int)(TCSCommandEvent.Pulsante_Man)])
                    {
                        TriggerSoundWarning2();
                        SCMTState = SCMTSTATE.IntroduzioneDatiOManovra;
                        TCSButtonPressed[(int)(TCSCommandEvent.Pulsante_Man)] = false;
                        SetCabDisplayControl((int)(TCSCommandEvent.Pulsante_Man) - 1, 0);
                    }
                    break;
                case SCMTSTATE.IntroduzioneDatiOManovra:
                    if (TCSButtonPressed[(int)(TCSCommandEvent.Pulsante_Dati)])
                    {
                        TriggerSoundWarning2();
                        SCMTState = SCMTSTATE.IntroduzioneDati;
                        TCSButtonPressed[(int)(TCSCommandEvent.Pulsante_Dati)] = false;
                    }
                    if (TCSButtonPressed[(int)(TCSCommandEvent.Pulsante_Man)])
                    {
                        TriggerSoundWarning2();
                        SCMTState = SCMTSTATE.Manovra;
                        TCSButtonPressed[(int)(TCSCommandEvent.Pulsante_Man)] = false;
                        SetCabDisplayControl((int)(TCSCommandEvent.Pulsante_Man) - 1, 1);
                    }
                    break;
                case SCMTSTATE.IntroduzioneDati:
                    if (TCSButtonPressed[(int)(TCSCommandEvent.Pulsante_OK)])
                    {
                        TriggerSoundWarning2();
                        SCMTState = SCMTSTATE.Predisposizione;
                        TCSButtonPressed[(int)(TCSCommandEvent.Pulsante_OK)] = false;
                    }
                    break;
                case SCMTSTATE.Predisposizione:
                SetCabDisplayControl((int)(TCSCommandEvent.Visualizz_GuastoATerra) - 1, 0); 
                    if (TCSButtonPressed[(int)(TCSCommandEvent.Pulsante_SCMT)])
                    {
                        if (!EsclusioneSCMTTimer.Started)
                            EsclusioneSCMTTimer.Start();
                        SCMTState = SCMTSTATE.EsclusioneRequestedFromPred;
                    }
                    if (TCSButtonPressed[(int)(TCSCommandEvent.Pulsante_Man)])
                    {
                        TriggerSoundWarning2();
                        SCMTState = SCMTSTATE.Manovra;
                        TCSButtonPressed[(int)(TCSCommandEvent.Pulsante_Man)] = false;
                        SetCabDisplayControl((int)(TCSCommandEvent.Pulsante_Man) - 1, 1);
                        RSCState = RSCSTATE.Inactive;
                    }
                    break;
                case SCMTSTATE.EsclusioneRequestedFromPred:
                    if (EsclusioneSCMTTimer.Triggered) 
                    {
                        EsclusioneSCMTTimer.Stop();
                        TriggerSoundWarning2();
                        SCMTState = SCMTSTATE.EsclusoFromPred;
                    }
                    break;
                case SCMTSTATE.EsclusoFromPred:
                SetCabDisplayControl((int)(TCSCommandEvent.Visualizz_GuastoATerra) - 1, 1); 
                    if (TCSButtonPressed[(int)(TCSCommandEvent.Pulsante_SCMT)]) 
                    {
                        if (!EsclusioneSCMTTimer.Started)
                            EsclusioneSCMTTimer.Start();
                        SCMTState = SCMTSTATE.ReinclusioneFromPred;
                    }
                    break;
                case SCMTSTATE.ReinclusioneFromPred:
                SetCabDisplayControl((int)(TCSCommandEvent.Visualizz_GuastoATerra) - 1, 1); 
                    if (EsclusioneSCMTTimer.Triggered)
                    {
                        EsclusioneSCMTTimer.Stop();
                        TriggerSoundWarning2();
                        SCMTState = SCMTSTATE.Predisposizione;
                    }
                    break;
                case SCMTSTATE.Active:
                SetCabDisplayControl((int)(TCSCommandEvent.Visualizz_GuastoATerra) - 1, 0); 
                    if (TCSButtonPressed[(int)(TCSCommandEvent.Pulsante_SCMT)])
                    {
                        if (!EsclusioneSCMTTimer.Started)
                            EsclusioneSCMTTimer.Start();
                        SCMTState = SCMTSTATE.EsclusioneRequestedFromActive;
                    }
                    if (TCSButtonPressed[(int)(TCSCommandEvent.Pulsante_Man)])
                    {
                        TriggerSoundWarning2();
                        SCMTState = SCMTSTATE.Manovra;
                        TCSButtonPressed[(int)(TCSCommandEvent.Pulsante_Man)] = false;
                        SetCabDisplayControl((int)(TCSCommandEvent.Pulsante_Man) - 1, 1);
                        RSCState = RSCSTATE.Inactive;
                    }
                    break;
                case SCMTSTATE.EsclusioneRequestedFromActive:
                    if (EsclusioneSCMTTimer.Triggered) 
                    {
                        EsclusioneSCMTTimer.Stop();
                        TriggerSoundWarning2();
                        SCMTState = SCMTSTATE.EsclusoFromActive;
                    }
                    break;
                case SCMTSTATE.EsclusoFromActive:
                SetCabDisplayControl((int)(TCSCommandEvent.Visualizz_GuastoATerra) - 1, 1); 
                    if (TCSButtonPressed[(int)(TCSCommandEvent.Pulsante_SCMT)]) 
                    {
                        if (!EsclusioneSCMTTimer.Started)
                            EsclusioneSCMTTimer.Start();
                        SCMTState = SCMTSTATE.ReinclusioneFromActive;
                    }
                    break;
                case SCMTSTATE.ReinclusioneFromActive:
                SetCabDisplayControl((int)(TCSCommandEvent.Visualizz_GuastoATerra) - 1, 1); 
                    if (EsclusioneSCMTTimer.Triggered) 
                    {
                        EsclusioneSCMTTimer.Stop();
                        TriggerSoundWarning2();
                        SCMTState = SCMTSTATE.StandByReinclusoFromActive;
                    }
                    break;
                case SCMTSTATE.StandByReinclusoFromActive: 
                SetCabDisplayControl((int)(TCSCommandEvent.Visualizz_GuastoATerra) - 1, 0);
                    if (normalSignalPassed)
                    {
                        SCMTState = SCMTSTATE.Active;
                        TriggerSoundInfo1();
                    }
                    if (TCSButtonPressed[(int)(TCSCommandEvent.Pulsante_Man)])
                    {
                        TriggerSoundWarning2();
                        SCMTState = SCMTSTATE.Manovra;
                        TCSButtonPressed[(int)(TCSCommandEvent.Pulsante_Man)] = false;
                        SetCabDisplayControl((int)(TCSCommandEvent.Pulsante_Man) - 1, 1);
                        RSCState = RSCSTATE.Inactive;
                    }
                    break;
                case SCMTSTATE.ActiveAndRSC:
                    if (TCSButtonPressed[(int)(TCSCommandEvent.Pulsante_Man)])
                    {
                        TriggerSoundWarning2();
                        SCMTState = SCMTSTATE.Manovra;
                        TCSButtonPressed[(int)(TCSCommandEvent.Pulsante_Man)] = false;
                        SetCabDisplayControl((int)(TCSCommandEvent.Pulsante_Man) - 1, 1);
                        RSCState = RSCSTATE.Inactive;
                    }
                    break;
            }
            if (TCSButtonReleased[(int)(TCSCommandEvent.Pulsante_Dati)])
            {
                TriggerSoundPenalty2();
                TCSButtonReleased[(int)(TCSCommandEvent.Pulsante_Dati)] = false;
            }
            if (TCSButtonReleased[(int)(TCSCommandEvent.Pulsante_OK)])
            {
                TriggerSoundPenalty2();
                TCSButtonReleased[(int)(TCSCommandEvent.Pulsante_OK)] = false;
            }
            if (TCSButtonReleased[(int)(TCSCommandEvent.Pulsante_Man)])
            {
                TriggerSoundPenalty2();
                TCSButtonReleased[(int)(TCSCommandEvent.Pulsante_Man)] = false;
            }

            if (TCSButtonReleased[(int)(TCSCommandEvent.Pulsante_SCMT)])
            {
                TriggerSoundPenalty2();
                TCSButtonReleased[(int)(TCSCommandEvent.Pulsante_SCMT)] = false;
            }
        }

         protected void UpdateRSCState()
        {
            if (TCSButtonPressed[(int)(TCSCommandEvent.Pulsante_RSC)])  
            {
                if (!EsclusioneRSCTimer.Started)
                    EsclusioneRSCTimer.Start();
            }
            if (TCSButtonReleased[(int)(TCSCommandEvent.Pulsante_RSC)])
            {
                if (EsclusioneRSCTimer.Triggered)  
                {  
                    RSCState = RSCSTATE.Disabled;
                }
                else
                {
                    EsclusioneRSCTimer.Stop();
                }
            }
            switch (RSCState)
            {
                case RSCSTATE.Active:
                    if (TCSButtonPressed[(int)(TCSCommandEvent.Pulsante_RSC)]) 
                    {
                        TriggerSoundWarning2();
                    }
                    if (NoRSCZone || RSCForceNoCod)
                    {
                        RSCState = RSCSTATE.WaitingShutdown;
                        TriggerSoundWarning1();
                        SCMTWarningTimer.Start();
                        if (Autopilot) AutopilotTimer.Start();
                    }
                    else
                    {
                        RSCFirstRun = false;
                        if (TCSButtonPressed[(int)(TCSCommandEvent.Pulsante_RSC)]) 
                        {
                            TriggerSoundInfo1(); 
                            RSCState = RSCSTATE.Inactive;
                            RSCPrericonoscimentoState = PRERICONOSCIMENTOSTATE.Invalid;
                            SetCabDisplayControl((int)(TCSCommandEvent.Pulsante_Pre) - 1, 0);
                        }
                    }
                    break;
                case RSCSTATE.Inactive:
                    if (RSCCodeConfirmation1Timer.Triggered) 
                    {
                        RSCCodeConfirmation1Timer.Stop();
                        RSCState = RSCSTATE.WaitingAck; 
                        TriggerSoundWarning1();
                        SCMTWarningTimer.Start();
                        if (Autopilot) AutopilotTimer.Start();
                        RSCPresent = true;
                    }
                    else if (RSCPIPassed) 
                    {
                        if (!RSCCodeConfirmation1Timer.Started)
                            RSCCodeConfirmation1Timer.Start();
                    }
                    else if (TCSButtonPressed[(int)(TCSCommandEvent.Pulsante_RSC)] && RSCPresent) 
                    {
                        SetCabDisplayControl((int)(TCSCommandEvent.Visualizz_Pulsante_RSC) - 1, 0);
                        if (!RSCManualActivationTimer.Started)
                            RSCManualActivationTimer.Start();
                        RSCState = RSCSTATE.ActivationRequested;
                        //TriggerSoundWarning2();
                    }
                    break;
                case RSCSTATE.ActivationRequested:
                    if (TCSButtonPressed[(int)(TCSCommandEvent.Pulsante_RSC)]) 
                    {
                        TriggerSoundWarning2();
                    }
                SetCabDisplayControl((int)(TCSCommandEvent.Visualizz_Pulsante_RSC) - 1, 0);
                    if (RSCManualActivationTimer.Triggered)
                    {
                        //TriggerSoundWarning2(); //fa suonare bip tasto prima del rilascio all'attivazione
                        //RSCManualActivationTimer.Stop();
                        RSCState = RSCSTATE.Decision;
                    }
                    break;
                case RSCSTATE.Decision:
                
                    if (TCSButtonPressed[(int)(TCSCommandEvent.Pulsante_RSC)]) 
                    {
                        TriggerSoundWarning2();
                    }
                    if (RSCManualActivationTimer.Triggered && (TCSButtonReleased[(int)(TCSCommandEvent.Pulsante_RSC)]))
                    {
                        TriggerSoundWarning2(); 
                        RSCManualActivationTimer.Stop();
                        RSCState = RSCSTATE.Active;
                    }
                    else if (RSCManualActivationTimer.Triggered && !(TCSButtonReleased[(int)(TCSCommandEvent.Pulsante_RSC)])) 
                    {
                        if (!EsclusioneRSCTimer.Started) EsclusioneRSCTimer.Start();

                        if (EsclusioneRSCTimer.Triggered)
                        {
                            TriggerSoundWarning2(); 
                            EsclusioneRSCTimer.Stop();
                            RSCState = RSCSTATE.Disabled;
                        }
                    }
                    break;
                case RSCSTATE.WaitingAck: 
                SetCabDisplayControl((int)(TCSCommandEvent.Visualizz_Pulsante_RSC) - 1, 2);
                    if ((TCSButtonPressed[(int)(TCSCommandEvent.Pulsante_RSC)] || AutopilotTimer.Triggered) && SCMTWarningTimer.Started)
                    {
                        TriggerSoundWarning2();
                        TriggerSoundAlert2();
                        SCMTWarningTimer.Stop();
                        AutopilotTimer.Stop();
                        if (Autopilot) AutopilotButtonPressTimer.Start();
                        RSCState = RSCSTATE.Active;
                        NoRSCZone = false;
                        RSCPreviousCode = RSCCODE.None;
                        RSCFirstRun = true;
                        RSCFirstCodeReceived = true;
                        SetCabDisplayControl((int)(TCSCommandEvent.Visualizz_Pulsante_RSC) - 1, 0);
                    }
                    if (SCMTWarningTimer.Started && SCMTWarningTimer.Triggered)
                    {
                        SCMTEmergencyBraking = true;
                        SetCabDisplayControl((int)(TCSCommandEvent.Visualizz_Pulsante_RF) - 1, 2);
                        RSCState = RSCSTATE.AckMissed;
                        SCMTWarningTimer.Stop();
                    }
                    break;
                case RSCSTATE.WaitingShutdown:
                SetCabDisplayControl((int)(TCSCommandEvent.Visualizz_Pulsante_RSC) - 1, 2);
                    if ((TCSButtonPressed[(int)(TCSCommandEvent.Pulsante_RSC)] || AutopilotTimer.Triggered) && SCMTWarningTimer.Started)
                    {
                        TriggerSoundInfo1(); 
                        TriggerSoundWarning2();
                        TriggerSoundAlert2();
                        SCMTWarningTimer.Stop();
                        AutopilotTimer.Stop();
                        if (Autopilot) AutopilotButtonPressTimer.Start();
                        RSCState = RSCSTATE.Inactive;
                        RSCPreviousCode = RSCCODE.None;
                        RSCFirstRun = false;
                        RSCPrericonoscimentoState = PRERICONOSCIMENTOSTATE.Invalid;
                        SetCabDisplayControl((int)(TCSCommandEvent.Pulsante_Pre) - 1, 0);
                        SetCabDisplayControl((int)(TCSCommandEvent.Visualizz_Pulsante_RSC) - 1, 0);
                        RSCFirstCodeReceived = false;
                    }
                    else if (SCMTWarningTimer.Triggered)
                    {
                        SCMTWarningTimer.Stop();
                        SetCabDisplayControl((int)(TCSCommandEvent.Visualizz_Pulsante_RF) - 1, 2);
                        SCMTEmergencyBraking = true;
                    }
                    break;
                case RSCSTATE.Disabled:
                RSCManualActivationTimer.Stop();
                SetCabDisplayControl((int)(TCSCommandEvent.Visualizz_GuastoATerraRSC) - 1, 1);
                
                    if (TCSButtonPressed[(int)(TCSCommandEvent.Pulsante_RSC)])
                    {
                        TriggerSoundWarning2();
                        TriggerSoundInfo1(); 
                        RSCState = RSCSTATE.Inactive; 
                        RSCPrericonoscimentoState = PRERICONOSCIMENTOSTATE.Invalid;
                        SetCabDisplayControl((int)(TCSCommandEvent.Pulsante_Pre) - 1, 0);
                        SetCabDisplayControl((int)(TCSCommandEvent.Visualizz_GuastoATerraRSC) - 1, 0);

                        EsclusioneRSCTimer.Stop();

                        
                    }
                    break;
                default:
                    break;
            }
            if (TCSButtonReleased[(int)(TCSCommandEvent.Pulsante_RSC)])
            {
                TriggerSoundPenalty2();
                TCSButtonReleased[(int)(TCSCommandEvent.Pulsante_RSC)] = false;
            }
        }

        protected void CheckNoRSCZone()
        {
            if (!NoRSCZone && !RSCForceCod && !RSCForceCod9)
            {
                var nextStationName = NextStationName();
                if (nextStationName != "" && NoRSCStations.Contains(nextStationName) && NextStationDistanceM() < 2000f && normalSignalDistanceM < 100f
                    && (NextSignalDistanceM(1) > NextStationDistanceM() || NextSignalDistanceM(1) == normalSignalDistanceM))
                {
                    NoRSCZone = true;
                    RSCPresent = false;
                }
            }
        }

        protected void CheckRSCPresent()
        {
            if (RSCForceCod || RSCForceCod9)
            {
                RSCPresent = true;
                return;
            }
            var nextTrailingSwitchDistanceM = NextTrailingDivergingSwitchDistanceM(RSCMaxTrailingDivergingSwitchDistanceM);
            if (nextTrailingSwitchDistanceM == float.MaxValue && !RSCForceNoCod)
                RSCPresent = true;
        }

        protected void UpdateSCMT()
        {
            if (SCMTState == SCMTSTATE.Manovra || (SCMTState != SCMTSTATE.Active && SCMTState != SCMTSTATE.ActiveAndRSC))
            {
                SCMTCurrentSignalSpeedLimitKpH = 30f;
                SetNextSpeedLimitMpS(MpS.FromKpH(SCMTCurrentSignalSpeedLimitKpH));
                SCMTCurrentSpeedPostSpeedLimitKpH = MpS.ToKpH(CurrentPostSpeedLimitMpS());
                SetCurrentSpeedLimitMpS(MpS.FromKpH(Math.Min(SCMTCurrentSignalSpeedLimitKpH, SCMTCurrentSpeedPostSpeedLimitKpH)));
                SCMTSignalEmergencySpeedCurveKpH = SCMTCurrentSignalSpeedLimitKpH + SCMTCurrentEBSpeedKpH;
                SCMTSignalAlertSpeedCurveKpH = SCMTCurrentSignalSpeedLimitKpH + SCMTCurrentAlertSpeedKpH;
                SCMTSpeedPostEmergencySpeedCurveKpH = SCMTCurrentSpeedPostSpeedLimitKpH + SCMTCurrentEBSpeedKpH;
                SCMTSpeedPostAlertSpeedCurveKpH = SCMTCurrentSpeedPostSpeedLimitKpH + SCMTCurrentAlertSpeedKpH;
            }
            else
            {
                SCMTTrainLengthM = (float)Math.Ceiling((double)(TrainLengthM() / 100f)) * 100f;
                if (HeavyFreightTrain)
                    SCMTDelayBeforeBrakingEstablishedS = 12f + SCMTTrainLengthM / 200f;
                else
                    SCMTDelayBeforeBrakingEstablishedS = 2f + 2f * SCMTTrainLengthM * SCMTTrainLengthM * 0.00001f;
                var oldSCMTNextSignalSpeedLimitKpH = SCMTNextSignalSpeedLimitKpH;
                if (RSCState == RSCSTATE.Active)
                    SCMTNextSignalSpeedLimitKpH = RSCNextSignalAllowedSpeedKpH;
                else
                    SCMTNextSignalSpeedLimitKpH = Math.Min(150f, RSCNextSignalAllowedSpeedKpH);
                if (oldSCMTNextSignalSpeedLimitKpH == 0 && SCMTNextSignalSpeedLimitKpH != 0 && SCMTVelocitaRilascio == 10f)
                {
                    TriggerGenericSound(Event.GenericEvent7);
                    SCMTVelocitaRilascio = 30f;
                }
                    SCMTSignalTargetSpeedKpH = Math.Max(SCMTNextSignalSpeedLimitKpH == -3.6f ? SCMTTrainSpeedLimitKpH : SCMTNextSignalSpeedLimitKpH, SCMTVelocitaRilascio);
                var incIndex = 0;
                //if next normal signal is a virtual signal that restores line speed, it's not considered
                var nextNormalSignalMainHeadSignalType = NextGenericSignalFeatures("NORMAL", 0, float.MaxValue).MainHeadSignalTypeName;
                if (nextNormalSignalMainHeadSignalType == "riprvel" || nextNormalSignalMainHeadSignalType == "fsvirtfinelim")
                    incIndex = 1;
                SCMTSignalTargetDistanceM = NextSignalDistanceM(incIndex);
                if (SCMTNextSignalSpeedLimitKpH == 0) SCMTSignalTargetDistanceM = Math.Max(SCMTSignalTargetDistanceM - 200, 0);

                SCMTCurrentSignalSpeedLimitKpH = MpS.ToKpH(CurrentSignalSpeedLimitMpS());
                if (SCMTCurrentSignalSpeedLimitKpH == -3.6f) SCMTCurrentSignalSpeedLimitKpH = MpS.ToKpH(TrainSpeedLimitMpS());

                // Update current speed limit when speed is below the target or when the train approaches the signal
                /*               if (NextSignalDistanceM(0) <= 5f)
                               {
                                   if (nextSignalSpeedLimitKpH > 0f && nextSignalSpeedLimitKpH < SCMTTrainSpeedLimitKpH)
                                       SCMTCurrentSignalSpeedLimitKpH = nextSignalSpeedLimitKpH;
                                   else
                                       SCMTCurrentSignalSpeedLimitKpH = SCMTTrainSpeedLimitKpH;
                               }*/


                // Speed post speed limit preparation

                SCMTNextSpeedPostSpeedLimitKpH = (NextPostSpeedLimitMpS(0) > 0 ? MpS.ToKpH(NextPostSpeedLimitMpS(0)) : SCMTTrainSpeedLimitKpH);
                SCMTCurrentSpeedPostSpeedLimitKpH = MpS.ToKpH(CurrentPostSpeedLimitMpS());
                SCMTSpeedPostTargetSpeedKpH = SCMTNextSpeedPostSpeedLimitKpH;
                SCMTSpeedPostTargetDistanceM = NextPostDistanceM(0);


                SetNextSpeedLimitMpS(MpS.FromKpH(Math.Min(SCMTNextSignalSpeedLimitKpH, SCMTNextSpeedPostSpeedLimitKpH)));
                SetCurrentSpeedLimitMpS(MpS.FromKpH(Math.Min(SCMTCurrentSignalSpeedLimitKpH, SCMTCurrentSpeedPostSpeedLimitKpH)));
                UpdateSCMTSpeedCurve();
            }
        }

        protected void UpdateSCMTSpeedCurve()
        {
            SCMTSignalEmergencySpeedCurveKpH =
                Math.Min(
                    Math.Min(
                        Math.Max(
                            MpS.ToKpH(SpeedCurve(
                                SCMTSignalTargetDistanceM,
                                MpS.FromKpH(SCMTSignalTargetSpeedKpH),
                                SCMTDeclivity,
                                SCMTDelayBeforeBrakingEstablishedS,
                                SafeDecelerationMpS2
                            )),
                            SCMTSignalTargetSpeedKpH + SCMTNextEBSpeedKpH
                        ),
                        SCMTTrainSpeedLimitKpH + SCMTCurrentEBSpeedKpH
                    ),
                    SCMTCurrentSignalSpeedLimitKpH + SCMTCurrentEBSpeedKpH
                );
            SCMTSignalAlertSpeedCurveKpH =
                Math.Min(
                    Math.Min(
                        Math.Max(
                            MpS.ToKpH(SpeedCurve(
                                SCMTSignalTargetDistanceM,
                                MpS.FromKpH(SCMTSignalTargetSpeedKpH),
                                SCMTDeclivity,
                                SCMTDelayBeforeBrakingEstablishedS + SCMTDelayBeforeEmergencyBrakingS,
                                SafeDecelerationMpS2
                            )),
                            SCMTSignalTargetSpeedKpH + SCMTNextAlertSpeedKpH
                        ),
                        SCMTTrainSpeedLimitKpH + SCMTCurrentAlertSpeedKpH
                    ),
                    SCMTCurrentSignalSpeedLimitKpH + SCMTCurrentAlertSpeedKpH
                );
            SCMTSpeedPostEmergencySpeedCurveKpH =
                Math.Min(
                    Math.Min(
                        Math.Max(
                            MpS.ToKpH(SpeedCurve(
                                SCMTSpeedPostTargetDistanceM,
                                MpS.FromKpH(SCMTSpeedPostTargetSpeedKpH),
                                SCMTDeclivity,
                                SCMTDelayBeforeBrakingEstablishedS,
                                SafeDecelerationMpS2
                            )),
                            SCMTNextSpeedPostSpeedLimitKpH + SCMTNextEBSpeedKpH
                        ),
                        SCMTTrainSpeedLimitKpH + SCMTCurrentEBSpeedKpH
                    ),
                    SCMTCurrentSpeedPostSpeedLimitKpH + SCMTCurrentEBSpeedKpH
                );
            SCMTSpeedPostAlertSpeedCurveKpH =
                Math.Min(
                    Math.Min(
                        Math.Max(
                            MpS.ToKpH(SpeedCurve(
                                SCMTSpeedPostTargetDistanceM,
                                MpS.FromKpH(SCMTSpeedPostTargetSpeedKpH),
                                SCMTDeclivity,
                                SCMTDelayBeforeBrakingEstablishedS + SCMTDelayBeforeEmergencyBrakingS,
                                SafeDecelerationMpS2
                            )),
                            SCMTNextSpeedPostSpeedLimitKpH + SCMTNextAlertSpeedKpH
                        ),
                        SCMTTrainSpeedLimitKpH + SCMTCurrentAlertSpeedKpH
                    ),
                    SCMTCurrentSpeedPostSpeedLimitKpH + SCMTCurrentAlertSpeedKpH
                );

            SetCurrentSpeedLimitMpS(MpS.FromKpH(Math.Min(SCMTSignalAlertSpeedCurveKpH, SCMTSpeedPostAlertSpeedCurveKpH) - SCMTCurrentAlertSpeedKpH));

        }

        protected void UpdateSCMTAutotest()
        {
            switch (AutotestPhase)
            {
                case AUTOTESTPHASE.FirstBraking:
                    if (SCMTAutotestTimer.Triggered)
                    {
                        SetFullBrake(false);
                        SCMTAutotestTimer.Stop();
                        AutotestPhase = AUTOTESTPHASE.WaitFirstRelease;
                        SCMTAutotestTimer.Setup(SCMTAutotestTimerDelayS[(int)AutotestPhase]);
                    }
                    else if (!SCMTAutotestTimer.Started)
                    {
                        SCMTAutotestTimer.Start();
                        SetFullBrake(true);
                    }
                    break;
                case AUTOTESTPHASE.WaitFirstRelease:
                    if (SCMTAutotestTimer.Triggered)
                    {
                        SCMTAutotestTimer.Stop();
                        AutotestPhase = AUTOTESTPHASE.SecondBraking;
                        SCMTAutotestTimer.Setup(SCMTAutotestTimerDelayS[(int)AutotestPhase]);
                    }
                    else if (!SCMTAutotestTimer.Started)
                    {
                        SCMTAutotestTimer.Start();
                    }
                    break;
                case AUTOTESTPHASE.SecondBraking:
                    if (SCMTAutotestTimer.Triggered)
                    {
                        SetFullBrake(false);
                        SCMTAutotestTimer.Stop();
                        AutotestPhase = AUTOTESTPHASE.WaitSecondRelease;
                        SCMTAutotestTimer.Setup(SCMTAutotestTimerDelayS[(int)AutotestPhase]);
                    }
                    else if (!SCMTAutotestTimer.Started)
                    {
                        SCMTAutotestTimer.Start();
                        SetFullBrake(true);
                    }
                    break;
                case AUTOTESTPHASE.WaitSecondRelease:
                    if (SCMTAutotestTimer.Triggered)
                    {
                        SCMTAutotestTimer.Stop();
                        AutotestPhase = AUTOTESTPHASE.PulsanteSCMT;
                        SCMTAutotestTimer.Setup(SCMTAutotestTimerDelayS[(int)AutotestPhase]);
                    }
                    else if (!SCMTAutotestTimer.Started)
                    {
                        SCMTAutotestTimer.Start();
                    }
                    break;
                case AUTOTESTPHASE.PulsanteSCMT:
                    if (SCMTAutotestTimer.Triggered)
                    {
                        SetCabDisplayControl((int)(TCSCommandEvent.Visualizz_Pulsante_SCMT) - 1, 0);
                        SCMTAutotestTimer.Stop();
                        AutotestPhase = AUTOTESTPHASE.PulsanteMan;
                        SCMTAutotestTimer.Setup(SCMTAutotestTimerDelayS[(int)AutotestPhase]);
                    }
                    else if (!SCMTAutotestTimer.Started)
                    {
                        SetCabDisplayControl((int)(TCSCommandEvent.Visualizz_Pulsante_SCMT) - 1, 1);
                        SCMTAutotestTimer.Start();
                    }
                    break;
                case AUTOTESTPHASE.PulsanteMan:
                    if (SCMTAutotestTimer.Triggered)
                    {
                        SetCabDisplayControl((int)(TCSCommandEvent.Pulsante_Man) - 1, 0);
                        SCMTAutotestTimer.Stop();
                        AutotestPhase = AUTOTESTPHASE.PulsanteRSC;
                        SCMTAutotestTimer.Setup(SCMTAutotestTimerDelayS[(int)AutotestPhase]);
                    }
                    else if (!SCMTAutotestTimer.Started)
                    {
                        SetCabDisplayControl((int)(TCSCommandEvent.Pulsante_Man) - 1, 1);
                        SCMTAutotestTimer.Start();
                    }
                    break;
                case AUTOTESTPHASE.PulsanteRSC:
                    if (SCMTAutotestTimer.Triggered)
                    {
                        SetCabDisplayControl((int)(TCSCommandEvent.Visualizz_Pulsante_RSC) - 1, 0);
                        SCMTAutotestTimer.Stop();
                        AutotestPhase = AUTOTESTPHASE.PulsanteSR;
                        SCMTAutotestTimer.Setup(SCMTAutotestTimerDelayS[(int)AutotestPhase]);
                    }
                    else if (!SCMTAutotestTimer.Started)
                    {
                        SetCabDisplayControl((int)(TCSCommandEvent.Visualizz_Pulsante_RSC) - 1, 1);
                        SCMTAutotestTimer.Start();
                    }
                    break;
                case AUTOTESTPHASE.PulsanteSR:
                    if (SCMTAutotestTimer.Triggered)
                    {
                        SetCabDisplayControl((int)(TCSCommandEvent.Pulsante_SR) - 1, 0);
                        SCMTAutotestTimer.Stop();
                        AutotestPhase = AUTOTESTPHASE.PulsanteDebug;
                        SCMTAutotestTimer.Setup(SCMTAutotestTimerDelayS[(int)AutotestPhase]);
                    }
                    else if (!SCMTAutotestTimer.Started)
                    {
                        SetCabDisplayControl((int)(TCSCommandEvent.Pulsante_SR) - 1, 1);
                        SCMTAutotestTimer.Start();
                    }
                    break;
                case AUTOTESTPHASE.PulsanteDebug:
                    if (SCMTAutotestTimer.Triggered)
                    {
                        SetCabDisplayControl((int)(TCSCommandEvent.Pulsante_Debug) - 1, 0);
                        SCMTAutotestTimer.Stop();
                        AutotestPhase = AUTOTESTPHASE.PulsantePre;
                        SCMTAutotestTimer.Setup(SCMTAutotestTimerDelayS[(int)AutotestPhase]);
                    }
                    else if (!SCMTAutotestTimer.Started)
                    {
                        SetCabDisplayControl((int)(TCSCommandEvent.Pulsante_Debug) - 1, 0);
                        SCMTAutotestTimer.Start();
                    }
                    break;
                case AUTOTESTPHASE.PulsantePre:
                    if (SCMTAutotestTimer.Triggered)
                    {
                        SetCabDisplayControl((int)(TCSCommandEvent.Pulsante_Pre) - 1, 0);
                        SCMTAutotestTimer.Stop();
                        AutotestPhase = AUTOTESTPHASE.PulsanteRic;
                        SCMTAutotestTimer.Setup(SCMTAutotestTimerDelayS[(int)AutotestPhase]);
                    }
                    else if (!SCMTAutotestTimer.Started)
                    {
                        SetCabDisplayControl((int)(TCSCommandEvent.Pulsante_Pre) - 1, 1);
                        SCMTAutotestTimer.Start();
                    }
                    break;
                case AUTOTESTPHASE.PulsanteRic:
                    if (SCMTAutotestTimer.Triggered)
                    {
                        SetCabDisplayControl((int)(TCSCommandEvent.Pulsante_Ric) - 1, 0);
                        SCMTAutotestTimer.Stop();
                        AutotestPhase = AUTOTESTPHASE.PulsanteRF;
                        SCMTAutotestTimer.Setup(SCMTAutotestTimerDelayS[(int)AutotestPhase]);
                    }
                    else if (!SCMTAutotestTimer.Started)
                    {
                        SetCabDisplayControl((int)(TCSCommandEvent.Pulsante_Ric) - 1, 1);
                        SCMTAutotestTimer.Start();
                    }
                    break;
                case AUTOTESTPHASE.PulsanteRF:
                    if (SCMTAutotestTimer.Triggered)
                    {
                        SetCabDisplayControl((int)(TCSCommandEvent.Visualizz_Pulsante_RF) - 1, 0);
                        SCMTAutotestTimer.Stop();
                        AutotestPhase = AUTOTESTPHASE.Beep;
                        SCMTAutotestTimer.Setup(SCMTAutotestTimerDelayS[(int)AutotestPhase]);
                    }
                    else if (!SCMTAutotestTimer.Started)
                    {
                        SetCabDisplayControl((int)(TCSCommandEvent.Visualizz_Pulsante_RF) - 1, 1);
                        SCMTAutotestTimer.Start();
                    }
                    break;
                case AUTOTESTPHASE.Beep:
                    if (SCMTAutotestTimer.Triggered)
                    {
                        TriggerSoundPenalty2();
                        SCMTAutotestTimer.Stop();
                        AutotestPhase = AUTOTESTPHASE.ThirdBraking;
                        SCMTAutotestTimer.Setup(SCMTAutotestTimerDelayS[(int)AutotestPhase]);
                    }
                    else if (!SCMTAutotestTimer.Started)
                    {
                        TriggerSoundWarning2();
                        SCMTAutotestTimer.Start();
                    }
                    break;
                case AUTOTESTPHASE.ThirdBraking:
                    if (SCMTAutotestTimer.Triggered)
                    {
                        SetFullBrake(false);
                        SCMTAutotestTimer.Stop();
                        AutotestPhase = AUTOTESTPHASE.WaitThirdRelease;
                        SCMTAutotestTimer.Setup(SCMTAutotestTimerDelayS[(int)AutotestPhase]);
                    }
                    else if (!SCMTAutotestTimer.Started)
                    {
                        SCMTAutotestTimer.Start();
                        SetFullBrake(true);
                    }
                    break;
                case AUTOTESTPHASE.WaitThirdRelease:
                    if (SCMTAutotestTimer.Triggered)
                    {
                        SCMTAutotestTimer.Stop();
                        AutotestPhase = AUTOTESTPHASE.FourthBraking;
                        SCMTAutotestTimer.Setup(SCMTAutotestTimerDelayS[(int)AutotestPhase]);
                    }
                    else if (!SCMTAutotestTimer.Started)
                    {
                        SCMTAutotestTimer.Start();
                    }
                    break;
                case AUTOTESTPHASE.FourthBraking:
                    if (SCMTAutotestTimer.Triggered)
                    {
                        SetFullBrake(false);
                        SCMTAutotestTimer.Stop();
                        AutotestPhase = AUTOTESTPHASE.WaitFourthRelease;
                        SCMTAutotestTimer.Setup(SCMTAutotestTimerDelayS[(int)AutotestPhase]);
                    }
                    else if (!SCMTAutotestTimer.Started)
                    {
                        SCMTAutotestTimer.Start();
                        SetFullBrake(true);
                    }
                    break;
                case AUTOTESTPHASE.WaitFourthRelease:
                    if (SCMTAutotestTimer.Triggered)
                    {
                        SCMTAutotestTimer.Stop();
                        AutotestPhase = AUTOTESTPHASE.FinalWait;
                        SCMTAutotestTimer.Setup(SCMTAutotestTimerDelayS[(int)AutotestPhase]);
                    }
                    else if (!SCMTAutotestTimer.Started)
                    {
                        SCMTAutotestTimer.Start();
                    }
                    break;
                case AUTOTESTPHASE.FinalWait:
                    if (SCMTAutotestTimer.Triggered)
                    {
                        SCMTAutotestTimer.Stop();
                        SCMTState = SCMTSTATE.IntroduzioneDatiOManovra;
                        AutotestPhase = AUTOTESTPHASE.FirstBraking;
                        SCMTAutotestTimer.Setup(SCMTAutotestTimerDelayS[(int)AutotestPhase]);
                    }
                    else if (!SCMTAutotestTimer.Started)
                    {
                        SCMTAutotestTimer.Start();
                    }
                    break;
            }
        }

        protected void UpdateLuceBlu()
        {
            if (normalSignalDistanceM > 200)
            {
                SetCabDisplayControl((int)(TCSCommandEvent.Luce_blu_tacho) - 1, 1);
                nextNormalSignalAspectWasAtStop = false;
                return;
            }
            if (nextSignalAspect == Aspect.Stop)
            {
                SetCabDisplayControl((int)(TCSCommandEvent.Luce_blu_tacho) - 1, 2);
                nextNormalSignalAspectWasAtStop = true;
                return;
            }
            if (nextNormalSignalAspectWasAtStop && SCMTState != SCMTSTATE.Manovra && RSCState == RSCSTATE.Active && RSCCode != RSCCODE.AC)
            {
                SetCabDisplayControl((int)(TCSCommandEvent.Luce_blu_tacho) - 1, 1);
                return;
            }
            if (nextNormalSignalAspectWasAtStop)
            {
                SetCabDisplayControl((int)(TCSCommandEvent.Luce_blu_tacho) - 1, 2);
                return;
            }
            SetCabDisplayControl((int)(TCSCommandEvent.Luce_blu_tacho) - 1, 1);
        }

            protected void UpdateRSC()
        {
            if ((TCSButtonPressed[(int)(TCSCommandEvent.Pulsante_Ric)] || AutopilotTimer.Triggered) && SCMTWarningTimer.Started)
            {
                TriggerSoundWarning2();
                TriggerSoundAlert2();
                SCMTWarningTimer.Stop();
                AutopilotTimer.Stop();
                if (Autopilot) AutopilotButtonPressTimer.Start();
                if (RSCPrericonoscimentoState == PRERICONOSCIMENTOSTATE.WaitingRic)
                    RSCPrericonoscimentoState = PRERICONOSCIMENTOSTATE.WaitingRicEnd;
                SetCabDisplayControl((int)(TCSCommandEvent.Pulsante_Ric) - 1, 0);
                TCSButtonPressed[(int)(TCSCommandEvent.Pulsante_Ric)] = false;
            }
            if (TCSButtonReleased[(int)(TCSCommandEvent.Pulsante_Ric)] || AutopilotButtonPressTimer.Triggered)
            {
                AutopilotButtonPressTimer.Stop();
                TriggerSoundPenalty2();
                TCSButtonReleased[(int)(TCSCommandEvent.Pulsante_Ric)] = false;
                if (RSCPrericonoscimentoState == PRERICONOSCIMENTOSTATE.WaitingRicEnd)
                {
                    RSCPrericonoscimentoState = PRERICONOSCIMENTOSTATE.WaitingPre;
                    SetCabDisplayControl((int)(TCSCommandEvent.Pulsante_Pre) - 1, 1);
                }
            }
            if (SCMTWarningTimer.Started && SCMTWarningTimer.Triggered)
            {
                SCMTEmergencyBraking = true;
                SetCabDisplayControl((int)(TCSCommandEvent.Visualizz_Pulsante_RF) - 1, 2);
                SCMTWarningTimer.Stop();
            }
            if (RSCCode != RSCCODE.AC && RSCPrericonoscimentoState != PRERICONOSCIMENTOSTATE.Active && RSCPrericonoscimentoState != PRERICONOSCIMENTOSTATE.AckMissed)
            {
                if ((RSCFirstCodeReceived || RSCFirstRun || (int)RSCCode < (int)RSCPreviousCode) && RSCCode != RSCCODE.C75)
                {
                    // più permissivo
                    SetCabDisplayControl((int)(TCSCommandEvent.Ripetizioni_estese) - 1, 11 - (int)RSCCode);
                    if (RSCCode != RSCCODE.None)
                        TriggerSoundInfo1();
                    if (RSCPrericonoscimentoState == PRERICONOSCIMENTOSTATE.WaitingRic)
                    {
                        RSCPrericonoscimentoState = PRERICONOSCIMENTOSTATE.WaitingPre;
                        SetCabDisplayControl((int)(TCSCommandEvent.Pulsante_Pre) - 1, 1);
                    }
                }
                else if ((int)RSCCode > (int)RSCPreviousCode || (RSCCode == RSCCODE.C75 && RSCCode != RSCPreviousCode))
                {
                    // più restrittivo
                    TriggerSoundWarning1();
                    SetCabDisplayControl((int)(TCSCommandEvent.Ripetizioni_estese) - 1, 11 - (int)RSCCode);
                    SCMTWarningTimer.Start();
                    if (Autopilot && !AutopilotTimer.Started) AutopilotTimer.Start();
                    SetCabDisplayControl((int)(TCSCommandEvent.Pulsante_Ric) - 1, 1);
                }
                RSCFirstCodeReceived = false;
            }
            else if (RSCCode == RSCCODE.AC && RSCState == RSCSTATE.Active)
                SetCabDisplayControl((int)(TCSCommandEvent.Ripetizioni_estese) - 1, 11 - (int)RSCCode);
        }

        protected void UpdateAttivazioneSR()
        {
            SetCabDisplayControl((int)(TCSCommandEvent.Pulsante_SR) - 1, 0);
            switch (AttivazioneSR)
            {
                case ATTIVAZIONESR.Inactive:
                    if (SpeedKpH > 30f)
                        return;
                    if (TCSButtonPressed[(int)(TCSCommandEvent.Pulsante_SR)])
                    {
                        TriggerSoundWarning2();
                        AttivazioneSR = ATTIVAZIONESR.Timer12SOn;
                        if (!AttivazioneSRTimer.Started)
                            AttivazioneSRTimer.Start();
                        SetCabDisplayControl((int)(TCSCommandEvent.Pulsante_SR) - 1, 1);
                        TCSButtonPressed[(int)(TCSCommandEvent.Pulsante_SR)] = false;
                    }
                    break;
                case ATTIVAZIONESR.Timer12SOn:
                    if (AttivazioneSRTimer.Triggered)
                    {
                        AttivazioneSRTimer.Stop();
                        AttivazioneSR = ATTIVAZIONESR.Inactive;
                    }
                    else if (normalSignalPassed && (previousSignalAspect == Aspect.Stop || previousSignalAspect == Aspect.Permission))
                    {
                        AttivazioneSRTimer.Stop();
                        AttivazioneSRTimer.Start();
                        AttivazioneSR = ATTIVAZIONESR.SignalPassed;
                        if (previousSignalAspect == Aspect.Stop)
                        {
                            RequestToggleManualMode();
                            RSCCode = RSCCODE.AC;
                        }
                    }
                    else
                        SetCabDisplayControl((int)(TCSCommandEvent.Pulsante_SR) - 1, 1);
                    break;
                case ATTIVAZIONESR.SignalPassed:
                    if (AttivazioneSRTimer.Triggered)
                    {
                        AttivazioneSRTimer.Stop();
                        AttivazioneSR = ATTIVAZIONESR.Inactive;
                        ControlMode = GetControlMode();
                        if (ControlMode != TRAIN_CONTROL.EXPLORER)
                            RequestToggleManualMode();
                        CheckACFinita(600);
                    }
                    break;
            }
            if (TCSButtonReleased[(int)(TCSCommandEvent.Pulsante_SR)])
            {
                TCSButtonReleased[(int)(TCSCommandEvent.Pulsante_SR)] = false;
                TriggerSoundPenalty2();
            }
        }

        protected void CheckSPAD()
        {
            if (normalSignalPassed && (previousSignalAspect == Aspect.Stop || previousSignalAspect == Aspect.Permission) &&
                AttivazioneSR != ATTIVAZIONESR.SignalPassed)
            {
                SCMTSpad = true;
                TriggerSoundWarning1();
                SCMTEmergencyBraking = true;
                RSCCode = RSCCODE.AC;
                RSCCodeConfirmationTimer.Stop();
                RequestToggleManualMode();
                SetCabDisplayControl((int)(TCSCommandEvent.SR) - 1, 1);
                SetCabDisplayControl((int)(TCSCommandEvent.Visualizz_Pulsante_RF) - 1, 2);
                SetCabDisplayControl((int)(TCSCommandEvent.Ripetizioni_estese) - 1, 11 - (int)RSCCode);
            }
        }

        protected void UpdatePrericonoscimento()
        {
            switch (RSCPrericonoscimentoState)
            {
                case PRERICONOSCIMENTOSTATE.WaitingPre:
                    if (prericSignalPassed && RSCCode != RSCCODE.AC)
                    {
                        if (!RSCPrericonoscimento1Timer.Started)
                            RSCPrericonoscimento1Timer.Start();
                    }
                    if (TCSButtonPressed[(int)(TCSCommandEvent.Pulsante_Pre)] || Autopilot && normalSignalDistanceM / SpeedMpS() < 5)
                    {
                        TriggerSoundWarning2();
                        SetCabDisplayControl((int)(TCSCommandEvent.Pulsante_Pre) - 1, 0);
                        RSCPrericonoscimentoState = PRERICONOSCIMENTOSTATE.Timer12secOn;
                        if (Autopilot) AutopilotButtonPressTimer.Start();
                        if (normalSignalDistanceM > 100) RSCPrericonoscimentoTimer.Start();
                        if (RSCPrericonoscimento1Timer.Started)
                            RSCPrericonoscimento1Timer.Stop();
                    }
                    if (RSCPrericonoscimento1Timer.Triggered)
                    {
                        RSCPrericonoscimento1Timer.Stop();
                        TriggerSoundWarning1();
                        SCMTEmergencyBraking = true;
                        RSCMinimumLengthM = Math.Max(GetTrackNodeOffset(), RSCMinimumLengthWithoutSwitchesM);
                        SetCabDisplayControl((int)(TCSCommandEvent.Visualizz_Pulsante_RF) - 1, 2);
                        RSCPrericonoscimentoState = PRERICONOSCIMENTOSTATE.AckMissed;
                    }
                    break;
                case PRERICONOSCIMENTOSTATE.Timer12secOn:
                    {
                        if (TCSButtonReleased[(int)(TCSCommandEvent.Pulsante_Pre)])
                        {
                            TriggerSoundPenalty2();
                            TCSButtonReleased[(int)(TCSCommandEvent.Pulsante_Pre)] = false;
                        }
                        if (AutopilotButtonPressTimer.Triggered)
                        {
                            AutopilotButtonPressTimer.Stop();
                            TriggerSoundPenalty2();
                        }
                        if (prericSignalPassed && RSCCode != RSCCODE.AC)
                        {
                            RSCPrericonoscimentoTimer.Stop();
                            RSCPrericonoscimentoState = PRERICONOSCIMENTOSTATE.PreActive;
                            RSCMinimumLengthM = Math.Max(GetTrackNodeOffset(), RSCMinimumLengthWithoutSwitchesM);
                            RSCPrericonoscimento1Timer.Start();
                        }
                        if (RSCPrericonoscimentoTimer.Triggered)
                        {
                            RSCPrericonoscimentoTimer.Stop();
                            TriggerSoundWarning1();
                            SCMTEmergencyBraking = true;
                            SetCabDisplayControl((int)(TCSCommandEvent.Visualizz_Pulsante_RF) - 1, 2);
                            RSCPrericonoscimentoState = PRERICONOSCIMENTOSTATE.Timer12secExpired;
                            //                           SetCabDisplayControl((int)(TCSCommandEvent.Pulsante_Pre) - 1, 1);
                            //                           RSCPrericonoscimentoState = PRERICONOSCIMENTOSTATE.WaitingPre;
                        }
                    }
                    break;
                case PRERICONOSCIMENTOSTATE.PreActive:
                    if (RSCPrericonoscimento1Timer.Triggered)
                    {
                        RSCPrericonoscimento1Timer.Stop();
                        RSCPrericonoscimentoState = PRERICONOSCIMENTOSTATE.Active;
                    }
                    break;
                case PRERICONOSCIMENTOSTATE.Active:
                    if (RSCCode != RSCCODE.AC)
                    {
                        TriggerSoundInfo1();
                        RSCCode = RSCCODE.AC;
                        RSCPresent = false;
                        RSCForceCod9 = false;
                        RSCForceCod = false;
                        SetCabDisplayControl((int)(TCSCommandEvent.Ripetizioni_estese) - 1, 11 - (int)RSCCode);
                    }
                    break;
                case PRERICONOSCIMENTOSTATE.AckMissed:
                    if (RSCCode != RSCCODE.AC)
                    {
                        RSCPresent = false;
                        RSCCode = RSCCODE.AC;
                        RSCForceCod9 = false;
                        RSCForceCod = false;
                        SetCabDisplayControl((int)(TCSCommandEvent.Ripetizioni_estese) - 1, 11 - (int)RSCCode);
                    }
                    break;
                case PRERICONOSCIMENTOSTATE.Timer12secExpired:
                    if (prericSignalPassed && RSCCode != RSCCODE.AC)
                    {
                        RSCPrericonoscimentoTimer.Stop();
                        RSCPrericonoscimentoState = PRERICONOSCIMENTOSTATE.PreActive;
                        RSCMinimumLengthM = Math.Max(GetTrackNodeOffset(), RSCMinimumLengthWithoutSwitchesM);
                        RSCPrericonoscimento1Timer.Start();
                    }
                    break;
                default:
                    break;
            }
        }

        public override void HandleEvent(TCSEvent evt, string message)
        {
            if (message == String.Empty)
            {
                switch (evt)
                {
                    case TCSEvent.AlerterPressed:
                        ResetButtonPressed = true;
                        break;

                    case TCSEvent.AlerterReleased:
                        ResetButtonPressed = false;
                        break;
                    case TCSEvent.CircuitBreakerClosed:
                        SSBState = SSBSTATE.ReadyToOn;
                        break;
                    case TCSEvent.CircuitBreakerOpen:
                        SCMTState = SCMTSTATE.Off;
                        RSCState = RSCSTATE.Inactive;
                        SSBState = SSBSTATE.Off;
                        circuitBreakerOpened = true;
                        break;
                }
            }
            else
            {
                var commandEvent = TCSCommandEvent.None;
                var messageIndex = 0;
                if (Int32.TryParse(message, out messageIndex))
                {
                    commandEvent = (TCSCommandEvent)(messageIndex + 1);
                    switch (evt)
                    {
                        case TCSEvent.GenericTCSButtonPressed:
                            TCSButtonPressed[(int)commandEvent] = true;
                            break;
                        case TCSEvent.GenericTCSButtonReleased:
                            TCSButtonPressed[(int)commandEvent] = false;
                            TCSButtonReleased[(int)commandEvent] = true;
                            break;
                    }
                }
            }
        }

        public override void Save(BinaryWriter outf)
        {
            outf.Write((int)SSBState);
            outf.Write((int)SCMTState);
            outf.Write((int)RSCState);
            outf.Write((int)RSCCode);
            outf.Write((int)RSCPrericonoscimentoState);
            outf.Write(RSCPresent);
            outf.Write(NoRSCZone);
            outf.Write(RSCFirstRun);
            outf.Write(RSCForceCod);
            outf.Write(RSCForceCod9);
            outf.Write(RSCForceNoCod);
            outf.Write(normalSignalDistanceM);
            outf.Write(SCMTVelocitaRilascio);
        }

        public override void Restore(BinaryReader inf)
        {
            SSBState = (SSBSTATE)(inf.ReadInt32());
            SCMTState = (SCMTSTATE)(inf.ReadInt32());
            RSCState = (RSCSTATE)(inf.ReadInt32());
            RSCCode = (RSCCODE)(inf.ReadInt32());
            RSCPrericonoscimentoState = (PRERICONOSCIMENTOSTATE)(inf.ReadInt32());
            RSCPresent = inf.ReadBoolean();
            NoRSCZone = inf.ReadBoolean();
            RSCFirstRun = inf.ReadBoolean();
            RSCForceCod = inf.ReadBoolean();
            RSCForceCod9 = inf.ReadBoolean();
            RSCForceNoCod = inf.ReadBoolean();
            normalSignalDistanceM = inf.ReadSingle();
            SCMTVelocitaRilascio = inf.ReadSingle();
            ColdStart = false;
        }

        protected void UpdateSignal()
        {
            GetSignalData();

            normalSignalPassed = false;
            distanceSignalPassed = false;
            prericSignalPassed = false;
            infoSignalPassed = false;
            RSCPIPassed = false;
            PreviousDistanceSignalDistanceM = distanceSignalDistanceM;
            distanceSignalDistanceM = NextDistanceSignalDistanceM();
            PreviousSignalDistanceM = normalSignalDistanceM;
            var incIndex = 0;
            //if next normal signal is a virtual signal that restores line speed, it's not considered
            var nextNormalSignalMainHeadSignalType = NextGenericSignalFeatures("NORMAL", 0, float.MaxValue).MainHeadSignalTypeName;
            if (nextNormalSignalMainHeadSignalType == "riprvel" || nextNormalSignalMainHeadSignalType == "fsvirtfinelim")
                incIndex = 1;
            normalSignalDistanceM = NextSignalDistanceM(incIndex);
            PreviousInfoSignalDistanceM = infoSignalDistanceM;
            switch (infoSignalMainHeadSignalType)
            {
                case "startcod":
                case "prescod":
                case "startcod9":
                case "prescod9":
                case "endcod":
                case "asscod":
                case "approccio10":
				case "fineapproccio10":
                    PreviousInfoSignalMainHeadSignalType = infoSignalMainHeadSignalType;
                    break;
                default:
                    break;
            }
            infoSignalDistanceM = NextGenericSignalDistanceM("INFO");
            infoSignalMainHeadSignalType = NextGenericSignalMainHeadSignalType("INFO");

            if (normalSignalDistanceM > 0)
            {
                if (normalSignalDistanceM > PreviousSignalDistanceM + 1.0f && SpeedMpS() > 0.1f)
                {
                    if (normalSignalDistanceM != float.MaxValue && AutodetectSignalFilesType)
                    {
                        SignalFilesType = DoesNextNormalSignalHaveRepeaterHead() ? SIGNALFILESTYPE.SerriniBaldi : SIGNALFILESTYPE.PriviteraBono;
                    }
                    normalSignalPassed = true;
                    if (PreviousInfoSignalMainHeadSignalType == "approccio10")
                        PreviousInfoSignalMainHeadSignalType = "";
                    if (SCMTVelocitaRilascio != 30f)
                        TriggerGenericSound(Event.GenericEvent7);
                    SCMTVelocitaRilascio = 30f;
                    prericSignalPassed = true;
                    distanceSignalPassed = true;
                    if (RSCPrericonoscimentoState != PRERICONOSCIMENTOSTATE.Invalid && RSCPrericonoscimentoState != PRERICONOSCIMENTOSTATE.Active &&
                        RSCPrericonoscimentoState != PRERICONOSCIMENTOSTATE.AckMissed)
                    // Check if there is another signal in between
                    {
                        // cerca primo scambio dopo segnale successivo
                        if (normalSignalDistanceM != float.MaxValue)
                        {
                            nextDivergingSwitchDistanceM = NextDivergingSwitchDistanceM(normalSignalDistanceM + RSCNextDivergingSwitchMaxDistanceM);
                            if (nextDivergingSwitchDistanceM > normalSignalDistanceM && GetTrackNodeOffset() > normalSignalDistanceM) prericSignalPassed = false;
                        }
                    }
                    RSCEndsThisSection = false;
                    RSCEndsNextSection = false;
                    RSCEndsNextNextSection = false;
                    RSCEndsNextNextNextSection = false;
                    if (RSCState == RSCSTATE.Active) TestForRSCEnd();
                }
            }

            if ((infoSignalDistanceM > PreviousInfoSignalDistanceM + 1.0f || (infoSignalMainHeadSignalType != PreviousInfoSignalMainHeadSignalType &&
               PreviousInfoSignalMainHeadSignalType != "")) && SpeedMpS() > 0)
            {
                // check if it is a signal which is interesting for us
                switch (PreviousInfoSignalMainHeadSignalType)
                {
                    case "startcod":
                    case "prescod":
                        RSCForceCod = true;
                        RSCForceCod9 = false;
                        RSCForceNoCod = false;
                        RSCPIPassed = true;
                        PreviousInfoSignalMainHeadSignalType = "";
                        break;
                    case "startcod9":
                    case "prescod9":
                        RSCForceCod = false;
                        RSCForceCod9 = true;
                        RSCForceNoCod = false;
                        RSCPIPassed = true;
                        PreviousInfoSignalMainHeadSignalType = "";
                        break;
                    case "endcod":
                    case "asscod":
                        RSCForceCod = false;
                        RSCForceCod9 = false;
                        RSCForceNoCod = true;
                        PreviousInfoSignalMainHeadSignalType = "";
                        break;
                    case "approccio10":
                        if (SCMTVelocitaRilascio != 10f && SCMTNextSignalSpeedLimitKpH == 0)
                            TriggerGenericSound(Event.GenericEvent6);
                        if (SCMTNextSignalSpeedLimitKpH == 0)
                            SCMTVelocitaRilascio = 10f;
                        break;
					case "fineapproccio10":
					//fa il suono solo se rsc non è attivo, altrimenti lo farebbe anche con rsc attivo quando passi sopra alla boa ma già con segnale aperto
						if(RSCState != RSCSTATE.Active) 
                            TriggerGenericSound(Event.GenericEvent7); //suono fine vril 10
                        SCMTVelocitaRilascio = 30f; //ripristina tetto a 30
                        PreviousInfoSignalMainHeadSignalType = "";
                        break;												 			 
                    default:
                        break;
                }
                infoSignalPassed = true;
            }

            OldRemainingLengthM = RemainingLengthM;
            RemainingLengthM = GetTrackNodeOffset();
            // presenza RSC testata per lunghezza senza scambi
            if (RemainingLengthM >= RSCMinimumLengthWithoutSwitchesM && RemainingLengthM > OldRemainingLengthM && SpeedKpH > 0.1f && !RSCForceNoCod)
            {
                RSCPIPassed = true;
                NoRSCZone = false;
                IntervalDistanceM = 0f;
            }
            // presenza RSC segnalata dopo passaggio segnale
            else if (RSCPresent && (normalSignalPassed || distanceSignalPassed) && SpeedKpH > 0.1f && !RSCForceNoCod)
                RSCPIPassed = true;

            // presenza RSC testata dopo passaggio segnale per lunghezza senza scambi in rientro da deviata
            else if (!NoRSCZone && !RSCPresent && (normalSignalPassed || distanceSignalPassed) && SpeedKpH > 0.1f && !RSCForceNoCod)
            {
                CheckRSCPresent();
                if (RSCPresent)
                    RSCPIPassed = true;
            }
            // presenza RSC segnalata dopo x metri in tratta lunga senza scambi
            else if (RemainingLengthM >= RSCMinimumLengthWithoutSwitchesM && SpeedKpH > 0.1f && !RSCForceNoCod)
            {
                IntervalDistanceM += OldRemainingLengthM - RemainingLengthM;
                if (IntervalDistanceM > RSCMinimumLengthWithoutSwitchesM)
                {
                    IntervalDistanceM = 0f;
                    if (RSCPresent)
                        RSCPIPassed = true;
                }
            }

            if ((RSCForceCod9 || RSCForceCod) && RSCState != RSCSTATE.Active && normalSignalPassed)
            {
                // Check wheter there are no other signals up to next diverging or converging switch
                // and in such case set the RSC code as AC
                if (NextDivergingSwitchDistanceM(350) < normalSignalDistanceM || NextTrailingDivergingSwitchDistanceM(350) < normalSignalDistanceM)
                {
                    RSCPIPassed = true;
                    RSCForceCod9 = false;
                    RSCForceCod = false;
                    // Behaves like when entering AC zone
                    RSCPrericonoscimentoState = PRERICONOSCIMENTOSTATE.PreActive;
                    if (!RSCPrericonoscimento1Timer.Started) RSCPrericonoscimento1Timer.Start();
                }
            }

            if (RSCState == RSCSTATE.Active)
                UpdatePrericonoscimento();
            UpdateParams();
            /*           if (RSCPrericonoscimentoState > (int)PRERICONOSCIMENTOSTATE.Invalid)
                       {
                           PreviousNextDivergingSwitchDistanceM = nextDivergingSwitchDistanceM;
                           nextDivergingSwitchDistanceM = NextDivergingSwitchDistanceM(normalSignalDistanceM + RSCNextDivergingSwitchMaxDistanceM);
                           if (nextDivergingSwitchDistanceM > PreviousNextDivergingSwitchDistanceM + 1)
                               DivergingSwitchPassed = true;
                       }*/
            if (distanceSignalDistanceM != 0 && distanceSignalDistanceM > PreviousDistanceSignalDistanceM + 1.0f && SpeedMpS() > 0)
            {
                distanceSignalPassed = true;
            }
        }

        protected void TestForRSCEnd()
        {
            if (TrueNormalSignals[0].DistanceM == float.MaxValue || TrueNormalSignals[0].DistanceM < 0 || CurrentTrainMUDirection() == Direction.Reverse)
            {
                RSCEndsThisSection = true;
                return;
            }
            var maxTestingDistanceM = TrueNormalSignals[3].DistanceM;
            if (TrueNormalSignals[1].DistanceM == float.MaxValue || TrueNormalSignals[1].DistanceM < 0 || CurrentTrainMUDirection() == Direction.Reverse)
            {
                RSCEndsNextSection = true;
                maxTestingDistanceM = TrueNormalSignals[0].DistanceM;
            }
            else if (TrueNormalSignals[2].DistanceM == float.MaxValue || TrueNormalSignals[2].DistanceM < 0 || CurrentTrainMUDirection() == Direction.Reverse)
            {
 //               RSCEndsNextNextSection = true;
                maxTestingDistanceM = TrueNormalSignals[1].DistanceM;
            }

            var isig = 0;
            do
            {
                genericSignalFeatures = NextGenericSignalFeatures("INFO", isig, maxTestingDistanceM);
                if (genericSignalFeatures.MainHeadSignalTypeName == "endcod")
                {
                    if (genericSignalFeatures.DistanceM < TrueNormalSignals[0].DistanceM + 0.5f)
                        RSCEndsThisSection = true;
                    else if (genericSignalFeatures.DistanceM < TrueNormalSignals[1].DistanceM + 0.5f) RSCEndsNextSection = true;
                    else RSCEndsNextNextSection = true;
                    return;
                }
                isig++;
            }
            while (genericSignalFeatures.DistanceM < float.MaxValue);
            return;
        }

        protected void UpdateParams()
        {

            //if next normal signal is a virtual signal that restores line speed, it's not considered

            for (int ind = 0; ind <= 2; ind++)
                incIndex[ind] = 0;

            if (CurrentTrainMUDirection() != Direction.Reverse)
            {
                // discard fake normal signals
                var validNormalSignalsFound = 0;
                var signalMainHeadSignalType = "";
                var isig = 0;
                do
                {
                    signalMainHeadSignalType = NextGenericSignalFeatures("NORMAL", isig, float.MaxValue).MainHeadSignalTypeName;
                    if (signalMainHeadSignalType == "riprvel" || signalMainHeadSignalType == "fsvirtfinelim")
                        incIndex[validNormalSignalsFound]++;
                    else validNormalSignalsFound++;
                    isig++;
                }
                while (signalMainHeadSignalType != "" && validNormalSignalsFound < RequiredNormalSignals);
                for (int ind = 0; ind <= 1; ind++)
                    incIndex[ind + 1] += incIndex[ind];
            }

            nextSignalSpeedLimitKpH = (float)Math.Round(MpS.ToKpH(NextSignalSpeedLimitMpS(incIndex[0])), 0);
            previousSignalAspect = nextSignalAspect;
            nextSignalAspect = NextSignalAspect(incIndex[0]);
            var nextSignalAspect1 = NextSignalAspect(1 + incIndex[1]);
            var nextSignalSpeedLimit1MpS = NextSignalSpeedLimitMpS(1 + incIndex[1]);
            if (RSCCode == RSCCODE.AC && RSCPrericonoscimentoState != PRERICONOSCIMENTOSTATE.AckMissed)
            {
                if (normalSignalPassed)
                    RSCMinimumLengthM = 600f;
                CheckACFinita(RSCMinimumLengthM);
            }
            if (RSCCode != RSCCODE.AC && !SCMTSpad && ((SCMTState == SCMTSTATE.Active || SCMTState == SCMTSTATE.Predisposizione) && (normalSignalPassed || distanceSignalPassed)
                || SCMTState == SCMTSTATE.ActiveAndRSC || RSCState == RSCSTATE.Active || SCMTState == SCMTSTATE.Active && normalSignalDistanceM > 4000))
            {
                RSCNextSignalAllowedSpeedKpH = (nextSignalSpeedLimitKpH == -3.6f || nextSignalSpeedLimitKpH == -4f) ? MpS.ToKpH(LineSpeedMpS()) : nextSignalSpeedLimitKpH;
                if (Debug == 1)
                {
                    SetCabDisplayControl((int)(TCSCommandEvent.NextSignalSpeed) - 1, nextSignalSpeedLimitKpH);
                    SetCabDisplayControl((int)(TCSCommandEvent.NextSignalAspect1) - 1, (int)NextSignalAspect(1));
                    SetCabDisplayControl((int)(TCSCommandEvent.NextSignalAspect2) - 1, (int)NextSignalAspect(2));
                    SetCabDisplayControl((int)(TCSCommandEvent.NextSignalAspect3) - 1, (int)NextSignalAspect(3));
                }
                currentPostSpeedLimitKpH = MpS.ToKpH(CurrentPostSpeedLimitMpS());
                RSCPreviousCode = RSCCode;
                RSCTempNewCode = RSCCODE.None;
                switch (SignalFilesType)
                {
                    case SIGNALFILESTYPE.SerriniBaldi:
                        {
                            switch (nextSignalAspect)
                            {
                                case Aspect.Stop:
                                    RSCNextSignalAllowedSpeedKpH = 0;
                                    RSCTempNewCode = RSCCODE.C75;
                                    break;
                                case Aspect.Clear_2:
                                    //                                    if ((nextSignalAspect1 != Aspect.Clear_2 && !(nextSignalAspect1 == Aspect.Approach_1 && nextSignalSpeedLimit1MpS == -1) &&
                                    //                                       !(nextSignalAspect1 == Aspect.Restricted && MpS.ToKpH(nextSignalSpeedLimit1MpS) != 30)) || NextSignalDistanceM(1) == float.MaxValue)
                                    if (NextSignalDistanceM(1 + incIndex[1]) == float.MaxValue || RSCEndsThisSection)
                                    {
                                        if ((currentPostSpeedLimitKpH <= 180 && !RSCForceCod9 && !RSCForceCod) || HeavyFreightTrain || RSCForceCod || RSCEndsThisSection)
                                        {
                                            RSCNextSignalAllowedSpeedKpH = RSCMaxSignalSpeedCode180KpH;
                                            RSCTempNewCode = RSCCODE.C180;
                                        }
                                        else
                                        {
                                            RSCNextSignalAllowedSpeedKpH = RSCMaxSignalSpeedCode180StarKpH;
                                            RSCTempNewCode = RSCCODE.C180S;
                                        }
                                    }
                                    else if ((currentPostSpeedLimitKpH <= 180 && !RSCForceCod9) || RSCForceCod || nextSignalAspect1 != Aspect.Clear_2
                                        || NextSignalDistanceM(1 + incIndex[1]) == float.MaxValue
                                        || NextPostDistanceM(0) < 1500 && NextPostSpeedLimitMpS(0) <= 130 || DoesStartFromTerminalStation() || HeavyFreightTrain
                                        || RSCEndsNextSection)// Un modo per selezionare se i codici 270* e 270** esistono in quel punto
                                    {
                                        RSCNextSignalAllowedSpeedKpH = RSCMaxSignalSpeedCode270KpH;
                                        RSCTempNewCode = RSCCODE.C270;
                                    }
                                    else if (currentPostSpeedLimitKpH <= 205 || NextSignalAspect(2 + incIndex[2]) != Aspect.Clear_2
                                        || NextSignalDistanceM(2 + incIndex[2]) == float.MaxValue || RSCEndsNextNextSection)
                                    {
                                        RSCNextSignalAllowedSpeedKpH = RSCMaxSignalSpeedCode270StarKpH;
                                        RSCTempNewCode = RSCCODE.C270S;
                                    }
                                    else
                                    {
                                        RSCNextSignalAllowedSpeedKpH = RSCMaxSignalSpeedCode270DoubleStarKpH;
                                        RSCTempNewCode = RSCCODE.C270SS;
                                    }
                                    break;
                                case Aspect.Clear_1:
                                    if (HeavyFreightTrain || (currentPostSpeedLimitKpH <= 130 && !RSCForceCod9) || RSCForceCod)
                                    {
                                        RSCNextSignalAllowedSpeedKpH = 100;
                                        RSCTempNewCode = RSCCODE.C120;
                                    }
                                    else
                                    {
                                        RSCNextSignalAllowedSpeedKpH = 100;
                                        RSCTempNewCode = RSCCODE.C120S;
                                    }
                                    Prericonoscimento();
                                    break;
                                case Aspect.Approach_3:
                                    if (nextSignalSpeedLimitKpH != 30)
                                    {
                                        RSCNextSignalAllowedSpeedKpH = 60f;
                                        RSCTempNewCode = RSCCODE.C120;
                                        Prericonoscimento();
                                    }
                                    break;
                                case Aspect.Approach_2:
                                    RSCTempNewCode = RSCCODE.C120;
                                    if (nextSignalSpeedLimitKpH == 30)
                                        RSCNextSignalAllowedSpeedKpH = 30f;
                                    else if (nextSignalSpeedLimitKpH == 60)
                                        RSCNextSignalAllowedSpeedKpH = 60f;
                                    else if (nextSignalSpeedLimitKpH == 0)
                                        RSCNextSignalAllowedSpeedKpH = 0f;
                                    Prericonoscimento();
                                    break;
                                case Aspect.Approach_1:
                                    if (nextSignalSpeedLimitKpH == 30)
                                    {
                                        RSCNextSignalAllowedSpeedKpH = 30f;
                                        RSCTempNewCode = RSCCODE.C120;
                                        Prericonoscimento();
                                    }
                                    else
                                    {
                                        if ((currentPostSpeedLimitKpH <= 180 && !RSCForceCod9) || HeavyFreightTrain || nextSignalAspect1 == Aspect.Approach_3 ||
                                            nextSignalAspect1 == Aspect.Approach_2 || nextSignalAspect1 == Aspect.Stop)
                                        {
                                            RSCNextSignalAllowedSpeedKpH = RSCMaxSignalSpeedCode180KpH;
                                            RSCTempNewCode = RSCCODE.C180;
                                        }
                                        else
                                        {
                                            RSCNextSignalAllowedSpeedKpH = RSCMaxSignalSpeedCode180StarKpH;
                                            RSCTempNewCode = RSCCODE.C180S;
                                        }
                                    }
                                    break;
                                case Aspect.Restricted:
                                    RSCTempNewCode = RSCCODE.C180;
                                    if (nextSignalSpeedLimitKpH == -1)
                                    {
                                        RSCNextSignalAllowedSpeedKpH = RSCMaxSignalSpeedCode180KpH;
                                    }
                                    else if (nextSignalSpeedLimitKpH == 30)
                                    {
                                        RSCNextSignalAllowedSpeedKpH = nextSignalSpeedLimitKpH;
                                    }
                                    else
                                        RSCNextSignalAllowedSpeedKpH = nextSignalSpeedLimitKpH;
                                    break;
                                case Aspect.StopAndProceed:
                                    RSCTempNewCode = RSCCODE.C75;
                                    break;
                                default:
                                    break;
                            }
                            break;
                        }
                    case SIGNALFILESTYPE.PriviteraBono:
                        {
                            switch (nextSignalAspect)
                            {
                                case Aspect.Stop:
                                    RSCNextSignalAllowedSpeedKpH = 0;
                                    RSCTempNewCode = RSCCODE.C75;
                                    break;
                                case Aspect.Clear_2:
                                    if (NextSignalDistanceM(1 + incIndex[1]) == float.MaxValue || RSCEndsThisSection)
                                    {
                                        if ((currentPostSpeedLimitKpH <= 180 && !RSCForceCod9 && !RSCForceCod) || HeavyFreightTrain || RSCEndsThisSection || RSCForceCod)
                                        {
                                            RSCNextSignalAllowedSpeedKpH = RSCMaxSignalSpeedCode180KpH;
                                            RSCTempNewCode = RSCCODE.C180;
                                        }
                                        else
                                        {
                                            RSCNextSignalAllowedSpeedKpH = RSCMaxSignalSpeedCode180StarKpH;
                                            RSCTempNewCode = RSCCODE.C180S;
                                        }
                                    }
                                    else if ((currentPostSpeedLimitKpH <= 180 && !RSCForceCod9) || NextSignalAspect(1 + incIndex[1]) != Aspect.Clear_2
                                        || NextSignalDistanceM(1 + incIndex[1]) == float.MaxValue
                                        || (NextPostDistanceM(0) < 1500 && NextPostSpeedLimitMpS(0) <= 130 && !RSCForceCod9) || RSCForceCod ||
                                        DoesStartFromTerminalStation() || HeavyFreightTrain || RSCEndsNextSection)// Un modo per selezionare se i codici 270* e 270* esistono in quel punto
                                    {
                                        RSCNextSignalAllowedSpeedKpH = RSCMaxSignalSpeedCode270KpH;
                                        RSCTempNewCode = RSCCODE.C270;
                                    }
                                    else if (currentPostSpeedLimitKpH <= 205 || NextSignalAspect(2 + incIndex[2]) != Aspect.Clear_2
                                        || NextSignalDistanceM(2 + incIndex[2]) == float.MaxValue || RSCEndsNextNextSection)
                                    {
                                        RSCNextSignalAllowedSpeedKpH = RSCMaxSignalSpeedCode270StarKpH;
                                        RSCTempNewCode = RSCCODE.C270S;
                                    }
                                    else
                                    {
                                        RSCNextSignalAllowedSpeedKpH = RSCMaxSignalSpeedCode270DoubleStarKpH;
                                        RSCTempNewCode = RSCCODE.C270SS;
                                    }
                                    break;
                                case Aspect.Clear_1:
                                    if (HeavyFreightTrain || (currentPostSpeedLimitKpH <= 130 && !RSCForceCod9) || RSCForceCod)
                                    {
                                        RSCNextSignalAllowedSpeedKpH = 100;
                                        RSCTempNewCode = RSCCODE.C120;
                                    }
                                    else
                                    {
                                        RSCNextSignalAllowedSpeedKpH = 100;
                                        RSCTempNewCode = RSCCODE.C120S;
                                    }
                                    Prericonoscimento();
                                    break;
                                case Aspect.Approach_3:
                                    RSCTempNewCode = RSCCODE.C120;
                                    if (nextSignalSpeedLimitKpH == 30)
                                        RSCNextSignalAllowedSpeedKpH = 30f;
                                    Prericonoscimento();
                                    break;
                                case Aspect.Approach_2:
                                    if (nextSignalSpeedLimitKpH == 60)
                                        RSCNextSignalAllowedSpeedKpH = 60f;
                                    RSCTempNewCode = RSCCODE.C120;
                                    Prericonoscimento();
                                    break;
                                case Aspect.Approach_1:
                                    RSCTempNewCode = RSCCODE.C120;
                                    if (nextSignalSpeedLimitKpH == 30)
                                        RSCNextSignalAllowedSpeedKpH = 30f;
                                    Prericonoscimento();
                                    break;
                                case Aspect.Restricted:
                                    if (nextSignalSpeedLimitKpH == 30)
                                    {
                                        RSCNextSignalAllowedSpeedKpH = 30f;
                                        RSCTempNewCode = RSCCODE.C75;
                                        //                                        Prericonoscimento();
                                    }
                                    else
                                    {
                                        if ((currentPostSpeedLimitKpH <= 180 && !RSCForceCod9) || HeavyFreightTrain || RSCForceCod ||
                                            nextSignalAspect1 == Aspect.Approach_2 || nextSignalAspect1 == Aspect.Approach_1 || nextSignalAspect1 == Aspect.Stop)
                                        {
                                            RSCNextSignalAllowedSpeedKpH = RSCMaxSignalSpeedCode180KpH;
                                            RSCTempNewCode = RSCCODE.C180;
                                        }
                                        else
                                        {
                                            RSCNextSignalAllowedSpeedKpH = RSCMaxSignalSpeedCode180StarKpH;
                                            RSCTempNewCode = RSCCODE.C180S;
                                        }
                                    }
                                    break;
                                case Aspect.StopAndProceed:
                                    RSCTempNewCode = RSCCODE.C75;
                                    break;
                                default:
                                    break;
                            }
                            break;
                        }
                }
                if (RSCState != RSCSTATE.Active) RSCTempNewCode = RSCCODE.None;
                if (RSCTempNewCode != RSCCode && !RSCCodeConfirmationTimer.Started)
                    RSCCodeConfirmationTimer.Start();
                if (RSCCodeConfirmationTimer.Triggered)
                {
                    RSCCodeConfirmationTimer.Stop();
                    RSCCode = RSCTempNewCode;
                }
            }
        }

        protected void Prericonoscimento()
        {
            if (RSCState == RSCSTATE.Active)
            {
                if (RSCPrericonoscimentoState == PRERICONOSCIMENTOSTATE.Invalid)
                {
                    // cerca primo scambio dopo segnale successivo
                    if (normalSignalDistanceM == float.MaxValue) return;
                    nextDivergingSwitchDistanceM = NextDivergingSwitchDistanceM(normalSignalDistanceM + RSCNextDivergingSwitchMaxDistanceM);
                    if (nextDivergingSwitchDistanceM < normalSignalDistanceM) return;
                    else if (GetTrackNodeOffset() != float.MaxValue)
                    {
                        // to be improved
                        RSCPrericonoscimentoState = PRERICONOSCIMENTOSTATE.WaitingRic;
                    }
                    // setta flag intero prenotazione prericonoscimento
                    else RSCPrericonoscimentoState = PRERICONOSCIMENTOSTATE.WaitingRic;
                }
            }
        }

        protected void CheckACFinita(float rSCMinimumLengthM)
        {
            if (RSCCheckACFinitaTimer.Triggered)
            {
                RSCPrericonoscimentoState = PRERICONOSCIMENTOSTATE.Invalid;
                RSCFirstCodeReceived = true;
                if (!NoRSCZone) RSCPresent = true;
                RSCCode = RSCCODE.None;
                RSCCheckACFinitaTimer.Stop();
                return;
            }
            if (GetTrackNodeOffset() >= rSCMinimumLengthM ||
                ((NextDivergingSwitchDistanceM(1000) > normalSignalDistanceM || NextTrailingDivergingSwitchDistanceM(1000) > normalSignalDistanceM) &&
                (RSCForceCod || RSCForceCod9)))
            {
                if (!RSCCheckACFinitaTimer.Started)
                    RSCCheckACFinitaTimer.Start();
            }
        }

        protected void GetSignalData()
        {
            for (int i = 0; i < TrueNormalSignals.Length; i++)
            {
                TrueNormalSignals[i].DistanceM = float.MaxValue;
                TrueNormalSignals[i].MainHeadSignalTypeName = "";
            }
            var k = 0;
            for (int i = 0; i < NormalSignals.Length; i++)
            {
                NormalSignals[i] = NextGenericSignalFeatures("NORMAL", i, 12000.0f);
                var signalTypeName = NormalSignals[i].MainHeadSignalTypeName.ToLower();
                if (signalTypeName != "riprvel" && signalTypeName != "fsvirtfinelim")
                {
                    TrueNormalSignals[k].MainHeadSignalTypeName = signalTypeName;
                    TrueNormalSignals[k].Aspect = NormalSignals[i].Aspect;
                    TrueNormalSignals[k].SpeedLimitMpS = NormalSignals[i].SpeedLimitMpS;
                    TrueNormalSignals[k].DistanceM = NormalSignals[i].DistanceM;
                    TrueNormalSignals[k].AltitudeM = NormalSignals[i].AltitudeM;
                    k++;
                }
                VirtualSignals[i] = NextGenericSignalFeatures("REPEATER", i, 12000.0f);
                if (NormalSignals[i].DistanceM == float.MaxValue)
                    break;
            }
            for (int i = 0; i < InfoSignals.Length; i++)
            {
                InfoSignals[i] = NextGenericSignalFeatures("INFO", i, 12000.0f);
                if (InfoSignals[i].DistanceM == float.MaxValue)
                    break;
            }
        }
     }
}