//                           UNCLASSIFIED
/*-------------------------------------------------------------------------
RAYTHEON PROPRIETARY: THIS DOCUMENT CONTAINS DATA OR INFORMATION
PROPRIETARY TO RAYTHEON COMPANY AND IS RESTRICTED TO USE ONLY BY PERSONS
AUTHORIZED BY RAYTHEON COMPANY IN WRITING TO USE IT. DISCLOSURE TO
UNAUTHORIZED PERSONS WOULD LIKELY CAUSE SUBSTANTIAL COMPETITIVE HARM TO
RAYTHEON COMPANY'S BUSINESS POSITION. NEITHER SAID DOCUMENT NOR ITS
CONTENTS SHALL BE FURNISHED OR DISCLOSED TO OR COPIED OR USED BY PERSONS
OUTSIDE RAYTHEON COMPANY WITHOUT THE EXPRESS WRITTEN APPROVAL OF RAYTHEON
COMPANY.

THIS PROPRIETARY NOTICE IS NOT APPLICABLE IF DELIVERED TO THE U.S.
GOVERNMENT.

UNPUBLISHED WORK - COPYRIGHT RAYTHEON COMPANY.
-------------------------------------------------------------------------*/

using System;
using System.Threading;
using NLog;
using Raytheon.Units;

namespace Raytheon.Instruments
{
   /// <summary>
   /// A class that provides an interface for controlling simulated power supply systems and their modules.
   /// </summary>
   public class PowerSupplySim : IDCPwr
   {
      #region PublicClassMembers
#pragma warning disable CS0067
      public event EventHandler<OverCurrentEventArgs> OverCurrent;
      public event EventHandler<OverVoltageEventArgs> OverVoltage;
#pragma warning restore

      #endregion

      #region PublicFuctions

      /// <summary>
      /// The constructor for a sim power supply (simulated).
      /// </summary>
      /// <param name="overCurrentProtection">The overcurrent protection setting (Amps).</param>
      /// <param name="overVoltageProtection">The overvoltage protection setting (Volts).</param>
      /// <param name="voltageSetpoint">The voltage setpoint (Volts).</param>
      /// <param name="maxVoltageSetpoint">The max voltage setpoint (Volts).</param>
      /// <param name="minVoltageSetpoint">The min voltage setpoint (Volts).</param>
      /// <param name="moduleNumber">The module number (multiple modules in a system).</param>
      public PowerSupplySim(string name, double overCurrentProtection, double overVoltageProtection, double voltageSetpoint, double maxVoltageSetpoint, double minVoltageSetpoint, double slewRateVoltsPerSecond, int moduleNumber = -1)
      {
         _name = name;
         _logger = LogManager.GetCurrentClassLogger();
         _overCurrentProtection = overCurrentProtection;
         _overVoltageProtection = overVoltageProtection;
         _voltageSetpoint = voltageSetpoint;
         _voltageSetpointInitial = voltageSetpoint;
         _maxVoltageSetpoint = maxVoltageSetpoint;
         _minVoltageSetpoint = minVoltageSetpoint;
         _moduleNumber = moduleNumber;
         _isPowerOn = false;
         _slewRateVoltsPerSecond = slewRateVoltsPerSecond;

         // make sure it is off
         Enabled = false;

         // set up power supply
         OutputVoltage = Voltage.FromVolts(_voltageSetpoint);

         _state = State.Uninitialized;
      }

      /// <summary>
      /// 
      /// </summary>
      /// <returns></returns>
      public bool ClearErrors()
      {
         throw new NotImplementedException();
      }

      /// <summary>
      /// 
      /// </summary>
      public Current CurrentLimit
      {
         get
         {
            // a small 10 ms sleep for simulation
            Thread.Sleep(10);

            return Current.FromAmps(_overCurrentProtection);
         }

         set
         {
            _overCurrentProtection = value.Amps;
         }
      }

      /// <summary>
      /// 
      /// </summary>
      public string DetailedStatus
      {
         get
         {
            return "This is a Sim Power Supply called " + _name;
         }
      }

      /// <summary>
      /// 
      /// </summary>
      public bool DisplayEnabled
      {
         get
         {
            throw new NotImplementedException();
         }

         set
         {
            throw new NotImplementedException();
         }
      }

