
using CtrEditor.Siemens;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using Newtonsoft.Json;
using CommunityToolkit.Mvvm.ComponentModel;

namespace CtrEditor.ObjetosSim
{
    /// <summary>
    /// Interaction logic for ucVMmotorSim.xaml
    /// </summary>
    /// 

    public partial class osVMmotorSim : osBase, IosBase
    {

        // Otros datos y métodos relevantes para la simulación
              
        private VMSimMotor motState = new VMSimMotor();

        public static string NombreClase()
        {
            return "VetroMeccanica Motor";
        }
        private string nombre = NombreClase();
        public override string Nombre
        {
            get => nombre;
            set => SetProperty(ref nombre, value);
        }

        [JsonIgnore]
        [ObservableProperty]
        public ImageSource imageSource_oculta;

        [ObservableProperty]
        public float angulo;

        [ObservableProperty]
        public float tamano;
        [ObservableProperty]
        public float proporcionalSpeed;

        [ObservableProperty]
        public float max_Speed_for_Ramp;


        [ObservableProperty]
        public float tiempoRampa;

        partial void OnTiempoRampaChanged(float value)
        {
            if (value < 0.1f)
                value = 0.1f;
            tiempoRampa = value;
        }

        [ObservableProperty]
        public bool encendido;
        [ObservableProperty]
        public int pLC_NumeroMotor;
        [ObservableProperty]
        public float ratio;

        [ObservableProperty]
        public float velocidad;

        partial void OnVelocidadChanged(float value)
        {
            if (value > 0)
                ImageSource_oculta = ImageFromPath("/imagenes/motorVerde.png");
            else
                ImageSource_oculta = ImageFromPath("/imagenes/motorNegro.png");
        }

        public osVMmotorSim()
        {
            Tamano = 0.30f;
            PLC_NumeroMotor = 31;
            ProporcionalSpeed = 100;
            Max_Speed_for_Ramp = 100;
            TiempoRampa = 3;
            ImageSource_oculta = ImageFromPath("/imagenes/motor2.png");
        }        

        public override void UpdateGeometryStart()
        {
            // Se llama antes de la simulacion

        }
        public override void UpdatePLC(PLCModel plc, int elapsedMilliseconds) {

            motState.UpdatePLC(plc,PLC_NumeroMotor,Encendido, elapsedMilliseconds);
            Velocidad = (ProporcionalSpeed / 100) * (motState.STATUS_VFD_ACT_Speed_Hz / 10);
        }

        public override void UpdateControl(int elapsedMilliseconds)
        {
            // Calculamos la velocidad
            motState.UpdateSpeed(Max_Speed_for_Ramp, TiempoRampa, elapsedMilliseconds);

        }

        public override void ucLoaded()
        {
            // El UserControl ya se ha cargado y podemos obtener las coordenadas para 
            // crear el objeto de simulacion
            ActualizarLeftTop();
            OnVelocidadChanged(Velocidad);

        }
    }

    public partial class ucVMmotorSim : UserControl, IDataContainer
    {
        public osBase? Datos { get; set; }

        public ucVMmotorSim()
        {
            InitializeComponent();
            this.Loaded += OnLoaded;
            this.Unloaded += OnUnloaded;
        }
        private void OnLoaded(object sender, RoutedEventArgs e)
        {
            Datos?.ucLoaded();
        }
        private void OnUnloaded(object sender, RoutedEventArgs e)
        {
            Datos?.ucUnLoaded();
        }
        public void Resize(float width, float height) { }
        public void Move(float LeftPixels, float TopPixels)
        {
            if (Datos != null)
            {
                Datos.Left = PixelToMeter.Instance.calc.PixelsToMeters(LeftPixels);
                Datos.Top = PixelToMeter.Instance.calc.PixelsToMeters(TopPixels);
            }
        }
        public void Rotate(float Angle) {
            if (Datos != null)
                if (Datos is osVMmotorSim datos)
                    datos.Angulo = Angle;
        }
        public void Highlight(bool State) { }
        public int ZIndex()
        {
            return 10;
        }
    }

