// *******************************************************************************************
// **                                                                                       **
// **      AbstractDmm.cs
// **      4/14/2023
// **                                                                                       **
// **      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 2023.
// **                                                                                       **
// **      WARNING: THIS DOCUMENT CONTAINS TECHNICAL DATA AND / OR TECHNOLOGY WHOSE         **
// **      EXPORT OR DISCLOSURE TO NON-U.S.PERSONS, WHEREVER LOCATED, IS RESTRICTED         **
// **      BY THE INTERNATIONAL TRAFFIC IN ARMS REGULATIONS (ITAR) (22 C.F.R.SECTION        **
// **      120-130) OR THE EXPORT ADMINISTRATION REGULATIONS(EAR) (15 C.F.R.SECTION         **
// **      730-774). THIS DOCUMENT CANNOT BE EXPORTED(E.G., PROVIDED TO A SUPPLIER          **
// **      OUTSIDE OF THE UNITED STATES) OR DISCLOSED TO A NON-U.S.PERSON, WHEREVER         **
// **      LOCATED, UNTIL A FINAL JURISDICTION AND CLASSIFICATION DETERMINATION HAS         **
// **      BEEN COMPLETED AND APPROVED BY RAYTHEON, AND ANY REQUIRED U.S.GOVERNMENT         **
// **      APPROVALS HAVE BEEN OBTAINED. VIOLATIONS ARE SUBJECT TO SEVERE CRIMINAL          **
// **      PENALTIES.                                                                       **
// **                                                                                       **
// **      CAPITAL EQUIPMENT/SOFTWARE: THIS TECHNICAL DATA WAS DEVELOPED OR ACQUIRED        **
// **      EXCLUSIVELY AT CONTRACTOR EXPENSE AND IS INTENDED FOR USE ON MULTIPLE            **
// **      PROJECTS/PROGRAMS.                                                               **
// **                                                                                       **
// *******************************************************************************************

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Raytheon.Units;
using Raytheon.Instruments.Dmm;

//disable the no xml warning on this abstract class
#pragma warning disable 1591

namespace Raytheon.Instruments
{
    /// <summary>
    /// AbstractDmm - will do a bunch of work for DMM's as to keep the code to do that work
    ///               in a single place
    /// </summary>
    public abstract class AbstractDmm : IDmm
    {
        #region Private Fields

        private volatile object _configurationLock = new object();
        private MeasurementFunction _currentMeasurementType = MeasurementFunction.None;

        #endregion

        #region IDmm Interface

        #region Voltage Measurements

        /// <summary>
        /// Configures a voltage measurement, but first checks if the type is valid.
        /// </summary>
        public void ConfigureVoltageMeasurement(MeasurementFunction type, Voltage range, Voltage resolution)
        {
            //lock the configuration while checking it out
            lock (_configurationLock)
            {
                //validate the measurement type
                switch (type)
                {
                    case MeasurementFunction.ACPlusDCVolts:
                    case MeasurementFunction.ACVolts:
                    case MeasurementFunction.DCVolts:
                        break;
                    default:
                        throw new InvalidMeasurementConfigurationException(type, "Voltage units do not match the measurement type");
                }

                try
                {
                    InternalConfigureVoltageMeasurement(type, range, resolution);
                    //only set the type if the configure passed
                    _currentMeasurementType = type;
                }
                catch (InstrumentException ex)
                {
                    _currentMeasurementType = MeasurementFunction.None;
                    throw new InvalidMeasurementConfigurationException(type, ex.Message);
                }
            }
        }

        /// <summary>
        /// Configures the voltage measurement in the implementation class
        /// </summary>
        /// <param name="type">The voltage specific type of measurement.</param>
        /// <param name="range">The range.</param>
        /// <param name="resolution">The resolution.</param>
        /// <remarks>
        /// throw an InstrumentException if the configuration does not take, the abstract class will
        /// catch that and fail the configuration
        /// </remarks>
        protected abstract void InternalConfigureVoltageMeasurement(MeasurementFunction type, Voltage range, Voltage resolution);

        /// <summary>
        /// Measure - locks on the configuration and then makes sure the proper type is selected
        ///           then, calls the abstract class to do the work
        /// </summary>
        public Voltage MeasureVoltage(int timeout)
        {
            //lock the configuration while measuring
            lock (_configurationLock)
            {
                //validate the measurement type
                switch (_currentMeasurementType)
                {
                    case MeasurementFunction.ACPlusDCVolts:
                    case MeasurementFunction.ACVolts:
                    case MeasurementFunction.DCVolts:
                        break;
                    default:
                        throw new InvalidMeasurementRequestException(_currentMeasurementType, "Voltage units do not match the configured measurement type");
                }

                return InternalMeasureVoltage(timeout);
            }
        }

