source: Scheduling/trunk/cs/bsdx0200GUISourceCode/CGSchedLib.cs@ 1097

Last change on this file since 1097 was 1097, checked in by Sam Habiel, 13 years ago

DPatientLookup.cs: Usings Cleanup
DApptSearch: Extensive refactoring. Now uses new algorithm to find appointments. Now outputs CGAvailability
CGView: Appointments checked in now set the Checkin time on the appointment structure; changes to support DApptSearch modified output.
CGSchedLib: Extensive refactoring; only 2 methods remain: CreateAppointmentSchedule and CreateAvailabilitySchedule
CGDocument: SlotsAvailable uses a new algorithm
CGAVView: Uses CalendarGrid.TimesOverlap instead of the removed one in CGSchedLib
CGAVDocument: Uses CalendarGrid.TimesOverlap instead of the removed one in CGSchedLib; CreateAssignedSlotSchedule reassigned to CreateAvailabilitySchedule

File size: 34.6 KB
Line 
1using System;
2using System.Data;
3using System.Collections;
4using System.Diagnostics;
5using System.Drawing;
6
7namespace IndianHealthService.ClinicalScheduling
8{
9 public enum ScheduleType
10 {
11 Resource,
12 Clinic
13 }
14
15 /// <summary>
16 /// CGSchedLib contains static functions that are called from throughout the
17 /// scheduling application.
18 /// </summary>
19 public static class CGSchedLib
20 {
21 /// <summary>
22 /// Gets appointments from VISTA to display in Grid
23 /// </summary>
24 /// <param name="docManager">God Class</param>
25 /// <param name="saryResNames">Resource Names Array</param>
26 /// <param name="StartTime">Self Explanatory</param>
27 /// <param name="EndTime">Self Explanatory</param>
28 /// <returns></returns>
29 public static DataTable CreateAppointmentSchedule(CGDocumentManager docManager, ArrayList saryResNames, DateTime StartTime, DateTime EndTime)
30 {
31 string sResName = string.Join("|", saryResNames.ToArray());
32 string sStart = FMDateTime.Create(StartTime).DateOnly.FMDateString;
33 string sEnd = FMDateTime.Create(EndTime).FMDateString;
34 string sSql = "BSDX CREATE APPT SCHEDULE^" + sResName + "^" + sStart + "^" + sEnd ;
35 DataTable dtRet = docManager.RPMSDataTable(sSql, "AppointmentSchedule");
36 return dtRet;
37 }
38
39
40 /// <summary>
41 /// Gets all Availabilities and Appointments, then substracts Appointments from availabilities.
42 /// </summary>
43 /// <param name="docManager">God Class</param>
44 /// <param name="saryResourceNames">Resource Array (ArrayList)</param>
45 /// <param name="StartTime">Self-Explanatory</param>
46 /// <param name="EndTime">Self-Explanatory</param>
47 /// <param name="saryApptTypes">Array of Access Type IDs</param>
48 /// <param name="stType">Not used</param>
49 /// <param name="sSearchInfo">Specific Search Parameters</param>
50 /// <returns></returns>
51 public static DataTable CreateAvailabilitySchedule(CGDocumentManager docManager,
52 ArrayList saryResourceNames, DateTime StartTime, DateTime EndTime,
53 ArrayList saryApptTypes,/**/ ScheduleType stType, string sSearchInfo)
54 {
55 DataTable rsOut = new DataTable("AvailabilitySchedule");
56 if (saryResourceNames.Count == 0) return rsOut;
57 string sResNames = string.Join("|", saryResourceNames.ToArray());
58 string sApptTypeIDs = string.Join("|", saryApptTypes.ToArray());
59 string sStart = FMDateTime.Create(StartTime).DateOnly.FMDateString;
60 string sEnd = FMDateTime.Create(EndTime).FMDateString;
61 string sSql = "BSDX CREATE ASGND SLOT SCHED^" + sResNames + "^" + sStart + "^" + sEnd + "^" + sApptTypeIDs + "^" + sSearchInfo; //+ "^" + sSTType ;
62 rsOut = docManager.RPMSDataTable(sSql, "AssignedSlotSchedule");
63
64 return rsOut;
65 }
66
67 /*NOT USED ANYMORE
68 //TODO: Optimize: no need to keep looping through resources.
69 // for each resource
70 for (int i = 0; i < nSize; i++)
71 {
72 sResName = saryResourceNames[i].ToString();
73 //Gets all the slots (or Availabities, or AV Blocks if you like)
74 rsSlotSchedule = CGSchedLib.CreateAssignedSlotSchedule(docManager, sResName, StartTime, EndTime, saryApptTypes, stType, sSearchInfo);
75 rsTemp1 = rsSlotSchedule;
76
77 //if we have slots
78 if (rsSlotSchedule.Rows.Count > 0 )
79 {
80 // Get appointment count to substract from the slots
81 rsApptSchedule = CGSchedLib.CreateAppointmentSlotSchedule(docManager, sResName, StartTime, EndTime, stType);
82
83 // Perform the substraction
84 rsTemp1 = CGSchedLib.SubtractSlotsRS2(rsSlotSchedule, rsApptSchedule, sResName);
85
86 }
87 //otherwise, just return the slot schedule we have.
88 else
89 {
90 rsTemp1 = rsSlotSchedule;
91
92 }
93
94
95 // if only one resource was passed in, its availablility is what we want
96 if (i == 0)
97 {
98 rsOut = rsTemp1;
99
100 }
101 // if more than one resource, merge them together
102 else
103 {
104 rsOut = CGSchedLib.UnionBlocks(rsTemp1, rsOut);
105 }
106 }
107 return rsOut;
108 }
109 */
110
111 /* NOT USED ANYMORE!!!
112 public static DataTable CreateAssignedTypeSchedule(CGDocumentManager docManager, string sResourceName, DateTime StartTime, DateTime EndTime, ScheduleType stType)
113 {
114
115 string sStart = FMDateTime.Create(StartTime).DateOnly.FMDateString;
116 string sEnd = FMDateTime.Create(EndTime).DateOnly.FMDateString;
117 string sSql = "BSDX TYPE BLOCKS OVERLAP^" + sStart + "^" + sEnd + "^" + sResourceName;
118
119 DataTable rs = docManager.RPMSDataTable(sSql, "AssignedTypeSchedule");
120
121 if (rs.Rows.Count == 0)
122 return rs;
123
124 DataTable rsCopy = new DataTable("rsCopy");
125 DataColumn dCol = new DataColumn();
126 dCol.DataType = Type.GetType("System.DateTime");
127 dCol.ColumnName = "StartTime";
128 dCol.ReadOnly = true;
129 dCol.AllowDBNull = false;
130 dCol.Unique = false;
131 rsCopy.Columns.Add(dCol);
132
133 dCol = new DataColumn();
134 dCol.DataType = Type.GetType("System.DateTime");
135 dCol.ColumnName = "EndTime";
136 dCol.ReadOnly = true;
137 dCol.AllowDBNull = false;
138 dCol.Unique = false;
139 rsCopy.Columns.Add(dCol);
140
141 dCol = new DataColumn();
142 dCol.DataType = Type.GetType("System.Int16");
143 dCol.ColumnName = "AppointmentTypeID";
144 dCol.ReadOnly = true;
145 dCol.AllowDBNull = false;
146 dCol.Unique = false;
147 rsCopy.Columns.Add(dCol);
148
149 dCol = new DataColumn();
150 dCol.DataType = Type.GetType("System.Int32");
151 dCol.ColumnName = "AvailabilityID";
152 dCol.ReadOnly = true;
153 dCol.AllowDBNull = false;
154 dCol.Unique = false;
155 rsCopy.Columns.Add(dCol);
156
157 dCol = new DataColumn();
158 dCol.DataType = Type.GetType("System.String");
159 dCol.ColumnName = "ResourceName";
160 dCol.ReadOnly = true;
161 dCol.AllowDBNull = false;
162 dCol.Unique = false;
163 rsCopy.Columns.Add(dCol);
164
165
166 DateTime dLastEnd;
167 DateTime dStart;
168 DateTime dEnd;
169 DataRow rNew; //Temporary Holding place for first or last row
170
171 // Get Last Date from final row
172 rNew = rs.Rows[rs.Rows.Count - 1];
173 dLastEnd = (DateTime) rNew["EndTime"];
174 // Get First Date from first row
175 rNew = rs.Rows[0];
176 dStart = (DateTime) rNew["StartTime"];
177
178 long UNSPECIFIED_TYPE = 10;
179 long UNSPECIFIED_ID = 0;
180
181 //if first block in vgetrows starts later than StartTime,
182 // then pad with a new block
183
184 // if First Row time is later than the StartTime param (should always be true)
185 // then make a new row whose time starts from StartTime and ends with dStart
186 if (dStart > StartTime)
187 {
188 dEnd = dStart;
189 rNew = rsCopy.NewRow();
190 rNew["StartTime"] = StartTime;
191 rNew["EndTime"] = dEnd;
192 rNew["AppointmentTypeID"] = UNSPECIFIED_TYPE;
193 rNew["AvailabilityID"] = UNSPECIFIED_ID;
194 rNew["ResourceName"] = sResourceName;
195 rsCopy.Rows.Add(rNew);
196 }
197
198 //if first block start time is < StartTime then trim (shouldn't happen)
199 if (dStart < StartTime)
200 {
201 rNew = rs.Rows[0];
202 rNew["StartTime"] = StartTime;
203 dStart = StartTime;
204 }
205
206 int nAppointmentTypeID;
207 int nAvailabilityID;
208
209 //dStart holds the first date for the availabilities returned from RPMS
210 dEnd = dStart;
211 foreach (DataRow rEach in rs.Rows)
212 {
213 dStart = (DateTime) rEach["StartTime"];
214 if (dStart > dEnd)
215 {
216 rNew = rsCopy.NewRow();
217 rNew["StartTime"] = dEnd;
218 rNew["EndTime"] = dStart;
219 rNew["AppointmentTypeID"] = 0;
220 rNew["AvailabilityID"] = UNSPECIFIED_ID;
221 rNew["ResourceName"] = sResourceName;
222 rsCopy.Rows.Add(rNew);
223 }
224
225 //dEnd now EndTime for AV Block
226 dEnd = (DateTime) rEach["EndTime"];
227
228 // if dEnd is greater than endime, set dEnd to be the same as EndTime.
229 if (dEnd > EndTime) { dEnd = EndTime; }
230
231
232 nAppointmentTypeID = (int) rEach["AppointmentTypeID"];
233 nAvailabilityID = (int) rEach["AvailabilityID"];
234
235 rNew = rsCopy.NewRow();
236 rNew["StartTime"] = dStart;
237 rNew["EndTime"] = dEnd;
238 rNew["AppointmentTypeID"] = nAppointmentTypeID;
239 rNew["AvailabilityID"] = nAvailabilityID;
240 rNew["ResourceName"] = sResourceName;
241 rsCopy.Rows.Add(rNew);
242 }
243
244 //Pad the end if necessary
245 if (dLastEnd < EndTime)
246 {
247 rNew = rsCopy.NewRow();
248 rNew["StartTime"] = dLastEnd;
249 rNew["EndTime"] = EndTime;
250 rNew["AppointmentTypeID"] = UNSPECIFIED_TYPE;
251 rNew["AvailabilityID"] = UNSPECIFIED_ID;
252 rNew["ResourceName"] = sResourceName;
253 rsCopy.Rows.Add(rNew);
254 }
255
256 return rsCopy;
257 }
258 */
259
260 /// <summary>
261 /// Gets the Availability Slots from the Server
262 /// </summary>
263 /// <param name="docManager">God Class</param>
264 /// <param name="sResourceName">Resource for which to get slots</param>
265 /// <param name="StartTime"></param>
266 /// <param name="EndTime"></param>
267 /// <param name="rsaryApptTypeIDs">Access Type IDs to retrieve</param>
268 /// <param name="stType">Not used</param>
269 /// <param name="sSearchInfo">If performing a slot search (i.e. for empty appointments), has search info here. Used by Find Appointments</param>
270 /// <returns>DataTable with the following Columns:
271 /// D00030START_TIME^D00030END_TIME^I00010SLOTS^T00030RESOURCE^T00010ACCESS_TYPE^T00250NOTE^I00030AVAILABILITYID
272 /// </returns>
273 /*
274 * public static DataTable CreateAssignedSlotSchedule(CGDocumentManager docManager, string sResourceName, DateTime StartTime,
275 DateTime EndTime, ArrayList rsaryApptTypeIDs, ScheduleType stType, string sSearchInfo)
276 {
277 //Appointment type ids is now always "" so that all appointment types are returned.
278 string sApptTypeIDs = string.Join("|", rsaryApptTypeIDs.ToArray());
279 string sStart = FMDateTime.Create(StartTime).DateOnly.FMDateString;
280 string sEnd = FMDateTime.Create(EndTime).FMDateString;
281 string sSql = "BSDX CREATE ASGND SLOT SCHED^" + sResourceName + "^" + sStart + "^" + sEnd + "^" + sApptTypeIDs + "^" + sSearchInfo; //+ "^" + sSTType ;
282 DataTable dtRet = docManager.RPMSDataTable(sSql, "AssignedSlotSchedule");
283
284 return dtRet;
285 }
286 */
287
288 /*
289 public static DataTable CreateCopyTable()
290 {
291 DataTable dtCopy = new DataTable("dtCopy");
292 DataColumn dCol = new DataColumn();
293 dCol.DataType = Type.GetType("System.DateTime");
294 dCol.ColumnName = "START_TIME";
295 dCol.ReadOnly = true;
296 dCol.AllowDBNull = false;
297 dCol.Unique = false;
298 dtCopy.Columns.Add(dCol);
299
300 dCol = new DataColumn();
301 dCol.DataType = Type.GetType("System.DateTime");
302 dCol.ColumnName = "END_TIME";
303 dCol.ReadOnly = true;
304 dCol.AllowDBNull = false;
305 dCol.Unique = false;
306 dtCopy.Columns.Add(dCol);
307
308 dCol = new DataColumn();
309 dCol.DataType = Type.GetType("System.Int16");
310 dCol.ColumnName = "SLOTS";
311 dCol.ReadOnly = true;
312 dCol.AllowDBNull = false;
313 dCol.Unique = false;
314 dtCopy.Columns.Add(dCol);
315
316 dCol = new DataColumn();
317 dCol.DataType = Type.GetType("System.String");
318 dCol.ColumnName = "RESOURCE";
319 dCol.ReadOnly = true;
320 dCol.AllowDBNull = true;
321 dCol.Unique = false;
322 dtCopy.Columns.Add(dCol);
323
324 dCol = new DataColumn();
325 dCol.DataType = Type.GetType("System.String");
326 dCol.ColumnName = "ACCESS_TYPE";
327 dCol.ReadOnly = true;
328 dCol.AllowDBNull = true;
329 dCol.Unique = false;
330 dtCopy.Columns.Add(dCol);
331
332 dCol = new DataColumn();
333 dCol.DataType = Type.GetType("System.String");
334 dCol.ColumnName = "NOTE";
335 dCol.ReadOnly = true;
336 dCol.AllowDBNull = true;
337 dCol.Unique = false;
338 dtCopy.Columns.Add(dCol);
339
340
341 return dtCopy;
342 }
343 */
344
345 /// <summary>
346 /// This gets a datatable which shows the appointments between start and end time, one row per appointment
347 /// </summary>
348 /// <param name="docManager"></param>
349 /// <param name="sResourceName"></param>
350 /// <param name="StartTime"></param>
351 /// <param name="EndTime"></param>
352 /// <param name="stType"></param>
353 /// <returns>DataTable with 4 columns: START_TIME, END_TIME, SLOTS, RESOURCE </returns>
354 /*
355 public static DataTable CreateAppointmentSlotSchedule(CGDocumentManager docManager, string sResourceName, DateTime StartTime, DateTime EndTime, ScheduleType stType)
356 {
357 //Change Dates to FM Format
358 string sStart = FMDateTime.Create(StartTime).DateOnly.FMDateString;
359 string sEnd = FMDateTime.Create(EndTime).DateOnly.FMDateString;
360
361 string sSTType = (stType == ScheduleType.Resource ? "ST_RESOURCE" : "ST_CLINIC");
362 string sSql = "BSDX APPT BLOCKS OVERLAP^" + sStart + "^" + sEnd + "^" + sResourceName ;//+ "^" + sSTType;
363
364 //This gets you a table with 2 columns containing start and end time for each appt
365 //Each appt gets its own row
366 DataTable dtRet = docManager.RPMSDataTable(sSql, "AppointmentSlotSchedule");
367
368 if (dtRet.Rows.Count < 1)
369 return dtRet;
370
371 //Create CDateTimeArray & load records from rsOut
372 int nRC = dtRet.Rows.Count; // nRC is row count from Appointments table just retrieved
373 ArrayList cdtArray = new ArrayList();
374 cdtArray.Capacity = (nRC * 2); //new ArrayList has capacity double that of appointment table
375 DateTime v;
376 int i = 0;
377
378 //for each row in the Appointment Table, ArrayList cdtArray gets 2 entries: Start and End times
379 foreach (DataRow r in dtRet.Rows)
380 {
381 v = (DateTime) r[dtRet.Columns["START_TIME"]];
382 cdtArray.Add(v);
383 v = (DateTime) r[dtRet.Columns["END_TIME"]];
384 cdtArray.Add(v);
385 }
386
387 //Sort start and end times (for use in ScheduleFromArray method)
388 cdtArray.Sort();
389
390 //Create a CTimeBlockArray and load it from rsOut
391
392 //Now, create a new ArrayList with the size of the appointment table to hold availabilities
393 ArrayList ctbAppointments = new ArrayList(nRC);
394 CGAvailability cTB;
395 i = 0;
396 //For each appointment, create an availability
397 foreach (DataRow r in dtRet.Rows)
398 {
399 cTB = new CGAvailability();
400 cTB.StartTime = (DateTime) r[dtRet.Columns["START_TIME"]];
401 cTB.EndTime = (DateTime) r[dtRet.Columns["END_TIME"]];
402 ctbAppointments.Add(cTB);
403 }
404
405 //Create a TimeBlock Array from the data in the DateTime array
406 ArrayList ctbApptSchedule = new ArrayList();
407
408 //Convert Appointments to Availabilities, where all appointments become squeezed together.
409 ScheduleFromArray(cdtArray, StartTime, EndTime, ref ctbApptSchedule);
410
411 So far, we have the following:
412 * dtRet -> List of Appointments Start and End times, one row per appointment
413 * cdtArray -> Linear 1 dimensional Array of dtRet Start and End times, sorted
414 * ctbAppointments -> Arraylist of dtRet as Availabilities
415 * ctbApptSchedule -> Arraylist of dtRet as Availabilities with no overlapping boundaries
416 * (overlaps in appointments get converted into availabilties themselves: so
417 * 2 appts as 10:10-10:30 and 10:20-10:40 get converted into 10:10-10:20,
418 * 10:20-10:30, 10:30-10:40).
419
420
421 //Find number of TimeBlocks in ctbApptSchedule that overlap the TimeBlocks in ctbAppointments
422 ArrayList ctbApptSchedule2 = new ArrayList();
423 CGAvailability cTB2;
424 int nSlots = 0;
425 for (i=0; i< ctbApptSchedule.Count; i++) //for each non-overlapping appts as availabilities
426 {
427 cTB = (CGAvailability) ctbApptSchedule[i];
428 //How many times does the non-overlapping part show up in an appointment slot?
429 nSlots = BlocksOverlap(cTB, ctbAppointments);
430 cTB2 = new CGAvailability();
431 cTB2.Create(cTB.StartTime, cTB.EndTime, nSlots);
432 ctbApptSchedule2.Add(cTB2);
433 }
434
435 ConsolidateBlocks(ctbApptSchedule2);
436
437 DataTable dtCopy = new DataTable("dtCopy");
438 DataColumn dCol = new DataColumn();
439 dCol.DataType = Type.GetType("System.DateTime");
440 dCol.ColumnName = "START_TIME";
441 dCol.ReadOnly = true;
442 dCol.AllowDBNull = false;
443 dCol.Unique = false;
444 dtCopy.Columns.Add(dCol);
445
446 dCol = new DataColumn();
447 dCol.DataType = Type.GetType("System.DateTime");
448 dCol.ColumnName = "END_TIME";
449 dCol.ReadOnly = true;
450 dCol.AllowDBNull = false;
451 dCol.Unique = false;
452 dtCopy.Columns.Add(dCol);
453
454 dCol = new DataColumn();
455 dCol.DataType = Type.GetType("System.Int16");
456 dCol.ColumnName = "SLOTS";
457 dCol.ReadOnly = true;
458 dCol.AllowDBNull = false;
459 dCol.Unique = false;
460 dtCopy.Columns.Add(dCol);
461
462 dCol = new DataColumn();
463 dCol.DataType = Type.GetType("System.String");
464 dCol.ColumnName = "RESOURCE";
465 dCol.ReadOnly = true;
466 dCol.AllowDBNull = false;
467 dCol.Unique = false;
468 dtCopy.Columns.Add(dCol);
469
470 for (int k=0; k < ctbApptSchedule2.Count; k++)
471 {
472 cTB = (CGAvailability) ctbApptSchedule2[k];
473 DataRow newRow;
474 newRow = dtCopy.NewRow();
475 newRow["START_TIME"] = cTB.StartTime;
476 newRow["END_TIME"] = cTB.EndTime;
477 newRow["SLOTS"] = cTB.Slots;
478 newRow["RESOURCE"] = sResourceName;
479 dtCopy.Rows.Add(newRow);
480 }
481
482 return dtCopy;
483
484 }
485 */
486
487 /*
488 public static int BlocksOverlap(CGAvailability rBlock, ArrayList rTBArray)
489 {
490 //this overload implements default false for bCountSlots
491 return CGSchedLib.BlocksOverlap(rBlock, rTBArray, false);
492 }
493 public static int BlocksOverlap(CGAvailability rBlock, ArrayList rTBArray, bool bCountSlots)
494 {
495 //If bCountSlots == true, then returns
496 //sum of Slots in overlapping blocks
497 //instead of the count of overlapping blocks
498
499 DateTime dStart1;
500 DateTime dStart2;
501 DateTime dEnd1;
502 DateTime dEnd2;
503 int nSlots;
504 int nCount = 0;
505 CGAvailability cBlock;
506
507 dStart1 = rBlock.StartTime;
508 dEnd1 = rBlock.EndTime;
509
510 for (int j=0; j< rTBArray.Count; j++)
511 {
512 cBlock = (CGAvailability) rTBArray[j];
513 dStart2 = cBlock.StartTime;
514 dEnd2 = cBlock.EndTime;
515 nSlots = cBlock.Slots;
516 if (TimesOverlap(dStart1, dEnd1, dStart2, dEnd2))
517 {
518 if (bCountSlots == true)
519 {
520 nCount += nSlots;
521 }
522 else
523 {
524 nCount++;
525 }
526 }
527 }
528
529 return nCount;
530 }
531 */
532
533 /// <summary>
534 /// Does an appointment overlap with another appointment in the same day?
535 /// </summary>
536 /// <param name="dStart1">Start Time of First Appt</param>
537 /// <param name="dEnd1">End Time of First Appt</param>
538 /// <param name="dStart2">Start Time of Second Appt</param>
539 /// <param name="dEnd2">End Time of Second Appt</param>
540 /// <returns>true or false</returns>
541 /// <remarks>Draws 2 rectangles and sees if they overlap using minutes from 1980 as the start point</remarks>
542 /*
543 public static bool TimesOverlap(DateTime dStart1, DateTime dEnd1, DateTime dStart2, DateTime dEnd2)
544 {
545 Rectangle rect1 = new Rectangle();
546 Rectangle rect2 = new Rectangle();
547 rect1.X = 0;
548 rect2.X = 0;
549 rect1.Width = 1;
550 rect2.Width = 1;
551
552 rect1.Y = CGSchedLib.MinSince80(dStart1);
553 rect1.Height = CGSchedLib.MinSince80(dEnd1) - rect1.Y;
554 rect2.Y = CGSchedLib.MinSince80(dStart2);
555 rect2.Height = CGSchedLib.MinSince80(dEnd2) - rect2.Y;
556 bool bRet = rect2.IntersectsWith(rect1);
557 return bRet;
558 }
559 */
560
561 /*
562 public static void ConsolidateBlocks(ArrayList rTBArray)
563 {
564 //TODO: Test this function
565
566 int j = 0;
567 bool bDirty = false;
568 CGAvailability cBlockA;
569 CGAvailability cBlockB;
570 CGAvailability cTemp1;
571 if (rTBArray.Count < 2)
572 return;
573 do
574 {
575 bDirty = false;
576 for (j = 0; j < (rTBArray.Count - 1); j++) //TODO: why minus 1?
577 {
578 cBlockA = (CGAvailability) rTBArray[j];
579 cBlockB = (CGAvailability) rTBArray[j+1];
580 if ((cBlockA.EndTime == cBlockB.StartTime)
581 && (cBlockA.Slots == cBlockB.Slots)
582 && (cBlockA.ResourceList == cBlockB.ResourceList)
583 && (cBlockA.AccessRuleList == cBlockB.AccessRuleList)
584 )
585 {
586 cTemp1 = new CGAvailability();
587 cTemp1.StartTime = cBlockA.StartTime;
588 cTemp1.EndTime = cBlockB.EndTime;
589 cTemp1.Slots = cBlockA.Slots;
590 cTemp1.AccessRuleList = cBlockA.AccessRuleList;
591 cTemp1.ResourceList = cBlockA.ResourceList;
592 rTBArray.Insert(j, cTemp1);
593 rTBArray.RemoveRange(j+1, 2);
594 bDirty = true;
595 break;
596 }
597 }
598 }
599 while (!((bDirty == false) || (rTBArray.Count == 1)));
600 } */
601
602 /// <summary>
603 /// My guess is that this calculates remaining slots
604 /// </summary>
605 /// <param name="rsBlocks1"></param>
606 /// <param name="rsBlocks2"></param>
607 /// <param name="sResource"></param>
608 /// <returns></returns>
609 /*
610 public static DataTable SubtractSlotsRS2(DataTable rsBlocks1, DataTable rsBlocks2, string sResource)
611 {
612 //Subtract slots in rsBlocks2 from rsBlocks1
613 //7-16-01 SUBCLINIC data field in rsBlocks1 persists thru routine.
614 //7-18-01 RESOURCE and ACCESS_TYPE fields presisted
615
616 if ((rsBlocks2.Rows.Count == 0) || (rsBlocks1.Rows.Count == 0))
617 return rsBlocks1;
618
619
620 //Create an array of the start and end times of blocks2
621 ArrayList cdtArray = new ArrayList(2*(rsBlocks1.Rows.Count + rsBlocks2.Rows.Count));
622
623 foreach (DataRow r in rsBlocks1.Rows)
624 {
625 cdtArray.Add(r[rsBlocks1.Columns["START_TIME"]]);
626 cdtArray.Add(r[rsBlocks1.Columns["END_TIME"]]);
627 }
628
629 foreach (DataRow r in rsBlocks2.Rows)
630 {
631 cdtArray.Add(r[rsBlocks2.Columns["START_TIME"]]);
632 cdtArray.Add(r[rsBlocks2.Columns["END_TIME"]]);
633 }
634
635 cdtArray.Sort();
636
637 ArrayList ctbReturn = new ArrayList();
638 DateTime cDate = new DateTime();
639 ScheduleFromArray(cdtArray, cDate, cDate, ref ctbReturn);
640
641 //Set up return table
642 DataTable rsCopy = CGSchedLib.CreateCopyTable(); //TODO: There's a datatable method that does this.
643 long nSlots = 0;
644 CGAvailability cTB;
645
646 for (int j=0; j < (ctbReturn.Count -1); j++) //TODO: why minus 1?
647 {
648 cTB = (CGAvailability) ctbReturn[j];
649 nSlots = SlotsInBlock(cTB, rsBlocks1) - SlotsInBlock(cTB, rsBlocks2);
650 string sResourceList = "";
651 string sAccessRuleList = "";
652 string sNote = "";
653
654 if (nSlots > 0)
655 {
656 bool bRet = ResourceRulesInBlock(cTB, rsBlocks1, ref sResourceList, ref sAccessRuleList, ref sNote);
657 }
658 DataRow newRow;
659 newRow = rsCopy.NewRow();
660 newRow["START_TIME"] = cTB.StartTime;
661 newRow["END_TIME"] = cTB.EndTime;
662 newRow["SLOTS"] = nSlots;
663 //Subclinic, Access Rule and Resource are null in subtractedSlot sets
664 newRow["RESOURCE"] = sResource;
665 newRow["ACCESS_TYPE"] = sAccessRuleList;
666
667 newRow["NOTE"] = sNote;
668
669 rsCopy.Rows.Add(newRow);
670 }
671 return rsCopy;
672
673 }
674 */
675
676 /*
677 public static DataTable UnionBlocks(DataTable rs1, DataTable rs2)
678 {
679 //Test input tables
680 Debug.Assert(rs1 != null);
681 Debug.Assert(rs2 != null);
682
683 DataTable rsCopy;
684 DataRow dr;
685 if (rs1.Columns.Count >= rs2.Columns.Count)
686 {
687 rsCopy = rs1.Copy();
688 foreach (DataRow dr2 in rs2.Rows)
689 {
690 dr = rsCopy.NewRow();
691 dr.ItemArray = dr2.ItemArray;
692 //dr["START_TIME"] = dr2["START_TIME"];
693 //dr["END_TIME"] = dr2["END_TIME"];
694 //dr["SLOTS"] = dr2["SLOTS"];
695 rsCopy.Rows.Add(dr);
696 }
697 }
698 else
699 {
700 rsCopy = rs2.Copy();
701 foreach (DataRow dr2 in rs1.Rows)
702 {
703 dr = rsCopy.NewRow();
704 dr.ItemArray = dr2.ItemArray;
705 rsCopy.Rows.Add(dr);
706 }
707 }
708 return rsCopy;
709 }
710 */
711
712 /*
713 public static DataTable IntersectBlocks(DataTable rs1, DataTable rs2)
714 {
715 DataTable rsCopy = CGSchedLib.CreateCopyTable();
716
717 //Test input tables
718
719 if ((rs1 == null) || (rs2 == null))
720 return rsCopy;
721
722 if ((rs1.Rows.Count == 0) || (rs2.Rows.Count == 0))
723 return rsCopy;
724
725 int nSlots1 = 0;
726 int nSlots2 = 0;
727 int nSlots3 = 0;
728 DateTime dStart1;
729 DateTime dStart2;
730 DateTime dStart3;
731 DateTime dEnd1;
732 DateTime dEnd2;
733 DateTime dEnd3;
734 string sClinic;
735 string sClinic2;
736// Rectangle rect1 = new Rectangle();
737// Rectangle rect2 = new Rectangle();
738// rect1.X = 0;
739// rect2.X = 0;
740// rect1.Width = 1;
741// rect2.Width = 1;
742
743 // DataColumn cSlots = rs1.Columns["SLOTS"];
744 foreach (System.Data.DataRow r1 in rs1.Rows)
745 {
746 nSlots1 = (int) r1[rs1.Columns["SLOTS"]];
747 if (nSlots1 > 0)
748 {
749 dStart1 = (DateTime) r1[rs1.Columns["START_TIME"]];
750 dEnd1 = (DateTime) r1[rs1.Columns["END_TIME"]];
751 sClinic = r1[rs1.Columns["SUBCLINIC"]].ToString();
752 if (sClinic == "NULL")
753 sClinic = "";
754// rect1.Y = CGSchedLib.MinSince80(dStart1);
755// rect1.Height = CGSchedLib.MinSince80(dEnd1) - rect1.Y;
756 foreach (System.Data.DataRow r2 in rs2.Rows)
757 {
758 nSlots2 = (int) r2[rs2.Columns["SLOTS"]];
759
760 if (nSlots2 > 0)
761 {
762 dStart2 = (DateTime) r2[rs2.Columns["START_TIME"]];
763 dEnd2 = (DateTime) r2[rs2.Columns["END_TIME"]];
764 sClinic2 = r2[rs2.Columns["SUBCLINIC"]].ToString();
765// rect2.Y = CGSchedLib.MinSince80(dStart2);
766// rect2.Height = CGSchedLib.MinSince80(dEnd2) - rect2.Y;
767 if (
768 /*(rect2.IntersectsWith(rect1) == true)
769 (CGSchedLib.TimesOverlap(dStart1, dEnd1, dStart2, dEnd2) == true)
770 &&
771 ((sClinic == sClinic2) || (sClinic == "NONE") || (sClinic2 == "NONE"))
772 )
773 {
774 dStart3 = (dStart1 >= dStart2) ? dStart1 : dStart2 ;
775 dEnd3 = (dEnd1 >= dEnd2) ? dEnd2 : dEnd1;
776 nSlots3 = (nSlots1 >= nSlots2) ? nSlots2 : nSlots1 ;
777
778 DataRow newRow;
779 newRow = rsCopy.NewRow();
780 newRow["START_TIME"] = dStart3;
781 newRow["END_TIME"] = dEnd3;
782 newRow["SLOTS"] = nSlots3;
783 newRow["SUBCLINIC"] = (sClinic == "NONE") ? sClinic2 : sClinic;
784 //Access Rule and Resource are null in interesected sets
785 newRow["ACCESS_TYPE"] = "";
786 newRow["RESOURCE"] = "";
787 rsCopy.Rows.Add(newRow);
788 }
789 }//nSlots2 > 0
790 }//foreach r2 in rs2.rows
791 }//nSlots1 > 0
792 }//foreach r1 in rs1.rows
793 return rsCopy;
794 }//end IntersectBlocks
795 */
796
797 /// <summary>
798 /// Number of minutes since Jan 1 1980
799 /// </summary>
800 /// <param name="d">Date to compare</param>
801 /// <returns>Minutes as integer</returns>
802 /*
803 public static int MinSince80(DateTime d)
804 {
805 //Returns the total minutes between d and 1 Jan 1980
806 DateTime y = new DateTime(1980,1,1,0,0,0);
807 Debug.Assert(d > y);
808 TimeSpan ts = d - y;
809 //Assure ts.TotalMinutes within int range so that cast on next line works
810 Debug.Assert(ts.TotalMinutes < 2147483646);
811 int nMinutes = (int) ts.TotalMinutes;
812 return nMinutes;
813 }
814 */
815
816 /*
817 /// <summary>
818 /// Converts an Array of Times like this:
819 /// 10:00 10:00 10:20 10:20 10:30 10:30 10:30 10:40
820 /// To an array of availabilities like this:
821 /// 12:00-10:00 10:00-10:20 10:20-10:30 10:30-10:40
822 /// Where the 12:00 comes from the start time
823 /// </summary>
824 /// <param name="cdtArray">ArrayList containing start and end times of Appointments combmined and sorted</param>
825 /// <param name="dStartTime">Start Time for Schedule</param>
826 /// <param name="dEndTime">End Time for Schedule</param>
827 /// <param name="rTBArray">Output of Availabilities: Pass Empty</param>
828 public static void ScheduleFromArray(ArrayList cdtArray, DateTime dStartTime, DateTime dEndTime,
829 ref ArrayList rTBArray)
830 {
831 int j = 0;
832 CGAvailability cTB;
833
834 if (cdtArray.Count == 0)
835 return;
836
837 Debug.Assert(cdtArray.Count > 0);
838 Debug.Assert(cdtArray[0].GetType() == typeof(DateTime));
839
840 //If StartTime passed in, then adjust for it
841 if (dStartTime.Ticks > 0)
842 {
843 // if first Array Entry greater than start time, then create an availability
844 // with the start time as dStartTime, and end time as the first array entry, and 0 slots
845 // then add this to the output array
846 if ((DateTime) cdtArray[0] > dStartTime)
847 {
848 cTB = new CGAvailability();
849 cTB.Create(dStartTime, (DateTime) cdtArray[0], 0);
850 rTBArray.Add(cTB);
851 }
852
853 // if first Array Entry less than start time (shouldn't happen),
854 // convert all input array's times less than the start time to all be the start time
855 if ((DateTime) cdtArray[0] < dStartTime)
856 {
857 for (j = 0; j < cdtArray.Count; j++)
858 {
859 if ((DateTime) cdtArray[j] < dStartTime)
860 cdtArray[j] = dStartTime;
861 }
862 }
863 }
864
865 //Trim the end if necessary
866 //If end time is passed, set all the times in the original array greater
867 //than the end time to be the end time (Shouldn't happen).
868 if (dEndTime.Ticks > 0)
869 {
870 for (j = 0; j < cdtArray.Count; j++)
871 {
872 if ((DateTime) cdtArray[j] > dEndTime)
873 cdtArray[j] = dEndTime;
874 }
875 }
876
877 //build the schedule in rTBArray
878 DateTime dTemp = new DateTime(); //hold previous appt time.
879 DateTime dStart;
880 DateTime dEnd;
881 int k = 0;
882 //for each time in appointment array
883 for (j = 0; j < (cdtArray.Count -1); j++) // -1 b/c k below starts with j+1.
884 {
885 if ((DateTime) cdtArray[j] != dTemp)
886 {
887 dStart =(DateTime) cdtArray[j];
888 dTemp = dStart;
889
890 //for each time in appointment array, starting with the next one
891 for (k = j+1; k < cdtArray.Count; k++)
892 {
893 dEnd = new DateTime();
894 if ((DateTime) cdtArray[k] != dStart) //if the next time isn't the same
895 {
896 dEnd = (DateTime) cdtArray[k]; // set the end to be the next time
897 }
898 if (dEnd.Ticks > 0) //make a new availability and add it to the output array.
899 {
900 cTB = new CGAvailability();
901 cTB.Create(dStart, dEnd, 0);
902 rTBArray.Add(cTB);
903 break;
904 }
905 // if the end time is still empty, loop
906 }
907 }
908 }
909
910 }//end ScheduleFromArray
911 */
912
913 /*
914 //long CResourceLink::SlotsInBlock(CTimeBlock &rTimeBlock, _RecordsetPtr rsBlock)
915 public static int SlotsInBlock(CGAvailability rTimeBlock, DataTable rsBlock)
916 {
917 DateTime dStart1;
918 DateTime dStart2;
919 DateTime dEnd1;
920 DateTime dEnd2;
921 int nSlots = 0;
922
923 if (rsBlock.Rows.Count == 0)
924 return nSlots;
925
926 Rectangle rect1 = new Rectangle();
927 Rectangle rect2 = new Rectangle();
928 rect1.X = 0;
929 rect2.X = 0;
930 rect1.Width = 1;
931 rect2.Width = 1;
932
933 dStart1 = rTimeBlock.StartTime;
934 dEnd1 = rTimeBlock.EndTime;
935 rect1.Y = CGSchedLib.MinSince80(dStart1);
936 rect1.Height = CGSchedLib.MinSince80(dEnd1) - rect1.Y;
937
938 //for each row in the availability schedule
939 foreach (DataRow r in rsBlock.Rows)
940 {
941 dStart2 = (DateTime) r[rsBlock.Columns["START_TIME"]];
942 dEnd2 = (DateTime) r[rsBlock.Columns["END_TIME"]];
943
944 rect2.Y = CGSchedLib.MinSince80(dStart2);
945 rect2.Height = CGSchedLib.MinSince80(dEnd2) - rect2.Y;
946 if (rect2.IntersectsWith(rect1) == true)
947 {
948 string sSlots = r[rsBlock.Columns["SLOTS"]].ToString();
949 nSlots = System.Convert.ToInt16(sSlots);
950// nSlots = (int) r[rsBlock.Columns["SLOTS"]];
951 break;
952 }
953 }
954 return nSlots;
955 }//end SlotsInBlock
956 */
957
958 /*
959 public static string ClinicInBlock(CGAvailability rTimeBlock, DataTable rsBlock)
960 {
961 DateTime dStart1;
962 DateTime dStart2;
963 DateTime dEnd1;
964 DateTime dEnd2;
965 string sClinic = "";
966
967 if (rsBlock.Rows.Count == 0)
968 return sClinic;
969
970 Rectangle rect1 = new Rectangle();
971 Rectangle rect2 = new Rectangle();
972 rect1.X = 0;
973 rect2.X = 0;
974 rect1.Width = 1;
975 rect2.Width = 1;
976
977 dStart1 = rTimeBlock.StartTime;
978 dEnd1 = rTimeBlock.EndTime;
979 rect1.Y = CGSchedLib.MinSince80(dStart1);
980 rect1.Height = CGSchedLib.MinSince80(dEnd1) - rect1.Y;
981
982 foreach (DataRow r in rsBlock.Rows)
983 {
984 dStart2 = (DateTime) r[rsBlock.Columns["START_TIME"]];
985 dEnd2 = (DateTime) r[rsBlock.Columns["END_TIME"]];
986
987 rect2.Y = CGSchedLib.MinSince80(dStart2);
988 rect2.Height = CGSchedLib.MinSince80(dEnd2) - rect2.Y;
989 if (rect2.IntersectsWith(rect1) == true)
990 {
991 sClinic = r[rsBlock.Columns["SUBCLINIC"]].ToString();
992 break;
993 }
994 }
995 return sClinic;
996 }//end ClinicInBlock
997 */
998
999 /*
1000 public static bool ResourceRulesInBlock(CGAvailability rTimeBlock, DataTable rsBlock, ref string sResourceList, ref string sAccessRuleList, ref string sNote)
1001 {
1002 DateTime dStart1;
1003 DateTime dStart2;
1004 DateTime dEnd1;
1005 DateTime dEnd2;
1006 string sResource;
1007 string sAccessRule;
1008
1009 if (rsBlock.Rows.Count == 0)
1010 return true;
1011
1012 Rectangle rect1 = new Rectangle();
1013 Rectangle rect2 = new Rectangle();
1014 rect1.X = 0;
1015 rect2.X = 0;
1016 rect1.Width = 1;
1017 rect2.Width = 1;
1018
1019 dStart1 = rTimeBlock.StartTime;
1020 dEnd1 = rTimeBlock.EndTime;
1021 rect1.Y = CGSchedLib.MinSince80(dStart1);
1022 rect1.Height = CGSchedLib.MinSince80(dEnd1) - rect1.Y;
1023
1024 foreach (DataRow r in rsBlock.Rows)
1025 {
1026 dStart2 = (DateTime) r[rsBlock.Columns["START_TIME"]];
1027 dEnd2 = (DateTime) r[rsBlock.Columns["END_TIME"]];
1028
1029 rect2.Y = CGSchedLib.MinSince80(dStart2);
1030 rect2.Height = CGSchedLib.MinSince80(dEnd2) - rect2.Y;
1031 if (rect2.IntersectsWith(rect1) == true)
1032 {
1033 sResource = r[rsBlock.Columns["RESOURCE"]].ToString();
1034 if (sResource == "NULL")
1035 sResource = "";
1036 if (sResource != "")
1037 {
1038 if (sResourceList == "")
1039 {
1040 sResourceList += sResource;
1041 }
1042 else
1043 {
1044 sResourceList += "^" + sResource;
1045 }
1046 }
1047 sAccessRule = r[rsBlock.Columns["ACCESS_TYPE"]].ToString();
1048 if (sAccessRule == "0")
1049 sAccessRule = "";
1050 if (sAccessRule != "")
1051 {
1052 if (sAccessRuleList == "")
1053 {
1054 sAccessRuleList += sAccessRule;
1055 }
1056 else
1057 {
1058 sAccessRuleList += "^" + sAccessRule;
1059 }
1060 }
1061 sNote = r[rsBlock.Columns["NOTE"]].ToString();
1062
1063 }
1064 }
1065 return true;
1066 }//End ResourceRulesInBlock
1067 */
1068
1069
1070 }
1071}
Note: See TracBrowser for help on using the repository browser.