using System;
using System.Ext.Xml;
using System.IO;
using System.Text;
using System.Xml;
using GHI.Processor;
using Microsoft.SPOT;
using SWModules;

//TODO P2 move all these parameters into appropriate classes

namespace HWModules
{
    public static class MissionConfig
    {

        static MissionConfig()
        {
            //default values
            PlatformName = "CPF003";
            IBFillLowerLimit = 3.0;
            IBFillUpperLimit = 97.0;
            SOSetBellowsPosition = 45.0;
            SOSetBellowsJV = 200000;
            RMSetBellowsPosition = 5.0;
            ABRetractSlowJV = 200000;
            ABRetractFastJV = 200000;
            ABPressureThreshold = 0.3;
            DeanchorJV = 150000;
            DeanchorVelocityLimit = 0.05;
            DeanchorPressureMinimum = 5.0;
            DeanchorPressureCountThreshold = 10;
            AccDeaccLimit = 100000;
            AnchorPressureCountThreshold = 4;
            AnchorPressureMinimum = 4.0;
            AnchorVelocityLimit = 0.025;
            ExitAnchorPressureThreshold = 5.0;
            ApproachVelocity = 0.01;
            CpPressureCutoff = 1;
            CpRunPumpTime = 2;
            CPMode = true;
            SBE41CommandModeSamplePeriod = 3000; //msec
            SBE41CPSamplePeriod = 1000; //msec
            EngrLoggerVerbosityLevel = 4;
            DebuggerVerbosityLevel = 4;
            SetPreMissionDelayPeriod(30);
            SetSystemDataSamplePeriod(10);
            StringPotInverseSlope = 7668560.96 ;// ORIG 1.304025625e-07;
            StringPotIntercept= 18.706119;
            MissionParkDepth = 150;
            MissionParkSamplePeriodMinutes = 2;
            MissionParkTimeHours = 0;
            MissionParkTimeMinutes = 5;
        }

        /// <summary>
        /// Time to spend in park states, minutes component 
        /// </summary>
        public static int MissionParkTimeMinutes
        {
            get { return _missionParkTimeMinutes; }
            set { if (CheckIntValue(value,ParkMinuteLimits))_missionParkTimeMinutes = value; }
        }

        /// <summary>
        /// Time to spend in park states, hours component 
        /// </summary>
        public static int MissionParkTimeHours
        {
            get { return _missionParkTimeHours; }
            set { if (CheckIntValue(value,ParkHourLimits))_missionParkTimeHours = value; }
        }

        /// <summary>
        /// Time between instrument sampling during park states in minutes.
        /// </summary>
        public static int MissionParkSamplePeriodMinutes
        {
            get { return _missionParkSamplePeriodMinutes; }
            set { if (CheckIntValue(value, ParkMinuteLimits)) _missionParkSamplePeriodMinutes = value; }
        }

        /// <summary>
        /// Depth (Pressure) to enter park state in decibar.
        /// </summary>
        public static float MissionParkDepth
        {
            get { return _missionParkDepth; }
            set { if (CheckDoubleValue(value, ParkDepthLimits)) _missionParkDepth = value; }
        }

        /// <summary>
        /// String representation for a unique identifier for each CPF,
        /// used in generation of logged data file names, tags, and logins
        /// back at the remote data & control portal. 
        /// </summary>
        public static string PlatformName { get; set; }

        /// <summary>
        /// Calibration inverted slope for the conversion of voltage to % full for internal bellows.
        /// </summary>
        public static double StringPotInverseSlope
        {
            get { return _stringPotInverseSlope;}
            set { _stringPotInverseSlope = value;
                _stringPotSlope = 1 / value;
            }
        }
        
        /// <summary>
        /// Calibration sloe for the conversion of voltage to % full internal bellows.
        /// This is a get only property, must be set with <see cref="StringPotInverseSlope"/>
        /// </summary>
        public static double StringPotSlope
        {
            get { return _stringPotSlope; }
        }

        /// <summary>
        /// Calibration intercept for the conversion of voltage to % full.
        /// </summary>
        public static double StringPotIntercept { get; set; }

