1: public class WorkoutController
2: {
3: private List<Checkpoint> m_checkpoints;
4: private Dictionary<int, UIElement> m_graphSegments;
5: private readonly DispatcherTimer m_timer;
6: private readonly IWorkoutInfoView m_workoutInfoView;
7:
8: private bool m_workoutLoaded;
9: private DateTime m_workoutStartTime;
10: private Rectangle progress;
11:
12: private int m_previousCheckpointIndex = -1;
13: private bool m_workoutStarted;
14:
15: public WorkoutController(IWorkoutInfoView workoutInfoView)
16: {
17: m_workoutInfoView = workoutInfoView;
18:
19: m_timer = new DispatcherTimer();
20: m_timer.Interval = new TimeSpan(0, 0, 0, 0, 500);
21: m_timer.Tick += new EventHandler(m_timer_Tick);
22: }
23:
24: public void LoadProgram(string uri)
25: {
26: XDocument doc = new XDocument();
27: doc = XDocument.Load(uri);
28: int i = 0;
29: var checkpoints = from checkpoint in doc.Descendants("workout").Descendants("checkpoint")
30: select new Checkpoint()
31: {
32: Time = int.Parse(checkpoint.Attribute("time").Value),
33: Speed = double.Parse(checkpoint.Attribute("speed").Value),
34: Incline = double.Parse(checkpoint.Attribute("incline").Value),
35: Index = i++
36: };
37:
38: m_checkpoints = checkpoints.ToList();
39: m_workoutLoaded = true;
40:
41: BuildWorkoutGraph();
42: }
43:
44:
45: private void BuildWorkoutGraph()
46: {
47: m_graphSegments = new Dictionary<int, UIElement>();
48: int totalTime = (int)GetProgramDuration().TotalSeconds;
49: Grid graphGrid = new Grid();
50:
51: // Progress
52: progress = new Rectangle();
53: progress.Width = 0;
54: progress.Height = m_workoutInfoView.WorkoutGraphContainer.ActualHeight;
55: progress.Margin = new Thickness(5);
56: progress.Style = App.Current.Resources["ProgressGraphRectangle"] as Style;
57: progress.HorizontalAlignment = HorizontalAlignment.Left;
58:
59: // Speeds
60: StackPanel speedGraph = new StackPanel();
61: speedGraph.VerticalAlignment = VerticalAlignment.Bottom;
62: speedGraph.Orientation = Orientation.Horizontal;
63: speedGraph.Margin = new Thickness(5);
64: int i = 0;
65: foreach (var checkpoint in m_checkpoints)
66: {
67: Rectangle r = new Rectangle();
68: r.VerticalAlignment = VerticalAlignment.Bottom;
69: r.Height = (checkpoint.Speed / 10) * m_workoutInfoView.WorkoutGraphContainer.ActualHeight;
70: r.Width = ((double)checkpoint.Time / totalTime) * m_workoutInfoView.WorkoutGraphContainer.ActualWidth;
71: r.Style = App.Current.Resources["SpeedGraphRectangle"] as Style;
72: r.SetValue(Rectangle.NameProperty, "GraphRect_" + i++);
73: speedGraph.Children.Add(r);
74: m_graphSegments.Add(checkpoint.Index, r);
75: }
76:
77: // Inclines
78: StackPanel inclineGraph = new StackPanel();
79: inclineGraph.VerticalAlignment = VerticalAlignment.Bottom;
80: inclineGraph.Orientation = Orientation.Horizontal;
81: inclineGraph.Margin = new Thickness(5);
82: foreach (var checkpoint in m_checkpoints)
83: {
84: Rectangle r = new Rectangle();
85: r.VerticalAlignment = VerticalAlignment.Bottom;
86: r.Height = (checkpoint.Incline / 10) * m_workoutInfoView.WorkoutGraphContainer.ActualHeight;
87: r.Width = ((double)checkpoint.Time / totalTime) * m_workoutInfoView.WorkoutGraphContainer.ActualWidth;
88: r.Style = App.Current.Resources["InclineGraphRectangle"] as Style;
89: inclineGraph.Children.Add(r);
90: }
91:
92: Rectangle background = new Rectangle();
93: background.Fill = new SolidColorBrush(Colors.Black);
94: background.Opacity = 0.3;
95: background.Stretch = Stretch.UniformToFill;
96:
97: graphGrid.Children.Add(background);
98: graphGrid.Children.Add(progress);
99: graphGrid.Children.Add(speedGraph);
100: graphGrid.Children.Add(inclineGraph);
101:
102:
103: if (m_workoutInfoView.WorkoutGraphContainer.Children.Count > 0)
104: m_workoutInfoView.WorkoutGraphContainer.Children.RemoveAt(0);
105: m_workoutInfoView.WorkoutGraphContainer.Children.Add(graphGrid);
106: }
107:
108: void m_timer_Tick(object sender, EventArgs e)
109: {
110: TimeSpan ts = DateTime.Now - m_workoutStartTime;
111: TimeSpan remaining = GetProgramDuration() - ts;
112:
113: if (remaining.Seconds < 0)
114: {
115: StopProgram();
116: return;
117: }
118:
119: m_workoutInfoView.WorkoutDuration = ts;
120: m_workoutInfoView.WorkoutTimeRemaining = remaining;
121:
122: progress.Width = (ts.TotalSeconds/GetProgramDuration().TotalSeconds)* m_workoutInfoView.WorkoutGraphContainer.ActualWidth;
123:
124: int currentCheckpoint = GetCurrentCheckpointIndex();
125: if (m_previousCheckpointIndex != currentCheckpoint)
126: {
127: // Change treadmill settings.
128: m_workoutInfoView.UpdateTreadmillSettings(m_checkpoints[currentCheckpoint].Speed, m_checkpoints[currentCheckpoint].Incline);
129:
130: if (m_previousCheckpointIndex != -1)
131: {
132: Rectangle previousRect = m_graphSegments[m_previousCheckpointIndex] as Rectangle;
133: previousRect.Stroke = null;
134: }
135:
136: Rectangle currentRect = m_graphSegments[currentCheckpoint] as Rectangle;
137: currentRect.Stroke = new SolidColorBrush(Colors.Yellow);
138:
139: m_previousCheckpointIndex = currentCheckpoint;
140: }
141: }
142:
143: private TimeSpan GetProgramDuration()
144: {
145: if (!m_workoutLoaded)
146: {
147: throw new InvalidOperationException("No workout loaded");
148: }
149:
150: int totalTime = 0;
151: foreach (var checkpoint in m_checkpoints)
152: {
153: totalTime += checkpoint.Time;
154: }
155: return new TimeSpan(0, 0, 0, totalTime);
156: }
157:
158: public int GetCurrentCheckpointIndex()
159: {
160: int elapsedTime = (int)(DateTime.Now - m_workoutStartTime).TotalSeconds;
161: int accTime = 0;
162: int i = 0;
163: while (elapsedTime >= accTime && i < m_checkpoints.Count)
164: {
165: accTime += m_checkpoints[i++].Time;
166: }
167:
168: return i - 1;
169: }
170:
171: public void StopProgram()
172: {
173: if (m_workoutStarted)
174: {
175: m_workoutStarted = false;
176: m_timer.Stop();
177: m_workoutInfoView.UpdateTreadmillSettings(0, 0);
178: }
179: }
180:
181: public void StartProgram()
182: {
183: if (m_workoutLoaded)
184: {
185: m_workoutStarted = true;
186: m_timer.Start();
187: m_workoutStartTime = DateTime.Now;
188: }
189: }
190:
191: public bool WorkoutStarted
192: {
193: get { return m_workoutStarted; }
194: }
195:
196: }