public static IDuration Create(IDuration.DurationType type, RegularStep parent)
        {
            IDuration newDuration;

            switch (type)
            {
                case IDuration.DurationType.LapButton:
                    {
                        newDuration = new LapButtonDuration(parent);
                        break;
                    }
                case IDuration.DurationType.Time:
                    {
                        newDuration = new TimeDuration(parent);
                        break;
                    }
                case IDuration.DurationType.Distance:
                    {
                        newDuration = new DistanceDuration(parent);
                        break;
                    }
                case IDuration.DurationType.HeartRateAbove:
                    {
                        newDuration = new HeartRateAboveDuration(parent);
                        break;
                    }
                case IDuration.DurationType.HeartRateBelow:
                    {
                        newDuration = new HeartRateBelowDuration(parent);
                        break;
                    }
                case IDuration.DurationType.Calories:
                    {
                        newDuration = new CaloriesDuration(parent);
                        break;
                    }
                case IDuration.DurationType.PowerAbove:
                    {
                        newDuration = new PowerAboveDuration(parent);
                        break;
                    }
                case IDuration.DurationType.PowerBelow:
                    {
                        newDuration = new PowerBelowDuration(parent);
                        break;
                    }
                default:
                    {
                        Debug.Assert(false);
                        newDuration = null;
                        break;
                    }
            }

            parent.Duration = newDuration;

            return newDuration;
        }
        public void TestTCXSerialization()
        {
            XmlDocument testDocument = new XmlDocument();
            XmlNode database;
            XmlAttribute attribute;
            Workout placeholderWorkout = new Workout("Test", PluginMain.GetApplication().Logbook.ActivityCategories[0]);
            RegularStep placeholderStep = new RegularStep(placeholderWorkout);

            // Setup document
            testDocument.AppendChild(testDocument.CreateXmlDeclaration("1.0", "UTF-8", "no"));
            database = testDocument.CreateNode(XmlNodeType.Element, "TrainingCenterDatabase", null);
            testDocument.AppendChild(database);
            attribute = testDocument.CreateAttribute("xmlns", "xsi", GarminFitnessPlugin.Constants.xmlns);
            attribute.Value = "http://www.w3.org/2001/XMLSchema-instance";
            database.Attributes.Append(attribute);

            // Lap button
            LapButtonDuration lapDuration = new LapButtonDuration(placeholderStep);
            lapDuration.Serialize(database, "LapDuration", testDocument);
            int durationPosition1 = testDocument.InnerXml.IndexOf(lapDurationResult);
            Assert.GreaterOrEqual(durationPosition1, 0, "Invalid lap duration serialization");

            // Time
            TimeDuration timeDuration = new TimeDuration(500, placeholderStep);
            timeDuration.Serialize(database, "TimeDuration1", testDocument);
            durationPosition1 = testDocument.InnerXml.IndexOf(timeDurationResult1);
            Assert.GreaterOrEqual(durationPosition1, 0, "Invalid time duration serialization");

            timeDuration.TimeInSeconds = 300;
            timeDuration.Serialize(database, "TimeDuration2", testDocument);
            int durationPosition2 = testDocument.InnerXml.IndexOf(timeDurationResult2);
            Assert.GreaterOrEqual(durationPosition2, 0, "Invalid time duration serialization");
            Assert.Greater(durationPosition2, durationPosition1, "Time durations serialization don't differ");

            // Distance
            DistanceDuration distanceDuration = new DistanceDuration(1, Length.Units.Kilometer, placeholderStep);
            distanceDuration.Serialize(database, "DistanceDuration1", testDocument);
            durationPosition1 = testDocument.InnerXml.IndexOf(distanceDurationResult1);
            Assert.GreaterOrEqual(durationPosition1, 0, "Invalid distance duration serialization");

            distanceDuration = new DistanceDuration(1, Length.Units.Mile, placeholderStep);
            distanceDuration.Serialize(database, "DistanceDuration2", testDocument);
            durationPosition2 = testDocument.InnerXml.IndexOf(distanceDurationResult2);
            Assert.GreaterOrEqual(durationPosition2, 0, "Invalid distance duration serialization");
            Assert.Greater(durationPosition2, durationPosition1, "Distance durations serialization don't differ");

            // Calories
            CaloriesDuration caloriesDuration = new CaloriesDuration(550, placeholderStep);
            caloriesDuration.Serialize(database, "CaloriesDuration1", testDocument);
            durationPosition1 = testDocument.InnerXml.IndexOf(caloriesDurationResult1);
            Assert.GreaterOrEqual(durationPosition1, 0, "Invalid calories duration serialization");

            caloriesDuration.CaloriesToSpend = 100;
            caloriesDuration.Serialize(database, "CaloriesDuration2", testDocument);
            durationPosition2 = testDocument.InnerXml.IndexOf(caloriesDurationResult2);
            Assert.GreaterOrEqual(durationPosition2, 0, "Invalid calories duration serialization");
            Assert.Greater(durationPosition2, durationPosition1, "Calories durations serialization don't differ");

            // HR Above
            HeartRateAboveDuration hrAboveDuration = new HeartRateAboveDuration(160, false, placeholderStep);
            hrAboveDuration.Serialize(database, "HRAboveDuration1", testDocument);
            durationPosition1 = testDocument.InnerXml.IndexOf(hrAboveDurationResult1);
            Assert.GreaterOrEqual(durationPosition1, 0, "Invalid HRAbove duration serialization");

            hrAboveDuration.MaxHeartRate = 130;
            hrAboveDuration.Serialize(database, "HRAboveDuration2", testDocument);
            durationPosition2 = testDocument.InnerXml.IndexOf(hrAboveDurationResult2);
            Assert.GreaterOrEqual(durationPosition2, 0, "Invalid HRAbove duration serialization");
            Assert.Greater(durationPosition2, durationPosition1, "HRAbove durations serialization don't differ");

            hrAboveDuration.IsPercentageMaxHeartRate = true;
            hrAboveDuration.MaxHeartRate = 50;
            hrAboveDuration.Serialize(database, "HRAboveDuration3", testDocument);
            durationPosition1 = testDocument.InnerXml.IndexOf(hrAboveDurationResult3);
            Assert.GreaterOrEqual(durationPosition1, 0, "Invalid HRAbove %Max duration serialization");

            hrAboveDuration.MaxHeartRate = 70;
            hrAboveDuration.Serialize(database, "HRAboveDuration4", testDocument);
            durationPosition2 = testDocument.InnerXml.IndexOf(hrAboveDurationResult4);
            Assert.GreaterOrEqual(durationPosition2, 0, "Invalid HRAbove duration serialization");
            Assert.Greater(durationPosition2, durationPosition1, "HRAbove %Max durations serialization don't differ");

            // HR Below
            HeartRateBelowDuration hrBelowDuration = new HeartRateBelowDuration(160, false, placeholderStep);
            hrBelowDuration.Serialize(database, "HRBelowDuration1", testDocument);
            durationPosition1 = testDocument.InnerXml.IndexOf(hrBelowDurationResult1);
            Assert.GreaterOrEqual(durationPosition1, 0, "Invalid HRBelow duration serialization");

            hrBelowDuration.MinHeartRate = 130;
            hrBelowDuration.Serialize(database, "HRBelowDuration2", testDocument);
            durationPosition2 = testDocument.InnerXml.IndexOf(hrBelowDurationResult2);
            Assert.GreaterOrEqual(durationPosition2, 0, "Invalid HRBelow duration serialization");
            Assert.Greater(durationPosition2, durationPosition1, "HRBelow durations serialization don't differ");

            hrBelowDuration.IsPercentageMaxHeartRate = true;
            hrBelowDuration.MinHeartRate = 50;
            hrBelowDuration.Serialize(database, "HRBelowDuration3", testDocument);
            durationPosition1 = testDocument.InnerXml.IndexOf(hrBelowDurationResult3);
            Assert.GreaterOrEqual(durationPosition1, 0, "Invalid HRBelow %Max duration serialization");

            hrBelowDuration.MinHeartRate = 70;
            hrBelowDuration.Serialize(database, "HRBelowDuration4", testDocument);
            durationPosition2 = testDocument.InnerXml.IndexOf(hrBelowDurationResult4);
            Assert.GreaterOrEqual(durationPosition2, 0, "Invalid HRBelow duration serialization");
            Assert.Greater(durationPosition2, durationPosition1, "HRBelow %Max durations serialization don't differ");

            // Power Above
            try
            {
                PowerAboveDuration powerAboveDuration = new PowerAboveDuration(160, false, placeholderStep);
                powerAboveDuration.Serialize(database, "PowerAboveDuration1", testDocument);
                Assert.Fail("PowerAbove duration was serialized in TCX");
            }
            catch (NotSupportedException)
            {
            }

            // Power Below
            try
            {
                PowerBelowDuration powerBelowDuration = new PowerBelowDuration(160, false, placeholderStep);
                powerBelowDuration.Serialize(database, "PowerBelowDuration1", testDocument);
                Assert.Fail("PowerBelow duration was serialized in TCX");
            }
            catch (NotSupportedException)
            {
            }
        }
        public void TestFITSerialization()
        {
            Workout placeholderWorkout = new Workout("Test", PluginMain.GetApplication().Logbook.ActivityCategories[0]);
            RegularStep placeholderStep = new RegularStep(placeholderWorkout);
            FITMessage serializedMessage = new FITMessage(FITGlobalMessageIds.WorkoutStep);
            FITMessageField messageField;

            // Lap button
            LapButtonDuration lapDuration = new LapButtonDuration(placeholderStep);
            lapDuration.FillFITStepMessage(serializedMessage);
            messageField = serializedMessage.GetField((Byte)FITWorkoutStepFieldIds.DurationType);
            Assert.IsNotNull(messageField, "Duration type field not serialized for lap button duration");
            Assert.AreEqual(FITWorkoutStepDurationTypes.Open, (FITWorkoutStepDurationTypes)messageField.GetEnum(), "Invalid duration type in field for lap button duration");
            serializedMessage.Clear();

            // Time duration
            TimeDuration timeDuration = new TimeDuration(500, placeholderStep);
            timeDuration.FillFITStepMessage(serializedMessage);
            messageField = serializedMessage.GetField((Byte)FITWorkoutStepFieldIds.DurationType);
            Assert.IsNotNull(messageField, "Duration type field not serialized for time duration");
            Assert.AreEqual(FITWorkoutStepDurationTypes.Time, (FITWorkoutStepDurationTypes)messageField.GetEnum(), "Invalid duration type in field for time duration");
            messageField = serializedMessage.GetField((Byte)FITWorkoutStepFieldIds.DurationValue);
            Assert.IsNotNull(messageField, "Duration type field not serialized for time duration");
            Assert.AreEqual(500000, messageField.GetUInt32(), "Invalid duration type in field for time duration");
            serializedMessage.Clear();

            timeDuration.TimeInSeconds = 15;
            timeDuration.FillFITStepMessage(serializedMessage);
            messageField = serializedMessage.GetField((Byte)FITWorkoutStepFieldIds.DurationType);
            Assert.IsNotNull(messageField, "Duration type field not serialized for time duration");
            Assert.AreEqual(FITWorkoutStepDurationTypes.Time, (FITWorkoutStepDurationTypes)messageField.GetEnum(), "Invalid duration type in field for time duration");
            messageField = serializedMessage.GetField((Byte)FITWorkoutStepFieldIds.DurationValue);
            Assert.IsNotNull(messageField, "Duration type field not serialized for time duration");
            Assert.AreEqual(15000, messageField.GetUInt32(), "Invalid duration type in field for time duration");
            serializedMessage.Clear();

            // Distance duration
            DistanceDuration distanceDuration = new DistanceDuration(1000, Length.Units.Centimeter, placeholderStep);
            distanceDuration.FillFITStepMessage(serializedMessage);
            messageField = serializedMessage.GetField((Byte)FITWorkoutStepFieldIds.DurationType);
            Assert.IsNotNull(messageField, "Duration type field not serialized for time duration");
            Assert.AreEqual(FITWorkoutStepDurationTypes.Distance, (FITWorkoutStepDurationTypes)messageField.GetEnum(), "Invalid duration type in field for distance duration");
            messageField = serializedMessage.GetField((Byte)FITWorkoutStepFieldIds.DurationValue);
            Assert.IsNotNull(messageField, "Duration type field not serialized for distance duration");
            Assert.AreEqual(1000, messageField.GetUInt32(), "Invalid duration value in field for distance duration");
            serializedMessage.Clear();

            distanceDuration = new DistanceDuration(15, Length.Units.NauticalMile, placeholderStep);
            distanceDuration.FillFITStepMessage(serializedMessage);
            messageField = serializedMessage.GetField((Byte)FITWorkoutStepFieldIds.DurationType);
            Assert.IsNotNull(messageField, "Duration type field not serialized for time duration");
            Assert.AreEqual(FITWorkoutStepDurationTypes.Distance, (FITWorkoutStepDurationTypes)messageField.GetEnum(), "Invalid duration type in field for distance duration");
            messageField = serializedMessage.GetField((Byte)FITWorkoutStepFieldIds.DurationValue);
            Assert.IsNotNull(messageField, "Duration type field not serialized for distance duration");
            Assert.AreEqual(2778000, messageField.GetUInt32(), "Invalid duration value in field for distance duration");
            serializedMessage.Clear();

            // Calories duration
            CaloriesDuration caloriesDuration = new CaloriesDuration(1000, placeholderStep);
            caloriesDuration.FillFITStepMessage(serializedMessage);
            messageField = serializedMessage.GetField((Byte)FITWorkoutStepFieldIds.DurationType);
            Assert.IsNotNull(messageField, "Duration type field not serialized for time duration");
            Assert.AreEqual(FITWorkoutStepDurationTypes.Calories, (FITWorkoutStepDurationTypes)messageField.GetEnum(), "Invalid duration type in field for calories duration");
            messageField = serializedMessage.GetField((Byte)FITWorkoutStepFieldIds.DurationValue);
            Assert.IsNotNull(messageField, "Duration type field not serialized for calories duration");
            Assert.AreEqual(1000, messageField.GetUInt32(), "Invalid duration value in field for calories duration");
            serializedMessage.Clear();

            caloriesDuration.CaloriesToSpend = 452;
            caloriesDuration.FillFITStepMessage(serializedMessage);
            messageField = serializedMessage.GetField((Byte)FITWorkoutStepFieldIds.DurationType);
            Assert.IsNotNull(messageField, "Duration type field not serialized for time duration");
            Assert.AreEqual(FITWorkoutStepDurationTypes.Calories, (FITWorkoutStepDurationTypes)messageField.GetEnum(), "Invalid duration type in field for calories duration");
            messageField = serializedMessage.GetField((Byte)FITWorkoutStepFieldIds.DurationValue);
            Assert.IsNotNull(messageField, "Duration type field not serialized for calories duration");
            Assert.AreEqual(452, messageField.GetUInt32(), "Invalid duration value in field for calories duration");
            serializedMessage.Clear();

            // HR Above
            HeartRateAboveDuration hrAboveDuration = new HeartRateAboveDuration(145, false, placeholderStep);
            hrAboveDuration.FillFITStepMessage(serializedMessage);
            messageField = serializedMessage.GetField((Byte)FITWorkoutStepFieldIds.DurationType);
            Assert.IsNotNull(messageField, "Duration type field not serialized for HRAbove duration");
            Assert.AreEqual(FITWorkoutStepDurationTypes.HeartRateGreaterThan, (FITWorkoutStepDurationTypes)messageField.GetEnum(), "Invalid duration type in field for HRAbove duration");
            messageField = serializedMessage.GetField((Byte)FITWorkoutStepFieldIds.DurationValue);
            Assert.IsNotNull(messageField, "Duration type field not serialized for HRAbove duration");
            Assert.AreEqual(245, messageField.GetUInt32(), "Invalid duration value in field for HRAbove duration");
            serializedMessage.Clear();

            hrAboveDuration = new HeartRateAboveDuration(75, true, placeholderStep);
            hrAboveDuration.FillFITStepMessage(serializedMessage);
            messageField = serializedMessage.GetField((Byte)FITWorkoutStepFieldIds.DurationType);
            Assert.IsNotNull(messageField, "Duration type field not serialized for HRAbove duration");
            Assert.AreEqual(FITWorkoutStepDurationTypes.HeartRateGreaterThan, (FITWorkoutStepDurationTypes)messageField.GetEnum(), "Invalid duration type in field for HRAbove duration");
            messageField = serializedMessage.GetField((Byte)FITWorkoutStepFieldIds.DurationValue);
            Assert.IsNotNull(messageField, "Duration type field not serialized for HRAbove duration");
            Assert.AreEqual(75, messageField.GetUInt32(), "Invalid duration value in field for HRAbove duration");
            serializedMessage.Clear();

            // HR Below
            HeartRateBelowDuration hrBelowDuration = new HeartRateBelowDuration(145, false, placeholderStep);
            hrBelowDuration.FillFITStepMessage(serializedMessage);
            messageField = serializedMessage.GetField((Byte)FITWorkoutStepFieldIds.DurationType);
            Assert.IsNotNull(messageField, "Duration type field not serialized for HRBelow duration");
            Assert.AreEqual(FITWorkoutStepDurationTypes.HeartRateLessThan, (FITWorkoutStepDurationTypes)messageField.GetEnum(), "Invalid duration type in field for HRBelow duration");
            messageField = serializedMessage.GetField((Byte)FITWorkoutStepFieldIds.DurationValue);
            Assert.IsNotNull(messageField, "Duration type field not serialized for HRBelow duration");
            Assert.AreEqual(245, messageField.GetUInt32(), "Invalid duration value in field for HRBelow duration");
            serializedMessage.Clear();

            hrBelowDuration = new HeartRateBelowDuration(55, true, placeholderStep);
            hrBelowDuration.FillFITStepMessage(serializedMessage);
            messageField = serializedMessage.GetField((Byte)FITWorkoutStepFieldIds.DurationType);
            Assert.IsNotNull(messageField, "Duration type field not serialized for HRBelow duration");
            Assert.AreEqual(FITWorkoutStepDurationTypes.HeartRateLessThan, (FITWorkoutStepDurationTypes)messageField.GetEnum(), "Invalid duration type in field for HRBelow duration");
            messageField = serializedMessage.GetField((Byte)FITWorkoutStepFieldIds.DurationValue);
            Assert.IsNotNull(messageField, "Duration type field not serialized for HRBelow duration");
            Assert.AreEqual(55, messageField.GetUInt32(), "Invalid duration value in field for HRBelow duration");
            serializedMessage.Clear();

            // Power Above
            PowerAboveDuration powerAboveDuration = new PowerAboveDuration(150, false, placeholderStep);
            powerAboveDuration.FillFITStepMessage(serializedMessage);
            messageField = serializedMessage.GetField((Byte)FITWorkoutStepFieldIds.DurationType);
            Assert.IsNotNull(messageField, "Duration type field not serialized for PowerAbove duration");
            Assert.AreEqual(FITWorkoutStepDurationTypes.PowerGreaterThan, (FITWorkoutStepDurationTypes)messageField.GetEnum(), "Invalid duration type in field for PowerAbove duration");
            messageField = serializedMessage.GetField((Byte)FITWorkoutStepFieldIds.DurationValue);
            Assert.IsNotNull(messageField, "Duration type field not serialized for PowerAbove duration");
            Assert.AreEqual(1150, messageField.GetUInt32(), "Invalid duration value in field for PowerAbove duration");
            serializedMessage.Clear();

            powerAboveDuration = new PowerAboveDuration(150, true, placeholderStep);
            powerAboveDuration.FillFITStepMessage(serializedMessage);
            messageField = serializedMessage.GetField((Byte)FITWorkoutStepFieldIds.DurationType);
            Assert.IsNotNull(messageField, "Duration type field not serialized for PowerAbove duration");
            Assert.AreEqual(FITWorkoutStepDurationTypes.PowerGreaterThan, (FITWorkoutStepDurationTypes)messageField.GetEnum(), "Invalid duration type in field for PowerAbove duration");
            messageField = serializedMessage.GetField((Byte)FITWorkoutStepFieldIds.DurationValue);
            Assert.IsNotNull(messageField, "Duration type field not serialized for PowerAbove duration");
            Assert.AreEqual(150, messageField.GetUInt32(), "Invalid duration value in field for PowerAbove duration");
            serializedMessage.Clear();

            // Power Below
            PowerBelowDuration powerBelowDuration = new PowerBelowDuration(175, false, placeholderStep);
            powerBelowDuration.FillFITStepMessage(serializedMessage);
            messageField = serializedMessage.GetField((Byte)FITWorkoutStepFieldIds.DurationType);
            Assert.IsNotNull(messageField, "Duration type field not serialized for PowerBelow duration");
            Assert.AreEqual(FITWorkoutStepDurationTypes.PowerLessThan, (FITWorkoutStepDurationTypes)messageField.GetEnum(), "Invalid duration type in field for PowerBelow duration");
            messageField = serializedMessage.GetField((Byte)FITWorkoutStepFieldIds.DurationValue);
            Assert.IsNotNull(messageField, "Duration type field not serialized for PowerBelow duration");
            Assert.AreEqual(1175, messageField.GetUInt32(), "Invalid duration value in field for PowerBelow duration");
            serializedMessage.Clear();

            powerBelowDuration = new PowerBelowDuration(60, true, placeholderStep);
            powerBelowDuration.FillFITStepMessage(serializedMessage);
            messageField = serializedMessage.GetField((Byte)FITWorkoutStepFieldIds.DurationType);
            Assert.IsNotNull(messageField, "Duration type field not serialized for PowerBelow duration");
            Assert.AreEqual(FITWorkoutStepDurationTypes.PowerLessThan, (FITWorkoutStepDurationTypes)messageField.GetEnum(), "Invalid duration type in field for PowerBelow duration");
            messageField = serializedMessage.GetField((Byte)FITWorkoutStepFieldIds.DurationValue);
            Assert.IsNotNull(messageField, "Duration type field not serialized for PowerBelow duration");
            Assert.AreEqual(60, messageField.GetUInt32(), "Invalid duration value in field for PowerBelow duration");
            serializedMessage.Clear();
        }