        /// <summary>
        /// Lower limit of the bellows (in percent full)
        /// </summary>
        public static double IBFillLowerLimit
        {
            get { return _bellowsLowerLimit; }
            set
            {
                if (CheckDoubleValue(value, BellowsLimits)) _bellowsLowerLimit = value;
            }
        }

        /// <summary>
        /// Upper limit of the bellows (in percent full)
        /// </summary>
        public static double IBFillUpperLimit
        {
            get { return _bellowsUpperLimit; }
            set
            {
                if (CheckDoubleValue(value, BellowsLimits)) _bellowsUpperLimit = value;
            }
        }

        /// <summary>
        /// Bellows position in percent full to set when in surface ops mode.
        /// </summary>
        public static double SOSetBellowsPosition
        {
            get { return _soSetBellowsPosition; }
            set
            {
                if (CheckDoubleValue(value, BellowsLimits)) _soSetBellowsPosition = value;
            }
        }

        /// <summary>
        /// Pump speed for adjustments to the bellows position in surface ops mode.
        /// </summary>
        public static int SOSetBellowsJV
        {
            get { return _soSetBellowsJv; }
            set
            {
                if (CheckIntValue(value, JVLimits)) _soSetBellowsJv = value;
            }
        }

        /// <summary>
        /// Bellows position in percent full to set when in recovery mode.
        /// </summary>
        public static double RMSetBellowsPosition
        {
            get { return _rmSetBellowsPosition; }
            set
            {
                if (CheckDoubleValue(value, BellowsLimits)) _rmSetBellowsPosition = value;
            }
        }

        /// <summary>
        /// Pump speed for bellows control during retract fast modes.
        /// </summary>
        public static int ABRetractFastJV
        {
            get { return _abRetractFastJv; }
            set
            {
                if (CheckIntValue(value, JVLimits)) _abRetractFastJv = value;
            }
        }

        /// <summary>
        /// Pump speed for bellows control during retract slow modes.
        /// </summary>
        public static int ABRetractSlowJV
        {
            get { return _abRetractSlowJv; }
            set
            {
                if (CheckIntValue(value, JVLimits)) _abRetractSlowJv = value;
            }
        }

        /// <summary>
        /// Minimum pressure in decibars to transition from ABretract Mode
        /// to Descend mode.
        /// </summary>
        public static double ABPressureThreshold
        {
            get { return _abPressureThreshold; }
            set { if (CheckDoubleValue(value,SurfacePressureLimits)) _abPressureThreshold = value; }
        }

        /// <summary>
        /// Pump velocity during deanchoring.
        /// </summary>
        public static int DeanchorJV
        {
            get { return _deanchorJv; }
            set
            {
                if (CheckIntValue(value, JVLimits)) _deanchorJv = value;
            }
        }

        //Anchoring//
        /// <summary>
        /// Sets the detection limit for determining when the system is deanchored.
        /// This is a pressure velocity (decibars/sec).
        /// </summary>
        public static double DeanchorVelocityLimit
        {
            get { return _deanchorVelocityLimit; }
            set { if (CheckDoubleValue(value, VelocityLimits)) _deanchorVelocityLimit = value; }
        }

        /// <summary>
        /// Minimum pressure in decibars away from anchored pressure to determine
        /// deanchoring is complete.
        /// </summary>
        public static double DeanchorPressureMinimum
        {
            get { return _deanchorPressureMinimum; }
            set { if (CheckDoubleValue(value, DeanchorPressureMinimumLimits)) _deanchorPressureMinimum = value; }
        }

        /// <summary>
        /// Number of consecutive valid points in the "deanchored" state to
        /// exit the deanchoring state. 
        /// </summary>
        public static int DeanchorPressureCountThreshold
        {
            get { return _deanchorPressureCountThreshold; }
            set { if (CheckIntValue(value, AnchorCountLimits)) _deanchorPressureCountThreshold = value; }
        }

