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

Last change on this file since 1071 was 1011, checked in by Sam Habiel, 14 years ago

UCPatientAppts: Fixes printing empty table bug reported by EHS.
DAccessTemplate: Various usability improvements.
CGDocumentManager: Fixed Delegate code so that it can operate asynchronously
CGAVView: Some temporary fixes (not totally usable): Added non-functional Delete Slots menu option; Added Background worker for saving acccess slots
In the future, Delete Slots will work; and will use ADO.net Updatable datatable for saving access slots.
calendarGrid: just some comments for now
AssemblyInfo: bumped version up to v1.4.2

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