Fix stringsource parsing to that apostrophes don't count as quotes.
[schedulator.git] / dateslider.cs
blob460fd1aae7638c56cdac5724745ba28c2342ee46
1 using System;
2 using Wv;
4 namespace Wv.Schedulator
6 public class DateSlider : ICloneable
8 double _hours_per_week = 40;
9 public double hours_per_week
11 get { return _hours_per_week; }
14 // Sunday first, to match the enum DayOfWeek
15 double[] _hours_per_day = {0,8,8,8,8,8,0};
16 public double[] hours_per_day
18 get { return _hours_per_day; }
21 double _loadfactor = 1.0;
22 public double loadfactor
24 get { return _loadfactor; }
28 public DateSlider new_hours_per_day(double[] hours_per_day)
30 DateSlider d = (DateSlider)this.Clone();
32 d._hours_per_day = (double[])hours_per_day.Clone();
33 d._hours_per_week = 0;
34 for (int i = 0; i < 7; i++)
36 if (d._hours_per_day[i] < 0 || d._hours_per_day[i] > 24)
37 throw new ArgumentException("Each day can have 0 "
38 + "to 24 hours.");
39 d._hours_per_week += d._hours_per_day[i];
41 if (d._hours_per_week < 1)
42 throw new ArgumentException("A week needs "
43 + "at least 1 hour.");
44 return d;
47 public DateSlider new_loadfactor(double loadfactor)
49 DateSlider d = (DateSlider)this.Clone();
50 d._loadfactor = loadfactor;
51 return d;
54 public DateSlider()
56 // double[] x = {0,8,8,8,8,8,0};
57 // _hours_per_day = x;
60 public object Clone()
62 DateSlider d = (DateSlider)this.MemberwiseClone();
63 d._hours_per_day = (double[])this.hours_per_day.Clone();
64 return d;
67 public override string ToString()
69 return String.Format("(loadfactor={0:f2} "
70 + "hours=[{1} {2} {3} {4} {5} {6} {7}])",
71 loadfactor,
72 hours_per_day[0],
73 hours_per_day[1],
74 hours_per_day[2],
75 hours_per_day[3],
76 hours_per_day[4],
77 hours_per_day[5],
78 hours_per_day[6]);
81 public override bool Equals(object _y)
83 DateSlider y = (DateSlider)_y;
84 return hours_per_day == y.hours_per_day
85 && loadfactor == y.loadfactor;
88 public override int GetHashCode()
90 return hours_per_day.GetHashCode() + loadfactor.GetHashCode();
93 public DateTime add(DateTime point, TimeSpan span)
95 WvLog log = new WvLog("slider", WvLog.L.Debug5);
96 log.print("* {0} + {1}\n", point, span.TotalHours);
98 int sign = (span.Ticks < 0) ? -1 : 1;
99 bool less_one = false;
101 // speed through times >= 1 week
102 double hpw = hours_per_week / loadfactor;
103 while (Math.Abs(span.TotalHours) >= hpw)
105 log.print("W {0} + {1} ({2})\n", point, span.TotalHours, hpw);
106 point = point.AddDays(7*sign);
107 span = span.Add(TimeSpan.FromHours(-hpw*sign));
110 // inside a week, count a day at a time
111 while (Math.Abs(span.TotalHours) > 0.01)
113 int day = (int)point.DayOfWeek;
115 // we might be partway through the current day...
116 double dayfraction = point.TimeOfDay.TotalHours / 24.0;
117 if (sign > 0)
119 if (dayfraction > 0.999)
121 day = (day + 1) % 7;
122 dayfraction = 0.0;
125 // we want the remaining part of the day
126 dayfraction = 1.0 - dayfraction;
128 else
130 if (dayfraction < 0.001)
132 day--;
133 if (day < 0) day = 6;
134 dayfraction = 1.0;
135 less_one = true;
138 // we want the expired part of the day: keep dayfraction
141 double hpd = hours_per_day[day] * dayfraction / loadfactor;
143 log.print("D {0} + {1} ({2})\n", point, span.TotalHours, hpd);
144 if (Math.Abs(span.TotalHours) >= hpd)
146 // avoid rounding errors by forcing the date
147 if (sign > 0 || less_one)
148 point = point.Date.AddDays(1*sign);
149 else
150 point = point.Date;
151 span = span.Add(TimeSpan.FromHours(-hpd*sign));
153 else
155 point = point.AddHours(span.TotalHours/hpd
156 * 24 * dayfraction);
157 span = TimeSpan.Zero;
161 log.print(": {0} + {1}\n", point, span.TotalHours);
163 // ah, rounding errors. The above should make things work out
164 // to within the nearest minute or so, which is close enough(tm).
165 double th = point.TimeOfDay.TotalHours;
166 point = point.AddHours(Math.Round(th, 1) - th + 0.5/60.0/60.0);
167 point = new DateTime(point.Year, point.Month, point.Day,
168 point.Hour, point.Minute, 0, 0);
169 log.print(". {0} + {1} ({2})\n",
170 point, span.TotalHours, Math.Round(th, 1));
171 return point;
174 // returns d = x - y, such that x = add(y, d).
175 // Note that if day 'x' has zero working hours, this doesn't make
176 // sense, so we choose the closest timespan that will get us up
177 // to, but not including, x.
178 public TimeSpan diff(DateTime x, DateTime y)
180 WvLog log = new WvLog("slider", WvLog.L.Debug5);
181 wv.assert(x > y);
183 DateTime point = y, end = x;
184 TimeSpan result = TimeSpan.Zero;
186 while (point < end)
188 TimeSpan remain = end - point;
189 double hpd = hours_per_day[(int)point.DayOfWeek];
191 if (remain.TotalDays >= 7)
193 int weeks = (int)Math.Round(remain.TotalDays / 7);
194 point += TimeSpan.FromDays(weeks * 7);
195 result += TimeSpan.FromHours(
196 weeks * hours_per_week / loadfactor);
198 else if (remain.TotalHours >= 24)
200 point += TimeSpan.FromDays(1);
201 result += TimeSpan.FromHours(hpd / loadfactor);
203 else if (remain.TotalHours > 0)
205 double dayfraction = remain.TotalHours / 24;
206 point = end;
207 result += TimeSpan.FromHours(
208 dayfraction * hpd / loadfactor);
212 log.print("result: {0} hours\n", result.TotalHours);
213 return result;