        /// <summary>
        /// Sets the number of consecutive count of pressures below target
        /// to determine the system has been anchored. 
        /// </summary>
        public static int AnchorPressureCountThreshold
        {
            get { return _anchorPressureCountThreshold; }
            set { if (CheckIntValue(value, AnchorCountLimits)) _anchorPressureCountThreshold = value; }
        }

        /// <summary>
        /// The minimum pressure in decibars where anchoring can be tested against.
        /// </summary>
        public static double AnchorPressureMinimum
        {
            get { return _anchorPressureMinimum; }
            set { if (CheckDoubleValue(value, SurfacePressureLimits)) _anchorPressureMinimum = value; }
        }

        /// <summary>
        /// Maximum vertical velocity in decibars per second when
        /// determining if the system has reached bottom.
        /// </summary>
        public static double AnchorVelocityLimit
        {
            get { return _anchorVelocityLimit; }
            set { if (CheckDoubleValue(value, VelocityLimits)) _anchorVelocityLimit = value; }
        }

        /// <summary>
        /// Counts per second squared motor acceleration/deacceleration limit for Elmo Twitter
        /// </summary>
        // TODO P1 work into XML file
        public static int AccDeaccLimit
        {
            get { return _accDeaccLimit; }
            private set { _accDeaccLimit = value; }
        }
        /// <summary>
        /// Pressure difference in decibar we are willing to accept between pressure sensor
        /// updates to make sure we are properly anchored.
        /// </summary>
        public static double ExitAnchorPressureThreshold
        {
            get { return _exitAnchorPressureThreshold; }
            set { if (CheckDoubleValue(value,ExitAnchorLimits)) _exitAnchorPressureThreshold = value; }
        }

        /// <summary>
        /// Target pressure velocity (decibars/sec) when approaching a target depth.
        /// </summary>
        public static double ApproachVelocity
        {
            get { return _approachVelocity; }
            set { if (CheckDoubleValue(value, VelocityLimits)) _approachVelocity = value; }
        }

        /// <summary>
        /// CP mode stops below this pressure in deciBars
        /// </summary>
        public static double CpPressureCutoff
        {
            get { return _cpPressureCutoff; }
            set { if (CheckDoubleValue(value, CpPressureCutoffLimits))_cpPressureCutoff = value; }
        }

        /// <summary>
        /// run the pump for this many seconds before starting CP mode
        /// </summary>
        public static int CpRunPumpTime
        {
            get { return _cpRunPumpTime; }
            set { if (CheckIntValue(value, CpRunTimeLimits)) _cpRunPumpTime = value; }
        }

        /// <summary>
        /// Sample period for the SBE when in Sample mode in milliseconds.
        /// </summary>
        public static int SBE41CommandModeSamplePeriod
        {
            get { return _sbe41CommandModeSamplePeriod; }
            set { if (CheckIntValue(value,SBE41CommandPeriodLimits)) _sbe41CommandModeSamplePeriod = value; }
        } 

        /// <summary>
        /// Sample Period for the SBE CTD when in CP mode in milliseconds
        /// </summary>
        public static int SBE41CPSamplePeriod
        {
            get { return _sbe41CpSamplePeriod; }
            set { if (CheckIntValue(value, SBE41SamplePeriodLimits)) _sbe41CpSamplePeriod = value; }
        } 

        /// <summary>
        /// Puts SBE41 in CP mode during ascend states only.
        /// </summary>
        public static bool CPMode { get; set; } //Puts SBE41 in CP mode during ascend state only

        /// <summary>
        /// Verbosity level when printing messages to the console (0-5)
        /// </summary>
        public static int EngrLoggerVerbosityLevel
        {
            get { return _engrLoggerVerbosityLevel; }
            set { if (CheckIntValue(value,VerbosityLimits)) _engrLoggerVerbosityLevel = value; }
        }

        /// <summary>
        /// Verbosity level when printing messages to the debugger (0-5)
        /// </summary>
        public static int DebuggerVerbosityLevel
        {
            get { return _debuggerVerbosityLevel; }
            set { if (CheckIntValue(value,VerbosityLimits)) _debuggerVerbosityLevel = value; }
        }

