00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018 #ifdef HAVE_CONFIG_H
00019 #include <config.h>
00020 #endif
00021
00022 #include <cmath>
00023 #include <iostream>
00024
00025 using namespace std;
00026
00027 #include "project.h"
00028
00029 int Project::ResourceIsUsedForTask( RESOURCE *r, TASK *t, int dayNo )
00030 {
00031 for( ResourceTimeBlockIterator tb = r->begin_booked() ;
00032 tb != r->end_booked() ; tb++ )
00033 {
00034 if ( ( dayNo >= tb->start() )
00035 && ( dayNo <= tb->finish() )
00036 && ( tb->task() == t ) )
00037 {
00038 Debug("ResourceIsUsedForTask(%s,%s,%d) - yes",
00039 r->id(), t->id(), dayNo);
00040 return 1;
00041 }
00042 }
00043
00044 Debug("ResourceIsUsedForTask(%s,%s,%d) - no", r->id(), t->id(), dayNo);
00045 return 0;
00046 }
00047
00048
00049 int Project::FirstFreeTime(TASK *task, RESOURCE *r, int earliest, int duration)
00050 {
00051 Debug("FirstFreeTime(%s,%d/%s,%d)",
00052 r->id(),earliest,days[earliest].s,duration);
00053
00054 for ( int i = 0; earliest+i+duration<MAX_TIME; ++i )
00055 {
00056 if ( r->IsAvailable( earliest+i, earliest+i+duration-1 ) )
00057 return earliest+i;
00058 }
00059
00060 Error("Resource %s not available to do %s at time >= %s",
00061 r->id(), task->id(), days[earliest].s);
00062
00063
00064 return -1;
00065 }
00066
00067
00068 void Project::BookResource(TASK *t, RESOURCE *parent, RESOURCE *r,
00069 int tstart, int tfinish, TimeBlock::Type type)
00070 {
00071 Debug("BookResource(%s,%s,%s,%d,%d)", t->id(),
00072 parent==NULL?"NULL":parent->id(),
00073 r==NULL?"NULL":r->id(),
00074 tstart, tfinish);
00075
00076 if ( ! r->IsAvailable(tstart, tfinish) )
00077 {
00078 bool only_vac = true;
00079 Warning("Double booking! %s / %s / %s-%s", r->id(), t->id(),
00080 days[tstart].s, days[tfinish].s);
00081 for ( ResourceTimeBlockIterator tb = r->begin_booked() ;
00082 tb != r->end_booked() ;
00083 tb++ )
00084 {
00085 if ( tb->overlap(tstart, tfinish) )
00086 {
00087 Warning("Overlap: %s %s (%s-%s) / %s %s %s-%s",
00088 tb->task()->id(),
00089 tb->task()->assigned() == NULL ? "(unassigned)" :
00090 tb->task()->assigned()->id(),
00091 days[tb->task()->start()].s, days[tb->task()->finish()].s,
00092 t->id(),
00093 t->assigned()==NULL?"(unassigned)":t->assigned()->id(),
00094 days[tb->start()].s, days[tb->finish()].s);
00095 if ( ! tb->task()->isVacation() || ! t->isVacation() )
00096 only_vac = false;
00097 }
00098 }
00099 if ( only_vac )
00100 Warning("You have double-booked vacations for %s. Ignoring.",
00101 r->id());
00102 else
00103 Error("You cannot double-book tasks.");
00104 }
00105
00106
00107 t->addTimeBlock(r, tstart, tfinish, type);
00108 r->addTimeBlock(t, tstart, tfinish, type);
00109
00110 if ( r->is_group )
00111 {
00112 for ( RPLCI rl = r->contains.begin() ; rl != r->contains.end() ; rl++ )
00113 {
00114 if ( ( *rl != parent ) && ( *rl != r ) )
00115 (*rl)->addTimeBlock(t, tstart, tfinish, type);
00116 }
00117 }
00118 else
00119 {
00120 for ( RPLCI rl = r->belongs_to.begin() ; rl != r->belongs_to.end() ; rl++ )
00121 {
00122 if ( ( *rl != parent ) && ( *rl != r ) )
00123 (*rl)->addTimeBlock(t, tstart, tfinish, type);
00124 }
00125 }
00126 }
00127
00128
00129 void Project::ReverseBookResource(TASK *t, RESOURCE *parent, RESOURCE *r,
00130 int tstart, int tfinish, TimeBlock::Type type)
00131 {
00132 Debug("ReverseBookResource(%s,%s,%s,%d,%d)", t->id(),
00133 parent==NULL?"NULL":parent->id(),
00134 r==NULL?"NULL":r->id(),
00135 tstart, tfinish);
00136
00137 if ( ! r->reverseIsAvailable(tstart, tfinish) )
00138 {
00139 bool only_vac = true;
00140 Warning("Reverse Double booking! %s / %s / %s-%s", r->id(), t->id(),
00141 days[tstart].s, days[tfinish].s);
00142 for ( ResourceTimeBlockIterator tb = r->begin_rbooked() ;
00143 tb != r->end_rbooked() ;
00144 tb++ )
00145 {
00146 if ( tb->overlap(tstart, tfinish) )
00147 {
00148 Warning("Overlap: %s %s (%s-%s) / %s %s %s-%s",
00149 tb->task()->id(),
00150 tb->task()->assigned() == NULL ? "(unassigned)" :
00151 tb->task()->assigned()->id(),
00152 days[tb->task()->start()].s, days[tb->task()->finish()].s,
00153 t->id(),
00154 t->assigned()==NULL?"(unassigned)":t->assigned()->id(),
00155 days[tb->start()].s, days[tb->finish()].s);
00156 if ( ! tb->task()->isVacation() || ! t->isVacation() )
00157 only_vac = false;
00158 }
00159 }
00160 if ( only_vac )
00161 Warning("ReverseBookResource: You have double-booked vacations for %s. Ignoring.",
00162 r->id());
00163 else
00164 Error("ReverseBookResource: You cannot double-book tasks.");
00165 }
00166
00167
00168 t->addReverseTimeBlock(r, tstart, tfinish, type);
00169
00170 r->addReverseTimeBlock(t, tstart, tfinish, type);
00171
00172 if ( r->is_group )
00173 {
00174 for ( RPLCI rl = r->contains.begin() ; rl != r->contains.end() ; rl++ )
00175 {
00176 if ( ( *rl != parent ) && ( *rl != r ) )
00177 (*rl)->addReverseTimeBlock(t, tstart, tfinish, type);
00178 }
00179 }
00180 else
00181 {
00182 for ( RPLCI rl = r->belongs_to.begin() ; rl != r->belongs_to.end() ; rl++ )
00183 {
00184 if ( ( *rl != parent ) && ( *rl != r ) )
00185 (*rl)->addReverseTimeBlock(t, tstart, tfinish, type);
00186 }
00187 }
00188 }
00189
00190
00191 void Project::AssignResource(TASK *t, RESOURCE *r, int tstart)
00192 {
00193 int real_remaining;
00194
00195 Debug("AssignResource %s/%s start=%d", t->id(), r->id(), tstart);
00196
00197 Debug("AssignResource(%s,%s,%d)", t->id(), r->id(), tstart);
00198
00199 if ( t->scheduled )
00200 Error("Trying to double-book (%s,%s,%d)", t->id(), r->id(), tstart);
00201
00202 if ( t->assigned() == NULL )
00203 {
00204 if ( t->remaining == 0.0 )
00205 Error("AssignResource: t->remaining == 0 but no assigned resource");
00206 t->setAssigned( r) ;
00207 }
00208 else
00209 {
00210 if ( t->assigned() != r )
00211 Error("AssignResource trying to assign second resource to task %s",
00212 t->id() );
00213 }
00214
00215
00216 if ( t->remaining == -1 )
00217 {
00218
00219 t->remaining = t->fullduration();
00220 }
00221 else
00222 {
00223 Debug("AssignResource(%s,%s): remaining pre-set to %d",
00224 t->id(), r->id(), t->remaining);
00225 }
00226
00227
00228
00229 if ( !t->isVacation() )
00230 {
00231 real_remaining = int(t->remaining/r->efficiency()+.5);
00232 Debug("%s %d %f %d",
00233 t->id(), t->remaining, r->efficiency(), real_remaining);
00234 }
00235 else
00236 {
00237 real_remaining = t->remaining;
00238 }
00239
00240 if ( t->block() )
00241 {
00242 while ( r->IsAvailable(tstart, tstart+real_remaining-1) == 0 )
00243 ++tstart;
00244 BookResource(t, NULL, r, tstart, tstart+real_remaining-1,
00245 TimeBlock::AUTO_SCHEDULE);
00246 if ( ( t->start() == INVALIDDAYNO ) || ( tstart < t->start() ) )
00247 t->setStart( tstart );
00248 tstart += real_remaining;
00249 t->remaining = 0;
00250 t->scheduled = 1;
00251 }
00252 else
00253 {
00254
00255 while ( real_remaining > 0 )
00256 {
00257
00258 while ( ! r->IsAvailable(tstart, tstart) )
00259 ++tstart;
00260
00261 if ( ( t->start() == INVALIDDAYNO ) || ( tstart < t->start() ) )
00262 t->setStart( tstart );
00263
00264 for ( int i = real_remaining ; i > 0 ; --i )
00265 {
00266 if ( r->IsAvailable(tstart, tstart + i - 1) )
00267 {
00268 Debug("AddTimeBlock(%s,%s,%d,%d)", t->id(), r->id(),
00269 tstart, tstart + i - 1);
00270 BookResource(t, NULL, r, tstart, tstart + i - 1,
00271 TimeBlock::AUTO_SCHEDULE);
00272 real_remaining -= i;
00273 tstart += i;
00274 break;
00275 }
00276 }
00277 }
00278 t->remaining = 0;
00279 }
00280
00281 --tstart;
00282 Debug("%s finish = %d", t->id(), tstart);
00283 t->setFinish( tstart );
00284 t->scheduled = 1;
00285 }
00286
00287
00288 void Project::ReverseAssignResource(TASK *t, RESOURCE *r, int tfinish)
00289 {
00290 int i;
00291 int real_rremaining;
00292
00293 Debug("ReverseAssignResource(%s,%s,%d)", t->id(), r->id(), tfinish);
00294
00295 if ( t->rscheduled )
00296 {
00297 Error("Trying to double-book (%s,%s,%d)", t->id(), r->id(), tfinish);
00298 return;
00299 }
00300
00301 if ( t->assigned() == NULL )
00302 Error("ReverseAssignResource: t->assigned == NULL");
00303 if ( t->assigned() != r )
00304 Error("ReverseAssignResource trying to assign second resource to task %s",
00305 t->id());
00306
00307 if ( t->rremaining == -1 )
00308 t->rremaining = t->fullduration();
00309
00310 Debug("ReverseAssignResource t->rremaining = %d", t->rremaining);
00311
00312 #if 0
00313
00314 t->lfinish = tfinish;
00315 tfinish -= t->rremaining;
00316 t->rremaining = 0;
00317
00318 #else
00319
00320
00321
00322 if ( !t->isVacation() )
00323 {
00324 real_rremaining = int(t->rremaining/r->efficiency()+.5);
00325 }
00326 else
00327 {
00328 real_rremaining = t->rremaining;
00329 }
00330 if ( t->block() )
00331 {
00332 while ( ! r->reverseIsAvailable(tfinish-real_rremaining+1, tfinish) )
00333 --tfinish;
00334 ReverseBookResource(t, NULL, r, tfinish-real_rremaining+1, tfinish,
00335 TimeBlock::AUTO_SCHEDULE);
00336 if ( ( t->lfinish() == INVALIDDAYNO ) || ( tfinish > t->lfinish() ) )
00337 t->setLfinish( tfinish );
00338 tfinish -= real_rremaining;
00339 t->rremaining = 0;
00340 }
00341 else
00342 {
00343 while (real_rremaining > 0 )
00344 {
00345
00346 Debug("ReverseAssignResource tfinish=%d", tfinish);
00347
00348
00349
00350
00351 while ( ! r->reverseIsAvailable(tfinish, tfinish) )
00352 --tfinish;
00353
00354 Debug("ReverseAssignResource got tfinish=%d", tfinish);
00355
00356
00357 if ( ( t->lfinish() == INVALIDDAYNO ) || ( tfinish > t->lfinish() ) )
00358 t->setLfinish( tfinish );
00359
00360 for ( i = real_rremaining ; i > 0 ; --i )
00361 {
00362 if ( r->reverseIsAvailable(tfinish - i + 1, tfinish) )
00363 {
00364 Debug("Reverse AddTimeBlock(%s,%s,%d,%d)",
00365 t->id(), r->id(),
00366 tfinish -i + 1, tfinish);
00367 ReverseBookResource(t, NULL, r, tfinish - i + 1, tfinish,
00368 TimeBlock::AUTO_SCHEDULE);
00369 real_rremaining -= i;
00370 tfinish -= i;
00371 break;
00372 }
00373 }
00374 }
00375 t->rremaining = 0;
00376 }
00377
00378 #endif
00379
00380 ++tfinish ;
00381 Debug("Reverse %s start = %d", t->id(), tfinish);
00382 t->setLstart( tfinish );
00383 t->rscheduled = 1;
00384 }
00385
00386
00387 int EarliestByDependency(TASK *t)
00388 {
00389 int t_earliest;
00390
00391 if ( t->start() == INVALIDDAYNO )
00392 t_earliest = 0;
00393 else
00394 t_earliest = t->start();
00395
00396 for ( TaskTimeBlockIterator tb = t->begin_when(); tb != t->end_when(); tb++ )
00397 {
00398 if ( tb->finish() + 1 > t_earliest )
00399 {
00400 t_earliest = tb->finish() + 1;
00401
00402 }
00403 }
00404
00405 for ( TASK::PTRLIST::const_iterator pt = t->begin_depends();
00406 pt != t->end_depends();
00407 pt++ )
00408 {
00409 if ( (*pt)->finish() + 1 > t_earliest )
00410 {
00411 t_earliest = (*pt)->finish() + 1;
00412 }
00413 }
00414 return t_earliest;
00415 }
00416
00417 RESOURCE *Project::FindEarliestResource(TASK *t, int t_earliest)
00418 {
00419 RESOURCE *r = NULL;
00420 RESOURCE *r2 = NULL;
00421 int tmin = MAX_TIME, tr;
00422 int real_remaining;
00423
00424 for ( RPLCI rl = t->begin_cando(); rl != t->end_cando(); rl++ )
00425 {
00426 r2 = *rl;
00427 real_remaining = int(t->remaining/r2->efficiency()+.5);
00428 tr = FirstFreeTime(t, *rl, t_earliest, t->block() ? real_remaining : 1 );
00429 if( tmin > tr )
00430 {
00431 tmin = tr;
00432 r = *rl;
00433 }
00434 }
00435
00436 return r;
00437 }
00438
00439
00440 void Project::AssignTask(TASK *t)
00441 {
00442 Debug("AssignTask(%s)", t->id());
00443
00444 if ( t->scheduled )
00445 {
00446 Debug("AssignTask(%s) -- already scheduled.", t->id());
00447 return;
00448 }
00449
00450
00451 if ( ( t->assigned() == NULL ) && ( t->numCandidates() == 1 ) )
00452 t->setAssigned( *(t->begin_cando()) );
00453
00454
00455 if ( t->assigned() == NULL )
00456 {
00457 RESOURCE *r;
00458 int t_earliest = EarliestByDependency(t);
00459
00460 if ( t->start() != INVALIDDAYNO )
00461 {
00462 if ( t_earliest <= t->start() )
00463 t_earliest = t->start();
00464 else
00465 Warning("Cannot start task %s at %s - moving to %s",
00466 t->id(), days[t->start()].s, days[t_earliest].s);
00467 }
00468
00469 r = FindEarliestResource(t, t_earliest);
00470 Debug("AssignTask(1)");
00471 AssignResource(t, r, t_earliest );
00472 }
00473 else
00474 {
00475 if ( t->start() == INVALIDDAYNO )
00476 {
00477 int t_earliest = EarliestByDependency(t);
00478 Debug("AssignTask(2)");
00479 AssignResource(t, t->assigned(), t_earliest );
00480 }
00481 else
00482 {
00483 Debug("AssignTask(3)");
00484 int t_earliest = t->start();
00485 for ( TaskTimeBlockIterator tb=t->begin_when(); tb != t->end_when(); tb++ )
00486 {
00487 if ( tb->finish() + 1 > t_earliest )
00488 {
00489 t_earliest = tb->finish() + 1;
00490 }
00491 }
00492 AssignResource(t, t->assigned(), t_earliest);
00493 }
00494 }
00495 if ( t->start() == INVALIDDAYNO )
00496 Error("t->start == INVALIDDAYNO for task id %s", t->id());
00497 }
00498
00499
00500 int EligibleTask(TASK *t)
00501 {
00502
00503 if ( t->scheduled )
00504 return 0;
00505
00506
00507
00508
00509
00510
00511
00512
00513 for ( TASK::PTRLIST::const_iterator pt = t->begin_depends();
00514 pt != t->end_depends();
00515 pt++ )
00516 if ( !(*pt)->scheduled )
00517 return 0;
00518
00519 return 1;
00520 }
00521
00522
00523 void Project::ReverseAssignTask(TASK *t)
00524 {
00525 int t_latest;
00526
00527 Debug("ReverseAssignTask(%s)", t->id());
00528
00529 if ( t->rscheduled )
00530 {
00531 Debug("ReverseAssignTask(%s) -- already scheduled.", t->id());
00532 return;
00533 }
00534
00535
00536
00537 if ( t->assigned() == NULL )
00538 Error("ReverseAssignTask(%s) -- no resource assigned.", t->id());
00539
00540 if ( t->lfinish() == INVALIDDAYNO )
00541 {
00542 t_latest = finishDay;
00543 for ( TASK::PTRLIST::const_iterator pt = t->begin_follows();
00544 pt != t->end_follows();
00545 pt++ )
00546 if ( (*pt)->lstart() <= t_latest )
00547 t_latest = (*pt)->lstart() - 1;
00548 ReverseAssignResource(t, t->assigned(), t_latest );
00549 }
00550 else
00551 {
00552 t_latest = t->lfinish();
00553 for ( TaskTimeBlockIterator tb = t->begin_when(); tb != t->end_when(); tb++ )
00554 if ( tb->start() - 1 < t_latest )
00555 t_latest = tb->start() - 1;
00556 ReverseAssignResource(t, t->assigned(), t_latest);
00557 }
00558
00559 if ( t->lfinish() == INVALIDDAYNO )
00560 Error("t->lfinish == INVALIDDAYNO for task id %s", t->id());
00561 }
00562
00563
00564 int ReverseEligibleTask(TASK *t)
00565 {
00566
00567 if ( t->rscheduled )
00568 return 0;
00569
00570 for ( TASK::PTRLIST::const_iterator pt = t->begin_follows();
00571 pt != t->end_follows();
00572 pt++ )
00573 if ( !(*pt)->rscheduled )
00574 return 0;
00575
00576 return 1;
00577 }
00578
00579
00580 void Project::PredictOverruns()
00581 {
00582 int duration;
00583 char buf[1000];
00584
00585 for ( TPLCI pt = mTaskList.begin() ; pt != mTaskList.end() ; pt++ )
00586 {
00587 TASK * t = *pt;
00588 float relative_days;
00589
00590
00591
00592 t->setOrigfullduration();
00593
00594 if ( t->percent_complete() == 0 )
00595 continue;
00596
00597 if ( ( t->begin_when() == t->end_when() ) && ( t->nDays() == 0 ) )
00598 continue;
00599
00600 if ( t->begin_when() != t->end_when() )
00601 {
00602 relative_days = 0.;
00603 for ( TaskTimeBlockIterator tb = t->begin_when() ; tb != t->end_when(); tb++ )
00604 {
00605 if ( tb->type() == TimeBlock::WORK_DONE )
00606 {
00607 relative_days += (tb->finish() - tb->start() + 1 )*tb->resource()->efficiency();
00608 }
00609 }
00610 t->setDaysDone ( (int)(relative_days+0.5));
00611 }
00612
00613
00614 duration = (int)((double)t->nDays() / (0.01 * t->percent_complete()) + 0.5);
00615
00616
00617 if ( duration != t->fullduration() )
00618 {
00619 sprintf(buf,
00620 "%s changed from %d to %d days, based on completion of %g%% in %d day%s.",
00621 t->id(), t->fullduration(), duration, t->percent_complete(),
00622 t->nDays(), t->nDays()>1?"s":"");
00623 t->setFullduration( duration );
00624
00625 if ( t->begin_when() != t->end_when() )
00626 t->remaining = duration - t->nDays();
00627 if ( t->remaining > 0 )
00628 t->scheduled = 0;
00629 t->setOverrun(buf);
00630 }
00631 }
00632 }
00633
00634
00635 void Project::ReverseScheduleTasks()
00636 {
00637 TASK *preferred;
00638 int parents;
00639 int schedFinish;
00640 int finish;
00641
00642
00643
00644 schedFinish = finishDay;
00645 for ( TPLCI pt = mTaskList.begin() ; pt != mTaskList.end() ; pt++ )
00646 {
00647 if ( (*pt)->isVacation() )
00648 continue;
00649 if ( ( schedFinish == INVALIDDAYNO )
00650 || ( (*pt)->finish() > schedFinish ) )
00651 schedFinish = (*pt)->finish();
00652 }
00653 if ( finishDay == INVALIDDAYNO )
00654 {
00655 finishDay = schedFinish;
00656 }
00657 else if ( schedFinish > finishDay )
00658 {
00659 Warning("Scheduled finish day (%s) is after assigned finish day (%s), ignoring latter",
00660 days[schedFinish].s, days[finishDay].s);
00661 finishDay = schedFinish;
00662 }
00663
00664
00665
00666
00667
00668
00669 for ( TPLCI pt = mTaskList.begin() ; pt != mTaskList.end() ; pt++ )
00670 if ( ( (*pt)->percent_complete() > 0.0 ) || (*pt)->isVacation() )
00671 {
00672 (*pt)->rscheduled = 1;
00673 (*pt)->setLstart( (*pt)->start() );
00674 (*pt)->setLfinish( (*pt)->finish() );
00675 (*pt)->copyWhenToReverseWhen();
00676 for (TaskTimeBlockIterator tb = (*pt)->begin_rwhen();
00677 tb != (*pt)->end_rwhen() ; tb++ )
00678 (*pt)->assigned()->addReverseTimeBlock((*pt),
00679 tb->start(),
00680 tb->finish(),
00681 tb->type());
00682 }
00683
00684 do
00685 {
00686
00687 finish = -1;
00688 parents = -1;
00689 preferred = NULL;
00690 for ( TPLCI pt = mTaskList.begin() ; pt != mTaskList.end() ; pt++ )
00691 {
00692 if ( !ReverseEligibleTask(*pt) )
00693 continue;
00694 else
00695 {
00696 if( (*pt)->finish() > finish )
00697 {
00698 finish = (*pt)->finish();
00699 preferred = (*pt);
00700 }
00701 }
00702 }
00703
00704 if ( preferred != NULL )
00705 ReverseAssignTask(preferred);
00706
00707 }
00708 while ( preferred != NULL );
00709
00710 for ( TPLCI pt = mTaskList.begin() ; pt != mTaskList.end() ; pt++ )
00711 if( !(*pt)->rscheduled )
00712 Error("Task %s not reverse scheduled - do you have a dependency loop?",
00713 (*pt)->id());
00714
00715
00716 for ( TPLCI pt = mTaskList.begin() ; pt != mTaskList.end() ; pt++ )
00717 (*pt)->setSlack( (*pt)->lstart() - (*pt)->start() );
00718
00719 #if 0
00720 for ( TPLCI pt = mTaskList.begin() ; pt != mTaskList.end() ; pt++ )
00721 if ( !(*pt)->isVacation() )
00722 fprintf(stderr, "task %s lstart %d lfinish %d slack %d\n",
00723 (*pt)->id,
00724 (*pt)->lstart,
00725 (*pt)->lfinish,
00726 (*pt)->slack);
00727 #endif
00728 }
00729
00730
00731 void Project::ScheduleMilestones()
00732 {
00733
00734 for ( MPLCI ml = beginMilestoneList() ; ml != endMilestoneList() ; ml++ )
00735 {
00736 MILESTONE *m = *ml;
00737 int day = INVALIDDAYNO;
00738 TASK *ct = NULL;
00739
00740 for ( TPLCI tl = m->begin_depends() ; tl != m->end_depends() ; tl++ )
00741 {
00742 TASK *t = *tl;
00743 if ( ( day == INVALIDDAYNO ) || ( t->finish() > day ) )
00744 {
00745 day = t->finish();
00746 ct = t;
00747 }
00748 }
00749
00750 m->setDay( day );
00751 m->setCritical( ct );
00752 }
00753 }
00754
00755
00756 void Project::ScheduleTasks()
00757 {
00758 TASK *preferred;
00759 int children;
00760
00761 Debug("Scheduling tasks");
00762
00763 do
00764 {
00765 children = -1;
00766 preferred = NULL;
00767 for ( TPLCI pt = mTaskList.begin() ; pt != mTaskList.end() ; pt++ )
00768 {
00769 if ( !EligibleTask(*pt) )
00770 continue;
00771
00772 if( (*pt)->children() > children )
00773 {
00774 children = (*pt)->children();
00775 preferred = (*pt);
00776 }
00777 }
00778
00779 if ( preferred != NULL )
00780 AssignTask(preferred);
00781
00782 }
00783 while ( preferred != NULL );
00784
00785 for ( TPLCI pt = mTaskList.begin() ; pt != mTaskList.end() ; pt++ )
00786 if( !(*pt)->scheduled )
00787 Error("Task %s not scheduled - do you have a dependency loop?",
00788 (*pt)->id());
00789 }
00790
00791
00792 void Project::DoScheduling()
00793 {
00794 Debug("Doing scheduling");
00795
00796 LoadDays();
00797
00798 PredictOverruns();
00799
00800 ScheduleTasks();
00801
00802 ReverseScheduleTasks();
00803
00804 ScheduleMilestones();
00805 }
00806
00807
00808 void Project::WorkBlock( TASK *t, RESOURCE * r, int d1, int d2,
00809 TimeBlock::Type type )
00810 {
00811 if ( t->nDays() != 0 )
00812 Error("Can't use past/future and done at same time(2)");
00813
00814 if ( t->assigned() == NULL )
00815 {
00816 t->setAssigned(r);
00817 }
00818 else
00819 {
00820 if ( t->assigned() != r )
00821 Error("Two resources assigned to same task %s", t->id());
00822 }
00823
00824 if ( t->start() == INVALIDDAYNO )
00825 t->setStart( d1 );
00826
00827 if ( d1 < t->start() )
00828 Error("Out of order assignment to task %s", t->id());
00829
00830 BookResource( t, NULL, r, d1, d2, static_cast<TimeBlock::Type>(type) );
00831
00832 if ( t->remaining == -1 )
00833 {
00834 t->remaining = t->duration();
00835 t->setFullduration( t->remaining );
00836 }
00837
00838 t->remaining -= (int)((d2-d1+1)*r->efficiency()+0.5);
00839 Debug("%d %d",(d2-d1+1), (int)((d2-d1+1)*r->efficiency()+0.5));
00840 if ( t->remaining <= 0 )
00841 {
00842 t->setFinish( d2 );
00843 t->scheduled = 1;
00844 if ( !t->isVacation() )
00845 Warning("Completed task %s",t->id());
00846 }
00847 }
00848
00849
00850
00851 void Project::StartTask( TASK *t, int d, int type )
00852 {
00853 switch(type)
00854 {
00855 case TNORM:
00856 t->setStart(d);
00857
00858 cerr << "StartTask: Invoking garbage - tread with care!\n";
00859
00860
00861 if( t->finish() == INVALIDDAYNO )
00862 {
00863 t-> setFinish( t->start() + t->duration() );
00864
00865 }
00866 else
00867 t->setDuration( t->finish() - t->start() );
00868
00869
00870 if ( t->numCandidates() == 1 )
00871 {
00872 t->setAssigned( *(t->begin_cando()) );
00873 BookResource( t, NULL, t->assigned(), t->start(), t->start(),
00874 TimeBlock::AUTO_SCHEDULE );
00875 t->setDuration( t->duration() - 1 );
00876 }
00877
00878
00879 t->setLstart(d);
00880
00881 break;
00882
00883 case TACTUAL:
00884 t->setAstart(d);
00885
00886
00887 break;
00888
00889 case TBASE:
00890 t->setBstart( d );
00891
00892
00893 break;
00894
00895 default:
00896 Error("Internal Error, unknown start-finish type; check that patchs are complete");
00897 break;
00898 }
00899 }
00900
00901
00902
00903 void Project::FinishTask( TASK *t, int d, int type )
00904 {
00905 switch(type)
00906 {
00907 case TNORM:
00908 t->setFinish( d );
00909
00910 cerr << "TASK::FinishTask: Invoking garbage - tread with care!\n";
00911
00912 if ( t->start() == INVALIDDAYNO )
00913 {
00914 t->setStart( t->finish() - t->duration() );
00915 if ( t->start() < 0 )
00916 Error("Finish task date generates too early start date");
00917 }
00918 else
00919 {
00920 t->setDuration( t->finish() - t->start() );
00921 if ( t->duration() <= 0 )
00922 Error("Finish task date generates duration <= 0");
00923 }
00924
00925 if ( t->assigned() != NULL )
00926 {
00927 BookResource( t, NULL, t->assigned(), t->start(), t->finish(),
00928 TimeBlock::AUTO_SCHEDULE );
00929 }
00930 break;
00931
00932 case TACTUAL:
00933
00934
00935 t->setAfinish( d );
00936 break;
00937
00938 case TBASE:
00939 t->setBfinish( d );
00940 break;
00941
00942 default:
00943 Error("Internal Error, unknown start-finish type; check that patchs are complete");
00944 break;
00945 }
00946 }
00947
00948