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

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

Absorbed all changed from Radiology Support branch.
Patient and Provider classes now serializable to address new bug: Availablity slots cannot be saved b/c these classes are not serializable.

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