        //System//

        /// <summary>
        /// Period of seconds between acquisition of core health
        /// data for the vehicle. 
        /// </summary>
        public static TimeSpan SystemDataSamplePeriod
        {
            get { return _systemDataSamplePeriod; }
        }

        /// <summary>
        /// Sets the period for checking mission critical system sensors.
        /// </summary>
        /// <param name="secs"></param>
        public static void SetSystemDataSamplePeriod(int secs)
        {
            if (!CheckIntValue(secs, SystemSamplePeriodLimits)) return;

            _systemDataSamplePeriod = new TimeSpan(0,0,secs);
        }


        /// <summary>
        /// Sets the value of the PremissionDelayPeriod timespan object. 
        /// </summary>
        /// <param name="secs"></param>
        public static void SetPreMissionDelayPeriod(int secs)
        {
            if (!CheckIntValue(secs, PremissionDelayLimits)) return;

            _preMissionDelayPeriod = new TimeSpan(0,0,secs);
        }


        /// <summary>
        /// Timespan of premission, limited to 20 minutes (1200 seconds)
        /// </summary>
        public static TimeSpan PreMissionDelayPeriod
        {
            get { return _preMissionDelayPeriod; }
        }

        private static bool CheckDoubleValue(double value, DoubleLimits limits)
        {
            return value >= limits.Min && value <= limits.Max;
        }

        private static bool CheckIntValue(int value, IntLimits limits)
        {
            return value >= limits.Min && value <= limits.Max;
        }

        #region CONSTANTS

        public static readonly TimeSpan smCyclePeriod = new TimeSpan(0, 0, 0, 1, 0); //msec

        public static readonly int smCyclePeriodMilliseconds =
            (int) (smCyclePeriod.Ticks / TimeSpan.TicksPerMillisecond);

        private struct IntLimits
        {
            public int Max;
            public int Min;
        }

        private struct DoubleLimits
        {
            public double Max;
            public double Min;
        }

        // Limits Definitions //
        private static readonly DoubleLimits BellowsLimits = new DoubleLimits() {Max = 100.0, Min = 0};
        private static readonly IntLimits JVLimits = new IntLimits() {Max = 200000, Min = -200000};
        private static readonly IntLimits VerbosityLimits = new IntLimits() {Max = 5, Min = 0};
        private static readonly DoubleLimits VelocityLimits = new DoubleLimits() {Min = -1, Max = 1.0};
        private static readonly DoubleLimits ExitAnchorLimits = new DoubleLimits() {Min = 1, Max = 10};
        private static readonly DoubleLimits SurfacePressureLimits = new DoubleLimits() {Min = 0, Max=10.0 };//decibars
        private static readonly IntLimits PremissionDelayLimits = new IntLimits() { Min = 0 ,Max = 1200 }; //seconds
        private static readonly IntLimits SystemSamplePeriodLimits = new IntLimits() {Min = 1, Max = 1200};//seconds
        private static readonly DoubleLimits CpPressureCutoffLimits = new DoubleLimits() {Min = 1.0, Max = 20.0}; //decibars
        private static readonly IntLimits CpRunTimeLimits = new IntLimits() {Min = 0, Max = 1200 };//seconds
        private static readonly IntLimits SBE41SamplePeriodLimits = new IntLimits() {Min = 1000, Max = 3000};//milliseconds
        private static readonly IntLimits SBE41CommandPeriodLimits = new IntLimits() {Min = 2600, Max = 60000};//milliseconds
        private static readonly IntLimits AnchorCountLimits = new IntLimits() {Min = 1, Max = 200};//counts
        private static readonly DoubleLimits DeanchorPressureMinimumLimits = new DoubleLimits() {Min = .1, Max = 10.0}; //decibars
        private static readonly IntLimits ParkMinuteLimits = new IntLimits() {Max = 1000, Min = 0};
        private static readonly IntLimits ParkHourLimits = new IntLimits() {Max = 100, Min = 0};
        private static readonly DoubleLimits ParkDepthLimits = new DoubleLimits() {Max = 125, Min = 0};