      /// <summary>
      /// Dispose of this object's resources.
      /// </summary>
      public void Dispose()
      {
         Dispose(true);

         GC.SuppressFinalize(this);
      }

      /// <summary>
      /// 
      /// </summary>
      public bool Enabled
      {
         get
         {
            // a small 10 ms sleep for simulation
            Thread.Sleep(10);

            return _isPowerOn;
         }

         set
         {
            // a small 10 ms sleep for simulation
            Thread.Sleep(10);

            if (value == false)
            {

               _isPowerOn = false;
            }
            else
            {
               _isPowerOn = true;
            }
         }
      }

      /// <summary>
      /// 
      /// </summary>
      public bool FrontPanelEnabled
      {
         get
         {
            throw new NotImplementedException();
         }

         set
         {
            throw new NotImplementedException();
         }
      }

      /// <summary>
      /// 
      /// </summary>
      /// <returns></returns>
      public double GetSlewRate()
      {
         return _slewRateVoltsPerSecond;
      }

      /// <summary>
      /// 
      /// </summary>
      public bool InhibitEnabled
      {
         get
         {
            throw new NotImplementedException();
         }

         set
         {
            throw new NotImplementedException();
         }
      }

      /// <summary>
      /// 
      /// </summary>
      public void Initialize()
      {
         // if we have not yet been initialized, go ahead and create the socket
         if (_state == State.Uninitialized)
         {
            _state = State.Ready;
         }
         else
         {
            throw new Exception("Expected the supply " + _name + "  to be Uninitialized, state was: " + _state.ToString());
         }
      }

      /// <summary>
      /// 
      /// </summary>
      public InstrumentMetadata Info
      {
         get
         {
            throw new NotImplementedException();
         }
      }

      /// <summary>
      /// Control the power supply internal mechanical relay state
      /// </summary>
      /// <param name="shallWeConnect">True to connect, false to disconnect</param>
      public void MechanicalRelayOutputControl(bool shallWeConnect)
      {
         // nothing to do here
      }

      /// <summary>
      /// 
      /// </summary>
      /// <returns></returns>
      public Current MeasureCurrent()
      {
         return Current.FromAmps(ReadCurrent());
      }

      /// <summary>
      /// 
      /// </summary>
      /// <returns></returns>
      public Voltage MeasureVoltage()
      {
         return Voltage.FromVolts(ReadVoltage());
      }

      /// <summary>
      /// 
      /// </summary>
      public string Name
      {
         get
         {
            return _name;
         }
         set { _name = value; }
      }

      /// <summary>
      /// 
      /// </summary>
      public Voltage OutputVoltage
      {
         get
         {
            // a small 10 ms sleep for simulation
            Thread.Sleep(10);

            return Voltage.FromVolts(_voltageSetpoint);
         }

         set
         {
            // a small 10 ms sleep for simulation
            Thread.Sleep(10);

            double volts = value.Volts;

            // do not let host set the voltage out of range, unless it is being set to 0
            if (volts != 0.0)
            {
               if (volts > _maxVoltageSetpoint || volts < _minVoltageSetpoint)
               {
                  throw new Exception("Desired voltage setpoint out of range for supply " + _name + ". Commanded setpoint: " + value.ToString() + ", Max: " + _maxVoltageSetpoint.ToString() + ", Min: " + _minVoltageSetpoint.ToString());
               }
            }

            _voltageSetpoint = volts;
         }
      }

      /// <summary>
      /// 
      /// </summary>
      public Voltage OverVoltageProtection
      {
         get
         {
            // a small 10 ms sleep for simulation
            Thread.Sleep(10);

            return Voltage.FromVolts(_overVoltageProtection);
         }

         set
         {
            _overVoltageProtection = value.Volts;
         }
      }

      /// <summary>
      /// 
      /// </summary>
      public bool OverVoltageProtectionEnabled
      {
         get
         {
            return true;
         }

         set
         {
            throw new NotImplementedException();
         }
      }

      /// <summary>
      /// 
      /// </summary>
      /// <returns></returns>
      public SelfTestResult PerformSelfTest()
      {
         throw new NotImplementedException();
      }

