//                           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;

namespace Raytheon.Instruments
{
	public class SwitchNise : ISwitch
	{
		private int _hSession = 0;
		/// <summary>
		/// NLog logger
		/// </summary>
		private readonly ILogger _logger;
		/// <summary>
		/// Raytheon configuration
		/// </summary>
		private readonly IConfigurationManager _configurationManager;
		private readonly IConfiguration _configuration;

		/// <summary>
		/// SwitchNise factory constructor
		/// </summary>
		/// <param name="deviceName"></param>
		/// <param name="configurationManager"></param>
		public SwitchNise(string deviceName, IConfigurationManager configurationManager, ILogger logger)
		{
			Name = deviceName;

			_logger = logger;

			_configurationManager = configurationManager;
			_configuration = _configurationManager.GetConfiguration(Name);

			var virtualDeviceName = _configuration.GetConfigurationValue("SwitchNise", "VirtualDeviceName", "");
			string options = _configuration.GetConfigurationValue("SwitchNise", "Options", "");

			try
			{
				int status = NiseNativeMethods.niSE_OpenSession(virtualDeviceName, options, out _hSession);
				if (status != 0)
				{
					throw new InstrumentException(string.Format("Could not open NISE session '{0}', error # {1}", virtualDeviceName, status));
				}
			}
			catch (BadImageFormatException ex)
			{
				throw new InstrumentException("Possible 32/64-bit issue with NI Switch Executive, see inner exception.", ex);
			}

			DetailedStatus = "";
			DisplayEnabled = false;
			FrontPanelEnabled = false;
			Info = new InstrumentMetadata
			{
				ModelNumber = "NISE"
			};
			Name = virtualDeviceName;
			SelfTestResult = Raytheon.Instruments.SelfTestResult.Pass;
			Status = State.Ready;
		}

		public SwitchNise(string virtualDeviceName)
		{
			string options = "";
			var status = -123;

			_logger = LogManager.GetCurrentClassLogger();

			try
			{
				status = NiseNativeMethods.niSE_OpenSession(virtualDeviceName, options, out _hSession);

				if (status != 0)
				{
					throw new InstrumentException(string.Format("Could not open NISE session '{0}', error # {1}", virtualDeviceName, status));
				}
			}
			catch (BadImageFormatException ex)
			{
				throw new InstrumentException("Possible 32/64-bit issue with NI Switch Executive, see inner exception.", ex);
			}

			DetailedStatus = "";
			DisplayEnabled = false;
			FrontPanelEnabled = false;
			Info = new InstrumentMetadata();
			Info.ModelNumber = "NISE";
			Name = virtualDeviceName;
			SelfTestResult = Raytheon.Instruments.SelfTestResult.Pass;
			Status = State.Ready;
		}

		public bool ClearErrors()
		{
			int status = NiseNativeMethods.niSE_ClearError(_hSession);

			if (status != 0)
			{
				Status = State.HardwareFailure;
				DetailedStatus = "ClearError failed";

				throw new InstrumentException("" + string.Format("Could not clear errors, error # {0}", status));
			}

			Status = State.Ready;

			return true;
		}

		public void Connect(string path)
		{
			int status = NiseNativeMethods.niSE_Connect(_hSession, path, NiseNativeMethods.MulticonnectMode.NoMulticonnect, true);

			if (status != 0)
			{
				Status = State.HardwareFailure;
				DetailedStatus = "Connect failed";

				throw new InstrumentException("" + string.Format("Could not connect '{0}', NISE error # {1}", path, status));
			}
		}

		public string DetailedStatus
		{
			get;
			private set;
		}

		public void Disconnect(string path)
		{
			int status = NiseNativeMethods.niSE_Disconnect(_hSession, path);

			if (status != 0)
			{
				throw new InstrumentException(string.Format("" + "Could not disconnect '{0}', NISE error # {1}", path, status));
			}
		}

		public void DisconnectAll()
		{
			int status = NiseNativeMethods.niSE_DisconnectAll(_hSession);

			if (status != 0)
			{
				Status = State.HardwareFailure;
				DetailedStatus = "DisconnectAll failed";

				throw new InstrumentException(string.Format("" + "Could not disconnect all, NISE error # {0}", status));
			}
		}

		//*** consider implementing 'set' to change back to some default value
		// not available
		public bool DisplayEnabled
		{
			get;
			set;
		}

		//*** consider implementing 'set' to change back to some default value
		// not available
		public bool FrontPanelEnabled
		{
			get;
			set;
		}

		public InstrumentMetadata Info
		{
			get;
			private set;
		}

		public void Initialize()
		{
			// do not want to allow user to open another session since they must close each one 
			// they open.  already opened in constructor

			ClearErrors();
		}

		public bool IsDebounced
		{
			get
			{
				bool isDebounced;
				int status = NiseNativeMethods.niSE_IsDebounced(_hSession, out isDebounced);

				if (status != 0)
				{
					Status = State.HardwareFailure;
					DetailedStatus = "IsDebounced failed";

					throw new InstrumentException("" + string.Format("Could not check debounce, error # {0}", status));
				}

				return isDebounced;
			}
		}

		public string Name
		{
			get;
			private set;
		}

		public SelfTestResult PerformSelfTest()
		{
			return SelfTestResult.Pass;
		}

		public void Reset()
		{
			ClearErrors();
			DisconnectAll();

			Status = State.Ready;
			DetailedStatus = "";
		}

		// not available
		public SelfTestResult SelfTestResult
		{
			get;
			private set;
		}

		public void Shutdown()
		{
			Int32 status = NiseNativeMethods.niSE_CloseSession(_hSession);

			if (status != 0)
			{
				Status = State.HardwareFailure;
				DetailedStatus = "Close failed";

				throw new InstrumentException("" + string.Format("Could not close NISE session, error # {0}", status));
			}
		}

		public State Status
		{
			get;
			private set;
		}
	}
}