        // backing fields definitions //
        private static int _engrLoggerVerbosityLevel;
        private static int _debuggerVerbosityLevel;
        private static double _deanchorVelocityThreshold;
        private static double _deanchorVelocityLimit;
        private static double _anchorVelocityLimit;
        private static int _accDeaccLimit;
        private static double _approachVelocity;
        private static double _exitAnchorPressureThreshold;
        private static double _anchorPressureMinimum;
        private static double _abPressureThreshold;
        private static TimeSpan _preMissionDelayPeriod;
        private static double _cpPressureCutoff;
        private static int _cpRunPumpTime;
        private static int _sbe41CommandModeSamplePeriod;
        private static int _sbe41CpSamplePeriod;
        private static int _anchorPressureCountThreshold;
        private static TimeSpan _systemDataSamplePeriod;
        private static double _bellowsLowerLimit;
        private static double _rmSetBellowsPosition;
        private static double _soSetBellowsPosition;
        private static double _bellowsUpperLimit;
        private static int _abRetractFastJv;
        private static int _abRetractSlowJv;
        private static int _soSetBellowsJv;
        private static int _deanchorJv;
        private static int _stringPotDirection;
        private static double _deanchorPressureMinimum;
        private static int _deanchorPressureCountThreshold;
        private static int _missionParkSamplePeriodMinutes;
        private static double _stringPotInverseSlope;
        private static double _stringPotSlope;
        private static float _missionParkDepth;
        private static int _missionParkTimeHours;
        private static int _missionParkTimeMinutes;

        #endregion


        #region FILE_IO

