using System.Threading;
using HWModules;
using Microsoft.SPOT;
using Microsoft.SPOT.Hardware;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System.Text;

namespace CPFUnitTests
{
    [TestClass]
    internal class LheBoardUnitTests
    {
        private static bool _runOnce;

        [TestMethod]
        public void TestReadAllRegisters()
        {
            Init();

            byte address = 0x20;
            Thread.Sleep(500);
            var pio1 = new LhePio(new I2CDevice.Configuration(address, 200), 6);
            Thread.Sleep(1000);
            byte register = 0;

            if (pio1.readRegister(LhePio.Command.InputPort, ref register))
                Debug.Print("input register: \t" + register);
            if (pio1.readRegister(LhePio.Command.OutputPort, ref register))
                Debug.Print("output register: \t" + register);
            if (pio1.readRegister(LhePio.Command.PolarityInversion, ref register))
                Debug.Print("polarity register: \t" + register);
            if (pio1.readRegister(LhePio.Command.Configuration, ref register))
                Debug.Print("config register: \t" + register);

            address = 0x21;
            pio1 = new LhePio(new I2CDevice.Configuration(address, 400), 6);
            register = 0;

            if (pio1.readRegister(LhePio.Command.InputPort, ref register))
                Debug.Print("input register: \t" + register);
            if (pio1.readRegister(LhePio.Command.OutputPort, ref register))
                Debug.Print("output register: \t" + register);
            if (pio1.readRegister(LhePio.Command.PolarityInversion, ref register))
                Debug.Print("polarity register: \t" + register);
            if (pio1.readRegister(LhePio.Command.Configuration, ref register))
                Debug.Print("config register: \t" + register);
        }


        [TestMethod]
        public void TestSetupIo()
        {
            Init();
            var mb = MotherBoard.Instance;

            mb.Enable5V();
            Thread.Sleep(500);

            byte register = 0x00;
            const LhePio.RegOutput defaultOutput = LhePio.RegOutput.O0 |
                                                   LhePio.RegOutput.O1 |
                                                   LhePio.RegOutput.O2 |
                                                   LhePio.RegOutput.O3 |
                                                   LhePio.RegOutput.O4 |
                                                   LhePio.RegOutput.O5;
            //0b 0011 1111

            /**
             * Setup PIOs
             */
            byte address = 0x21;
            var pio1 = new LhePio(new I2CDevice.Configuration(address, 400), 6);
            address = 0x20;
            var pio2 = new LhePio(new I2CDevice.Configuration(address, 400), 6);
            Thread.Sleep(1000);

            pio1.setOutputs(defaultOutput);
            if (pio1.readRegister(LhePio.Command.OutputPort, ref register))
                Debug.Print("output register: \t" + register);

            LhePio.RegConfiguration config = 0x00; //0b000000 ALL OUTPUT
            pio1.setPortDirections(config);
            if (pio1.readRegister(LhePio.Command.Configuration, ref register))
                Debug.Print("config register: \t" + register);


            //THIS WORKS
            var outputTest = defaultOutput | LhePio.RegOutput.O6 | LhePio.RegOutput.O7;


            pio1.setOutputs(outputTest);
            if (pio1.readRegister(LhePio.Command.OutputPort, ref register))
                Debug.Print("output register: \t" + register);

            /**
             * Setup PIO2
             */
            if (pio2.readRegister(LhePio.Command.Configuration, ref register))
                Debug.Print("config register: \t" + register);
            if (pio2.readRegister(LhePio.Command.InputPort, ref register))
                Debug.Print("input register: \t" + register);
        }

        [TestMethod]
        public void TestLheSleep()
        {
            Init();
            var lhe = HWModules.LheBoard.Instance;
            lhe.Sleep(0x3);
        }

        [TestMethod]
        public void TestLheBatteryCommunications()
        {
            Init();
            var lhe = HWModules.LheBoard.Instance;
            ulong goodCount = 0;
            ulong downFor = 0;
            ulong errCount = 0;
            uint attempts = 1000;
            while (--attempts > 0)
            {
                if (lhe.UpdateBatteryBank())
                {
                    lhe.PrintBatteryData();
                    goodCount++;
                }

                else
                {
                    errCount++;
                    downFor++;
                    Debug.Print("[LOG_DATA] " + goodCount + " " + errCount + " " + downFor);
                }

                if (goodCount % 10 != 0) continue;

                downFor = 0;
                Debug.Print("[LOG_DATA] " + goodCount + " " + errCount + " " + downFor);
            }
        }

