/*-------------------------------------------------------------------------
//                           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 NLog;
using Raytheon.Common;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Raytheon.Instruments.PowerSupplies
{
   /// <summary>
   /// Class to simulate any power supply module
   /// </summary>
   class PowerSupplyModuleSim : PowerSupplyModule
   {
      private List<string> _groupedModules;
      private List<string> _coupledModules;
      private string _powerSupplySystemName;
      private bool _frontPanelEnabled = true;

      private ILogger _logger;

      /// <summary>
      /// Constructor
      /// </summary>
      public PowerSupplyModuleSim(string iniFilePath, string powerSupplySystemName)
      {
         _logger = LogManager.GetCurrentClassLogger();
         _powerSupplySystemName = powerSupplySystemName;

         IConfigurationFile config = new ConfigurationFile(iniFilePath);

         string moduleDef = config.ReadValue(PowerSupplyConfigIni.GENERAL.ToString(), PowerSupplyConfigIni.MODULE_DEFINITION.ToString(), Raytheon.Common.GeneralConstants.DefaultConfigValue);
         string coupledModules = config.ReadValue(PowerSupplyConfigIni.GENERAL.ToString(), PowerSupplyConfigIni.COUPLED_MODULES.ToString(), Raytheon.Common.GeneralConstants.DefaultConfigValue);
         string groupedModules = config.ReadValue(PowerSupplyConfigIni.GENERAL.ToString(), PowerSupplyConfigIni.GROUPED_MODULES.ToString(), Raytheon.Common.GeneralConstants.DefaultConfigValue);

         PowerModules = moduleDef.Split(new string[] { ", " }, StringSplitOptions.RemoveEmptyEntries).ToList();
         _coupledModules = coupledModules.Split(new string[] { ", " }, StringSplitOptions.RemoveEmptyEntries).ToList();
         _groupedModules = groupedModules.Split(new string[] { ", " }, StringSplitOptions.RemoveEmptyEntries).ToList();

         if (_groupedModules.Count() > 1)
         {
            PowerModules.Clear();
            // since modules are grouped, we pick the first module as the representative module
            PowerModules.Add(_groupedModules[0]);
         }

         // build the power module map
         string moduleIndex = "";
         double ovp = 0.0;
         double ocp = 0.0;
         double voltageSetPoint = 0.0;
         double voltageSlewRate = 0.0;

         double minVoltage = 0.0;
         double maxVoltage = 0.0;
         double minCurrent = 0.0;
         double maxCurrent = 0.0;

         for (int i = 0; i < PowerModules.Count(); i++)
         {
            string moduleName = PowerModules[i];

            moduleIndex = config.ReadValue(moduleName, PowerSupplyConfigIni.INDEX.ToString(), Raytheon.Common.GeneralConstants.DefaultConfigValue);
            Double.TryParse(config.ReadValue(moduleName, PowerSupplyConfigIni.OCP.ToString(), Raytheon.Common.GeneralConstants.DefaultConfigValue), out ocp);
            Double.TryParse(config.ReadValue(moduleName, PowerSupplyConfigIni.OVP.ToString(), Raytheon.Common.GeneralConstants.DefaultConfigValue), out ovp);
            Double.TryParse(config.ReadValue(moduleName, PowerSupplyConfigIni.VOLTAGE_SETPOINT.ToString(), Raytheon.Common.GeneralConstants.DefaultConfigValue), out voltageSetPoint);
            Double.TryParse(config.ReadValue(moduleName, PowerSupplyConfigIni.VOLTAGE_SLEW_RATE.ToString(), Raytheon.Common.GeneralConstants.DefaultConfigValue), out voltageSlewRate);
            Double.TryParse(config.ReadValue(moduleName, PowerSupplyConfigIni.MIN_VOLTAGE.ToString(), Raytheon.Common.GeneralConstants.DefaultConfigValue), out minVoltage);
            Double.TryParse(config.ReadValue(moduleName, PowerSupplyConfigIni.MAX_VOLTAGE.ToString(), Raytheon.Common.GeneralConstants.DefaultConfigValue), out maxVoltage);
            Double.TryParse(config.ReadValue(moduleName, PowerSupplyConfigIni.MIN_CURRENT.ToString(), Raytheon.Common.GeneralConstants.DefaultConfigValue), out minCurrent);
            Double.TryParse(config.ReadValue(moduleName, PowerSupplyConfigIni.MAX_CURRENT.ToString(), Raytheon.Common.GeneralConstants.DefaultConfigValue), out maxCurrent);

            PowerModuleInfoDict[moduleName] = new Raytheon.Instruments.PowerSupplies.PowerSupplyModuleInfo(moduleIndex, ocp, ovp, voltageSetPoint, voltageSlewRate, minVoltage, maxVoltage, minCurrent, maxCurrent);
         }
      }

      /// <summary>
      /// Enable or Disable Front Panel
      /// </summary>
      /// <param name="name"></param>
      /// <returns></returns>
      public override bool DisplayEnabled
      {
         set { SemObj?.Release(); }
      }

      /// <summary>
      /// Enable or disable Front Panel
      /// </summary>
      /// <param name="name"></param>
      /// <returns></returns>
      public override bool FrontPanelEnabled
      {
         set {_frontPanelEnabled = value; SemObj?.Release(); } 
      }

      /// <summary>
      /// Turn on power module's output
      /// </summary>
      /// <param name="name"></param>
      /// <returns></returns>
      public override void On()
      {
         try
         {
            lock (SyncObj)
            {
               CheckActivePowerModuleValidity();

               if (_coupledModules.Contains(ActivePowerModule))
               {
                  foreach (string module in _coupledModules)
                  {
                     PowerModuleInfoDict[module].isOn_ = true;
                  }
               }
               else
                  PowerModuleInfoDict[ActivePowerModule].isOn_ = true;
            }
         }
         finally { SemObj?.Release(); }
      }

      /// <summary>
      /// Turn off power module's output
      /// </summary>
      /// <param name="name"></param>
      /// <returns></returns>
      public override void Off()
      {
         try
         {
            lock (SyncObj)
            {
               CheckActivePowerModuleValidity();

               if (_coupledModules.Contains(ActivePowerModule))
               {
                  foreach (string module in _coupledModules)
                  {
                     PowerModuleInfoDict[module].isOn_ = false;
                  }
               }
               else
                  PowerModuleInfoDict[ActivePowerModule].isOn_ = false;
            }
         }
         finally { SemObj?.Release(); };
      }

      /// <summary>
      /// Perform self test
      /// </summary>
      /// <param name=""></param>
      /// <returns></returns>
      public override SelfTestResult PerformSelfTest()
      {
         try
         {
            lock (SyncObj)
            {
               SelfTestResult = SelfTestResult.Pass;
            }
         }
         finally { SemObj?.Release(); };
      
         return SelfTestResult;
      }

      /// <summary>
      /// Read voltage
      /// </summary>
      /// <param></param>
      /// <returns></returns>
      protected override double ReadVoltage()
      {
         double val = 0.0;

         lock (SyncObj)
         {
            if (PowerModuleInfoDict[ActivePowerModule].isOn_)
               val = PowerModuleInfoDict[ActivePowerModule].voltageSetpoint_;
         }

         return val;
      }

      /// <summary>
      /// Read current
      /// </summary>
      /// <param></param>
      /// <returns></returns>
      protected override double ReadCurrent()
      {
         double val = 0.0;

         lock (SyncObj)
         {
            if (PowerModuleInfoDict[ActivePowerModule].isOn_)
               val = (PowerModuleInfoDict[ActivePowerModule].currentLowerLimit_ + PowerModuleInfoDict[ActivePowerModule].currentUpperLimit_) / 2.0;
         }

         return val;
      }

      /// <summary>
      /// Read protection status
      /// </summary>
      /// <param></param>
      /// <returns></returns>
      protected override int ReadProtectionStatus()
      {
         lock (SyncObj)
         {
            return 0;
         }
      }

      /// <summary>
      /// Get error code
      /// </summary>
      /// <param name=""></param>
      /// <returns></returns>
      protected override string GetErrorCode(out int errorCode)
      {
         lock (SyncObj)
         {
            errorCode = 0;
            return "";
         }
      }

   }
}