        public static bool LoadConfig(string fname)
        {
            var sd = SDStorage.Instance;
            if (!File.Exists(fname))
            {
                EngrLogger.Comment("Configuration File Does Not Exist, Creating...");
                CreateDefaultConfigFile(fname);
                return true;
            }
            using (var stream = new FileStream(fname, FileMode.Open, FileAccess.Read, FileShare.None, 2048))
            {
                //var xmlSettings = new XmlReaderSettings()
                //{
                    //IgnoreComments = true,
                    //IgnoreWhitespace = true,
                    //IgnoreProcessingInstructions = false,
                //};
                using (XmlReader reader = XmlReader.Create(stream))
                {

                    var count = 0;
                    while (!reader.EOF && stream.CanRead)
                    {

                        try
                        {
                            reader.Read();
                            
                            count++;

                            if (reader.Name != "item")
                                continue;

                            string key = null;
                            string value = reader.GetAttribute("value");

                            try
                            {
                                switch (key = reader.GetAttribute("key").ToLower()) {
                                    case "name":
                                        PlatformName = value;
                                        break;
                                    case "engrlogverb":
                                        EngrLoggerVerbosityLevel = int.Parse(value);
                                        break;
                                    case "debuglogverb":
                                        DebuggerVerbosityLevel = int.Parse(value);
                                        break;
                                    case "sysdatasampperiod":
                                        SetSystemDataSamplePeriod(int.Parse(value));
                                        break;
                                    case "premissdelayperiod":
                                        SetPreMissionDelayPeriod(int.Parse(value));
                                        break;
                                    case "stringpotinverseslope":
                                        StringPotInverseSlope = double.Parse(value);
                                        break;
                                    case "stringpotint":
                                        StringPotIntercept = double.Parse(value);
                                        break;
                                    case "bellowslower":
                                        IBFillLowerLimit = double.Parse(value);
                                        break;
                                    case "bellowsupper":
                                        IBFillUpperLimit = double.Parse(value);
                                        break;
                                    case "sobellowspos":
                                        SOSetBellowsPosition = double.Parse(value);
                                        break;
                                    case "sobellowsjv":
                                        SOSetBellowsJV = int.Parse(value);
                                        break;
                                    case "rmbellowspos":
                                        RMSetBellowsPosition = double.Parse(value);
                                        break;
                                    case "abretfastjv":
                                        ABRetractFastJV = int.Parse(value);
                                        break;
                                    case "abretslowjv":
                                        ABRetractSlowJV = int.Parse(value);
                                        break;
                                    case "abpressthres":
                                        ABPressureThreshold = double.Parse(value);
                                        break;
                                    case "deanchorjv":
                                        DeanchorJV = int.Parse(value);
                                        break;
                                    case "deanchorvellim":
                                        DeanchorVelocityLimit = double.Parse(value);
                                        break;
                                    case "deanchorpressmin":
                                        DeanchorPressureMinimum = double.Parse(value);
                                        break;
                                    case "deanchorcount":
                                        DeanchorPressureCountThreshold = int.Parse(value);
                                        break;
                                    case "anchorcount":
                                        AnchorPressureCountThreshold = int.Parse(value);
                                        break;
                                    case "anchorpressmin":
                                        AnchorPressureMinimum = double.Parse(value);
                                        break;
                                    case "anchorvellim":
                                        AnchorVelocityLimit = double.Parse(value);
                                        break;
                                    case "exitanchorpressthres":
                                        ExitAnchorPressureThreshold = double.Parse(value);
                                        break;
                                    case "approachvel":
                                        ApproachVelocity = double.Parse(value);
                                        break;
                                    case "cppresscutoff":
                                        CpPressureCutoff = double.Parse(value);
                                        break;
                                    case "cprunpumptime":
                                        CpRunPumpTime = int.Parse(value);
                                        break;
                                    case "cpmode":
                                        CPMode = int.Parse(value) == 1;
                                        break;
                                    case "sbecomsampperiod":
                                        SBE41CPSamplePeriod = int.Parse(value);
                                        break;
                                    case "sbecpsampperiod":
                                        SBE41CPSamplePeriod = int.Parse(value);
                                        break; 
                                    case "parkdepth":
                                        MissionParkDepth = (float) double.Parse(value);
                                        break;
                                    case "parksampmin":
                                        MissionParkSamplePeriodMinutes = int.Parse(value);
                                        break;
                                    case "parktimehrs":
                                        MissionParkTimeHours = int.Parse(value);
                                        break;
                                    case "parktimemin":
                                        MissionParkTimeMinutes = int.Parse(value);
                                        break;

                                    default:
                                        throw new ArgumentException("Unknown item present in xml file: " + key);
                                }
                            }
                            catch (Exception err) {
                                EngrLogger.Comment(err.ToString());
                            }
                            //finally{ Debug.Print(key);}


                        }
                        catch (Exception e) {
                            EngrLogger.Comment(e.ToString());
                            // If we can't load a config, let's at least try to create one. 
                            EngrLogger.Comment("MissionConfig::LoadConfig: Error Loading config, creating new file.");
                            stream.Close();
                            CreateDefaultConfigFile(fname);
                        }
                    }
                    EngrLogger.Comment("Configuration load complete for file " + fname + ", " + count + " attributes loaded.");
                }
            }

            return true;
        }

