#define WIN64
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Drawing.Drawing2D;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
using System.Windows;

namespace Jeti_Test
{
    internal class Specbos
    {
        #region DLLimport
        internal class JETI_RadioExDll
        {
#if WIN64
		private const string JetiRadioExDll = "jeti_radio_ex64.dll";
#else
            private const string JetiRadioExDll = "jeti_radio_ex.dll";
#endif

            [DllImport(JetiRadioExDll)]
            public static extern UInt32 JETI_GetNumRadioEx(out UInt32 uiNumDevices);

            [DllImport(JetiRadioExDll, CharSet = CharSet.Ansi)]
            public static extern UInt32 JETI_GetSerialRadioEx(UInt32 uiDeviceNum, [MarshalAs(UnmanagedType.LPStr), Out] System.Text.StringBuilder sbBoardSerialNr,
                [MarshalAs(UnmanagedType.LPStr), Out] System.Text.StringBuilder sbSpecSerialNr, [MarshalAs(UnmanagedType.LPStr), Out] System.Text.StringBuilder sbDeviceSerialNr);

            [DllImport(JetiRadioExDll)]
            public static extern UInt32 JETI_OpenRadioEx(UInt32 uiDeviceNum, out UIntPtr puiDevice);

            [DllImport(JetiRadioExDll)]
            public static extern UInt32 JETI_CloseRadioEx(UIntPtr puiDevice);

            [DllImport(JetiRadioExDll)]
            public static extern UInt32 JETI_MeasureEx(UIntPtr puiDevice, float fTint, ushort ushAver, UInt32 uiStep);

            [DllImport(JetiRadioExDll)]
            public static extern UInt32 JETI_MeasureAdaptEx(UIntPtr puiDevice, ushort ushAver, UInt32 uiStep);

            [DllImport(JetiRadioExDll)]
            public static extern UInt32 JETI_PrepareMeasureEx(UIntPtr puiDevice, float fTint, ushort ushAver, UInt32 uiStep);

            [DllImport(JetiRadioExDll)]
            public static extern UInt32 JETI_MeasureStatusEx(UIntPtr puiDevice, [MarshalAs(UnmanagedType.Bool)] out bool bStatus);

            [DllImport(JetiRadioExDll)]
            public static extern UInt32 JETI_MeasureAdaptStatusEx(UIntPtr puiDevice, out float fTint, out ushort ushAverage, [MarshalAs(UnmanagedType.Bool)] out bool bStatus);

            [DllImport(JetiRadioExDll)]
            public static extern UInt32 JETI_MeasureBreakEx(UIntPtr puiDevice);

            [DllImport(JetiRadioExDll)]
            public static extern UInt32 JETI_SpecRadEx(UIntPtr puiDevice, UInt32 uiBeg, UInt32 uiEnd, [Out] float[] faSprad);

            [DllImport(JetiRadioExDll)]
            public static extern UInt32 JETI_SaveSpecRadSPCEx(UIntPtr puiDevice, UInt32 uiBeg, UInt32 uiEnd, [MarshalAs(UnmanagedType.LPStr), Out] System.Text.StringBuilder sbPathName,
                [MarshalAs(UnmanagedType.LPStr), Out] System.Text.StringBuilder sbOperator, [MarshalAs(UnmanagedType.LPStr), Out] System.Text.StringBuilder sbMemo);

            [DllImport(JetiRadioExDll)]
            public static extern UInt32 JETI_SaveSpecRadCSVEx(UIntPtr puiDevice, UInt32 uiBeg, UInt32 uiEnd, [MarshalAs(UnmanagedType.LPStr), Out] System.Text.StringBuilder sbPathName,
                [MarshalAs(UnmanagedType.LPStr), Out] System.Text.StringBuilder sbOperator, [MarshalAs(UnmanagedType.LPStr), Out] System.Text.StringBuilder sbMemo);

            [DllImport(JetiRadioExDll)]
            public static extern UInt32 JETI_RadioEx(UIntPtr puiDevice, UInt32 uiBeg, UInt32 uiEnd, out float fRadio);

            [DllImport(JetiRadioExDll)]
            public static extern UInt32 JETI_PhotoEx(UIntPtr puiDevice, out float fPhoto);

            [DllImport(JetiRadioExDll)]
            public static extern UInt32 JETI_ChromxyEx(UIntPtr puiDevice, out float fChromx, out float fChromy);

            [DllImport(JetiRadioExDll)]
            public static extern UInt32 JETI_Chromxy10Ex(UIntPtr puiDevice, out float fChromx10, out float fChromy10);

            [DllImport(JetiRadioExDll)]
            public static extern UInt32 JETI_ChromuvEx(UIntPtr puiDevice, out float fChromu, out float fChromv);