      /// <summary>
      /// Reads the overcurrent and overvoltage protection (simulation).
      /// </summary>
      /// <returns>No Errors (simulated).</returns>
      public int ReadProtectionStatus()
      {
         const int PROTECTION_STATUS = 0;

         // a small 10 ms sleep for simulation
         Thread.Sleep(10);

         return PROTECTION_STATUS;
      }

      /// <summary>
      /// 
      /// </summary>
      public void Reset()
      {
         // nothing to do
      }

      /// <summary>
      /// 
      /// </summary>
      public SelfTestResult SelfTestResult
      {
         get
         {
            throw new NotImplementedException();
         }
      }

      /// <summary>
      /// 
      /// </summary>
      /// <param name="slew"></param>
      /*public void SetSlewRate(double slew)
		{
		   _slew = slew;
		}*/

      /// <summary>
      /// 
      /// </summary>
      public State Status
      {
         get
         {
            return _state;
         }
      }

      /// <summary>
      /// 
      /// </summary>
      public void Shutdown()
      {
         if (_state == State.Ready)
         {
            Off();

            Reset();

            _state = State.Uninitialized;
         }
      }

      /// <summary>
      /// 
      /// </summary>
      public Voltage VoltageSoftLimit
      {
         get
         {
            return Voltage.FromVolts(_maxVoltageSetpoint);
         }
         set
         {
            throw new NotImplementedException();
         }
      }

      #endregion

      #region PrivateClassMembers

      private string _name;
      private double _overCurrentProtection;
      private double _overVoltageProtection;
      private double _voltageSetpoint;
      private double _voltageSetpointInitial;
      private readonly double _maxVoltageSetpoint;
      private readonly double _minVoltageSetpoint;
      private readonly int _moduleNumber;
      private bool _isPowerOn;
      private double _slewRateVoltsPerSecond;
      private State _state;

      /// <summary>
      /// NLog logger
      /// </summary>
      private readonly ILogger _logger;

      #endregion

      #region PrivateFuctions

      /// <summary>
      /// The finalizer.
      /// </summary>
      ~PowerSupplySim()
      {
         Dispose(false);
      }

      /// <summary>
      /// Dispose of this object.
      /// </summary>
      /// <param name="disposing">True = currently disposing, False = not disposing.</param>
      protected virtual void Dispose(bool disposing)
      {
         if (disposing)
         {
            if (_state == State.Ready)
            {
               Off();

               _state = State.Uninitialized;
            }
         }
      }

      /// <summary>
      /// Returns this object module number.
      /// </summary>
      /// <returns>The module number.</returns>
      /*public int GetModuleNumber()
		{
		   return _moduleNumber;
		}*/

      /// <summary>
      /// Turn the output off (simulated).
      /// </summary>
      private void Off()
      {
         // a small 10 ms sleep for simulation
         Thread.Sleep(10);

         _isPowerOn = false;
      }

      /// <summary>
      /// Turn the output on (simulated).
      /// </summary>
      private void On()
      {
         // a small 10 ms sleep for simulation
         Thread.Sleep(10);

         _isPowerOn = true;
      }

      /// <summary>
      /// Read the current (simulated).
      /// </summary>
      /// <returns>The current (simulated).</returns>
      private double ReadCurrent()
      {
         // a small 10 ms sleep for simulation
         Thread.Sleep(100);

         double currentToReturn = 0.0;

         if (_isPowerOn)
         {
            double maxCurrent = _overCurrentProtection;
            double minCurrent = _overCurrentProtection - .5;

            Random rnd = new Random();

            double seed = rnd.NextDouble();

            currentToReturn = (seed * (maxCurrent - minCurrent)) + minCurrent;
         }

         return currentToReturn;
      }

      /// <summary>
      /// Read the voltage.
      /// </summary>
      /// <returns>The voltage (simulated).</returns>
      private double ReadVoltage()
      {
         // a small 10 ms sleep for simulation
         Thread.Sleep(100);

         double voltageToReturn = 0.0;

         if (_isPowerOn)
         {
            double maxVoltage = _voltageSetpoint + 1;
            double minVoltage = _voltageSetpoint - 1;

            Random rnd = new Random();

            double seed = rnd.NextDouble();

            voltageToReturn = (seed * (maxVoltage - minVoltage)) + minVoltage;
         }

         return voltageToReturn;
      }

      #endregion

   }
}