using System;
using System.Threading;
using HWModules;
using SensorModules;
using SWModules;

namespace CPF.Profile_States
{
    public class Descend : Profile
    {
        public Descend(string name)
        {
            stateName.Clear();
            stateName.Append(name);

            ECTimeout = 30 * 60 * 1000;
        }

        private enum Action : int
        {
            setPV = 1,
            lastAction,
            size = lastAction
        }
        private static Action currentAction;

        private static bool glideOn = false;

        public override int doStateEntryActions()
        {
            basicStateEntry();

            ctd1.startCommandModeTimer(MissionConfig.SBE41CommandModeSamplePeriod);

            currentAction = (Action)1;

            buoyancyEngine.openMV();
            SV.RunPVPID = true;
            glideOn = false;

            ProfileState.Clear();
            ProfileState.Append(profileStateNone);

            sbTemp.Clear();
            sbTemp.Append("Starting Descend");
            sbTemp.Append(Literals.tabChar);
            sbTemp.Append(DateTime.Now.ToString("yyyy-MMM-ddTHH:mm:ssZ"));
            SciLogger.appendToMsgFooter(sbTemp);

            return (1);
        }

        public override int doStateActions()
        {
            switch (currentAction)
            {
                #region Sequential state actions
                case (Action.setPV):
                    //setPV returns (int)1, so this switch statement will stay in setPV, which makes sense.
                    //no use in moving to lastAction, then back to setPV, and then over again and over again
                    nextAction = setPV();
                    checkForGlide();

                    break;
                case (Action.lastAction):
                    //here for consistency, but will likely never get here as setPV returns (int)1.
                    currentAction = Action.setPV;
                    break;
                #endregion
            }

            currentAction = (Action)checkActionReturn(nextAction, (int)currentAction);
            return (1);
        }

        private void checkForGlide()
        {
            double targetPV = System.Math.Abs(getTargetPV());
            double actualPV = System.Math.Abs(ctd1.lpfResults.Diff2Velocity);

            if (!glideOn)
            {
                if (ctd1.lpfResults.LPFPressure > 5.0)
                {
                    if ((actualPV > (0.9 * targetPV)) && (actualPV < (1.5 * targetPV)))
                    {
                        glideOn = true;
                        buoyancyEngine.stopMotor();
                        Thread.Sleep(500);
                        buoyancyEngine.closeMV();
                        SV.RunPVPID = false;
                        EngrLogger.writeToColumns("Descend glide on");
                    }
                }
            }
            else
            {
                if ((actualPV <= 0.85 * targetPV) || (actualPV > (1.6 * targetPV)))
                {
                    glideOn = false;
                    buoyancyEngine.openMV();
                    SV.RunPVPID = true;
                    EngrLogger.writeToColumns("Descend glide off");
                }
            }
        }

        private const bool inDescend = true;
        public override CPFStates checkEvents()
        {
            //see if CPF passed the target Pressure, and if so increment PressureTableNum
            //TODO P1: this is inconsistent with ascend checkEvents
            if (checkForParkOrSample())
                return (CPFStates.park);

            if (checkAnchorConditions())
                return (CPFStates.anchor);

            //if at final descend table entry, transition to StartCP
            if (SV.PressureTableNum >= Mission.descendTable.Length)         //TODO P1 seems like this should only happen after park time has expired
                return (CPFStates.startCP);

            return (CPFStates.descend);
        }

        public override int doExitActions(bool timedOut)
        {
            if (timedOut)
            {
                basicStateExit(true);
            }
            else
            {
                basicStateExit(false);
            }

            return (1);
        }

        public override CPFStates doTimeoutAction()
        {
            return (CPFStates.startCP);
        }

        private bool checkForParkOrSample()         //TODO P2 this should be split into a checkForPark and a separate checkForSample
        {
            if (ctd1.SBE41LPF.RawPressure>= PressureSetPoint)
            {
                if (getParkTime() == TimeSpan.Zero)
                {
                    //if (SciLogger.sampleInProgress)
                    //{
                        //EngrLogger.writeToColumns("Descend is writing SciLogger samples");
                        //SciLogger.writeSample();
                    //}
                    SciLogger.startNewSampleCycle(SciLogger.Instruments.AllInstruments);
                    SV.PressureTableNum++;
                    return (false);
                }
                else
                {
                    PVSetPoint = 0.0;
                    return (true);
                }
            }
            else
                return (false);
        }
    }

}
