//                           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 Raytheon.Instruments;
using Raytheon.Instruments.GeneralIO;
using System;
using System.Collections.Generic;
using System.Configuration;
using System.IO;
using System.Reflection;
using System.Threading;

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

      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();

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

				List<string> signalNames = dioModule.GetSignalNames();

				foreach (string signalName in signalNames)
				{
               if (_signalNameToObjectMap.ContainsKey(signalName.ToUpper()))
               {
                  throw new Exception("There is more than 1 DIO card that have the same signal name: " + signalName);
               }

               _signalNameToObjectMap[signalName.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 _signalNameToObjectMap[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)
      {
         _signalNameToObjectMap[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 _signalNameToObjectMap)
				{
					try
					{
						entry.Value.Shutdown();
					}
					catch (Exception err)
					{
						_logger?.Error(err.Message + "\r\n" + err.StackTrace);
					}
				}

				try
				{
					ErrorLogger.Instance().Dispose();
				}
				catch (Exception)
				{
					// nothing to do
				}
			}
		}
		#endregion
	}
}
