public DateTime CalculateLowerCutoffTime(Goal goal, decimal oldCurrentLevel, DateTime previousDoneItTime)
 {
     var hourdecr = GoalProcessor.GetHourlyDecreaseRate(goal);
     var lowerCutoff = goal.GetLowerCutoff();
     var hours = (oldCurrentLevel - lowerCutoff) / hourdecr;
     return previousDoneItTime.AddHours(Math.Abs(Convert.ToDouble(hours)));
 }
        public GoalViewModel ProcessGoal(Goal goal)
        {
            var vm = new GoalViewModel();
            vm.Status = GoalStatus.NotStarted;
            vm.Goal = goal;
            vm.Graph = new GraphViewModel();// gp.ProcessGraph(goal);
            //var timeFirstPoint = GraphProcessor.GetDateOfLastOrFirstGraphPoint(true, goal, _now);

            decimal currentLevel = 0;
            DateTime? previousDoneItTime = null;
            decimal perHour = GetHourlyDecreaseRate(goal);
            var cutoffLevel = goal.GetLowerCutoff();

            if (goal.DoneIts.Count > 0)
            {
                decimal oldCurrentLevel=0;
                foreach (var done in goal.DoneIts.OrderBy(d => d.Date))
                {
                    oldCurrentLevel = currentLevel;
                    if (previousDoneItTime == null)
                    {
                        // First doneit starts counting
                        currentLevel = done.Amount;
                        vm.Graph.AddPoint(done, oldCurrentLevel, currentLevel);
                    }
                    else
                    {
                        // Calculate current level
                        var dif = (done.Date - (DateTime)previousDoneItTime).TotalHours;
                        oldCurrentLevel = currentLevel - (perHour * Convert.ToDecimal(dif));
                        if (oldCurrentLevel < cutoffLevel)
                        {
                            // Add extra point at lower threshold
                            var cutoffTime = CalculateLowerCutoffTime(goal, currentLevel, previousDoneItTime.Value);

                            vm.Graph.Points.Add(new GraphPoint { Time = cutoffTime, Amount = 0, y = cutoffLevel });
                            oldCurrentLevel = cutoffLevel;
                        }

                        currentLevel = oldCurrentLevel + done.Amount;
                        vm.Graph.AddPoint(done, oldCurrentLevel, currentLevel);
                    }
                    previousDoneItTime = done.Date;
                }
                // Calculate current level
                var diff = (_now - (DateTime)previousDoneItTime).TotalHours;
                currentLevel -= (perHour * Convert.ToDecimal(diff));

                // Check for cutoff
                if (currentLevel < cutoffLevel)
                {
                    // Add extra point at lower threshold
                    var cutoffTime = CalculateLowerCutoffTime(goal, oldCurrentLevel, previousDoneItTime.Value);
                    vm.Graph.Points.Add(new GraphPoint { Time = cutoffTime, Amount = 0, y = cutoffLevel });
                    currentLevel = cutoffLevel;
                    vm.Cutoff = CutoffStatus.Active;
                }

                // Add current level
                vm.Graph.Points.Add(new GraphPoint { Time = _now, Amount = 0, y = currentLevel });

                vm.Status = currentLevel < 0 ? GoalStatus.Behind : GoalStatus.OnTrack;

                vm.AtZero = TimeSpan.FromHours(Convert.ToDouble(currentLevel / perHour));
                vm.CurrentLevel = currentLevel;
            }
            else
            {
                vm.Graph = GraphProcessor.CreateEmptyGraph(goal, _now);
            }

                var graph = vm.Graph;
                var first = graph.Points.OrderBy(x => x.Time).First().Time;
                var last = graph.Points.OrderBy(x => x.Time).Last().Time;
                var totalSecs = ((last - first).TotalSeconds);
                if (totalSecs > 0)
                {
                    foreach (var point in graph.Points)
                    {
                        point.x = Convert.ToDecimal((point.Time - first).TotalSeconds / totalSecs);
                    }
                }

            //GraphProcessor.CalculateXPositions(out vm);

            return vm;
        }