//                           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.Collections.Generic;
using System.Linq;
using System.Threading;
using NLog;
using Raytheon.Instruments;

namespace MeasurementManagerLib
{
   /// <summary>
   /// This class manages DIO instruments and provides an abstraction
   /// </summary>
   public class DioMeasurementManager : IDisposable
   {
      #region PrivateClassMembers
      private SortedDictionary<string, IGeneralIO> _signalNameToDioModuleMap = new SortedDictionary<string, IGeneralIO>();

      public Dictionary<string, IODatatypes.DIOChannelInfo> SignalNameToChannelInfoMap { get; private set; }

      private static NLog.ILogger _logger;
      #endregion

      #region PublicClassFunctions

      /// <summary>
      /// constructor with the instrument manager
      /// </summary>
      /// <param name="instrumentManager">General Instrument Manager</param>
      public DioMeasurementManager(IInstrumentManager instrumentManager)
      {
         _logger = LogManager.GetCurrentClassLogger();

         SignalNameToChannelInfoMap = new Dictionary<string, IODatatypes.DIOChannelInfo>();

         ICollection<object> dioModuleList = instrumentManager.GetInstruments(typeof(IGeneralIO));
         // populate the maps
         foreach (IGeneralIO dioModule in dioModuleList)
         {
            dioModule.Initialize();

            Dictionary<string, IODatatypes.DIOChannelInfo> signalNameToChannelInfoMap = dioModule.GetAllSignals();

            // add signal map for this DIO module to master signal map
            signalNameToChannelInfoMap.ToList().ForEach(x => SignalNameToChannelInfoMap.Add(x.Key, x.Value));

            foreach (KeyValuePair<string, IODatatypes.DIOChannelInfo> item in signalNameToChannelInfoMap)
            {
               if (_signalNameToDioModuleMap.ContainsKey(item.Key.ToUpper()))
               {
                  throw new Exception("There is more than 1 DIO card that have the same signal name: " + item.Key);
               }

               _signalNameToDioModuleMap[item.Key.ToUpper()] = dioModule;
            }
         }
      }

      /// <summary>
      /// Dispose of this objects resources
      /// </summary>
      public void Dispose()
      {
         try
         {
            Dispose(true);

            GC.SuppressFinalize(this);
         }
         catch (Exception err)
         {
            try
            {
               _logger?.Error(err.Message + "\r\n" + err.StackTrace);
            }
            catch (Exception)
            {
               //Do not rethrow. Exception from error logger that has already been garbage collected
            }
         }
      }

      /// <summary>
      /// Get the state(0 or 1) of an input signal
      /// </summary>
      /// <param name="signalName">The signal to get the state of</param>
      /// <returns>0 if the signal is low, 1 if the signal is high</returns>
      public IODatatypes.BitState GetInputSignalState(string signalName)
      {
         return _signalNameToDioModuleMap[signalName.ToUpper()].GetBitState(signalName);
      }

      /// <summary>
      /// Set the state of an output signal
      /// </summary>
      /// <param name="signalName">The name of the output signal</param>
      /// <param name="data">The state, 0 for low, 1 for high, 2 for logic Z</param>
      /// <param name="timeToSleepMs">number of ms to wait after setting signal</param>
      public void SetOutputSignalState(string signalName, IODatatypes.BitState state, uint timeToSleepMs = 100)
      {
         _signalNameToDioModuleMap[signalName.ToUpper()].SetBit(signalName, state);

         // wait a bit
         Thread.Sleep((int)timeToSleepMs);
      }

      #endregion

      #region PrivateClassFunctions

      /// <summary>
      /// The Finalizer
      /// </summary>
      ~DioMeasurementManager()
      {
         Dispose(false);
      }

      /// <summary>
      /// 
      /// </summary>
      /// <param name="disposing"></param>
      protected virtual void Dispose(bool disposing)
      {
         if (disposing)
         {
            foreach (KeyValuePair<string, IGeneralIO> entry in _signalNameToDioModuleMap)
            {
               entry.Value.Shutdown();
            }
         }
      }
      #endregion
   }
}
