using System;
using System.Reflection;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using CPF;
using System.Text;
using Microsoft.SPOT;
using System.Threading;
using HWModules;
using SWModules;
using Microsoft.SPOT.Hardware;
using SensorModules;

namespace CPFUnitTests
{
    [TestClass]
    public class UnitTestMsc
    {

        [TestMethod]
        public void TestWake()
        {
            EngrLogger.Comment("Start UT: Test Wake ");
            Init();

            try { doSimpleSequence(msc.Wake); }
            catch (Exception e) { EngrLogger.Comment(e.ToString());}
        }

        [TestMethod]
        public void TestConfigInfo()
        {
            EngrLogger.Comment("Start UT: TestConfigInfo");
            Init();
            try
            {
                doSimpleSequence(msc.ReqSensorConfig);
            }
            catch (Exception e)
            {
                EngrLogger.Comment(e.ToString());
            }
        }
        [TestMethod]
        public void TestErrorCounter()
        {
            EngrLogger.Comment("Start UT: TestErrorCounter");
            Init();
            try { doSimpleSequence(msc.ReqSendErrorCount); }
            catch (Exception e)
            {
                EngrLogger.Comment(e.ToString());
            }
        }
        [TestMethod]
        public void TestPowerCounter()
        {
            EngrLogger.Comment("Start UT: TestPowerCounter");
            Init();
            try
            {
                doSimpleSequence(msc.ReqPowerCount);
            }
            catch (Exception e)
            {
                EngrLogger.Comment(e.ToString());
            }
        }
        [TestMethod]
        public void TestSampleCounter()
        {
            EngrLogger.Comment("Start UT: Test Sample Counter");
            Init();
            try {doSimpleSequence(msc.ReqMscSampleCount);}
            catch (Exception e)
            {
                EngrLogger.Comment(e.ToString());
            }
                
           
        }
        [TestMethod]
        public void TestLastSampleTime()
        {
            EngrLogger.Comment("Start UT: Test SampleTime ");
            Init();
            try {doSimpleSequence(msc.ReqSampleTime);}
            
            catch (Exception e)
            {
                EngrLogger.Comment(e.ToString());
            }
            
                
           
        }
        [TestMethod]
        public void TestMSCConfig()
        {
            EngrLogger.Comment("Start UT: Test MSC Config ");
            Init();
            try {doSimpleSequence(msc.ReqMscConfig);}
            catch (Exception e)
            {
                EngrLogger.Comment(e.ToString());
            }
            
                
           
        }
        [TestMethod]
        public void TestInitCommand()
        {
            EngrLogger.Comment("Start UT: Test Init Command ");
            Init();
            try {doSimpleSequence(msc.InitMsc);}
            catch (Exception e)
            {
                EngrLogger.Comment(e.ToString());
            }
            
                
           
        }
        [TestMethod]
        public void TestSuspend()
        {
            EngrLogger.Comment("Start UT: Test Suspend ");
            Init();
            try {doSimpleSequence(msc.Suspend);}
            catch (Exception e)
            {
                EngrLogger.Comment(e.ToString());
            }
            
                
           
            Thread.Sleep(3000);
        }
        //Commented because this disables the sensor for all other tests
        //[TestMethod]
        //public void TestShutdown()
        //{
        //    doSimpleSequence(msc.Shutdown);
        //}

        [TestMethod]
        public void TestReqRtc()
        {
            EngrLogger.Comment("Start UT: Test Request RTC ");
            Init();
            try {doSimpleSequence(msc.ReqRTC);}
            catch (Exception e)
            {
                EngrLogger.Comment(e.ToString());
            }
            
                
           
        }
        [TestMethod]
        public void TestReqCtd()
        {
            EngrLogger.Comment("Start UT: Test Request CTD ");
            Init();
            try { doSimpleSequence(msc.ReqCTD); }
            catch(Exception e) {EngrLogger.Comment(e.ToString());}
        }
        [TestMethod]
        public void TestReqFit()
        {
            EngrLogger.Comment("Start UT: Test Request Fit ");
            Init();
            try { doSimpleSequence(msc.ReqFitWindow); }
            catch (Exception e) { EngrLogger.Comment(e.ToString()); }
        }
        [TestMethod]
        public void TestReqSpectra()
        {
            EngrLogger.Comment("Start UT: Test Request Spectra ");
            Init();
            try { doSimpleSequence(msc.ReqSpectra); }
            catch (Exception e) { EngrLogger.Comment(e.ToString()); }
        }
        [TestMethod]
        public void TestReqMode()
        {
            EngrLogger.Comment("Start UT: Test Request Mode ");
            Init();
            try { doSimpleSequence(msc.ReqMode); }
            catch (Exception e) { EngrLogger.Comment(e.ToString()); }
        }

        [TestMethod]
        public void TestSetRtc()
        { 
            EngrLogger.Comment("Start UT: Test Set RTC ");
            Init();
            try { doSimpleSequence(msc.SetRTC); }
            catch (Exception e) { EngrLogger.Comment(e.ToString()); }
        }
        