    public class VMSimMotor
    {
        public bool _STATUS_VFD_Ready;
        public float STATUS_VFD_ACT_Speed_Hz;
        public bool Motor_Running;
        public bool STATUS_VFD_Trip;
        public bool STATUS_VFD_Warning;
        public bool STATUS_VFD_Coasting;
        public bool OUT_Run;
        public bool OUT_Stop;
        public bool OUT_Reversal;
        public float OUT_OUT_VFD_REQ_Speed_Hz;

        public void UpdatePLC(PLCModel plc, int NumeroMotor, bool Encendido, int elapsedMilliseconds)
        {
            var index = 0;
            switch (NumeroMotor)
            {
                case < 100:
                    index = (int)NumeroMotor - 30 + 300;
                    break;
            }

            OUT_Run = plc.LeerTagBool($"\"DB MotorSimulate\".Motors[{index}].OUT.Run");
            OUT_Reversal = plc.LeerTagBool($"\"DB MotorSimulate\".Motors[{index}].OUT.\"Reversal Direction\"");
            OUT_OUT_VFD_REQ_Speed_Hz = (float)plc.LeerTagInt16($"\"DB MotorSimulate\".Motors[{index}].OUT.OUT_VFD_REQ_Speed_Hz");



            if (Encendido)
            {
                _STATUS_VFD_Ready = true;
                Motor_Running = true;
                STATUS_VFD_Trip = false;
                STATUS_VFD_Warning = false;
                STATUS_VFD_Coasting = false;
            }
            else
            {
                _STATUS_VFD_Ready = false;
                Motor_Running = false;
                STATUS_VFD_Trip = true;
                STATUS_VFD_Warning = false;
                STATUS_VFD_Coasting = false;
            }

            plc.EscribirTagBool($"\"DB MotorSimulate\".Motors[{index}].STATUS_VFD_Ready", _STATUS_VFD_Ready);
            plc.EscribirTagBool($"\"DB MotorSimulate\".Motors[{index}].Motor_Running", Motor_Running);
            plc.EscribirTagBool($"\"DB MotorSimulate\".Motors[{index}].STATUS_VFD_Trip", STATUS_VFD_Trip);
            plc.EscribirTagBool($"\"DB MotorSimulate\".Motors[{index}].STATUS_VFD_Warning", STATUS_VFD_Warning);
            plc.EscribirTagBool($"\"DB MotorSimulate\".Motors[{index}].STATUS_VFD_Coasting", STATUS_VFD_Coasting);

            plc.EscribirTagInt16($"\"DB MotorSimulate\".Motors[{index}].STATUS_VFD_ACT_Speed_Hz", (int)STATUS_VFD_ACT_Speed_Hz);

        }

        private float CalcSpeedRamp(float max_Speed_for_Ramp, float TiempoRampa, float actual, float expected, int elapsedMilliseconds)
        {
            float hzIncrementsRamp = (max_Speed_for_Ramp * 10) / (TiempoRampa * (1000.0f / elapsedMilliseconds));
            float delta = expected - actual;
            // Conrtolar si la diferencia no es mayor de lo que falta
            if (Math.Abs(hzIncrementsRamp) > Math.Abs(delta))
                hzIncrementsRamp = Math.Abs(delta);
            if (delta < 0)
                return -hzIncrementsRamp;
            else
                return hzIncrementsRamp;
        }

        public void UpdateSpeed(float max_Speed_for_Ramp, float TiempoRampa, int elapsedMilliseconds)
        {
            // Calculamos la velocidad
            STATUS_VFD_ACT_Speed_Hz += CalcSpeedRamp(max_Speed_for_Ramp, TiempoRampa, STATUS_VFD_ACT_Speed_Hz, OUT_OUT_VFD_REQ_Speed_Hz, elapsedMilliseconds);

        }
    }

}