        [TestMethod]
        public void TestLhePumpPowerAndEnergyMonitor()
        {
            Init();
            var lhe = HWModules.LheBoard.Instance;
            var emPump = EnergyMonitorPump.Instance;
            Debug.Print("Enabling Pump Power, observe LED if JP6 installed.");
            lhe.EnablePumpPower(true);
            for (var i = 0; i < 10; i++)
                Debug.Print(emPump.getVoltsAndMilliAmps().ToString());
            Thread.Sleep(1000);
            Debug.Print("Disable Pump Power, observe LED if JP6 installed.");
            lhe.EnablePumpPower(false);
        }

        [TestMethod]
        public void TestLhePumpEnergyMonitor()
        {
            Init();
            var emPump = EnergyMonitorPump.Instance;
            for (var i = 0; i < 100; i++)
            {
                Thread.Sleep(100);
                EngrLogger.Comment(emPump.getVoltsAndMilliAmps().ToString());
            }

        }

        StringBuilder sbTemp = new StringBuilder(64);

        [TestMethod]
        public void TestSystemEnergyMonitors()
        {
            Debug.Print("\r\nStarting LHE Board Unit Tests, TestSystemEnergyMonitors");

            Init();
            LheBoard lhe = LheBoard.Instance;
            lhe.EnablePumpPower(false);

            var emPump = EnergyMonitorPump.Instance;
            var emHotel = EnergyMonitorHotel.Instance;

            EnergyMonitorLTC2946.EM_VICE emVIE;

            byte returnByte;

            sbTemp.Clear();
            sbTemp.Append("Pump register A: ");
            returnByte = emPump.ReadCtlARegister();
            sbTemp.Append(returnByte.ToString());
            sbTemp.Append("  register B: ");
            returnByte = emPump.ReadCtlBRegister();
            sbTemp.Append(returnByte.ToString());
            Debug.Print(sbTemp.ToString());

            sbTemp.Clear();
            sbTemp.Append("Hotel register A: ");
            returnByte = emHotel.ReadCtlARegister();
            sbTemp.Append(returnByte.ToString());
            sbTemp.Append("  register B: ");
            returnByte = emHotel.ReadCtlBRegister();
            sbTemp.Append(returnByte.ToString());
            Debug.Print(sbTemp.ToString());

            emVIE.volts = double.NaN;
            emVIE.milliAmps = double.NaN;
            emVIE.milliJoules = double.NaN;

            for (int j = 0; j < 2; j++)
            {
                for (var i = 0; i < 10; i++)
                {
                    sbTemp.Clear();
                    emVIE = emPump.getVICE();
                    sbTemp.Append("\tPump Volts:\t" + emVIE.volts.ToString("d2") + "\tPump milliamps:\t" + emVIE.milliAmps.ToString("d2") + "\tPump Joules:\t" + emVIE.milliJoules.ToString("d2"));

                    emVIE.volts = double.NaN;
                    emVIE.milliAmps = double.NaN;
                    emVIE.milliJoules = double.NaN;
                    emVIE = emHotel.getVICE();
                    sbTemp.Append("\tHotel Volts:\t" + emVIE.volts.ToString("d2") + "\tHotel milliamps:\t" + emVIE.milliAmps.ToString("d2") + "\tHotel Joules:\t" + emVIE.milliJoules.ToString("d2"));
                    Debug.Print(sbTemp.ToString());

                    Thread.Sleep(1000);
                }

                Debug.Print("Resetting Energy Accumulators");
                emPump.ResetAccumulators();
                emHotel.ResetAccumulators();

                Debug.Print("Enabling pump power");
                lhe.EnablePumpPower(true);
            }

            lhe.EnablePumpPower(false);
            
            Debug.Print("Done");

        }

        private static bool _runonce;

        public void Init()
        {
            if (_runOnce) return;
            _runOnce = true;

            var mb = MotherBoard.Instance;
            mb.Enable5V();
            Thread.Sleep(100);
        }

        ~LheBoardUnitTests()
        {
        }
    }
}