        [TestMethod]
        public void TestSetCtd()
        {
            EngrLogger.Comment("Start UT: Test Set CTD ");
            Init();
            int ret = 0;
            try
            {
                do
                {
                    _mq.processQ();
                    Thread.Sleep(20);
                    msc.SetCTDValues(1512519524, (float)32.1, (float)15.1, (float)10.0);
                    ret = msc.SequenceSendCtdValues();
                } while (ret == 0);

                Assert.AreEqual(ret, 1);
                // Check the Ctd
                doSimpleSequence(msc.ReqCTD);
            }
            catch (Exception e) { EngrLogger.Comment(e.ToString()); }

        }
        
        [TestMethod]
        public void TestSetFit()
        { 
            EngrLogger.Comment("Start UT: Test Set Fit ");
            Init();
            int ret = 0;
            try
            {
                do
                {
                    _mq.processQ();
                    Thread.Sleep(20);
                    ret = msc.SequenceSendFitValues(220, 290);
                } while (ret == 0);

                Assert.AreEqual(ret, 1);
            }
            catch (Exception e) { EngrLogger.Comment(e.ToString()); }
        }

        [TestMethod]
        public void TestSetSpectra()
        { 
            EngrLogger.Comment("Start UT: Test Set Spectra ");
            Init();
            int ret = 0;
            try
            {
                do
                {
                    _mq.processQ();
                    Thread.Sleep(20);
                    ret = msc.SequenceSendSpectraValues(210, 349);
                } while (ret == 0);

                Assert.AreEqual(ret, 1);
            }
            catch (Exception e) { EngrLogger.Comment(e.ToString()); }
        }

        [TestMethod]
        public void TestSetMode()
        { 
            EngrLogger.Comment("Start UT: Test Set Mode ");
            Init();
            try
            {
                msc.CurrentMode = MSC.SampleMode.DuraFET;
                doSimpleSequence(msc.SendMode);
            }
            catch (Exception e) { EngrLogger.Comment(e.ToString()); }

        }

        [TestMethod]
        public void TestDownloadErrors()
        {
            EngrLogger.Comment("Start UT: Test Download Errors ");
            Init();
            int ret = 0;
            try
            {
                do
                {
                    _mq.processQ();
                    Thread.Sleep(20);
                    ret = msc.SequenceDownloadErrors();
                } while (ret == 0);

                if (ret != 1)
                {
                    EngrLogger.Comment("Test Download Errors Failed or no errors present.");
                }
            }
            catch (Exception e) { EngrLogger.Comment(e.ToString()); }
        }
        
        [TestMethod]
        public void TestGetConfigs()
        {
            EngrLogger.Comment("Start UT: Test Download Errors ");
            Init();
            int ret = 0;
            try
            {
                do
                {
                    _mq.processQ();
                    Thread.Sleep(20);
                    ret = msc.SequenceGetConfigs(false);
                } while (ret == 0);

                if (ret != 1)
                {
                    EngrLogger.Comment("Test Download Errors Failed or no errors present.");
                }
            }
            catch (Exception e) { EngrLogger.Comment(e.ToString()); }
        }

        [TestMethod]
        public void TestInitialize()
        {
            EngrLogger.Comment("Start UT: Test Initialize Sequence ");
            Init();
            int ret = 0;
            try
            {
                do
                {
                    _mq.processQ();
                    Thread.Sleep(20);
                    ret = msc.SequenceGetConfigs();
                } while (ret == 0);

                //Assert.AreEqual(ret, 1);

                //Check the rtc
                doSimpleSequence(msc.ReqRTC);
            }
            catch (Exception e) { EngrLogger.Comment(e.ToString()); }
        }

        [TestMethod]
        public void TestPHandNO3SampleT1T2()
        {
            
            EngrLogger.Comment("Start UT: Test Sample Sequence ");
            Init();
            for (int i = 0; i < 3; i++)
            {
                msc.startT1T2SampleSequence();
                msc.ResetSequencers();
                Debug.Print("Starting TestPHandNO3Sample " + (i + 1).ToString() + " of 3");
                int ret = 0;
                try
                {
                    msc.SetCTDValues(Utils.dateTimeToPosixTime(DateTime.Now), (float)15.0, (float)35.00, (float)62.00);
                    do
                    {
                        var cycleStartTime = Utility.GetMachineTime();
                        _mq.processQ();
                        ret = msc.SequenceT1T2Samples();
                        //We'd check the return value for success or failure.
                        StateMachinePacer(cycleStartTime);

                    } while (ret == 0);

                    Assert.AreEqual(ret, 1);
                }
                catch (Exception e) { EngrLogger.Comment(e.ToString()); }
            }
        }
        [TestMethod]
        public void TestPHandNO3Sample()
        {
            EngrLogger.Comment("Start UT: Test Sample Sequence ");
            Init();

            for (int i = 0; i < 3; i++)
            {
                Debug.Print("Starting TestPHandNO3Sample " + (i + 1).ToString() + " of 3");
                int ret = 0;
                try
                {
                    msc.SetCTDValues(Utils.dateTimeToPosixTime(DateTime.Now), (float)15.0, (float)35.00, (float)62.00);
                    do
                    {
                        var cycleStartTime = Utility.GetMachineTime();
                        _mq.processQ();
                        ret = msc.SequencePHandNO3Samples();
                        //We'd check the return value for success or failure.
                        StateMachinePacer(cycleStartTime);

                    } while (ret == 0);

                    Assert.AreEqual(ret, 1);
                }
                catch (Exception e) { EngrLogger.Comment(e.ToString()); }
            }
        }