        private static void CreateDefaultConfigFile(string fname)
        {
            // Check Directory Exists //
            if (!Directory.Exists(@"\SD\"))
            {
                EngrLogger.Comment("Cannot Create Config File, SD card not mounted.");
                return;
            }

            //using (var stream = new MemoryStream())
            using (var stream = new FileStream(fname, FileMode.Create, FileAccess.ReadWrite, FileShare.None,2048))
            {
                using (var xmlwrite = XmlWriter.Create(stream))
                {
                    xmlwrite.WriteProcessingInstruction("xml","version=\"1.0\" encoding=\"utf-8\"");
//                    xmlwrite.WriteComment("Automatically Generated by CPF Program");
                    xmlwrite.WriteStartElement("cpf");

                    AddItemToXml(xmlwrite,"name", PlatformName);
                    AddItemToXml(xmlwrite,"engrlogverb", EngrLoggerVerbosityLevel);
                    AddItemToXml(xmlwrite,"debuglogverb", DebuggerVerbosityLevel);
                    AddItemToXml(xmlwrite,"sysdatasampperiod", (int)(SystemDataSamplePeriod.Ticks/TimeSpan.TicksPerSecond));
                    AddItemToXml(xmlwrite,"premissdelayperiod", (int)(PreMissionDelayPeriod.Ticks/TimeSpan.TicksPerSecond));
                    AddItemToXml(xmlwrite,"stringpotinverseslope", StringPotInverseSlope);
                    AddItemToXml(xmlwrite,"stringpotint", StringPotIntercept);
                    AddItemToXml(xmlwrite,"bellowslower", IBFillLowerLimit);
                    AddItemToXml(xmlwrite,"bellowsupper",IBFillUpperLimit);
                    AddItemToXml(xmlwrite,"sobellowspos", SOSetBellowsPosition);
                    AddItemToXml(xmlwrite,"sobellowsjv", SOSetBellowsJV);
                    AddItemToXml(xmlwrite,"rmbellowspos", RMSetBellowsPosition);
                    AddItemToXml(xmlwrite,"abretfastjv", ABRetractFastJV);
                    AddItemToXml(xmlwrite,"abretslowjv",ABRetractSlowJV);
                    AddItemToXml(xmlwrite,"abpressthres", ABPressureThreshold);
                    AddItemToXml(xmlwrite,"deanchorjv",DeanchorJV);
                    AddItemToXml(xmlwrite,"deanchorvellim", DeanchorVelocityLimit);
                    AddItemToXml(xmlwrite,"deanchorpressmin", DeanchorPressureMinimum);
                    AddItemToXml(xmlwrite,"deanchorcount", DeanchorPressureCountThreshold);
                    AddItemToXml(xmlwrite,"anchorcount", AnchorPressureCountThreshold);
                    AddItemToXml(xmlwrite,"anchorpressmin", AnchorPressureMinimum);
                    AddItemToXml(xmlwrite,"anchorvellim", AnchorVelocityLimit);
                    AddItemToXml(xmlwrite,"exitanchorpressthres", ExitAnchorPressureThreshold);
                    AddItemToXml(xmlwrite,"approachvel", ApproachVelocity);
                    AddItemToXml(xmlwrite,"cppresscutoff", CpPressureCutoff);
                    AddItemToXml(xmlwrite,"cprunpumptime", CpRunPumpTime);
                    AddItemToXml(xmlwrite,"cpmode", CPMode?1:0);
                    AddItemToXml(xmlwrite,"sbecomsampperiod", SBE41CommandModeSamplePeriod);
                    AddItemToXml(xmlwrite,"sbecpsampperiod", SBE41CPSamplePeriod);
                    AddItemToXml(xmlwrite,"parkdepth", MissionParkDepth);
                    AddItemToXml(xmlwrite,"parksampmin", MissionParkSamplePeriodMinutes);
                    AddItemToXml(xmlwrite,"parktimehrs", MissionParkTimeHours);
                    AddItemToXml(xmlwrite,"parktimemin", MissionParkTimeMinutes);
                    xmlwrite.WriteEndElement();

                    xmlwrite.Flush();

                } //Ends XmlWriting
            } //Ends Filestream

            // Print File
            using (var stream = new FileStream(fname, FileMode.Open,FileAccess.Read, FileShare.None, 1890))
            {
                var b = new byte[1890];
                while (stream.Read(b, 0, b.Length) > 0)
                {
                    var ss = SafeEncoding.GetChars(b);
                    Debug.Print(new string(ss));
                    //Clear for next
                    Array.Clear(b,0,b.Length);
                }
            }
        }

        private static void AddItemToXml(XmlWriter writer, string key, string value)
        {
                    writer.WriteStartElement("item");
                    writer.WriteAttributeString("key",key);
                    writer.WriteAttributeString("value", value);
                    writer.WriteEndElement();
                    writer.Flush();
        }

        private static void AddItemToXml(XmlWriter writer, string key, int value) { AddItemToXml(writer,key,value.ToString()); }
        private static void AddItemToXml(XmlWriter writer, string key, double value) { AddItemToXml(writer,key,value.ToString("F2")); }


        #endregion

        public new static string ToString()
        {
            var builder = new StringBuilder(2000);
            const string crlf = "\r\n";
            builder.Append("MISSION CONFIGURATION").Append(crlf);
            builder.Append("Name:\t").Append(PlatformName).Append(crlf);
            builder.Append("StringPotInverseSlope:\t").Append(StringPotInverseSlope).Append(crlf);
            builder.Append("StringPotSlope:\t").Append(StringPotSlope).Append(crlf);
            builder.Append("StringPotIntercept:\t").Append(StringPotIntercept).Append(crlf);
            builder.Append("BellowsLowerLimit:\t").Append(IBFillLowerLimit).Append(crlf);
            builder.Append("BellowsUpperLimit:\t").Append(IBFillUpperLimit).Append(crlf);
            builder.Append("SOSetBellowsPosition:\t").Append(SOSetBellowsPosition).Append(crlf);
            builder.Append("SOSetBellowsJV:\t").Append(SOSetBellowsJV).Append(crlf);
            builder.Append("RMSetBellowsPosition:\t").Append(RMSetBellowsPosition).Append(crlf);
            builder.Append("ABRetractFastJV:\t").Append(ABRetractFastJV).Append(crlf);
            builder.Append("ABRetractSlowJV:\t").Append(ABRetractSlowJV).Append(crlf);
            builder.Append("ABPressureThreshold:\t").Append(ABPressureThreshold).Append(crlf);
            builder.Append("DeanchorJV:\t").Append(DeanchorJV).Append(crlf);
            builder.Append("DeanchorVelocityLimit:\t").Append(DeanchorVelocityLimit).Append(crlf);
            builder.Append("DeanchorPressureMinimum:\t").Append(DeanchorPressureMinimum).Append(crlf);
            builder.Append("DeanchorPressureCountThreshold:\t").Append(DeanchorPressureCountThreshold).Append(crlf);
            builder.Append("AnchorPressureCountThreshold:\t").Append(AnchorPressureCountThreshold).Append(crlf);
            builder.Append("AnchorPressureMinimum:\t").Append(AnchorPressureMinimum).Append(crlf);
            builder.Append("AnchorVelocityLimit:\t").Append(AnchorVelocityLimit).Append(crlf);
            builder.Append("ExitAnchorPressureThreshold:\t").Append(ExitAnchorPressureThreshold).Append(crlf);
            builder.Append("ApproachVelocity:\t").Append(ApproachVelocity).Append(crlf);
            builder.Append("CpPressureCutoff:\t").Append(CpPressureCutoff).Append(crlf);
            builder.Append("CpRunPumpTime:\t").Append(CpRunPumpTime).Append(crlf);
            builder.Append("SBE41CommandModeSamplePeriod:\t").Append(SBE41CommandModeSamplePeriod).Append(crlf);
            builder.Append("SBE41CPSamplePeriod:\t").Append(SBE41CPSamplePeriod).Append(crlf);
            builder.Append("CPMode:\t").Append(CPMode).Append(crlf);
            builder.Append("EngrLoggerVerbosityLevel:\t").Append(EngrLoggerVerbosityLevel).Append(crlf);
            builder.Append("DebuggerVerbosityLevel:\t").Append(DebuggerVerbosityLevel).Append(crlf);
            builder.Append("SystemDataSamplePeriod:\t").Append(SystemDataSamplePeriod).Append(crlf);
            builder.Append("PreMissionDelayPeriod:\t").Append(PreMissionDelayPeriod).Append(crlf);
            builder.Append("PreMissionDelayPeriod:\t").Append(PreMissionDelayPeriod).Append(crlf);
            builder.Append("MissionParkDepth:\t").Append(MissionParkDepth).Append(crlf);
            builder.Append("MissionParkSamplePeriodMinutes:\t").Append(MissionParkSamplePeriodMinutes).Append(crlf);
            builder.Append("MissionParkTimeHours:\t").Append(MissionParkTimeHours).Append(crlf);
            builder.Append("MissionParkTimeMinutes:\t").Append(MissionParkTimeMinutes).Append(crlf);

            return builder.ToString();
        }
    }
}