Fix stringsource parsing to that apostrophes don't count as quotes.
[schedulator.git] / task.cs
blobc15d3c82d129557f7b60615b6e8939b82f86df6b
1 using System;
2 using System.Collections;
3 using Wv;
4 using Wv.Obsolete;
6 namespace Wv.Schedulator
8 public class Task : IComparable
10 public Task(Source source, string id, string name)
12 this.source = source;
13 this.id = id;
14 this.name = name;
17 public int array_index; // used by TaskList; don't touch!
19 public Source source;
20 public string id;
21 public string name;
23 public string moniker
25 get { return source.name + ":" + id; }
28 public Task parent;
30 public FixFor fixfor;
31 public int priority;
33 public Person assignedto;
35 public bool done;
36 public bool halfdone; // eg. "needs verification" bugs
37 public DateTime donedate;
39 // set no more than two of the startdate, duedate, and work
40 // estimate, or scheduling results may be undefined!
41 public DateTime startdate, duedate;
43 public TimeSpan origest, currest, elapsed;
44 public TimeSpan remain
46 get { return currest - elapsed; }
49 public bool is_estimated()
51 return !wv.isempty(currest) || !wv.isempty(elapsed);
54 public DateSlider habits;
55 public DateSlider find_habits()
57 if (habits != null)
58 return habits;
59 else if (fixfor != null
60 && fixfor.default_habits != null)
61 return fixfor.default_habits;
62 else if (fixfor != null && fixfor.project != null
63 && fixfor.project.default_habits != null)
64 return fixfor.project.default_habits;
65 else
66 return source.s.default_habits;
69 public int firstpriority()
71 if (parent != null && parent.priority < priority)
72 return parent.firstpriority();
73 else
74 return priority;
77 public FixFor firstfixfor()
79 if (fixfor == null)
80 return null; // null fixfors always come "first"
81 if (parent != null && fixfor.CompareTo(parent.fixfor) > 0)
82 return parent.firstfixfor();
83 else
84 return fixfor;
87 public bool has_ancestor(Task t)
89 for (Task p = parent; p != null; p = p.parent)
90 if (p == t)
91 return true;
92 return false;
95 public int depth()
97 int depth = 0;
98 for (Task t = parent; t != null; t = t.parent)
99 depth++;
100 return depth;
103 public Task up(int n)
105 Task t = this;
106 for (int i = 0; i < n; i++)
107 t = t.parent;
108 return t;
111 // Note: the duedate field doesn't affect bug comparisons, because
112 // this is really a "bug priority comparison" algorithm, and simply
113 // having a due date doesn't make a bug more important. That said,
114 // it *might* make it get scheduled earlier than a more important bug,
115 // but that's a job for the scheduling algorithm, and there are too
116 // many variables involved in that to be able to include it in a
117 // simple bug-vs-bug comparison like this one.
119 // This prioritized list is useful for the scheduler, but it will have
120 // to pull out the due-date bugs and insert them at the appropriate
121 // times.
122 public int CompareTo(object _y)
124 if (_y == null)
125 return 1; // null task? Oh well, it comes first.
127 Task y = (Task)_y;
129 if (done != y.done)
130 return done ? -1 : 1;
131 else if (done) // so also y.done
133 if (donedate != y.donedate)
134 return donedate.CompareTo(y.donedate);
135 else // just preserve the original array ordering
136 return array_index - y.array_index;
138 else if (firstfixfor() != y.firstfixfor()) // & !done & !y.done
140 if (firstfixfor() == null)
141 return -y.firstfixfor().CompareTo(firstfixfor());
142 else
143 return firstfixfor().CompareTo(y.firstfixfor());
145 else if (firstpriority() != y.firstpriority())
147 // default priority 0 should be the highest - it means the
148 // task is uncategorized, so it should be at the top to
149 // remind you to prioritize it ASAP.
150 return firstpriority() - y.firstpriority();
152 else if (y.has_ancestor(this))
153 return -1; // parent before child
154 else if (has_ancestor(y))
155 return 1; // child after parent
156 else if (parent != y.parent)
158 // this is a bit complicated. If two subtasks are mostly
159 // equal but have different parents, this will order them
160 // in the same order as their parent. That sort of makes
161 // sense, since if one parent is more important than
162 // another parent, we might as well do all his subtasks
163 // before the less-important-parent's subtasks, but only
164 // if the subtasks themselves are otherwise equivalent.
165 // Whew!
167 // Anyway, the real reason this is important is that we
168 // want to group all of each parent's subtasks together
169 // in the much more common case that all the parents, and
170 // all the subtasks, have the same priority.
172 int dx = depth(), dy = y.depth();
173 if (dx > dy)
175 int d = -y.CompareTo(up(dx-dy));
176 if (d == 0)
177 return 1; // I'm deeper, so I'm later
178 else
179 return d;
181 else if (dx < dy)
183 int d = CompareTo(y.up(dy-dx));
184 if (d == 0)
185 return -1; // y is deeper, so I'm earlier
186 else
187 return d;
189 else
190 return parent.CompareTo(y.parent);
192 else // preserve the original array ordering
193 return array_index - y.array_index;
198 public class TaskList : SortedHash
200 protected string make_key(Source source, string id)
202 return source.name + "\0" + id;
205 public Task Add(Source source, string id, string name)
207 Task t = new Task(source, id, name);
208 base.Add(make_key(source, id), t);
209 t.array_index = Count-1;
210 return t;
213 #pragma warning disable 0109 // appease mono 1.1.13.6
214 public new virtual Task this[int index]
216 get { return (Task)base[index]; }
218 #pragma warning restore 0109
220 public Task Find(Source source, string id)
222 return (Task)base.Find(make_key(source, id));
225 public Task FindByName(string name)
227 foreach (Task t in this)
228 if (t.name == name)
229 return t;
230 return null;
233 public Task FindById(string id)
235 foreach (Task t in this)
236 if (id == t.id || id == (t.source.name + ":" + t.id))
237 return t;
238 return null;
241 public override void Sort()
243 // note: this doesn't update the array_index field, because
244 // it's the *original* array_index that is most useful.
245 base.Sort();