Moodle  2.2.1
http://www.collinsharper.com
C:/xampp/htdocs/moodle/mod/scorm/datamodels/sequencinglib.php
Go to the documentation of this file.
00001 <?php
00002 // This file is part of Moodle - http://moodle.org/
00003 //
00004 // Moodle is free software: you can redistribute it and/or modify
00005 // it under the terms of the GNU General Public License as published by
00006 // the Free Software Foundation, either version 3 of the License, or
00007 // (at your option) any later version.
00008 //
00009 // Moodle is distributed in the hope that it will be useful,
00010 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00011 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012 // GNU General Public License for more details.
00013 //
00014 // You should have received a copy of the GNU General Public License
00015 // along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
00016 
00017 require ($CFG->dirroot.'/mod/scorm/datamodels/scormlib.php');
00018 
00019 function scorm_seq_evaluate($scoid,$usertracks) {
00020     return true;
00021 }
00022 
00023 function scorm_seq_overall ($scoid,$userid,$request,$attempt) {
00024     $seq = scorm_seq_navigation($scoid,$userid,$request,$attempt);
00025     if ($seq->navigation) {
00026         if ($seq->termination != null) {
00027             $seq = scorm_seq_termination($scoid,$userid,$seq);
00028         }
00029         if ($seq->sequencing != null) {
00030             $seq = scorm_seq_sequencing($scoid,$userid,$seq);
00031             if($seq->sequencing == 'exit'){//return the control to the LTS
00032                 return 'true';
00033             }
00034         }
00035         if ($seq->delivery != null) {
00036             $seq = scorm_sequencing_delivery($scoid,$userid,$seq);
00037             $seq = scorm_content_delivery_environment ($seq,$userid);
00038         }
00039     }
00040     if ($seq->exception != null) {
00041         $seq = scorm_sequencing_exception($seq);
00042     }
00043     return 'true';
00044 }
00045 
00046 
00047 function scorm_seq_navigation ($scoid,$userid,$request,$attempt=0) {
00048     global $DB;
00049 
00051     $seq = new stdClass();
00052     $seq->currentactivity = scorm_get_sco($scoid);
00053     $seq->traversaldir = null;
00054     $seq->nextactivity = null;
00055     $seq->deliveryvalid = null;
00056     $seq->attempt = $attempt;
00057 
00058     $seq->identifiedactivity = null;
00059     $seq->delivery = null;
00060     $seq->deliverable = false;
00061     $seq->active = scorm_seq_is('active',$scoid,$userid);
00062     $seq->suspended = scorm_seq_is('suspended',$scoid,$userid);
00063     $seq->navigation = null;
00064     $seq->termination = null;
00065     $seq->sequencing = null;
00066     $seq->target = null;
00067     $seq->endsession = null;
00068     $seq->exception = null;
00069     $seq->reachable = true;
00070     $seq->prevact = true;
00071 
00072     switch ($request) {
00073         case 'start_':
00074             if (empty($seq->currentactivity)) {
00075                 $seq->navigation = true;
00076                 $seq->sequencing = 'start';
00077             } else {
00078                 $seq->exception = 'NB.2.1-1'; 
00079             }
00080         break;
00081         case 'resumeall_':
00082             if (empty($seq->currentactivity)) {
00083                 if ($track = $DB->get_record('scorm_scoes_track', array('scoid'=>$scoid,'userid'=>$userid,'element'=>'suspendedactivity'))) {//I think it's suspend instead of suspendedactivity
00084                     $seq->navigation = true;
00085                     $seq->sequencing = 'resumeall';
00086                 } else {
00087                     $seq->exception = 'NB.2.1-3'; 
00088                 }
00089             } else {
00090                 $seq->exception = 'NB.2.1-1'; 
00091             }
00092         break;
00093         case 'continue_':
00094         case 'previous_':
00095             if (!empty($seq->currentactivity)) {
00096                 $sco = $seq->currentactivity;
00097                 if ($sco->parent != '/') {
00098                     if ($parentsco = scorm_get_parent($sco)) {
00099 
00100                          if (isset($parentsco->flow) && ($parentsco->flow == true)) {//I think it's parentsco
00101                             // Current activity is active !
00102                             if (scorm_seq_is('active',$sco->id,$userid)) {
00103                                 if ($request == 'continue_') {
00104                                     $seq->navigation = true;
00105                                     $seq->termination = 'exit';
00106                                     $seq->sequencing = 'continue';
00107                                 } else {
00108                                     if (!isset($parentsco->forwardonly) || ($parentsco->forwardonly == false)) {
00109                                         $seq->navigation = true;
00110                                         $seq->termination = 'exit';
00111                                         $seq->sequencing = 'previous';
00112                                     } else {
00113                                         $seq->exception = 'NB.2.1-5'; 
00114                                     }
00115                                 }
00116                             }
00117                         }
00118 
00119                     }
00120                 }
00121             } else {
00122                 $seq->exception = 'NB.2.1-2'; 
00123             }
00124         break;
00125         case 'forward_':
00126         case 'backward_':
00127             $seq->exception = 'NB.2.1-7' ; 
00128         break;
00129         case 'exit_':
00130         case 'abandon_':
00131             if (!empty($seq->currentactivity)) {
00132                 // Current activity is active !
00133                 $seq->navigation = true;
00134                 $seq->termination = substr($request,0,-1);
00135                 $seq->sequencing = 'exit';
00136             } else {
00137                 $seq->exception = 'NB.2.1-2'; 
00138             }
00139         case 'exitall_':
00140         case 'abandonall_':
00141         case 'suspendall_':
00142             if (!empty($seq->currentactivity)) {
00143                 $seq->navigation = true;
00144                 $seq->termination = substr($request,0,-1);
00145                 $seq->sequencing = 'exit';
00146             } else {
00147                 $seq->exception = 'NB.2.1-2'; 
00148             }
00149         break;
00150         default: 
00151             if ($targetsco = $DB->get_record('scorm_scoes', array('scorm'=>$sco->scorm,'identifier'=>$request))) {
00152                 if ($targetsco->parent != '/') {
00153                     $seq->target = $request;
00154                 } else {
00155                     if ($parentsco = scorm_get_parent($targetsco)) {
00156                         if (!isset($parentsco->choice) || ($parentsco->choice == true)) {
00157                             $seq->target = $request;
00158                         }
00159                     }
00160                 }
00161                 if ($seq->target != null) {
00162                     if (empty($seq->currentactivity)) {
00163                         $seq->navigation = true;
00164                         $seq->sequencing = 'choice';
00165                     } else {
00166                         if (!$sco = scorm_get_sco($scoid)) {
00167                             return $seq;
00168                         }
00169                         if ($sco->parent != $targetsco->parent) {
00170                             $ancestors = scorm_get_ancestors($sco);
00171                             $commonpos = scorm_find_common_ancestor($ancestors,$targetsco);
00172                             if ($commonpos !== false) {
00173                                 if ($activitypath = array_slice($ancestors,0,$commonpos)) {
00174                                     foreach ($activitypath as $activity) {
00175                                         if (scorm_seq_is('active',$activity->id,$userid) && (isset($activity->choiceexit) && ($activity->choiceexit == false))) {
00176                                             $seq->navigation = false;
00177                                             $seq->termination = null;
00178                                             $seq->sequencing = null;
00179                                             $seq->target = null;
00180                                             $seq->exception = 'NB.2.1-8'; 
00181                                             return $seq;
00182                                         }
00183                                     }
00184                                 } else {
00185                                     $seq->navigation = false;
00186                                     $seq->termination = null;
00187                                     $seq->sequencing = null;
00188                                     $seq->target = null;
00189                                     $seq->exception = 'NB.2.1-9';
00190                                 }
00191                             }
00192                         }
00193                         // Current activity is active !
00194                         $seq->navigation = true;
00195                         $seq->sequencing = 'choice';
00196                     }
00197                 } else {
00198                     $seq->exception = 'NB.2.1-10';  
00199                 }
00200             } else {
00201                 $seq->exception = 'NB.2.1-11';  
00202             }
00203         break;
00204     }
00205     return $seq;
00206 }
00207 
00208 function scorm_seq_termination ($seq,$userid) {
00209     if (empty($seq->currentactivity)) {
00210         $seq->termination = false;
00211         $seq->exception = 'TB.2.3-1';
00212         return $seq;
00213     }
00214 
00215     $sco = $seq->currentactivity;
00216 
00217     if ((($seq->termination == 'exit') || ($seq->termination == 'abandon')) && !$seq->active) {
00218         $seq->termination = false;
00219         $seq->exception = 'TB.2.3-2';
00220         return $seq;
00221     }
00222     switch ($seq->termination) {
00223         case 'exit':
00224             scorm_seq_end_attempt($sco,$userid,$seq);
00225             $seq = scorm_seq_exit_action_rules($seq,$userid);
00226             do {
00227                 $exit = false;// I think this is false. Originally this was true
00228                 $seq = scorm_seq_post_cond_rules($seq,$userid);
00229                 if ($seq->termination == 'exitparent') {
00230                     if ($sco->parent != '/') {
00231                         $sco = scorm_get_parent($sco);
00232                         $seq->currentactivity = $sco;
00233                         $seq->active = scorm_seq_is('active',$sco->id,$userid);
00234                         scorm_seq_end_attempt($sco,$userid,$seq);
00235                         $exit = true;//I think it's true. Originally this was false
00236                     } else {
00237                         $seq->termination = false;
00238                         $seq->exception = 'TB.2.3-4';
00239                         return $seq;
00240                     }
00241                 }
00242             } while (($exit == false) && ($seq->termination == 'exit'));
00243             if ($seq->termination == 'exit') {
00244                 $seq->termination = true;
00245                 return $seq;
00246             }
00247         case 'exitall':
00248             if ($seq->active) {
00249                 scorm_seq_end_attempt($sco,$userid,$seq);
00250             }
00252 
00253 
00254             if ($ancestors = scorm_get_ancestors($sco)) {
00255                 foreach ($ancestors as $ancestor) {
00256                     scorm_seq_end_attempt($ancestor,$userid,$seq);
00257                     $seq->currentactivity = $ancestor;
00258                 }
00259             }
00260 
00261             $seq->active = scorm_seq_is('active',$seq->currentactivity->id,$userid);
00262             $seq->termination = true;
00263             $seq->sequencing = exit;
00264         break;
00265         case 'suspendall':
00266             if (($seq->active) || ($seq->suspended)) {
00267                 scorm_seq_set('suspended',$sco->id,$userid);
00268             } else {
00269                 if ($sco->parent != '/') {
00270                     $parentsco = scorm_get_parent($sco);
00271                     scorm_seq_set('suspended',$parentsco->id,$userid);
00272                 } else {
00273                     $seq->termination = false;
00274                     $seq->exception = 'TB.2.3-3';
00275                     // return $seq;
00276                 }
00277             }
00278             if ($ancestors = scorm_get_ancestors($sco)) {
00279                 foreach ($ancestors as $ancestor) {
00280                     scorm_seq_set('active',$ancestor->id,$userid,false);
00281                     scorm_seq_set('suspended',$ancestor->id,$userid);
00282                     $seq->currentactivity = $ancestor;
00283                 }
00284                 $seq->termination = true;
00285                 $seq->sequencing = 'exit';
00286             } else {
00287                 $seq->termination = false;
00288                 $seq->exception = 'TB.2.3-5';
00289             }
00290         break;
00291         case 'abandon':
00292             scorm_seq_set('active',$sco->id,$userid,false);
00293             $seq->active = null;
00294             $seq->termination = true;
00295         break;
00296         case 'abandonall':
00297             if ($ancestors = scorm_get_ancestors($sco)) {
00298                 foreach ($ancestors as $ancestor) {
00299                     scorm_seq_set('active',$ancestor->id,$userid,false);
00300                     $seq->currentactivity = $ancestor;
00301                 }
00302                 $seq->termination = true;
00303                 $seq->sequencing = 'exit';
00304             } else {
00305                 $seq->termination = false;
00306                 $seq->exception = 'TB.2.3-6';
00307             }
00308         break;
00309         default:
00310             $seq->termination = false;
00311             $seq->exception = 'TB.2.3-7';
00312         break;
00313     }
00314     return $seq;
00315 }
00316 
00317 function scorm_seq_end_attempt($sco,$userid,$seq) {
00318     global $DB;
00319 
00320     if (scorm_is_leaf($sco)) {
00321         if (!isset($sco->tracked) || ($sco->tracked == 1)) {
00322             if (!scorm_seq_is('suspended',$sco->id,$userid)) {
00323                 if (!isset($sco->completionsetbycontent) || ($sco->completionsetbycontent == 0)) {
00324                     if (!scorm_seq_is('attemptprogressstatus',$sco->id,$userid,$seq->attempt)) {
00325                   // if (!scorm_seq_is('attemptprogressstatus',$sco->id,$userid)) {
00326                         scorm_seq_set('attemptprogressstatus',$sco->id,$userid);
00327                         scorm_seq_set('attemptcompletionstatus',$sco->id,$userid);
00328                     }
00329                 }
00330                 if (!isset($sco->objectivesetbycontent) || ($sco->objectivesetbycontent == 0)) {
00331                     if ($objectives = $DB->get_records('scorm_seq_objective', array('scoid'=>$sco->id))) {
00332                         foreach ($objectives as $objective) {
00333                             if ($objective->primaryobj) {
00334                                 //if (!scorm_seq_objective_progress_status($sco,$userid,$objective)) {
00335                                 if (!scorm_seq_is('objectiveprogressstatus',$sco->id,$userid)) {
00336                                     scorm_seq_set('objectiveprogressstatus',$sco->id,$userid);
00337                                     scorm_seq_set('objectivesatisfiedstatus',$sco->id,$userid);
00338                                 }
00339                             }
00340                         }
00341                     }
00342                 }
00343             }
00344         }
00345     } else {
00346         if ($children = scorm_get_children($sco)) {
00347             $suspended = false;
00348             foreach ($children as $child) {
00349                 if (scorm_seq_is('suspended',$child,$userid)) {
00350                     $suspended = true;
00351                     break;
00352                 }
00353             }
00354             if ($suspended) {
00355                 scorm_seq_set('suspended',$sco,$userid);
00356             } else {
00357                 scorm_seq_set('suspended',$sco,$userid,false);
00358             }
00359         }
00360     }
00361     scorm_seq_set('active',$sco,$userid,0,false);
00362     scorm_seq_overall_rollup($sco,$userid, $seq);
00363 }
00364 
00365 function scorm_seq_is($what, $scoid, $userid, $attempt=0) {
00366     global $DB;
00367 
00369     $active = false;
00370     if ($track = $DB->get_record('scorm_scoes_track', array('scoid'=>$scoid,'userid'=>$userid,'attempt'=>$attempt,'element'=>$what))) {
00371         $active = true;
00372     }
00373     return $active;
00374 }
00375 
00376 function scorm_seq_set($what, $scoid, $userid, $attempt=0, $value='true') {
00377     global $DB;
00378 
00379     $sco = scorm_get_sco($scoid);
00380 
00382     if ($value == false) {
00383         $DB->delete_record('scorm_scoes_track', array('scoid'=>$scoid,'userid'=>$userid,'attempt'=>$attempt,'element'=>$what));
00384     } else {
00385         scorm_insert_track($userid, $sco->scorm, $sco->id, 0, $what, $value);
00386     }
00387 
00388     // update grades in gradebook
00389     $scorm = $DB->get_record('scorm', array('id'=>$sco->scorm));
00390     scorm_update_grades($scorm, $userid, true);
00391 }
00392 
00393 function scorm_seq_exit_action_rules($seq,$userid) {
00394     $sco = $seq->currentactivity;
00395     $ancestors = scorm_get_ancestors($sco);
00396     $exittarget = null;
00397     foreach (array_reverse($ancestors) as $ancestor) {
00398         if (scorm_seq_rules_check($ancestor,'exit') != null) {
00399             $exittarget = $ancestor;
00400             break;
00401         }
00402     }
00403     if ($exittarget != null) {
00404         $commons = array_slice($ancestors,0,scorm_find_common_ancestor($ancestors,$exittarget));
00405 
00407         if ($commons) {
00408             foreach ($commons as $ancestor) {
00409 
00410                 scorm_seq_end_attempt($ancestor,$userid,$seq->attempt);
00411                 $seq->currentactivity = $ancestor;
00412             }
00413         }
00414     }
00415     return $seq;
00416 }
00417 
00418 function scorm_seq_post_cond_rules($seq,$userid) {
00419     $sco = $seq->currentactivity;
00420     if (!$seq->suspended) {
00421         if ($action = scorm_seq_rules_check($sco,'post') != null) {
00422             switch($action) {
00423                 case 'retry':
00424                 case 'continue':
00425                 case 'previous':
00426                     $seq->sequencing = $action;
00427                 break;
00428                 case 'exitparent':
00429                 case 'exitall':
00430                     $seq->termination = $action;
00431                 break;
00432                 case 'retryall':
00433                     $seq->termination = 'exitall';
00434                     $seq->sequencing = 'retry';
00435                 break;
00436             }
00437         }
00438     }
00439     return $seq;
00440 }
00441 
00442 function scorm_seq_rules_check ($sco, $action){
00443     global $DB;
00444 
00445     $act = null;
00446     if($rules = $DB->get_records('scorm_seq_ruleconds', array('scoid'=>$sco->id,'action'=>$action))) {
00447         foreach ($rules as $rule){
00448             if($act = scorm_seq_rule_check($sco,$rule)){
00449                 return $act;
00450             }
00451         }
00452     }
00453     return $act;
00454 
00455 }
00456 
00457 function scorm_seq_rule_check ($sco, $rule){
00458     global $DB;
00459 
00460     $bag = Array();
00461     $cond = '';
00462     $ruleconds = $DB->get_records('scorm_seq_rulecond', array('scoid'=>$sco->id,'ruleconditionsid'=>$rule->id));
00463     foreach ($ruleconds as $rulecond){
00464          if ($rulecond->operator = 'not') {
00465              if ($rulecond->cond != 'unknown' ){
00466                 $rulecond->cond = 'not'.$rulecond;
00467              }
00468          }
00469          $bag [$rule->id] = $rulecond->cond;
00470 
00471     }
00472     if (empty($bag)){
00473         $cond = 'unknown';
00474         return $cond;
00475     }
00476 
00477     $size= sizeof($bag);
00478     $i=0;
00479 
00480     if ($rule->conditioncombination = 'all'){
00481         foreach ($bag as $con){
00482                 $cond = $cond.' and '.$con;
00483 
00484         }
00485     }
00486     else{
00487         foreach ($bag as $con){
00488             $cond = $cond.' or '.$con;
00489         }
00490     }
00491     return $cond;
00492 }
00493 
00494 
00495 function scorm_seq_overall_rollup($sco,$userid, $seq){//Carlos
00496 
00497      if ($ancestors = scorm_get_ancestors($sco)) {
00498             foreach ($ancestors as $ancestor) {
00499                 if(!scorm_is_leaf($ancestor)){
00500                     scorm_seq_measure_rollup($sco,$userid);
00501                 }
00502                 scorm_seq_objective_rollup($sco,$userid);
00503                 scorm_seq_activity_progress_rollup($sco,$userid, $seq);
00504 
00505             }
00506 
00507      }
00508 }
00509 
00510 /* For this next function I have defined measure weight and measure status as records with the attempt = 0 on the scorm_scoes_track table. According to the page 89 of the SeqNav.pdf those datas give us some information about the progress of the objective*/
00511 
00512 function scorm_seq_measure_rollup($sco,$userid){
00513     global $DB;
00514 
00515     $totalmeasure = 0; //Check if there is something similar in the database
00516     $valid = false;//Same as in the last line
00517     $countedmeasures = 0;//Same too
00518     $targetobjective = null;
00519     $readable = true;//to check if status and measure weight are readable
00520     $objectives = $DB->get_records('scorm_seq_objective', array('scoid'=>$sco->id));
00521 
00522     foreach ($objectives as $objective){
00523 
00524         if ($objective->primaryobj == true){//Objective contributes to rollup I'm using primaryobj field, but not
00525             $targetobjective = $objective;
00526             break;
00527         }
00528 
00529     }
00530 
00531     if ($targetobjective != null){
00532         $children = scorm_get_children($sco);
00533         foreach ($children as $child){
00534             $child = scorm_get_sco ($child);
00535             if (!isset($child->tracked) || ($child->tracked == 1)){
00536 
00537                 $rolledupobjective = null;// we set the rolled up activity to undefined
00538                 $objectives = $DB->get_records('scorm_seq_objective', array('scoid'=>$child->id));
00539                 foreach ($objectives as $objective){
00540                     if ($objective->primaryobj == true){//Objective contributes to rollup I'm using primaryobj field, but not
00541                         $rolledupobjective = $objective;
00542                         break;
00543                     }
00544                 }
00545                 if ($rolledupobjective != null){
00546                     $child = scorm_get_sco($child->id);
00547 
00548                     $countedmeasures = $countedmeasures + ($child->measureweight);
00549                     if (!scorm_seq_is('objectivemeasurestatus',$sco->id,$userid)) {
00550                         $normalizedmeasure = $DB->get_record('scorm_scoes_track', array('scoid'=>$child->id,'userid'=>$userid,'element'=>'objectivenormalizedmeasure'));
00551                         $totalmeasure = $totalmeasure + (($normalizedmeasure->value) * ($child->measureweight));
00552                         $valid = true;
00553                     }
00554 
00555 
00556 
00557                 }
00558             }
00559         }
00560 
00561 
00562         if(!$valid){
00563 
00564             scorm_seq_set('objectivemeasurestatus',$sco->id,$userid,false);
00565 
00566         }
00567         else{
00568             if($countedmeasures>0){
00569                 scorm_seq_set('objectivemeasurestatus',$sco->id,$userid);
00570                 $val=$totalmeasure/$countedmeasures;
00571                 scorm_seq_set('objectivenormalizedmeasure',$sco->id,$userid,$val);
00572 
00573             }
00574             else{
00575                 scorm_seq_set('objectivemeasurestatus',$sco->id,$userid,false);
00576 
00577             }
00578         }
00579 
00580     }
00581 
00582 }
00583 
00584 function scorm_seq_objective_rollup($sco,$userid){
00585     global $DB;
00586 
00587     scorm_seq_objective_rollup_measure($sco,$userid);
00588     scorm_seq_objective_rollup_rules($sco,$userid);
00589     scorm_seq_objective_rollup_default($sco,$userid);
00590 
00591 /*
00592     if($targetobjective->satisfiedbymeasure){
00593         scorm_seq_objective_rollup_measure($sco,$userid);
00594     }
00595     else{
00596         if ((scorm_seq_rollup_rule_check($sco,$userid,'incomplete'))|| (scorm_seq_rollup_rule_check($sco,$userid,'completed'))){
00597             scorm_seq_objective_rollup_rules($sco,$userid);
00598         }
00599         else{
00600 
00601             $rolluprules = $DB->get_record('scorm_seq_rolluprule', array('scoid'=>$sco->id,'userid'=>$userid));
00602             foreach($rolluprules as $rolluprule){
00603                 $rollupruleconds = $DB->get_records('scorm_seq_rolluprulecond', array('rollupruleid'=>$rolluprule->id));
00604                 foreach($rollupruleconds as $rolluprulecond){
00605 
00606                     switch ($rolluprulecond->cond!='satisfied' && $rolluprulecond->cond!='completed' && $rolluprulecond->cond!='attempted'){
00607 
00608                            scorm_seq_set('objectivesatisfiedstatus',$sco->id,$userid, false);
00609 
00610                         break;
00611                     }
00612                 }
00613 
00614 
00615         }
00616     }
00617 */
00618 }
00619 
00620 function scorm_seq_objective_rollup_measure($sco,$userid){
00621     global $DB;
00622 
00623     $targetobjective = null;
00624 
00625 
00626     $objectives = $DB->get_records('scorm_seq_objective', array('scoid'=>$sco->id));
00627     foreach ($objectives as $objective){
00628         if ($objective->primaryobj == true){
00629             $targetobjective = $objective;
00630             break;
00631         }
00632     }
00633     if ($targetobjective != null){
00634 
00635         if($targetobjective->satisfiedbymeasure){
00636 
00637 
00638             if (!scorm_seq_is('objectiveprogressstatus',$sco->id,$userid)) {
00639 
00640                 scorm_seq_set('objectiveprogressstatus',$sco->id,$userid,false);
00641 
00642             }
00643 
00644             else{
00645                 if (scorm_seq_is('active',$sco->id,$userid)) {
00646                     $isactive = true;
00647                 }
00648                 else{
00649                     $isactive = false;
00650                 }
00651 
00652                 $normalizedmeasure = $DB->get_record('scorm_scoes_track', array('scoid'=>$sco->id,'userid'=>$userid,'element'=>'objectivenormalizedmeasure'));
00653 
00654                 $sco = scorm_get_sco ($sco->id);
00655 
00656                 if (!$isactive || ($isactive && (!isset($sco->measuresatisfactionifactive) || $sco->measuresatisfactionifactive == true))){
00657                     if($normalizedmeasure->value >= $targetobjective->minnormalizedmeasure){
00658                         scorm_seq_set('objectiveprogressstatus',$sco->id,$userid);
00659                         scorm_seq_set('objectivesatisfiedstatus',$sco->id,$userid);
00660                     }
00661                     else{
00662                         scorm_seq_set('objectiveprogressstatus',$sco->id,$userid);
00663                         scorm_seq_set('objectivesatisfiedstatus',$sco->id,$userid,false);
00664                     }
00665                 }
00666                 else{
00667 
00668                     scorm_seq_set('objectiveprogressstatus',$sco->id,$userid,false);
00669 
00670                 }
00671             }
00672         }
00673     }
00674 
00675 }
00676 
00677 function scorm_seq_objective_rollup_default($sco,$userid){
00678     global $DB;
00679 
00680     if (!(scorm_seq_rollup_rule_check($sco,$userid,'incomplete')) && !(scorm_seq_rollup_rule_check($sco,$userid,'completed'))){
00681 
00682             $rolluprules = $DB->get_record('scorm_seq_rolluprule', array('scoid'=>$sco->id,'userid'=>$userid));
00683             foreach($rolluprules as $rolluprule){
00684                 $rollupruleconds = $DB->get_records('scorm_seq_rolluprulecond', array('rollupruleid'=>$rolluprule->id));
00685                 foreach($rollupruleconds as $rolluprulecond){
00686 
00687                     if ($rolluprulecond->cond!='satisfied' && $rolluprulecond->cond!='completed' && $rolluprulecond->cond!='attempted'){
00688 
00689                            scorm_seq_set('objectivesatisfiedstatus',$sco->id,$userid, false);
00690 
00691                         break;
00692                     }
00693                 }
00694 
00695 
00696             }
00697     }
00698 
00699 }
00700 
00701 
00702 function scorm_seq_objective_rollup_rules($sco,$userid){
00703     global $DB;
00704 
00705     $targetobjective = null;
00706 
00707     $objectives = $DB->get_records('scorm_seq_objective', array('scoid'=>$sco->id));
00708     foreach ($objectives as $objective){
00709         if ($objective->primaryobj == true){//Objective contributes to rollup I'm using primaryobj field, but not
00710             $targetobjective = $objective;
00711             break;
00712         }
00713     }
00714     if ($targetobjective != null){
00715 
00716 
00717 
00718         if(scorm_seq_rollup_rule_check($sco,$userid,'notsatisfied')){//with not satisfied rollup for the activity
00719 
00720 
00721             scorm_seq_set('objectiveprogressstatus',$sco->id,$userid);
00722             scorm_seq_set('objectivesatisfiedstatus',$sco->id,$userid,false);
00723         }
00724         if(scorm_seq_rollup_rule_check($sco,$userid,'satisfied')){//with satisfied rollup for the activity
00725             scorm_seq_set('objectiveprogressstatus',$sco->id,$userid);
00726             scorm_seq_set('objectivesatisfiedstatus',$sco->id,$userid);
00727         }
00728 
00729     }
00730 
00731 }
00732 
00733 function scorm_seq_activity_progress_rollup ($sco, $userid, $seq){
00734 
00735     if(scorm_seq_rollup_rule_check($sco,$userid,'incomplete')){
00736         //incomplete rollup action
00737         scorm_seq_set('attemptcompletionstatus',$sco->id,$userid,false,$seq->attempt);
00738         scorm_seq_set('attemptprogressstatus',$sco->id,$userid,true,$seq->attempt);
00739 
00740     }
00741     if(scorm_seq_rollup_rule_check($sco,$userid,'completed')){
00742         //incomplete rollup action
00743         scorm_seq_set('attemptcompletionstatus',$sco->id,true,$userid);
00744         scorm_seq_set('attemptprogressstatus',$sco->id,true,$userid);
00745     }
00746 
00747 }
00748 
00749 function scorm_seq_rollup_rule_check ($sco,$userid,$action){
00750     global $DB;
00751 
00752      if($rolluprules = $DB->get_record('scorm_seq_rolluprule', array('scoid'=>$sco->id,'userid'=>$userid,'action'=>$action))) {
00753 
00754         $childrenbag = Array ();
00755         $children = scorm_get_children ($sco);
00756 
00757         foreach($rolluprules as $rolluprule){
00758 
00759             foreach ($children as $child){
00760 
00761                 /*$tracked = $DB->get_records('scorm_scoes_track', array('scoid'=>$child->id,'userid'=>$userid));
00762                 if($tracked && $tracked->attemp != 0){*/
00763                  $child = scorm_get_sco ($child);
00764             if (!isset($child->tracked) || ($child->tracked == 1)){
00765 
00766                     if(scorm_seq_check_child ($child,$action,$userid)){
00767 
00768                         $rollupruleconds = $DB->get_records('scorm_seq_rolluprulecond', array('rollupruleid'=>$rolluprule->id));
00769                         $evaluate = scorm_seq_evaluate_rollupcond($child,$rolluprule->conditioncombination,$rollupruleconds,$userid);
00770                         if ($evaluate=='unknown'){
00771                             array_push($childrenbag,'unknown');
00772                         }
00773                         else{
00774                             if($evaluate == true){
00775                                 array_push($childrenbag,true);
00776                             }
00777                             else{
00778                                 array_push($childrenbag,false);
00779                             }
00780                         }
00781                     }
00782                 }
00783 
00784             }
00785             $change = false;
00786 
00787             switch ($rolluprule->childactivityset){
00788 
00789                 case 'all':
00790                     if((array_search(false,$childrenbag)===false)&&(array_search('unknown',$childrenbag)===false)){//I think I can use this condition instead equivalent to OR
00791                         $change = true;
00792                     }
00793                 break;
00794 
00795                 case 'any':
00796                     if(array_search(true,$childrenbag)!==false){//I think I can use this condition instead equivalent to OR
00797                         $change = true;
00798                     }
00799                 break;
00800 
00801                 case 'none':
00802                     if((array_search(true,$childrenbag)===false)&&(array_search('unknown',$childrenbag)===false)){//I think I can use this condition instead equivalent to OR
00803                         $change = true;
00804                     }
00805                 break;
00806 
00807                 case 'atleastcount':
00808                     foreach ($childrenbag as $itm){//I think I can use this condition instead equivalent to OR
00809                         $cont = 0;
00810                         if($itm === true){
00811                             $cont++;
00812                         }
00813                         if($cont >= $rolluprule->minimumcount){
00814                             $change = true;
00815                         }
00816                     }
00817                 break;
00818 
00819                 case 'atleastcount':
00820                     foreach ($childrenbag as $itm){//I think I can use this condition instead equivalent to OR
00821                         $cont = 0;
00822                         if($itm === true){
00823                             $cont++;
00824                         }
00825                         if($cont >= $rolluprule->minimumcount){
00826                             $change = true;
00827                         }
00828                     }
00829                 break;
00830 
00831                 case 'atleastpercent':
00832                     foreach ($childrenbag as $itm){//I think I can use this condition instead equivalent to OR
00833                         $cont = 0;
00834                         if($itm === true){
00835                             $cont++;
00836                         }
00837                         if(($cont/sizeof($childrenbag)) >= $rolluprule->minimumcount){
00838                             $change = true;
00839                         }
00840                     }
00841                 break;
00842             }
00843             if ($change==true){
00844                 return true;
00845             }
00846         }
00847      }
00848      return false;
00849 }
00850 
00851 
00852 function scorm_seq_evaluate_rollupcond($sco,$conditioncombination,$rollupruleconds,$userid){
00853     $bag = Array();
00854     $con = "";
00855     $val = false;
00856     $unk = false;
00857     foreach($rollupruleconds as $rolluprulecond){
00858 
00859         $condit = scorm_evaluate_condition($rolluprulecond,$sco,$userid);
00860 
00861         if($rolluprulecond->operator=='not'){// If operator is not, negate the condition
00862             if ($rolluprulecond->cond != 'unknown'){
00863                 if ($condit){
00864                     $condit = false;
00865                 }
00866                 else{
00867                     $condit = true;
00868                 }
00869             }
00870             else{
00871                 $condit = 'unknown';
00872             }
00873             array_push($childrenbag,$condit);
00874         }
00875 
00876     }
00877     if (empty($bag)){
00878         return 'unknown';
00879     }
00880     else{
00881         $i = 0;
00882         foreach ($bag as $b){
00883 
00884              if ($rolluprulecond->conditioncombination == 'all'){
00885 
00886                  $val = true;
00887                  if($b == 'unknown'){
00888                      $unk = true;
00889                  }
00890                  if($b === false){
00891                      return false;
00892                  }
00893              }
00894 
00895              else{
00896 
00897                 $val = false;
00898 
00899                 if($b == 'unknown'){
00900                      $unk = true;
00901                 }
00902                 if($b === true){
00903                     return true;
00904                 }
00905              }
00906 
00907 
00908         }
00909     }
00910     if ($unk){
00911         return 'unknown';
00912     }
00913     return $val;
00914 
00915 }
00916 
00917 function scorm_evaluate_condition ($rolluprulecond,$sco,$userid){
00918     global $DB;
00919 
00920             $res = false;
00921 
00922             switch ($rolluprulecond->cond){
00923 
00924                 case 'satisfied':
00925                      if($r=$DB->get_record('scorm_scoes_track', array('scoid'=>$sco->id,'userid'=>$userid,'element'=>'objectivesatisfiedstatus'))) {
00926                         if($r->value == true){
00927                             if ($r=$DB->get_record('scorm_scoes_track', array('scoid'=>$sco->id,'userid'=>$userid,'element'=>'objectiveprogressstatus'))) {
00928                                 if($r->value == true){
00929                                    $res= true;
00930                                 }
00931                             }
00932                         }
00933                     }
00934                 break;
00935 
00936                 case 'objectiveStatusKnown':
00937                     if ($r=$DB->get_record('scorm_scoes_track', array('scoid'=>$sco->id,'userid'=>$userid,'element'=>'objectiveprogressstatus'))) {
00938                         if($r->value == true){
00939                             $res= true;
00940                         }
00941                     }
00942                 break;
00943 
00944                 case 'objectiveMeasureKnown':
00945                     if ($r = $DB->get_record('scorm_scoes_track', array('scoid'=>$sco->id,'userid'=>$userid,'element'=>'objectivemeasurestatus'))) {
00946                         if($r->value == true){
00947                             $res = true;
00948                         }
00949 
00950                     }
00951 
00952                 break;
00953 
00954                 case 'completed':
00955                     if ($r = $DB->get_record('scorm_scoes_track', array('scoid'=>$sco->id,'userid'=>$userid,'element'=>'attemptcompletionstatus'))) {
00956                         if($r->value){
00957                             if ($r = $DB->get_record('scorm_scoes_track', array('scoid'=>$sco->id,'userid'=>$userid,'element'=>'attemptprogressstatus'))) {
00958                                if($r->value){
00959                                   $res = true;
00960                                }
00961 
00962                             }
00963                         }
00964 
00965                     }
00966                 break;
00967 
00968                 case 'attempted':
00969                     if ($r = $DB->get_record('scorm_scoes_track', array('scoid'=>$sco->id,'userid'=>$userid,'element'=>'activityprogressstatus'))) {
00970                         if($r->value){
00971                             if ($r = $DB->get_record('scorm_scoes_track', array('scoid'=>$sco->id,'userid'=>$userid,'element'=>'activityattemptcount'))) {
00972                                 if($r->value > 0){
00973                                     $res = true;
00974                                 }
00975 
00976                             }
00977                         }
00978 
00979                     }
00980                 break;
00981 
00982 
00983                 case 'attemptLimitExceeded':
00984                     if ($r = $DB->get_record('scorm_scoes_track', array('scoid'=>$sco->id,'userid'=>$userid,'element'=>'activityprogressstatus'))) {
00985                         if($r->value){
00986                             if ($r = $DB->get_record('scorm_scoes_track', array('scoid'=>$sco->id,'userid'=>$userid,'element'=>'limitconditionattemptlimitcontrol'))) {
00987                                 if($r->value){
00988                                    if ($r = $DB->get_record('scorm_scoes_track', array('scoid'=>$sco->id,'userid'=>$userid,'element'=>'activityattemptcount')) && $r2 = $DB->get_record('scorm_scoes_track', array('scoid'=>$sco->id,'userid'=>$userid,'element'=>'limitconditionattemptlimit')) ){
00989                                        if($r->value >= $r2->value){
00990                                            $res = true;
00991                                        }
00992 
00993                                    }
00994 
00995                                 }
00996 
00997                             }
00998 
00999                         }
01000 
01001                     }
01002 
01003                 break;
01004 
01005                 case 'activityProgressKnown':
01006 
01007                     if ($r = $DB->get_record('scorm_scoes_track', array('scoid'=>$sco->id,'userid'=>$userid,'element'=>'activityprogressstatus'))) {
01008                         if($r->value){
01009                             if ($r = $DB->get_record('scorm_scoes_track', array('scoid'=>$sco->id,'userid'=>$userid,'element'=>'attemptprogressstatus'))) {
01010                                 if($r->value){
01011                                     $res = true;
01012                                 }
01013 
01014                             }
01015 
01016                         }
01017 
01018                     }
01019 
01020                 break;
01021             }
01022             return $res;
01023 
01024 }
01025 
01026 function scorm_seq_check_child ($sco, $action, $userid){
01027     global $DB;
01028 
01029     $included = false;
01030     $sco=scorm_get_sco($sco->id);
01031     $r = $DB->get_record('scorm_scoes_track', array('scoid'=>$sco->id,'userid'=>$userid,'element'=>'activityattemptcount'));
01032     if ($action == 'satisfied' || $action == 'notsatisfied'){
01033       if (!$sco->rollupobjectivesatisfied){
01034         $included = true;
01035         if (($action == 'satisfied' && $sco->requiredforsatisfied == 'ifnotsuspended') || ($action == 'notsatisfied' && $sco->requiredfornotsatisfied == 'ifnotsuspended')){
01036 
01037             if (!scorm_seq_is('activityprogressstatus',$sco->id,$userid) || ((($r->value)>0)&& !scorm_seq_is('suspended',$sco->id,$userid))){
01038                 $included = false;
01039             }
01040 
01041         }
01042         else{
01043             if (($action == 'satisfied' && $sco->requiredforsatisfied == 'ifattempted') || ($action == 'notsatisfied' && $sco->requiredfornotsatisfied == 'ifattempted')){
01044                 if (!scorm_seq_is('activityprogressstatus',$sco->id,$userid) || (($r->value) == 0)){
01045                     $included = false;
01046                 }
01047             }
01048             else{
01049                 if (($action == 'satisfied' && $sco->requiredforsatisfied == 'ifnotskipped') || ($action == 'notsatisfied' && $sco->requiredfornotsatisfied == 'ifnotskipped')){
01050                     $rulch = scorm_seq_rules_check($sco, 'skip');
01051                     if ($rulch != null){
01052                         $included = false;
01053                     }
01054                 }
01055             }
01056         }
01057       }
01058     }
01059     if ($action == 'completed' || $action == 'incomplete'){
01060         if (!$sco->rollupprogresscompletion){
01061             $included = true;
01062 
01063             if (($action == 'completed' && $sco->requiredforcompleted == 'ifnotsuspended') || ($action == 'incomplete' && $sco->requiredforincomplete == 'ifnotsuspended')){
01064 
01065                 if (!scorm_seq_is('activityprogressstatus',$sco->id,$userid) || ( (($r->value)>0)&& !scorm_seq_is('suspended',$sco->id,$userid))){
01066                     $included = false;
01067                 }
01068 
01069             }
01070             else{
01071 
01072                 if (($action == 'completed' && $sco->requiredforcompleted == 'ifattempted') || ($action == 'incomplete' && $sco->requiredforincomplete == 'ifattempted')){
01073                     if (!scorm_seq_is('activityprogressstatus',$sco->id,$userid) || (($r->value)==0)){
01074                         $included = false;
01075                     }
01076 
01077                 }
01078                 else{
01079                     if (($action == 'completed' && $sco->requiredforsatisfied == 'ifnotskipped') || ($action == 'incomplete' && $sco->requiredfornotsatisfied == 'ifnotskipped')){
01080                         $rulch = scorm_seq_rules_check($sco, 'skip');
01081                         if ($rulch != null){
01082                             $included = false;
01083                         }
01084                     }
01085                 }
01086 
01087 
01088             }
01089 
01090         }
01091     }
01092     return $included;
01093 
01094 
01095 }
01096 function scorm_seq_sequencing ($scoid,$userid,$seq) {
01097 
01098     switch ($seq->sequencing) {
01099 
01100         case 'start':
01101             $seq = scorm_seq_start_sequencing($scoid,$userid,$seq); //We'll see the parameters we have to send, this should update delivery and end
01102             $seq->sequencing = true;
01103 
01104 
01105             break;
01106 
01107         case 'resumeall':
01108             $seq = scorm_seq_resume_all_sequencing($scoid,$userid,$seq); //We'll see the parameters we have to send, this should update delivery and end
01109             $seq->sequencing = true;
01110 
01111 
01112 
01113             break;
01114 
01115         case 'exit':
01116              $seq = scorm_seq_exit_sequencing($scoid,$userid,$seq); //We'll see the parameters we have to send, this should update delivery and end
01117             $seq->sequencing = true;
01118 
01119 
01120 
01121             break;
01122 
01123         case 'retry':
01124             $seq = scorm_seq_retry_sequencing($scoid,$userid,$seq); //We'll see the parameters we have to send, this should update delivery and end
01125             $seq->sequencing = true;
01126 
01127 
01128             break;
01129 
01130         case 'previous':
01131             $seq = scorm_seq_previous_sequencing($scoid,$userid,$seq);// We'll see the parameters we have to send, this should update delivery and end
01132             $seq->sequencing = true;
01133 
01134 
01135             break;
01136 
01137         case 'choice':
01138             $seq = scorm_seq_choice_sequencing($scoid,$userid,$seq);// We'll see the parameters we have to send, this should update delivery and end
01139              $seq->sequencing = true;
01140 
01141 
01142             break;
01143 
01144     }
01145 
01146     if ($seq->exception != null){
01147         $seq->sequencing = false;
01148         return $seq;
01149     }
01150 
01151     $seq->sequencing= true;
01152     return $seq;
01153 }
01154 
01155 
01156 function scorm_seq_start_sequencing($scoid,$userid,$seq){
01157     global $DB;
01158 
01159     if (!empty($seq->currentactivity)) {
01160         $seq->delivery = null;
01161         $seq->exception = 'SB.2.5-1';
01162         return $seq;
01163     }
01164     $sco = $DB->get_record('scorm_scoes', array('scoid'=>$scoid,'userid'=>$userid));
01165     if (($sco->parent == '/') && scorm_is_leaf($sco)) {//if the activity is the root and is leaf
01166         $seq->delivery = $sco;
01167     }
01168     else{
01169         $ancestors = scorm_get_ancestors($sco);
01170         $ancestorsroot = array_reverse($ancestors);
01171         $res = scorm_seq_flow($ancestorsroot[0],'forward',$seq,true,$userid);
01172         if($res){
01173             return $res;
01174         }
01175         else{
01176             //return end and exception
01177         }
01178     }
01179 }
01180 
01181 function scorm_seq_resume_all_sequencing($scoid,$userid,$seq){
01182     global $DB;
01183 
01184     if (!empty($seq->currentactivity)){
01185         $seq->delivery = null;
01186         $seq->exception = 'SB.2.6-1';
01187         return $seq;
01188     }
01189     $track = $DB->get_record('scorm_scoes_track', array('scoid'=>$scoid,'userid'=>$userid,'element'=>'suspendedactivity'));
01190     if (!$track) {
01191         $seq->delivery = null;
01192         $seq->exception = 'SB.2.6-2';
01193         return $seq;
01194     }
01195     $seq->delivery = $DB->get_record('scorm_scoes', array('scoid'=>$scoid,'userid'=>$userid));//we assign the sco to the delivery
01196 
01197 }
01198 
01199 function scorm_seq_continue_sequencing($scoid,$userid,$seq){
01200     if (empty($seq->currentactivity)) {
01201         $seq->delivery = null;
01202         $seq->exception = 'SB.2.7-1';
01203         return $seq;
01204     }
01205     $currentact= $seq->currentactivity;
01206     if ($currentact->parent != '/') {//if the activity is the root and is leaf
01207         $parent = scorm_get_parent ($currentact);
01208 
01209          if (!isset($parent->flow) || ($parent->flow == false)) {
01210             $seq->delivery = null;
01211             $seq->exception = 'SB.2.7-2';
01212             return $seq;
01213         }
01214 
01215         $res = scorm_seq_flow($currentact,'forward',$seq,false,$userid);
01216         if($res){
01217             return $res;
01218         }
01219         else{
01220             //return end and exception
01221         }
01222 
01223     }
01224 }
01225 
01226 function scorm_seq_previous_sequencing($scoid,$userid,$seq){
01227     if (empty($seq->currentactivity)) {
01228         $seq->delivery = null;
01229         $seq->exception = 'SB.2.8-1';
01230         return $seq;
01231     }
01232 
01233     $currentact= $seq->currentactivity;
01234     if ($currentact->parent != '/') {//if the activity is the root and is leaf
01235         $parent = scorm_get_parent ($currentact);
01236         if (!isset($parent->flow) || ($parent->flow == false)) {
01237             $seq->delivery = null;
01238             $seq->exception = 'SB.2.8-2';
01239             return $seq;
01240         }
01241 
01242         $res = scorm_seq_flow($currentact,'backward',$seq,false,$userid);
01243         if($res){
01244             return $res;
01245         }
01246         else{
01247             //return end and exception
01248         }
01249 
01250     }
01251 
01252 }
01253 
01254 function scorm_seq_exit_sequencing($scoid,$userid,$seq){
01255     if (empty($seq->currentactivity)) {
01256         $seq->delivery = null;
01257         $seq->exception = 'SB.2.11-1';
01258         return $seq;
01259     }
01260 
01261      if ($seq->active){
01262          $seq->endsession = false;
01263          $seq->exception = 'SB.2.11-2';
01264          return $seq;
01265      }
01266      $currentact= $seq->currentactivity;
01267      if ($currentact->parent == '/'){
01268          $seq->endsession = true;
01269          return $seq;
01270      }
01271 
01272     $seq->endsession = false;
01273     return $seq;
01274 }
01275 
01276 
01277 function scorm_seq_retry_sequencing($scoid,$userid,$seq){
01278     if (empty($seq->currentactivity)) {
01279         $seq->delivery = null;
01280         $seq->exception = 'SB.2.10-1';
01281         return $seq;
01282     }
01283     if ($seq->active || $seq->suspended){
01284         $seq->delivery = null;
01285         $seq->exception = 'SB.2.10-2';
01286         return $seq;
01287     }
01288 
01289     if (!scorm_is_leaf($seq->currentactivity)){
01290         $res = scorm_seq_flow($seq->currentactivity,'forward',$seq,true,$userid);
01291         if($res != null){
01292             return $res;
01293             //return deliver
01294         }
01295         else{
01296             $seq->delivery = null;
01297             $seq->exception = 'SB.2.10-3';
01298             return $seq;
01299         }
01300     }
01301     else{
01302         $seq->delivery = $seq->currentactivity;
01303         return $seq;
01304     }
01305 
01306 }
01307 
01308 function scorm_seq_flow ($candidate,$direction,$seq,$childrenflag,$userid){
01309     //TODO: $PREVDIRECTION NOT DEFINED YET
01310 
01311     $activity=$candidate;
01312     $prevdirection = null;
01313     $seq = scorm_seq_flow_tree_traversal ($activity,$direction,$childrenflag,$prevdirection,$seq,$userid);
01314     if($seq->identifiedactivity == null){//if identifies
01315         $seq->identifiedactivity = $candidate;
01316         $seq->deliverable = false;
01317         return $seq;
01318     }
01319     else{
01320         $activity = $seq->identifiedactivity;
01321         $seq = scorm_seq_flow_activity_traversal($activity,$userid,$direction,$childrenflag,$prevdirection,$seq,$userid);//
01322         return $seq;
01323 
01324     }
01325 }
01326 
01327 function scorm_seq_flow_activity_traversal ($activity, $userid, $direction, $childrenflag, $prevdirection, $seq,$userid){//returns the next activity on the tree, traversal direction, control returned to the LTS, (may) exception
01328     $activity = scorm_get_sco ($activity);
01329     $parent = scorm_get_parent ($activity);
01330    if (!isset($parent->flow) || ($parent->flow == false)) {
01331         $seq->deliverable = false;
01332         $seq->exception = 'SB.2.2-1';
01333         $seq->nextactivity = $activity;
01334         return $seq;
01335     }
01336 
01337     $rulch = scorm_seq_rules_check($sco, 'skipped'); // TODO: undefined
01338     if ($rulch != null){
01339         $seq = scorm_seq_flow_tree_traversal ($activity, $direction, false, $prevdirection, $seq,$userid);//endsession and exception
01340         if ($seq->identifiedactivity == null){
01341             $seq->deliverable = false;
01342             $seq->nextactivity = $activity;
01343             return $seq;
01344         }
01345         else{
01346 
01347             if ($prevdirection = 'backward' && $seq->traversaldir == 'backward'){
01348                 $seq = scorm_seq_flow_tree_traversal ($activity,$direction,false,null,$seq,$userid);
01349                 $seq = scorm_seq_flow_activity_traversal($seq->identifiedactivity, $userid, $direction, $childrenflag, $prevdirection, $seq,$userid);
01350             }
01351             else{
01352                 $seq = scorm_seq_flow_tree_traversal ($activity,$direction,false,null,$seq,$userid);
01353                 $seq = scorm_seq_flow_activity_traversal($seq->identifiedactivity, $userid, $direction, $childrenflag, $prevdirection, $seq,$userid);
01354             }
01355             return $seq;
01356         }
01357     }
01358 
01359     $ch=scorm_check_activity ($activity,$userid);
01360 
01361     if ($ch){
01362 
01363         $seq->deliverable = false;
01364         $seq->exception = 'SB.2.2-2';
01365         $seq->nextactivity = $activity;
01366         return $seq;
01367 
01368     }
01369 
01370     if (!scorm_is_leaf($activity)){
01371 
01372         $seq = scorm_seq_flow_tree_traversal ($activity,$direction,true,null,$seq,$userid);
01373 
01374         if ($seq->identifiedactivity == null){
01375             $seq->deliverable = false;
01376             $seq->nextactivity = $activity;
01377             return $seq;
01378         }
01379 
01380         else{
01381             if($direction == 'backward' && $seq->traversaldir == 'forward'){
01382                 $seq = scorm_seq_flow_activity_traversal($seq->identifiedactivity, $userid, 'forward', $childrenflag, 'backward', $seq,$userid);
01383             }
01384             else{
01385                 scorm_seq_flow_activity_traversal($seq->identifiedactivity, $userid, $direction, $childrenflag, null, $seq,$userid);
01386             }
01387             return $seq;
01388         }
01389 
01390     }
01391 
01392     $seq->deliverable = true;
01393     $seq->nextactivity = $activity;
01394     return $seq;
01395 
01396 }
01397 function scorm_seq_flow_tree_traversal ($activity,$direction,$childrenflag,$prevdirection,$seq,$userid){
01398 
01399     $revdirection = false;
01400     $parent = scorm_get_parent ($activity);
01401     $children = scorm_get_available_children ($parent);
01402     $siz = sizeof ($children);
01403 
01404     if (($prevdirection != null && $prevdirection == 'backward') && ($children[$siz-1]->id == $activity->id)){
01405         $direction = 'backward';
01406         $children[0] = $activity;
01407         $revdirection = true;
01408     }
01409 
01410     if($direction = 'forward'){
01411         $ancestors = scorm_get_ancestors($activity);
01412         $ancestorsroot = array_reverse($ancestors);
01413         $preorder = scorm_get_preorder ($ancestorsroot);
01414         $siz= sizeof ($preorder);
01415         if (($activity->id == $preorder[$siz-1]->id) || (($activity->parent == '/') && !($childrenflag))){
01416             scorm_seq_terminate_descent($ancestorsroot,$userid);
01417             $seq->endsession = true;
01418             $seq->nextactivity = null;
01419             return $seq;
01420         }
01421         if (scorm_is_leaf ($activity) || !$childrenflag){
01422             if ($children[$siz-1]->id == $activity->id){
01423 
01424                 $seq = scorm_seq_flow_tree_traversal ($parent, $direction, false, null, $seq,$userid);
01425                 // I think it's not necessary to do a return in here
01426             }
01427             else{
01428                 $parent = scorm_get_parent($activity);
01429                 $children = scorm_get_available_children($parent);
01430                 $seq->traversaldir = $direction;
01431                 $sib = scorm_get_siblings($activity);
01432                 $pos = array_search($sib, $activity);
01433                 if ($pos !== false) {
01434                     if ($pos != sizeof ($sib)){
01435                         $seq->nextactivity = $sib [$pos+1];
01436                         return $seq;
01437                     }
01438                     else{
01439                         $ch = scorm_get_children($sib[0]);
01440                         $seq->nextactivity = $ch[0];
01441                         return $seq;
01442                     }
01443                 }
01444             }
01445         }
01446         else{
01447             if (!empty ($children)){
01448                 $seq->traversaldir = $direction;
01449                 $seq->nextactivity = $children[0];
01450                 return $seq;
01451             }
01452             else{
01453                 $seq->traversaldir = null;
01454                 $seq->nextactivity = $children[0];
01455                 $seq->exception = 'SB.2.1-2';
01456                 return $seq;
01457             }
01458         }
01459 
01460     }
01461     if($direction = 'backward'){
01462 
01463          if ($activity->parent == '/'){
01464             $seq->traversaldir = null;
01465             $seq->nextactivity = null;
01466             $seq->exception = 'SB.2.1-3';
01467             return $seq;
01468          }
01469          if (scorm_is_leaf ($activity) || !$childrenflag){
01470              if (!$revdirection){
01471                  if (isset($parent->forwardonly) && ($parent->forwardonly == true)) {
01472                      $seq->traversaldir = null;
01473                      $seq->nextactivity = null;
01474                      $seq->exception = 'SB.2.1-4';
01475                      return $seq;
01476                  }
01477              }
01478              if ($children[0]->id == $activity->id){
01479                 $seq = scorm_seq_flow_tree_traversal ($parent, 'backward', false, null, $seq, $userid);
01480                 return $seq;
01481              }
01482              else{
01483                 $ancestors = scorm_get_ancestors($activity);
01484                 $ancestorsroot = array_reverse ($ancestors);
01485                 $preorder = scorm_get_preorder ($ancestorsroot);
01486                 $pos = array_search($preorder, $children[$siz]);
01487                 $preord = array_slice($preorder, 0, $pos-1);
01488                 $revpreorder = array_reverse($preord);
01489                 $position = array_search($revpreorder, $activity);
01490                 $seq->nextactivity = $revpreorder[$pos+1];
01491                 $seq->traversaldir = $direction;
01492                 return $seq;
01493              }
01494          }
01495          else{
01496              if (!empty($children)){
01497                  $activity = scorm_get_sco($activity->id);
01498                  if (isset($parent->flow) && ($parent->flow == true)) {
01499                      $children = scorm_get_children ($activity);
01500                      $seq->traversaldir = 'forward';
01501                      $seq->nextactivity = $children[0];
01502                      return $seq;
01503 
01504                  }
01505                  else{
01506                      $children = scorm_get_children ($activity);
01507                      $seq->traversaldir = 'backward';
01508                      $seq->nextactivity = $children[sizeof($children)-1];
01509                      return $seq;
01510                  }
01511 
01512              }
01513              else{
01514 
01515                      $seq->traversaldir = null;
01516                      $seq->nextactivity = null;
01517                      $seq->exception = 'SB.2.1-2';
01518                      return $seq;
01519              }
01520          }
01521 
01522     }
01523 
01524 
01525 }
01526 function scorm_check_activity ($activity,$userid){
01527     $act = scorm_seq_rules_check($activity,'disabled');
01528     if ($act != null){
01529         return true;
01530     }
01531     if(scorm_limit_cond_check ($activity,$userid)){
01532         return true;
01533     }
01534     return false;
01535 
01536 
01537 }
01538 
01539 function scorm_limit_cond_check ($activity,$userid){
01540     global $DB;
01541 
01542     if (isset($activity->tracked) && ($activity->tracked == 0)){
01543 
01544         return false;
01545     }
01546 
01547     if (scorm_seq_is('active',$activity->id,$userid) || scorm_seq_is('suspended',$activity->id,$userid)){
01548         return false;
01549     }
01550 
01551     if (!isset($activity->limitcontrol) || ($activity->limitcontrol == 1)){
01552         $r = $DB->get_record('scorm_scoes_track', array('scoid'=>$activity->id,'userid'=>$userid,'element'=>'activityattemptcount'));
01553         if (scorm_seq_is('activityprogressstatus',$activity->id,$userid) && ($r->value >=$activity->limitattempt)){
01554             return true;
01555         }
01556     }
01557 
01558      if (!isset($activity->limitabsdurcontrol) || ($activity->limitabsdurcontrol == 1)){
01559         $r = $DB->get_record('scorm_scoes_track', array('scoid'=>$activity->id,'userid'=>$userid,'element'=>'activityabsoluteduration'));
01560         if (scorm_seq_is('activityprogressstatus',$activity->id,$userid) && ($r->value >=$activity->limitabsduration)){
01561             return true;
01562         }
01563     }
01564 
01565     if (!isset($activity->limitexpdurcontrol) || ($activity->limitexpdurcontrol == 1)){
01566         $r = $DB->get_record('scorm_scoes_track', array('scoid'=>$activity->id,'userid'=>$userid,'element'=>'activityexperiencedduration'));
01567         if (scorm_seq_is('activityprogressstatus',$activity->id,$userid) && ($r->value >=$activity->limitexpduration)){
01568             return true;
01569         }
01570     }
01571 
01572      if (!isset($activity->limitattabsdurcontrol) || ($activity->limitattabsdurcontrol == 1)){
01573         $r = $DB->get_record('scorm_scoes_track', array('scoid'=>$activity->id,'userid'=>$userid,'element'=>'attemptabsoluteduration'));
01574         if (scorm_seq_is('activityprogressstatus',$activity->id,$userid) && ($r->value >=$activity->limitattabsduration)){
01575             return true;
01576         }
01577     }
01578 
01579     if (!isset($activity->limitattexpdurcontrol) || ($activity->limitattexpdurcontrol == 1)){
01580         $r = $DB->get_record('scorm_scoes_track', array('scoid'=>$activity->id,'userid'=>$userid,'element'=>'attemptexperiencedduration'));
01581         if (scorm_seq_is('activityprogressstatus',$activity->id,$userid) && ($r->value >=$activity->limitattexpduration)){
01582             return true;
01583         }
01584     }
01585 
01586     if (!isset($activity->limitbegincontrol) || ($activity->limitbegincontrol == 1)){
01587         $r = $DB->get_record('scorm_scoes_track', array('scoid'=>$activity->id,'userid'=>$userid,'element'=>'begintime'));
01588         if (time()>=$activity->limitbegintime){
01589             return true;
01590         }
01591     }
01592 
01593     if (!isset($activity->limitbegincontrol) || ($activity->limitbegincontrol == 1)){
01594         if (time()<$activity->limitbegintime){
01595             return true;
01596         }
01597     }
01598 
01599     if (!isset($activity->limitendcontrol) || ($activity->limitendcontrol == 1)){
01600 
01601         if (time()>$activity->limitendtime){
01602             return true;
01603         }
01604     }
01605     return false;
01606 
01607 
01608 }
01609 
01610 
01611 function scorm_seq_choice_sequencing($sco,$userid,$seq){
01612 
01613     $avchildren = Array ();
01614     $comancestor = null;
01615     $traverse = null;
01616 
01617     if ($sco == null){
01618         $seq->delivery = null;
01619         $seq->exception = 'SB.2.9-1';
01620         return $seq;
01621     }
01622 
01623     $ancestors = scorm_get_ancestors($sco);
01624     $arrpath = array_reverse($ancestors);
01625     array_push ($arrpath,$sco);//path from the root to the target
01626 
01627     foreach ($arrpath as $activity){
01628 
01629         if ($activity->parent != '/') {
01630             $avchildren = scorm_get_available_children (scorm_get_parent($activity));
01631             $position = array_search($avchildren, $activity);
01632             if ($position !== false){
01633                 $seq->delivery = null;
01634                 $seq->exception = 'SB.2.9-2';
01635                 return $seq;
01636             }
01637         }
01638 
01639         if (scorm_seq_rules_check($activity,'hidefromchoice' != null)){
01640 
01641             $seq->delivery = null;
01642             $seq->exception = 'SB.2.9-3';
01643             return $seq;
01644 
01645         }
01646 
01647     }
01648 
01649     if ($sco->parent != '/') {
01650         $parent = scorm_sco_get_parent ($sco);
01651         if ( isset($parent->choice) && ($parent->choice == false)){
01652             $seq->delivery = null;
01653             $seq->exception = 'SB.2.9-4';
01654             return $seq;
01655         }
01656     }
01657 
01658     if ($seq->currentactivity != null){
01659         $commonpos = scorm_find_common_ancestor($ancestors,$seq->currentactivity);
01660         $comancestor = $arrpath [$commonpos];
01661     }
01662     else{
01663         $comancestor = $arrpath [0];
01664     }
01665 
01666     if($seq->currentactivity === $sco) {
01667         break;
01668     }
01669 
01670     $sib = scorm_get_siblings($seq->currentactivity);
01671     $pos = array_search($sib, $sco);
01672 
01673     if ($pos !== false){
01674 
01675         $siblings = array_slice($sib, 0, $pos-1);
01676 
01677         if (empty($siblings)){
01678 
01679             $seq->delivery = null;
01680             $seq->exception = 'SB.2.9-5';
01681             return $seq;
01682 
01683         }
01684 
01685         $children = scorm_get_children (scorm_get_parent ($sco));
01686         $pos1 = array_search($children, $sco);
01687         $pos2 = array_search($seq->currentactivity, $sco);
01688         if ($pos1>$pos2){
01689             $traverse = 'forward';
01690         }
01691         else{
01692             $traverse = 'backward';
01693         }
01694 
01695         foreach ($siblings as $sibling){
01696             $seq = scorm_seq_choice_activity_traversal($sibling,$userid,$seq,$traverse);
01697             if(!$seq->reachable){
01698                 $seq->delivery = null;
01699                 return $seq;
01700             }
01701         }
01702         break;
01703 
01704     }
01705 
01706     if($seq->currentactivity == null || $seq->currentactivity == $comancestor){
01707         $commonpos = scorm_find_common_ancestor($ancestors,$seq->currentactivity);
01708         $comtarget = array_slice($ancestors, 1,$commonpos-1);//path from the common ancestor to the target activity
01709         $comtarget = array_reverse($comtarget);
01710 
01711         if (empty($comtarget)){
01712             $seq->delivery = null;
01713             $seq->exception = 'SB.2.9-5';
01714             return $seq;
01715         }
01716         foreach ($comtarget as $act){
01717             $seq = scorm_seq_choice_activity_traversal($act,$userid,$seq,'forward');
01718             if(!$seq->reachable){
01719                 $seq->delivery = null;
01720                 return $seq;
01721             }
01722             $act = scorm_get_sco ($acti->id);
01723             if(scorm_seq_is('active',$act->id,$userid) && ($act->id != $comancestor->id && $act->preventactivation)){//adlseq:can i write it like another property for the $seq object?
01724                 $seq->delivery = null;
01725                 $seq->exception = 'SB.2.9-6';
01726                 return $seq;
01727             }
01728         }
01729         break;
01730 
01731     }
01732 
01733     if ($comancestor->id == $sco->id){
01734 
01735         $ancestorscurrent = scorm_get_ancestors($seq->currentactivity);
01736         $possco = array_search ($ancestorscurrent, $sco);
01737         $curtarget = array_slice($ancestorscurrent,0,$possco);//path from the current activity to the target
01738 
01739         if (empty($curtarget)){
01740             $seq->delivery = null;
01741             $seq->exception = 'SB.2.9-5';
01742             return $seq;
01743         }
01744         $i=0;
01745         foreach ($curtarget as $activ){
01746             $i++;
01747             if ($i != sizeof($curtarget)){
01748                 if ( isset($activ->choiceexit) && ($activ->choiceexit == false)){
01749                     $seq->delivery = null;
01750                     $seq->exception = 'SB.2.9-7';
01751                     return $seq;
01752                 }
01753             }
01754         }
01755         break;
01756     }
01757 
01758     if (array_search ($ancestors, $comancestor)!== false){
01759         $ancestorscurrent = scorm_get_ancestors($seq->currentactivity);
01760         $commonpos = scorm_find_common_ancestor($ancestors,$sco);
01761         $curcommon = array_slice($ancestorscurrent,0,$commonpos-1);
01762         if(empty($curcommon)){
01763             $seq->delivery = null;
01764             $seq->exception = 'SB.2.9-5';
01765             return $seq;
01766         }
01767 
01768         $constrained = null;
01769         foreach ($curcommon as $acti){
01770             $acti = scorm_get_sco($acti->id);
01771             if ( isset($acti->choiceexit) && ($acti->choiceexit == false)){
01772                     $seq->delivery = null;
01773                     $seq->exception = 'SB.2.9-7';
01774                     return $seq;
01775             }
01776             if ($constrained == null){
01777                 if($acti->constrainchoice == true){
01778                     $constrained = $acti;
01779                 }
01780             }
01781         }
01782         if ($constrained != null){
01783             $fwdir = scorm_get_preorder($constrained);
01784 
01785             if(array_search ($fwdir, $sco)!== false){
01786                 $traverse = 'forward';
01787             }
01788             else{
01789                 $traverse = 'backward';
01790             }
01791             $seq = scorm_seq_choice_flow ($constrained, $traverse, $seq);
01792             $actconsider = $seq->identifiedactivity;
01793             $avdescendents = Array();
01794             $avdescendents= scorm_get_available_descendents ($actconsider);
01795             if (array_search ($avdescendents, $sco) !== false && $sco->id != $actconsider->id && $constrained->id != $sco->id ){
01796                 $seq->delivery = null;
01797                 $seq->exception = 'SB.2.9-8';
01798                 return $seq;
01799             }
01800 
01801 //CONTINUE 11.5.5
01802         }
01803 
01804         $commonpos = scorm_find_common_ancestor($ancestors,$seq->currentactivity);
01805         $comtarget = array_slice($ancestors, 1,$commonpos-1);//path from the common ancestor to the target activity
01806         $comtarget = array_reverse($comtarget);
01807 
01808         if (empty($comtarget)){
01809             $seq->delivery = null;
01810             $seq->exception = 'SB.2.9-5';
01811             return $seq;
01812         }
01813 
01814         $fwdir = scorm_get_preorder($seq->currentactivity);
01815 
01816         if(array_search ($fwdir, $sco)!== false){
01817 
01818             foreach ($comtarget as $act){
01819                 $seq = scorm_seq_choice_activity_traversal($act,$userid,$seq,'forward');
01820                 if(!$seq->reachable){
01821                     $seq->delivery = null;
01822                     return $seq;
01823                 }
01824                 $act = scorm_get_sco($act->id);
01825                 if(scorm_seq_is('active',$act->id,$userid) && ($act->id != $comancestor->id && ($act->preventactivation == true))){
01826                     $seq->delivery = null;
01827                     $seq->exception = 'SB.2.9-6';
01828                     return $seq;
01829                 }
01830             }
01831 
01832         }
01833         else{
01834             foreach ($comtarget as $act){
01835                 $act = scorm_get_sco($act->id);
01836                 if(scorm_seq_is('active',$act->id,$userid) && ($act->id != $comancestor->id && ($act->preventactivation==true))){
01837                     $seq->delivery = null;
01838                     $seq->exception = 'SB.2.9-6';
01839                     return $seq;
01840                 }
01841             }
01842         }
01843         break;
01844     }
01845 
01846     if(scorm_is_leaf ($sco)){
01847         $seq->delivery = $sco;
01848         $seq->exception = 'SB.2.9-6';
01849         return $seq;
01850     }
01851 
01852     $seq = scorm_seq_flow ($sco,'forward',$seq,true,$userid);
01853     if ($seq->deliverable == false){
01854         scorm_terminate_descendent_attempts($comancestor,$userid,$seq);
01855         scorm_seq_end_attempt($comancestor,$userid,$seq->attempt);
01856         $seq->currentactivity = $sco;
01857         $seq->delivery = null;
01858         $seq->exception = 'SB.2.9-9';
01859         return $seq;
01860 
01861     }
01862     else{
01863         return $seq;
01864     }
01865 
01866 }
01867 
01868 function scorm_seq_choice_flow ($constrained, $traverse, $seq){
01869     $seq = scorm_seq_choice_flow_tree ($constrained, $traverse, $seq);
01870     if ($seq->identifiedactivity == null){
01871         $seq->identifiedactivity = $constrained;
01872         return $seq;
01873     }
01874     else{
01875         return $seq;
01876     }
01877 }
01878 
01879 function scorm_seq_choice_flow_tree ($constrained, $traverse, $seq){
01880     $islast = false;
01881     $parent = scorm_get_parent ($constrained);
01882     if ($traverse== 'forward'){
01883         $preord = scorm_get_preorder ($constrained);
01884         if (sizeof($preorder) == 0 || (sizeof($preorder) == 0 && $preorder[0]->id = $constrained->id)){ // TODO: undefined
01885             $islast = true;//the function is the last activity available
01886         }
01887         if ($constrained->parent == '/' || $islast){
01888             $seq->nextactivity = null;
01889             return $seq;
01890         }
01891         $avchildren = scorm_get_available_children ($parent);//available children
01892         if ($avchildren [sizeof($avchildren)-1]->id == $constrained->id){
01893             $seq = scorm_seq_choice_flow_tree ($parent, 'forward', $seq);
01894             return $seq;
01895         }
01896         else{
01897             $i=0;
01898             while($i < sizeof($avchildren)){
01899                 if ($avchildren [$i]->id == $constrained->id){
01900                     $seq->nextactivity = $avchildren [$i+1];
01901                     return $seq;
01902                 }
01903                 else{
01904                     $i++;
01905                 }
01906             }
01907         }
01908 
01909     }
01910 
01911     if ($traverse== 'backward'){
01912         if($constrained->parent == '/' ){
01913             $seq->nextactivity = null;
01914             return $seq;
01915         }
01916 
01917         $avchildren = scorm_get_available_children ($parent);//available children
01918         if ($avchildren [0]->id == $constrained->id){
01919             $seq = scorm_seq_choice_flow_tree ($parent, 'backward', $seq);
01920             return $seq;
01921         }
01922         else{
01923             $i=sizeof($avchildren)-1;
01924             while($i >=0){
01925                 if ($avchildren [$i]->id == $constrained->id){
01926                     $seq->nextactivity = $avchildren [$i-1];
01927                     return $seq;
01928                 }
01929                 else{
01930                     $i--;
01931                 }
01932             }
01933         }
01934     }
01935 }
01936 function scorm_seq_choice_activity_traversal($activity,$userid,$seq,$direction){
01937 
01938     if($direction == 'forward'){
01939 
01940         $act = scorm_seq_rules_check($activity,'stopforwardtraversal');
01941 
01942         if($act != null){
01943             $seq->reachable = false;
01944             $seq->exception = 'SB.2.4-1';
01945             return $seq;
01946         }
01947         $seq->reachable = false;
01948         return $seq;
01949     }
01950 
01951     if($direction == 'backward'){
01952         $parentsco = scorm_get_parent($activity);
01953         if($parentsco!= null){
01954              if (isset($parentsco->forwardonly) && ($parentsco->forwardonly == true)){
01955                  $seq->reachable = false;
01956                  $seq->exception = 'SB.2.4-2';
01957                  return $seq;
01958              }
01959              else{
01960                 $seq->reachable = false;
01961                 $seq->exception = 'SB.2.4-3';
01962                 return $seq;
01963              }
01964         }
01965     }
01966     $seq->reachable = true;
01967     return $seq;
01968 
01969 }
01970 
01971 //Delivery Request Process
01972 
01973 function scorm_sequencing_delivery($scoid,$userid,$seq){
01974 
01975     if(!scorm_is_leaf ($seq->delivery)){
01976         $seq->deliveryvalid = false;
01977         $seq->exception = 'DB.1.1-1';
01978         return $seq;
01979     }
01980     $ancestors = scorm_get_ancestors($seq->delivery);
01981     $arrpath = array_reverse($ancestors);
01982     array_push ($arrpath,$seq->delivery);//path from the root to the target
01983 
01984     if (empty($arrpath)){
01985         $seq->deliveryvalid = false;
01986         $seq->exception = 'DB.1.1-2';
01987         return $seq;
01988     }
01989 
01990     foreach ($arrpath as $activity){
01991         if(scorm_check_activity ($activity,$userid)){
01992             $seq->deliveryvalid = false;
01993             $seq->exception = 'DB.1.1-3';
01994             return $seq;
01995         }
01996     }
01997 
01998     $seq->deliveryvalid = true;
01999     return $seq;
02000 
02001 }
02002 
02003 function scorm_content_delivery_environment ($seq,$userid){
02004     global $DB;
02005 
02006     $act = $seq->currentactivity;
02007     if(scorm_seq_is('active',$act->id,$userid)){
02008         $seq->exception = 'DB.2-1';
02009         return $seq;
02010     }
02011     $track = $DB->get_record('scorm_scoes_track', array('scoid'=>$act->id,'userid'=>$userid,'element'=>'suspendedactivity'));
02012     if ($track != null){
02013         $seq = scorm_clear_suspended_activity($seq->delivery, $seq, $userid);
02014 
02015     }
02016     $seq = scorm_terminate_descendent_attempts ($seq->delivery,$userid,$seq);
02017     $ancestors = scorm_get_ancestors($seq->delivery);
02018     $arrpath = array_reverse($ancestors);
02019     array_push ($arrpath,$seq->delivery);
02020     foreach ($arrpath as $activity){
02021         if(!scorm_seq_is('active',$activity->id,$userid)){
02022             if(!isset($activity->tracked) || ($activity->tracked == 1)){
02023                 if(!scorm_seq_is('suspended',$activity->id,$userid)){
02024                     $r = $DB->get_record('scorm_scoes_track', array('scoid'=>$activity->id,'userid'=>$userid,'element'=>'activityattemptcount'));
02025                     $r->value = ($r->value)+1;
02026                     $DB->update_record ('scorm_scoes_track',$r);
02027                     if ($r->value == 1){
02028                         scorm_seq_set('activityprogressstatus', $activity->id, $userid, 'true');
02029                     }
02030                     scorm_insert_track($userid, $activity->scorm, $activity->id, 0, 'objectiveprogressstatus', 'false');
02031                     scorm_insert_track($userid, $activity->scorm, $activity->id, 0, 'objectivesatisfiedstatus', 'false');
02032                     scorm_insert_track($userid, $activity->scorm, $activity->id, 0, 'objectivemeasurestatus', 'false');
02033                     scorm_insert_track($userid, $activity->scorm, $activity->id, 0, 'objectivenormalizedmeasure', 0.0);
02034 
02035                     scorm_insert_track($userid, $activity->scorm, $activity->id, 0, 'attemptprogressstatus', 'false');
02036                     scorm_insert_track($userid, $activity->scorm, $activity->id, 0, 'attemptcompletionstatus', 'false');
02037                     scorm_insert_track($userid, $activity->scorm, $activity->id, 0, 'attemptabsoluteduration', 0.0);
02038                     scorm_insert_track($userid, $activity->scorm, $activity->id, 0, 'attemptexperiencedduration', 0.0);
02039                     scorm_insert_track($userid, $activity->scorm, $activity->id, 0, 'attemptcompletionamount', 0.0);
02040                 }
02041             }
02042             scorm_seq_set('active', $activity->id, $userid, 'true');
02043         }
02044     }
02045     $seq->delivery = $seq->currentactivity;
02046     scorm_seq_set('suspendedactivity', $activity->id, $userid, 'false');
02047 
02048     //ONCE THE DELIVERY BEGINS (How should I check that?)
02049 
02050     if(isset($activity->tracked) || ($activity->tracked == 0)){
02051         //How should I track the info and what should I do to not record the information for the activity during delivery?
02052         $atabsdur = $DB->get_record('scorm_scoes_track', array('scoid'=>$activity->id,'userid'=>$userid,'element'=>'attemptabsoluteduration'));
02053         $atexpdur = $DB->get_record('scorm_scoes_track', array('scoid'=>$activity->id,'userid'=>$userid,'element'=>'attemptexperiencedduration'));
02054     }
02055     return $seq;
02056 
02057 
02058 }
02059 function scorm_clear_suspended_activity($act,$seq, $userid){
02060     global $DB;
02061     $currentact= $seq->currentactivity;
02062     $track = $DB->get_record('scorm_scoes_track', array('scoid'=>$currentact->id,'userid'=>$userid,'element'=>'suspendedactivity')); // TODO: undefined
02063     if ($track != null){
02064         $ancestors = scorm_get_ancestors($act);
02065         $commonpos = scorm_find_common_ancestor($ancestors,$currentact);
02066         if ($commonpos !== false) {
02067             if ($activitypath = array_slice($ancestors,0,$commonpos)) {
02068                 if (!empty ($activitypath)){
02069 
02070                     foreach ($activitypath as $activity) {
02071                         if (scorm_is_leaf($activity)){
02072                             scorm_seq_set('suspended',$activity->id,$userid,false);
02073                         }
02074                         else{
02075                             $children = scorm_get_children($activity);
02076                             $bool= false;
02077                             foreach ($children as $child){
02078                                 if(scorm_seq_is('suspended',$child->id,$userid)){
02079                                     $bool= true;
02080                                 }
02081                             }
02082                              if(!$bool){
02083                                 scorm_seq_set('suspended',$activity->id,$userid,false);
02084                              }
02085                         }
02086                     }
02087                 }
02088             }
02089         }
02090         scorm_seq_set('suspendedactivity',$act->id,$userid,false);
02091 
02092     }
02093 }
02094 
02095 function scorm_select_children_process($scoid,$userid){
02096     global $DB;
02097 
02098     $sco = scorm_get_sco($scoid);
02099     if (!scorm_is_leaf($sco)){
02100         if(!scorm_seq_is('suspended',$scoid,$userid) && !scorm_seq_is('active',$scoid,$userid)){
02101             $r = $DB->get_record('scorm_scoes_track', array('scoid'=>$scoid,'userid'=>$userid,'element'=>'selectiontiming'));
02102 
02103              switch($r->value) {
02104 
02105                 case 'oneachnewattempt':
02106                 case 'never':
02107                 break;
02108 
02109                 case 'once':
02110                     if(!scorm_seq_is('activityprogressstatus',$scoid,$userid)){
02111                         if(scorm_seq_is('selectioncountsstatus',$scoid,$userid)){
02112                             $childlist = '';
02113                             $res = $DB->get_record('scorm_scoes_track', array('scoid'=>$scoid,'userid'=>$userid,'element'=>'selectioncount'));
02114                             $i = ($res->value)-1;
02115                             $children = scorm_get_children ($sco);
02116 
02117                             while ($i>=0){
02118                                 $pos = array_rand($children);
02119                                 array_push($childlist,$children [$pos]);
02120                                 array_splice($children,$pos,1);
02121                                 $i--;
02122                             }
02123                             sort ($childlist);
02124                             $clist = serialize ($childlist);
02125                             scorm_seq_set('availablechildren', $scoid, $userid, false);
02126                             scorm_seq_set('availablechildren', $scoid, $userid, $clist);
02127 
02128 
02129                         }
02130                     }
02131                 break;
02132 
02133             }
02134 
02135         }
02136     }
02137 }
02138 
02139 function scorm_randomize_children_process($scoid,$userid){
02140     global $DB;
02141 
02142     $sco = scorm_get_sco($scoid);
02143     if (!scorm_is_leaf($sco)){
02144         if(!scorm_seq_is('suspended',$scoid,$userid) && !scorm_seq_is('active',$scoid,$userid)){
02145             $r = $DB->get_record('scorm_scoes_track', array('scoid'=>$scoid,'userid'=>$userid,'element'=>'randomizationtiming'));
02146 
02147              switch($r->value) {
02148 
02149 
02150                 case 'never':
02151                 break;
02152 
02153                 case 'oneachnewattempt':
02154                 case 'once':
02155                     if(!scorm_seq_is('activityprogressstatus',$scoid,$userid)){
02156                         if(scorm_seq_is('randomizechildren',$scoid,$userid)){
02157                             $childlist = array();
02158                             $res = scorm_get_available_children($sco);
02159                             $i = sizeof($res)-1;
02160                             $children = $res->value;
02161 
02162                             while ($i>=0){
02163                                 $pos = array_rand($children);
02164                                 array_push($childlist,$children [$pos]);
02165                                 array_splice($children,$pos,1);
02166                                 $i--;
02167                             }
02168 
02169                             $clist = serialize ($childlist);
02170                             scorm_seq_set('availablechildren', $scoid, $userid, false);
02171                             scorm_seq_set('availablechildren', $scoid, $userid, $clist);
02172 
02173 
02174                         }
02175                     }
02176                 break;
02177 
02178 
02179 
02180             }
02181 
02182         }
02183     }
02184 }
02185 
02186 function scorm_terminate_descendent_attempts ($activity,$userid,$seq){
02187     $ancestors = scorm_get_ancestors($seq->currentactivity);
02188     $commonpos = scorm_find_common_ancestor($ancestors,$activity);
02189         if ($commonpos !== false) {
02190             if ($activitypath = array_slice($ancestors,1,$commonpos-2)) {
02191                 if (!empty ($activitypath)){
02192 
02193                     foreach ($activitypath as $sco) {
02194                         scorm_seq_end_attempt($sco,$userid,$seq->attempt);
02195 
02196                     }
02197                 }
02198             }
02199         }
02200 }
02201 
02202 function scorm_sequencing_exception($seq){
02203     global $OUTPUT;
02204     if($seq->exception != null){
02205         switch($seq->exception){
02206 
02207             case 'NB.2.1-1':
02208                 echo $OUTPUT->notification("Sequencing session has already begun");
02209             break;
02210             case 'NB.2.1-2':
02211                 echo $OUTPUT->notification("Sequencing session has not begun");
02212             break;
02213             case 'NB.2.1-3':
02214                 echo $OUTPUT->notification("Suspended activity is not defined");
02215             break;
02216             case 'NB.2.1-4':
02217                 echo $OUTPUT->notification("Flow Sequencing Control Model Violation");
02218             break;
02219             case 'NB.2.1-5':
02220                 echo $OUTPUT->notification("Flow or Forward only Sequencing Control Model Violation");
02221             break;
02222             case 'NB.2.1-6':
02223                 echo $OUTPUT->notification("No activity is previous to the root");
02224             break;
02225             case 'NB.2.1-7':
02226                 echo $OUTPUT->notification("Unsupported Navigation Request");
02227             break;
02228             case 'NB.2.1-8':
02229                 echo $OUTPUT->notification("Choice Exit Sequencing Control Model Violation");
02230             break;
02231             case 'NB.2.1-9':
02232                 echo $OUTPUT->notification("No activities to consider");
02233             break;
02234             case 'NB.2.1-10':
02235                 echo $OUTPUT->notification("Choice Sequencing Control Model Violation");
02236             break;
02237             case 'NB.2.1-11':
02238                 echo $OUTPUT->notification("Target Activity does not exist");
02239             break;
02240             case 'NB.2.1-12':
02241                 echo $OUTPUT->notification("Current Activity already terminated");
02242             break;
02243             case 'NB.2.1-13':
02244                 echo $OUTPUT->notification("Undefined Navigation Request");
02245             break;
02246 
02247             case 'TB.2.3-1':
02248                 echo $OUTPUT->notification("Current Activity already terminated");
02249             break;
02250             case 'TB.2.3-2':
02251                 echo $OUTPUT->notification("Current Activity already terminated");
02252             break;
02253             case 'TB.2.3-4':
02254                 echo $OUTPUT->notification("Current Activity already terminated");
02255             break;
02256             case 'TB.2.3-5':
02257                 echo $OUTPUT->notification("Nothing to suspend; No active activities");
02258             break;
02259             case 'TB.2.3-6':
02260                 echo $OUTPUT->notification("Nothing to abandon; No active activities");
02261             break;
02262 
02263             case 'SB.2.1-1':
02264                 echo $OUTPUT->notification("Last activity in the tree");
02265             break;
02266             case 'SB.2.1-2':
02267                 echo $OUTPUT->notification("Cluster has no available children");
02268             break;
02269             case 'SB.2.1-3':
02270                 echo $OUTPUT->notification("No activity is previous to the root");
02271             break;
02272             case 'SB.2.1-4':
02273                 echo $OUTPUT->notification("Forward Only Sequencing Control Model Violation");
02274             break;
02275 
02276             case 'SB.2.2-1':
02277                 echo $OUTPUT->notification("Flow Sequencing Control Model Violation");
02278             break;
02279             case 'SB.2.2-2':
02280                 echo $OUTPUT->notification("Activity unavailable");
02281             break;
02282 
02283             case 'SB.2.3-1':
02284                 echo $OUTPUT->notification("Forward Traversal Blocked");
02285             break;
02286             case 'SB.2.3-2':
02287                 echo $OUTPUT->notification("Forward Only Sequencing Control Model Violation");
02288             break;
02289             case 'SB.2.3-3':
02290                 echo $OUTPUT->notification("No activity is previous to the root");
02291             break;
02292 
02293             case 'SB.2.5-1':
02294                 echo $OUTPUT->notification("Sequencing session has already begun");
02295             break;
02296 
02297             case 'SB.2.6-1':
02298                 echo $OUTPUT->notification("Sequencing session has already begun");
02299             break;
02300             case 'SB.2.6-2':
02301                 echo $OUTPUT->notification("No Suspended activity is defined");
02302             break;
02303 
02304             case 'SB.2.7-1':
02305                 echo $OUTPUT->notification("Sequencing session has not begun");
02306             break;
02307             case 'SB.2.7-2':
02308                 echo $OUTPUT->notification("Flow Sequencing Control Model Violation");
02309             break;
02310 
02311             case 'SB.2.8-1':
02312                 echo $OUTPUT->notification("Sequencing session has not begun");
02313             break;
02314             case 'SB.2.8-2':
02315                 echo $OUTPUT->notification("Flow Sequencing Control Model Violation");
02316             break;
02317 
02318             case 'SB.2.9-1':
02319                 echo $OUTPUT->notification("No target for Choice");
02320             break;
02321             case 'SB.2.9-2':
02322                 echo $OUTPUT->notification("Target Activity does not exist or is unavailable");
02323             break;
02324             case 'SB.2.9-3':
02325                 echo $OUTPUT->notification("Target Activity hidden from choice");
02326             break;
02327             case 'SB.2.9-4':
02328                 echo $OUTPUT->notification("Choice Sequencing Control Model Violation");
02329             break;
02330             case 'SB.2.9-5':
02331                 echo $OUTPUT->notification("No activities to consider");
02332             break;
02333             case 'SB.2.9-6':
02334                 echo $OUTPUT->notification("Unable to activate target; target is not a child of the Current Activity");
02335             break;
02336             case 'SB.2.9-7':
02337                 echo $OUTPUT->notification("Choice Exit Sequencing Control Model Violation");
02338             break;
02339             case 'SB.2.9-8':
02340                 echo $OUTPUT->notification("Unable to choose target activity - constrained choice");
02341             break;
02342             case 'SB.2.9-9':
02343                 echo $OUTPUT->notification("Choice Request Prevented by Flow-only Activity");
02344             break;
02345 
02346             case 'SB.2.10-1':
02347                 echo $OUTPUT->notification("Sequencing session has not begun");
02348             break;
02349             case 'SB.2.10-2':
02350                 echo $OUTPUT->notification("Current Activity is active or suspended");
02351             break;
02352             case 'SB.2.10-3':
02353                 echo $OUTPUT->notification("Flow Sequencing Control Model Violation");
02354             break;
02355 
02356             case 'SB.2.11-1':
02357                 echo $OUTPUT->notification("Sequencing session has not begun");
02358             break;
02359             case 'SB.2.11-2':
02360                 echo $OUTPUT->notification("Current Activity has not been terminated");
02361             break;
02362 
02363             case 'SB.2.12-2':
02364                 echo $OUTPUT->notification("Undefined Sequencing Request");
02365             break;
02366 
02367             case 'DB.1.1-1':
02368                 echo $OUTPUT->notification("Cannot deliver a non-leaf activity");
02369             break;
02370             case 'DB.1.1-2':
02371                 echo $OUTPUT->notification("Nothing to deliver");
02372             break;
02373             case 'DB.1.1-3':
02374                 echo $OUTPUT->notification("Activity unavailable");
02375             break;
02376 
02377             case 'DB.2-1':
02378                 echo $OUTPUT->notification("Identified activity is already active");
02379             break;
02380 
02381         }
02382 
02383     }
02384 }
02385 
02386 
02387 
02388 
02389 
 All Data Structures Namespaces Files Functions Variables Enumerations