        /// <summary>
        /// voltage measurement in the implementation class.
        /// </summary>
        /// <param name="timeout">The timeout.</param>
        /// <returns>measured voltage</returns>
        /// <remarks>
        /// throw an InstrumentException if the measurement fails
        /// </remarks>
        protected abstract Voltage InternalMeasureVoltage(int timeout);

        #endregion

        #region Current Measurements

        /// <summary>
        /// Configures a current measurement, but first checks if the type is valid.
        /// </summary>
        public void ConfigureCurrentMeasurement(MeasurementFunction type, Current range, Current resolution)
        {
            //lock the configuration while checking it out
            lock (_configurationLock)
            {
                //validate the measurement type
                switch (type)
                {
                    case MeasurementFunction.ACCurrent:
                    case MeasurementFunction.ACPlusDCCurrent:
                    case MeasurementFunction.DCCurrent:
                        break;
                    default:
                        throw new InvalidMeasurementConfigurationException(type, "Current units do not match the measurement type");
                }

                try
                {
                    InternalConfigureCurrentMeasurement(type, range, resolution);
                    //only set the type if the configure passed
                    _currentMeasurementType = type;
                }
                catch (InstrumentException ex)
                {
                    _currentMeasurementType = MeasurementFunction.None;
                    throw new InvalidMeasurementConfigurationException(type, ex.Message);
                }
            }
        }

        /// <summary>
        /// Configures the current measurement in the implementation class
        /// </summary>
        /// <param name="type">The current specific type of measurement.</param>
        /// <param name="range">The range.</param>
        /// <param name="resolution">The resolution.</param>
        /// <remarks>
        /// throw an InstrumentException if the configuration does not take, the abstract class will
        /// catch that and fail the configuration
        /// </remarks>
        protected abstract void InternalConfigureCurrentMeasurement(MeasurementFunction type, Current range, Current resolution);

        /// <summary>
        /// Measure - locks on the configuration and then makes sure the proper type is selected
        ///           then, calls the abstract class to do the work
        /// </summary>
        public Current MeasureCurrent(int timeout)
        {
            //lock the configuration while measuring
            lock (_configurationLock)
            {
                //validate the measurement type
                switch (_currentMeasurementType)
                {
                    case MeasurementFunction.ACCurrent:
                    case MeasurementFunction.ACPlusDCCurrent:
                    case MeasurementFunction.DCCurrent:
                        break;
                    default:
                        throw new InvalidMeasurementRequestException(_currentMeasurementType, "Current units do not match the configured measurement type");
                }

                return InternalMeasureCurrent(timeout);
            }
        }

        /// <summary>
        /// Current measurement in the implementation class.
        /// </summary>
        /// <param name="timeout">The timeout.</param>
        /// <returns>measured current</returns>
        /// <remarks>
        /// throw an InstrumentException if the measurement fails
        /// </remarks>
        protected abstract Current InternalMeasureCurrent(int timeout);

        #endregion

        #region Resistance Measurements

        /// <summary>
        /// Configures a resistance measurement, but first checks if the type is valid.
        /// </summary>
        public void ConfigureResistanceMeasurement(MeasurementFunction type, Resistance range, Resistance resolution)
        {
            //lock the configuration while checking it out
            lock (_configurationLock)
            {
                //validate the measurement type
                switch (type)
                {
                    case MeasurementFunction.FourWireResistance:
                    case MeasurementFunction.TwoWireResistance:
                        break;
                    default:
                        throw new InvalidMeasurementConfigurationException(type, "Resistance units do not match the measurement type");
                }

                try
                {
                    InternalConfigureResistanceMeasurement(type, range, resolution);
                    //only set the type if the configure passed
                    _currentMeasurementType = type;
                }
                catch (InstrumentException ex)
                {
                    _currentMeasurementType = MeasurementFunction.None;
                    throw new InvalidMeasurementConfigurationException(type, ex.Message);
                }
            }
        }

        /// <summary>
        /// Configures the resistance measurement in the implementation class
        /// </summary>
        /// <param name="type">The resistance specific type of measurement.</param>
        /// <param name="range">The range.</param>
        /// <param name="resolution">The resolution.</param>
        /// <remarks>
        /// throw an InstrumentException if the configuration does not take, the abstract class will
        /// catch that and fail the configuration
        /// </remarks>
        protected abstract void InternalConfigureResistanceMeasurement(MeasurementFunction type, Resistance range, Resistance resolution);