        [TestMethod]
        public void TestSample()
        {
            EngrLogger.Comment("Start UT: Test Sample Sequence ");
            Init();
            int ret = 0;
            try
            {
                do
                {
                    _mq.processQ();
                    ret = msc.SequenceSample(MSC.SampleMode.DuraFET);
                        //We'd check the return value for success or failure.
                    Thread.Sleep(50);
                } while (ret == 0);

                Assert.AreEqual(ret, 1);
            }
            catch (Exception e) { EngrLogger.Comment(e.ToString()); }

            try
            {
                do
                {
                    _mq.processQ();
                    ret = msc.SequenceSample(MSC.SampleMode.ISUS);
                        //We'd check the return value for success or failure.
                    Thread.Sleep(50);
                } while (ret == 0);

                Assert.AreEqual(ret, 1);
            }
            catch (Exception e) { EngrLogger.Comment(e.ToString()); }
        }



        static bool runonce = false;
        private static MSC1 msc;
        private static MessageQueue _mq;

        public void Init()
        {
            if (runonce) return;
            runonce = true;
            EngrLogger.Comment("Initializing MSC");
            HWModules.MotherBoard mb = HWModules.MotherBoard.Instance;
            _mq = MessageQueue.Instance;
            mb.Enable12V();
            mb.EnableChannelPower(MotherBoard.ChannelNames.MSCChannel);
            msc = MSC1.Instance;
            Thread.Sleep(10000);
            _mq.processQMaxLimit();
        }

        private void doSimpleSequence(MSC.SendCommand cmd)
        {
            short ret = 0;
            EngrLogger.Comment("TESTING: " + cmd.Method.Name);
            do
            {
                _mq.processQ();
                Thread.Sleep(20);
                ret = SimpleSequence(cmd);
            } while (ret == 0);
        
            //Assert.AreEqual(ret, 1);
        }

        private short _seq = -1;
        private TimeSpan _wfrTimeOut = new TimeSpan(0,0,2);
        private const short MaxAttempts = 5;
        private short _remAttempts = 0;
        private short SimpleSequence(MSC.SendCommand cmd)
        {
            short ret = 0;
            if (_seq < 0)
            {
                _seq = 0;
                _remAttempts = MaxAttempts;
            }
            switch (_seq) {
                case 0:
                    return msc.CheckStateAndTryAgain(msc.WaitForResponse(msc.Wake, _wfrTimeOut), ref _seq, ref _remAttempts);
                case 1:
                    return msc.CheckStateAndAdvance(msc.WaitForResponse(cmd, new TimeSpan(0, 0, 13)), ref _seq);
                case 2:
                    _seq = -1;
                    return 1;

                default:
                    _seq = -1;
                    return -1;
            }
        }

        public static void StateMachinePacer(TimeSpan SMCycleStartTime)
        {
            //Thread.Sleep(1);
            //return;
            var SMCyclePeriod = Microsoft.SPOT.Hardware.Utility.GetMachineTime() - SMCycleStartTime;
            var sbTemp = new StringBuilder();
            if (SMCyclePeriod < MissionConfig.smCyclePeriod)
            {
                var SMCycleSleepPeriod = (int)((MissionConfig.smCyclePeriod.Ticks - SMCyclePeriod.Ticks) / TimeSpan.TicksPerMillisecond);
                if (SMCycleSleepPeriod < 0)
                    SMCycleSleepPeriod = 0;
                if (SMCycleSleepPeriod > MissionConfig.smCyclePeriodMilliseconds)
                    SMCycleSleepPeriod = MissionConfig.smCyclePeriodMilliseconds;

                Thread.Sleep(SMCycleSleepPeriod);
            }
            else if (SMCyclePeriod > MissionConfig.smCyclePeriod)
            {
                //if (SV.CurrentState == CPFStates.initMission) return;
                sbTemp.Clear();
                sbTemp.Append("[ERROR] State machine cycle time exceeded SMCyclePeriod = ");
                sbTemp.Append(SMCyclePeriod.ToString());
                EngrLogger.writeToColumns(sbTemp);
            }
        }

    }
}
