private void CalculateDistance(PaceData calcData)
        {
            if (!calcData.HasPace || !calcData.HasTime || calcData.Distance == null) return;

            var pace = 0; // pace in seconds / miles
            var pacePortions = calcData.Pace.Split(':');

            var paceMinutes = 0;
            var paceSeconds = 0;

            // mm or mm:ss
            if (pacePortions.Length == 1) // mm
            {
                int.TryParse(pacePortions[0], out paceMinutes);
            }
            else // mm:ss
            {
                int.TryParse(pacePortions[0], out paceMinutes);
                int.TryParse(pacePortions[1], out paceSeconds);
            }
            pace = (paceMinutes * 60) + paceSeconds;

            var time = 0; // seconds
            if (string.IsNullOrWhiteSpace(calcData.Time))
                return;

            var timePortions = calcData.Time.Split(':');

            var hours = 0;
            var minutes = 0;
            var seconds = 0;

            // mm or mm:ss or hh:mm:ss
            if (timePortions.Length == 1) // mm
            {
                int.TryParse(timePortions[0], out minutes);
            }
            else if (timePortions.Length == 2) // mm:ss
            {
                int.TryParse(timePortions[0], out minutes);
                int.TryParse(timePortions[1], out seconds);
            }
            else // hh:mm:ss
            {
                int.TryParse(timePortions[0], out hours);
                int.TryParse(timePortions[1], out minutes);
                int.TryParse(timePortions[2], out seconds);
            }
            time = (hours * 60 * 60) + (minutes * 60) + seconds;

            if (pace == 0 || time == 0) return;

            var distance = time / (double) pace;
            calcData.Distance = new Distance(distance, calcData.Distance.BaseUnits);
        }
        public void Given_5_min_per_mile_should_convert_to_8_min_km()
        {
            var calc = new PaceCalculator();
            var pace = new PaceData { Pace = "5:00", Calc = "pacemilesunits" };
            calc.Calculate(pace);
            Assert.AreEqual("8:02", pace.Pace); // 5 min/mile is actually a little over 8 min/km

            pace.Calc = "pacekmunits";
            calc.Calculate(pace);
            Assert.AreEqual("4:59", pace.Pace); // and then due to rounding, converting back gives just under 5min/mile
        }
            public RunLogModel(ControllerContext context, dynamic runLogEvent)
            {
                this.context = context;
                RunLogEvent = runLogEvent;

                TimeTaken = runLogEvent.TimeTaken;
                Route = ((object)RunLogEvent).Route();
                Distance = ((object)Route).Distance().ConvertTo(context.UserDistanceUnits());

                var paceData = new PaceData { Distance = Distance, Time = TimeTaken, Calc = "Pace" };
                var paceCalc = new PaceCalculator();
                paceCalc.Calculate(paceData);
                Pace = paceData;
            }
 public void Calculate(PaceData calcData)
 {
     switch ((calcData.Calc ?? "").ToLower())
     {
         case "distance":
             CalculateDistance(calcData);
             break;
         case "time":
             CalculateTime(calcData);
             break;
         case "pace":
             CalculatePace(calcData);
             break;
         case "pacekmunits":
             ConvertPace(calcData, DistanceUnits.Kilometers);
             break;
         case "pacemilesunits":
             ConvertPace(calcData, DistanceUnits.Miles);
             break;
         case "normalizetime":
             NormalizeTime(calcData);
             break;
     }
 }
        public ActionResult CalcPace(PaceData paceCalculation)
        {
            if (!ModelState.IsValid)
                return new JsonResult { Data = paceCalculation };

            Trace.TraceInformation("Calculating pace (route/dist/time/pace/calc): {0}/{1}/{2}/{3}/{4}", paceCalculation.Route, paceCalculation.Distance, paceCalculation.Time, paceCalculation.Pace, paceCalculation.Calc);
            if (paceCalculation.HasRoute)
            {
                var userUnits = paceCalculation.Distance.BaseUnits;
                var route = MassiveDB.Current.FindRoute(paceCalculation.Route.Value);
                if (route != null)
                    paceCalculation.Distance = new Distance(route.Distance, (DistanceUnits)route.DistanceUnits).ConvertTo(userUnits);
            }

            paceCalc.Calculate(paceCalculation);
            Trace.TraceInformation("Calculated pace (route/dist/time/pace/calc): {0}/{1}/{2}/{3}/{4}", paceCalculation.Route, paceCalculation.Distance, paceCalculation.Time, paceCalculation.Pace, paceCalculation.Calc);

            return new JsonResult { Data = paceCalculation };
        }
 private Tuple<Distance, PaceData, string> DistanceAndPaceOfLogEvent(dynamic runLogEvent)
 {
     var route = ((object)runLogEvent).Route();
     var distance = ((object)route).Distance().ConvertTo(ControllerContext.UserDistanceUnits());
     var paceData = new PaceData { Distance = distance, Time = runLogEvent.TimeTaken, Calc = "Pace" };
     var paceCalc = new PaceCalculator();
     paceCalc.Calculate(paceData);
     return Tuple.Create(distance, paceData, route.Name.Replace('"', '\''));
 }
        private void CalculatePace(PaceData calcData)
        {
            calcData.Pace = "0";

            if (!calcData.HasDistance || !calcData.HasTime) return;

            if (!calcData.HasDistance)
                return;
            var distance = calcData.Distance.BaseDistance; // distance in user's units

            var time = 0; // seconds
            if (string.IsNullOrWhiteSpace(calcData.Time))
                return;

            var timePortions = calcData.Time.Split(':');

            var hours = 0;
            var minutes = 0;
            var seconds = 0;

            // mm or mm:ss or hh:mm:ss
            if (timePortions.Length == 1) // mm
            {
                int.TryParse(timePortions[0], out minutes);
            }
            else if (timePortions.Length == 2) // mm:ss
            {
                int.TryParse(timePortions[0], out minutes);
                int.TryParse(timePortions[1], out seconds);
            }
            else // hh:mm:ss
            {
                int.TryParse(timePortions[0], out hours);
                int.TryParse(timePortions[1], out minutes);
                int.TryParse(timePortions[2], out seconds);
            }
            time = (hours * 60 * 60) + (minutes * 60) + seconds;

            if (time == 0 || distance == 0) return;

            calcData.PaceInSeconds = time / distance;
            calcData.Pace = PaceToString(calcData.PaceInSeconds.Value);
        }
        private void NormalizeTime(PaceData calcData)
        {
            if (!calcData.HasTime) return;

            var time = 0; // seconds
            if (string.IsNullOrWhiteSpace(calcData.Time))
                return;

            var timePortions = calcData.Time.Split(':');

            var hours = 0;
            var minutes = 0;
            var seconds = 0;

            // mm or mm:ss or hh:mm:ss
            if (timePortions.Length == 1) // mm
            {
                int.TryParse(timePortions[0], out minutes);
            }
            else if (timePortions.Length == 2) // mm:ss
            {
                int.TryParse(timePortions[0], out minutes);
                int.TryParse(timePortions[1], out seconds);
            }
            else // hh:mm:ss
            {
                int.TryParse(timePortions[0], out hours);
                int.TryParse(timePortions[1], out minutes);
                int.TryParse(timePortions[2], out seconds);
            }
            time = (hours * 60 * 60) + (minutes * 60) + seconds;
            var timeVal = TimeSpan.FromSeconds(time);
            calcData.Time = timeVal.ToString(timeVal.TotalHours > 0 ? "hh\\:mm\\:ss" : "mm\\:ss");
        }
        private void ConvertPace(PaceData calcData, DistanceUnits fromUnits)
        {
            if (!calcData.HasPace) return;

            double pace = 0; // pace in seconds / miles
            var pacePortions = calcData.Pace.Split(':');

            var paceMinutes = 0;
            var paceSeconds = 0;

            // mm or mm:ss
            if (pacePortions.Length == 1) // mm
            {
                int.TryParse(pacePortions[0], out paceMinutes);
            }
            else // mm:ss
            {
                int.TryParse(pacePortions[0], out paceMinutes);
                int.TryParse(pacePortions[1], out paceSeconds);
            }
            pace = (paceMinutes * 60) + paceSeconds;

            if (fromUnits == DistanceUnits.Miles)
                pace *= DistanceCalculator.MilesToKilometers;
            else if (fromUnits == DistanceUnits.Kilometers)
                pace *= DistanceCalculator.KilometersToMiles;
            else return;

            calcData.Pace = string.Format("{0}:{1}", Convert.ToInt32(Math.Floor(pace / 60)).ToString("0"), Math.Floor(pace % 60).ToString("00"));
        }
        private void CalculateTime(PaceData calcData)
        {
            calcData.Time = "0";

            if (!calcData.HasDistance || !calcData.HasPace) return;

            var pace = 0; // pace in seconds / miles
            var pacePortions = calcData.Pace.Split(':');

            var paceMinutes = 0;
            var paceSeconds = 0;

            // mm or mm:ss
            if (pacePortions.Length == 1) // mm
            {
                int.TryParse(pacePortions[0], out paceMinutes);
            }
            else // mm:ss
            {
                int.TryParse(pacePortions[0], out paceMinutes);
                int.TryParse(pacePortions[1], out paceSeconds);
            }
            pace = (paceMinutes * 60) + paceSeconds;

            if (!calcData.HasDistance)
                return;
            var distance = calcData.Distance.BaseDistance; // distance in user units

            if (pace == 0 || distance == 0) return;

            calcData.Time = TimeSpan.FromSeconds(distance * pace).ToString("hh\\:mm\\:ss");
        }