        /// <summary>
        /// Measure - locks on the configuration and then makes sure the proper type is selected
        ///           then, calls the abstract class to do the work
        /// </summary>
        public Resistance MeasureResistance(int timeout)
        {
            //lock the configuration while measuring
            lock (_configurationLock)
            {
                //validate the measurement type
                switch (_currentMeasurementType)
                {
                    case MeasurementFunction.FourWireResistance:
                    case MeasurementFunction.TwoWireResistance:
                        break;
                    default:
                        throw new InvalidMeasurementRequestException(_currentMeasurementType, "Current units do not match the configured measurement type");
                }

                return InternalMeasureResistance(timeout);
            }
        }

        /// <summary>
        /// Resistance measurement in the implementation class.
        /// </summary>
        /// <param name="timeout">The timeout.</param>
        /// <returns>measured Resistance</returns>
        /// <remarks>
        /// throw an InstrumentException if the measurement fails
        /// </remarks>
        protected abstract Resistance InternalMeasureResistance(int timeout);

        #endregion

        #region Frequency Measurements

        /// <summary>
        /// Configures a frequency measurement, but first checks if the type is valid.
        /// </summary>
        public void ConfigureFrequencyMeasurement(MeasurementFunction type, Frequency range, Frequency resolution)
        {
            //lock the configuration while checking it out
            lock (_configurationLock)
            {
                //validate the measurement type
                switch (type)
                {
                    case MeasurementFunction.Frequency:
                        break;
                    default:
                        throw new InvalidMeasurementConfigurationException(type, "Frequency units do not match the measurement type");
                }

                try
                {
                    InternalConfigureFrequencyMeasurement(type, range, resolution);
                    //only set the type if the configure passed
                    _currentMeasurementType = type;
                }
                catch (InstrumentException ex)
                {
                    _currentMeasurementType = MeasurementFunction.None;
                    throw new InvalidMeasurementConfigurationException(type, ex.Message);
                }
            }
        }

        /// <summary>
        /// Configures the frequency measurement in the implementation class
        /// </summary>
        /// <param name="type">The frequency specific type of measurement.</param>
        /// <param name="range">The range.</param>
        /// <param name="resolution">The resolution.</param>
        /// <remarks>
        /// throw an InstrumentException if the configuration does not take, the abstract class will
        /// catch that and fail the configuration
        /// </remarks>
        protected abstract void InternalConfigureFrequencyMeasurement(MeasurementFunction type, Frequency range, Frequency resolution);

        /// <summary>
        /// Measure - locks on the configuration and then makes sure the proper type is selected
        ///           then, calls the abstract class to do the work
        /// </summary>
        public Frequency MeasureFrequency(int timeout)
        {
            //lock the configuration while measuring
            lock (_configurationLock)
            {
                //validate the measurement type
                switch (_currentMeasurementType)
                {
                    case MeasurementFunction.Frequency:
                        break;
                    default:
                        throw new InvalidMeasurementRequestException(_currentMeasurementType, "Frequency units do not match the configured measurement type");
                }

                return InternalMeasureFrequency(timeout);
            }
        }

        /// <summary>
        /// Frequency measurement in the implementation class.
        /// </summary>
        /// <param name="timeout">The timeout.</param>
        /// <returns>measured Frequency</returns>
        /// <remarks>
        /// throw an InstrumentException if the measurement fails
        /// </remarks>
        protected abstract Frequency InternalMeasureFrequency(int timeout);

        #endregion

        public MeasurementFunction MeasurementType
        {
            get
            {
                MeasurementFunction func = MeasurementFunction.None;
                lock (_configurationLock)
                {
                    func = _currentMeasurementType;
                }
                return func;
            }
        }

        #endregion

        // <summary>
        // The IInstrument interface is completely up to the impl class
        // </summary>
        #region IInstrument Interface

        public abstract bool ClearErrors();

        public abstract string DetailedStatus { get; protected set; }

        public abstract bool DisplayEnabled { get; set; }

        public abstract bool FrontPanelEnabled { get; set; }

        public abstract InstrumentMetadata Info { get; }

        public abstract void Initialize();

        public abstract string Name { get; protected set; }

        public abstract SelfTestResult PerformSelfTest();

        public abstract void Reset();

        public abstract SelfTestResult SelfTestResult { get; protected set; }

        public abstract void Shutdown();

        public abstract State Status { get; protected set; }

        #endregion
    }
}

#pragma warning restore 1591