            [DllImport(JetiRadioExDll)]
            public static extern UInt32 JETI_ChromXYZEx(UIntPtr puiDevice, out float fX, out float fY, out float fZ);

            [DllImport(JetiRadioExDll)]
            public static extern UInt32 JETI_DWLPEEx(UIntPtr puiDevice, out float fDWL, out float fPE);

            [DllImport(JetiRadioExDll)]
            public static extern UInt32 JETI_CCTEx(UIntPtr puiDevice, out float fCCT);

            [DllImport(JetiRadioExDll)]
            public static extern UInt32 JETI_DuvEx(UIntPtr puiDevice, out float fDuv);

            [DllImport(JetiRadioExDll)]
            public static extern UInt32 JETI_CRIEx(UIntPtr puiDevice, float fCCT, [Out] float[] fCRI);

            [DllImport(JetiRadioExDll)]
            public static extern UInt32 JETI_RadioTintEx(UIntPtr puiDevice, out float fTint);

            [DllImport(JetiRadioExDll)]
            public static extern UInt32 JETI_SetMeasDistEx(UIntPtr puiDevice, UInt32 uiDistance);

            [DllImport(JetiRadioExDll)]
            public static extern UInt32 JETI_GetMeasDistEx(UIntPtr puiDevice, out ushort ushDistance);

            [DllImport(JetiRadioExDll)]
            public static extern UInt32 JETI_GetRadioExDLLVersion(out ushort ushMajorVersion, out ushort ushMinorVersion, out ushort ushBuildNumber);

        }
        #endregion

        #region  members
        /// <summary>
        /// Number of devices available
        /// </summary>
        uint uiNumDevices;
        /// <summary>
        /// Device handle
        /// </summary>
        UIntPtr puiDevice = UIntPtr.Zero;
        /// <summary>
        /// Integration time in ms
        /// </summary>
        public float fTint = 0;
        /// <summary>
        /// Number of Averaging cycles
        /// </summary>
        public ushort ushAverage = 1;
        /// <summary>
        /// Stepping in nm
        /// </summary>
        public uint uiStep = 0;
        public uint nmStart;
        public uint nmEnd;
        /// <summary>
        /// Busy status
        /// </summary>
        bool bStatus;

        private float [] fSPRad;
        /// <summary>
        /// Array for the spectral radiance per wavelength.
        /// The wavelength range in [nm] is specified by dwBeg and dwEnd
        /// The wavelength step was specified by JETI_MeasureEx.
        /// </summary>
        public float[] FSPRad {  get { return fSPRad; } }

        private float fradio;
        /// <summary>
        /// Radiometric value aka Strahlungsintensität??
        /// </summary>
        public float FRadio { get {return fradio; } }
        private float fphoto;
        /// <summary>
        /// Photometric value aka Wellenlänge??
        /// </summary>
        public float FPhoto { get { return fphoto; } }
        


        //float fLight[];
        //Int32 iLight[];
        UInt32 uiPixel;
        //System.Text.StringBuilder sbBoardSerialNr = new System.Text.StringBuilder(16);
        //System.Text.StringBuilder sbSpecSerialNr = new System.Text.StringBuilder(16);
        //System.Text.StringBuilder sbDeviceSerialNr = new System.Text.StringBuilder(16);

        #endregion
        public Specbos() { }
        //{
        //    float[] fSPRat;
        //}
        public enum Errorcode : uint
        {
            SUCCESS = 0x00, // no error occured 
            ERROR_OPEN_PORT = 0x02, // could not open COM-port 
            ERROR_PORT_SETTING = 0x03,  // could not set COM-port settings 
            ERROR_BUFFER_SIZE = 0x04,   // could not set buffer size of COM-port 
            ERROR_PURGE = 0x05, // could not purge buffers of COM-port 
            ERROR_TIMEOUT_SETTING = 0x06,   // could not set COM-port timeout 
            ERROR_SEND = 0x07,  // could not send to device 
            TIMEOUT = 0x08, // communication timeout error 
            ERROR_RECEIVE = 0x0A,   // could not receive from device 
            ERROR_NAK = 0x0B,   // command not supported or invalid argument 
            ERROR_CONVERT = 0x0C,   // could not convert received data 
            ERROR_PARAMETER = 0x0D, // invalid argument 
            BUSY = 0x0E,    // device busy 
            CHECKSUM_ERROR = 0x11,  // invalid checksum of received data 
            INVALID_STEPWIDTH = 0x12,   // invalid step width 
            INVALID_NUMBER = 0x13,  // invalid device number 
            NOT_CONNECTED = 0x14,   // device not connected 
            INVALID_HANDLE = 0x15,  // invalid device handle 
            INVALID_CALIB = 0x16,   // invalid calibration file number 
            CALIB_NOT_READ = 0x17,  // calibration data not read 
            OVEREXPOSURE = 0x20,    // measurement failed due to overexposure 
            MEASURE_FAIL = 0x22,    // measurement failed due to other reasons 
            ADAPTION_FAIL = 0x23,   // adaption failed 
            DLL_ERROR = 0x80,   // internal DLL error 
            FATAL_ERROR = 0xFF,	// fatal communication error 
        }

