using System;
using System.Diagnostics;
using NationalInstruments.Visa;
using Ivi.Visa;
using System.Runtime.InteropServices;
using Testrong.Core.Primitives.TestrongSystem.Obsolete;
using System.Threading;
using System.Linq;

namespace Testrong.User.Program
{
    public class NiVisaComms
    {
        public enum Dmm3458AMeasureMode
        {
            VOLT,
            CURR,
            RES,
            INIT,
            STBY
        }


        private ResourceManager rm;
        private MessageBasedSession mbs;
        public string exceptionTrace;
        private bool connected;
        private bool isSetup;
        private Dmm3458AMeasureMode currentMode;
        public NiVisaComms()
        {
            exceptionTrace = string.Empty;
            connected = false;
            isSetup = false;
            currentMode = Dmm3458AMeasureMode.STBY;
        }
        public bool Init(string deviceAddress)
        {
            ResourceOpenStatus deviceStatus;
            try
            {
                rm = new ResourceManager();
                mbs = (MessageBasedSession)rm.Open(deviceAddress, AccessModes.None, 1000, out deviceStatus);
                mbs.TerminationCharacterEnabled = true;
                currentMode = Dmm3458AMeasureMode.INIT;
                if (deviceStatus == ResourceOpenStatus.Success)
                {
                    mbs.FormattedIO.WriteLine("ID?");
                    string deviceID = mbs.FormattedIO.ReadLine();
                    if (deviceID.IndexOf("3458A") < 0)
                    {
                        connected = false;
                        return false;
                    }
                    connected = true;
                    return true;
                }
                else
                {
                    connected = false;
                    return false;
                }
            }
            catch (Exception ex)
            {
                exceptionTrace = ex.StackTrace;
                connected = false;
                return false;
            }
        }
        public bool Setup(Dmm3458AMeasureMode mode, double range = -1, double nplc = 0.04)
        {
            try
            {
                if (!connected || currentMode == Dmm3458AMeasureMode.STBY)
                {
                    return false;
                }
                if (currentMode == Dmm3458AMeasureMode.INIT || currentMode != mode)
                {
                    string measComm;
                    string nplcSet = $"NPLC {nplc:F2}";
                    switch (mode)
                    {
                        case Dmm3458AMeasureMode.VOLT:
                            {
                                measComm = $"DCV,{range:F2}";
                                break;
                            }
                        case Dmm3458AMeasureMode.CURR:
                            {
                                measComm = $"DCI,{range:F2}";
                                break;
                            }
                        case Dmm3458AMeasureMode.RES:
                            {
                                measComm = $"OHM,{range:F2}";
                                break;
                            }
                        default:
                            {
                                return false;
                            }
                    }
                    mbs.FormattedIO.WriteLine("PRESET NORM");
                    mbs.FormattedIO.WriteLine("DISP OFF");
                    mbs.FormattedIO.WriteLine("BEEP OFF");
                    mbs.FormattedIO.WriteLine("TARM AUTO");
                    mbs.FormattedIO.WriteLine("TRIG HOLD");
                    mbs.FormattedIO.WriteLine("NRDGS 1,AUTO");
                    mbs.FormattedIO.WriteLine("MFORMAT DREAL");
                    mbs.FormattedIO.WriteLine("OFORMAT DREAL");
                    mbs.FormattedIO.WriteLine("MEM FIFO");
                    //mbs.FormattedIO.WriteLine("NPLC 0.04");
                    mbs.FormattedIO.WriteLine(nplcSet);
                    mbs.FormattedIO.WriteLine(measComm);
                    mbs.FormattedIO.WriteLine("AZERO OFF");
                    mbs.FormattedIO.WriteLine("ARANGE OFF");
                    mbs.FormattedIO.WriteLine("END ALWAYS");
                }
                isSetup = true;
                return true;
            }
            catch (Exception e)
            {
                exceptionTrace = e.StackTrace;
                return false;
            }
        }
        public bool TriggerSingleMeasure()
        {
            try
            {
                mbs.FormattedIO.WriteLine("TRIG SGL");
            }
            catch (Exception e)
            {
                exceptionTrace = e.StackTrace;
                return false;
            }
            return true;
        }
        public double SingleRead()
        {
            try
            {
                byte[] readOut = mbs.RawIO.Read(8);
                Array.Reverse(readOut);
                double value = BitConverter.ToDouble(readOut, 0);
                //double value = mbs.FormattedIO.ReadDouble();
                return value;
            }
            catch (Exception e)
            {
                exceptionTrace = e.StackTrace;
                return double.MinValue;
            }
        }
        public double[] MultiRead(int count)
        {
            try
            {
                double[] ans = new double[count];
                mbs.FormattedIO.WriteLine("MCOUNT?");
                int mCount = int.Parse(mbs.FormattedIO.ReadLine());
                if (mCount < count)
                {
                    count = mCount;
                }
                TimeSpan readDelay = new TimeSpan(20000); // 1ms
                for (int i = 0; i < count; i++)
                {
                    //ans[i] = mbs.FormattedIO.ReadDouble();
                    byte[] readOut = mbs.RawIO.Read(8);
                    while (readOut.Length < 8)
                    {
                        int readLength = 8 - readOut.Length;
                        byte[] nextRead = mbs.RawIO.Read(readLength);
                        readOut = readOut.Concat(nextRead).ToArray();
                    }
                    Array.Reverse(readOut);
                    ans[i] = BitConverter.ToDouble(readOut, 0);
                    //Thread.Sleep(1);
                }
                return ans;
            }
            catch (Exception e)
            {
                exceptionTrace = e.StackTrace;
                return null;
            }
        }
        public bool ClearReadingMemory()
        {
            try
            {
                mbs.FormattedIO.WriteLine("TRIG HOLD");
                mbs.FormattedIO.WriteLine("MEM FIFO");
            }
            catch (Exception e)
            {
                exceptionTrace = e.StackTrace;
                return false;
            }
            return true;
        }
        public bool ResetInstrument()
        {
            try
            {
                mbs.FormattedIO.WriteLine("RESET");
            }
            catch (Exception e)
            {
                exceptionTrace = e.StackTrace;
                return false;
            }
            return true;
        }
    }

}