        Errorcode uiError;
        /// <summary>
        /// True nach erfolgreicher Messung
        /// </summary>
        public bool Ready = false;

        /// <summary>
        /// FindDevices gets the number of connected JETI: should always be 0 or 1
        /// </summary>
        /// <returns></returns>
        public Errorcode FindDevices()
        {
            // determines the number of connected JETI devices
            uiError = (Errorcode)JETI_RadioExDll.JETI_GetNumRadioEx(out uiNumDevices);
            if (uiError != Errorcode.SUCCESS || (uiNumDevices == 0))
            {
                Console.WriteLine("No matching device found! Error code: " + uiError);
            }
            return uiError;
        }
        /// <summary>
        /// Opens a device (using device number puiDevice returned by JETI_GetNumRadioEx) and returns a handle for access
        /// </summary>
        /// <returns></returns>
        public Errorcode OpenDevice()
        {
            // open the first found device (zero-based index)
            uiError = (Errorcode)JETI_RadioExDll.JETI_OpenRadioEx(0, out puiDevice);
            if (uiError != Errorcode.SUCCESS)
            {
                Console.WriteLine("Could not open device! Error code: " + uiError);
            }
            return uiError;
        }
        public Errorcode CloseDevice()
        {
            // close device (zero-based index)
            uiError = (Errorcode)JETI_RadioExDll.JETI_CloseRadioEx(puiDevice);
            if (uiError != Errorcode.SUCCESS)
            {
                Console.WriteLine($"Could not close device! Error code: " + uiError);
            }
            return uiError;
        }
        /// <summary>
        /// Perform a complete radiometric measurement
        /// Start a radiometric measurement in the range of 380 to 780 nm with a step-width of 5nm.
        /// </summary>
        public Errorcode MeasureEx()
        {

            Console.WriteLine("Performing measurement. Please wait...\n");
            uiError = (Errorcode)JETI_RadioExDll.JETI_MeasureEx(puiDevice, fTint, ushAverage, uiStep);
            if (uiError != 0)
            {
                ShowError(uiError);
                return uiError;
            }
            else
                // Checks the measurment status until boStatus becomes TRUE (measurement has finished)
                do
                {
                    uiError = (Errorcode)JETI_RadioExDll.JETI_MeasureStatusEx(puiDevice, out bStatus);
                    if (uiError != 0)
                    {
                        ShowError(uiError);
                        break;
                    }
                } while (bStatus);
            Ready = (uiError == Errorcode.SUCCESS);
            return uiError;
        }
        /// <summary>
        /// Fills the array fSPRAD[] with float values from nmStart to nmEnd in nmStepping
        /// </summary>
        /// <returns></returns>
        public Errorcode GetRadiances()
        {
            fSPRad = new float[(nmEnd-nmStart)/uiStep+1];
            //fSPRad = new float[] { 3.3f, 4.4f, 5.5f, 6.0f, 1.5f, 3.5f, 7.0f };
            uiError = (Errorcode)JETI_RadioExDll.JETI_SpecRadEx(puiDevice, nmStart, nmEnd, fSPRad); //Errorcode.SUCCESS; //
            if (uiError != 0) ShowError(uiError);
            return uiError;
        }
        public Errorcode GetRadiance()
        {
            uiError = (Errorcode)JETI_RadioExDll.JETI_RadioEx(puiDevice, 380, 780, out fradio);
            if (uiError != 0)
                Console.WriteLine($"Could not get radiometric value! Error code :" + uiError);
            return uiError;
        }
        public Errorcode GetPhoto()
        {
            uiError = (Errorcode)JETI_RadioExDll.JETI_PhotoEx(puiDevice, out fphoto);
            if (uiError != 0)
                Console.WriteLine($"Could not get photometric value! Error code :" + uiError);
            return uiError;
        }
        private bool ShowError(Errorcode e)
        {
            if (e == Errorcode.SUCCESS) return true;
            if(MessageBox.Show(e.ToString(), "Driver Error", MessageBoxButton.OKCancel, MessageBoxImage.Exclamation) == MessageBoxResult.OK) return true;
            else return false;
        }
    }

}
