2 require ($CFG->dirroot.'/mod/scorm/datamodels/scormlib.php');
4 function scorm_seq_evaluate($scoid,$usertracks) {
8 function scorm_seq_overall ($scoid,$userid,$request,$attempt) {
9 $seq = scorm_seq_navigation($scoid,$userid,$request,$attempt);
10 if ($seq->navigation) {
11 if ($seq->termination != null) {
12 $seq = scorm_seq_termination($scoid,$userid,$seq);
14 if ($seq->sequencing != null) {
15 $seq = scorm_seq_sequencing($scoid,$userid,$seq);
16 if($seq->sequencing == 'exit'){//return the control to the LTS
20 if ($seq->delivery != null) {
21 $seq = scorm_sequencing_delivery($scoid,$userid,$seq);
22 $seq = scorm_content_delivery_environment ($seq,$userid);
25 if ($seq->exception != null) {
26 $seq = scorm_sequencing_exception($seq);
32 function scorm_seq_navigation ($scoid,$userid,$request,$attempt=0) {
35 /// Sequencing structure
36 $seq = new stdClass();
37 $seq->currentactivity = scorm_get_sco($scoid);
38 $seq->traversaldir = null;
39 $seq->nextactivity = null;
40 $seq->deliveryvalid = null;
41 $seq->attempt = $attempt;
43 $seq->identifiedactivity = null;
44 $seq->delivery = null;
45 $seq->deliverable = false;
46 $seq->active = scorm_seq_is('active',$scoid,$userid);
47 $seq->suspended = scorm_seq_is('suspended',$scoid,$userid);
48 $seq->navigation = null;
49 $seq->termination = null;
50 $seq->sequencing = null;
52 $seq->endsession = null;
53 $seq->exception = null;
54 $seq->reachable = true;
59 if (empty($seq->currentactivity)) {
60 $seq->navigation = true;
61 $seq->sequencing = 'start';
63 $seq->exception = 'NB.2.1-1'; /// Sequencing session already begun
67 if (empty($seq->currentactivity)) {
68 if ($track = $DB->get_record('scorm_scoes_track', array('scoid'=>$scoid,'userid'=>$userid,'element'=>'suspendedactivity'))) {//I think it's suspend instead of suspendedactivity
69 $seq->navigation = true;
70 $seq->sequencing = 'resumeall';
72 $seq->exception = 'NB.2.1-3'; /// No suspended activity found
75 $seq->exception = 'NB.2.1-1'; /// Sequencing session already begun
80 if (!empty($seq->currentactivity)) {
81 $sco = $seq->currentactivity;
82 if ($sco->parent != '/') {
83 if ($parentsco = scorm_get_parent($sco)) {
85 if (isset($parentsco->flow) && ($parentsco->flow == true)) {//I think it's parentsco
86 // Current activity is active !
87 if (scorm_seq_is('active',$sco->id,$userid)) {
88 if ($request == 'continue_') {
89 $seq->navigation = true;
90 $seq->termination = 'exit';
91 $seq->sequencing = 'continue';
93 if (!isset($parentsco->forwardonly) || ($parentsco->forwardonly == false)) {
94 $seq->navigation = true;
95 $seq->termination = 'exit';
96 $seq->sequencing = 'previous';
98 $seq->exception = 'NB.2.1-5'; /// Violates control mode
107 $seq->exception = 'NB.2.1-2'; /// Current activity not defined
112 $seq->exception = 'NB.2.1-7' ; /// None to be done, behavior not defined
116 if (!empty($seq->currentactivity)) {
117 // Current activity is active !
118 $seq->navigation = true;
119 $seq->termination = substr($request,0,-1);
120 $seq->sequencing = 'exit';
122 $seq->exception = 'NB.2.1-2'; /// Current activity not defined
127 if (!empty($seq->currentactivity)) {
128 $seq->navigation = true;
129 $seq->termination = substr($request,0,-1);
130 $seq->sequencing = 'exit';
132 $seq->exception = 'NB.2.1-2'; /// Current activity not defined
135 default: /// {target=<STRING>}choice
136 if ($targetsco = $DB->get_record('scorm_scoes', array('scorm'=>$sco->scorm,'identifier'=>$request))) {
137 if ($targetsco->parent != '/') {
138 $seq->target = $request;
140 if ($parentsco = scorm_get_parent($targetsco)) {
141 if (!isset($parentsco->choice) || ($parent->choice == true)) {
142 $seq->target = $request;
146 if ($seq->target != null) {
147 if (empty($seq->currentactivity)) {
148 $seq->navigation = true;
149 $seq->sequencing = 'choice';
151 if (!$sco = scorm_get_sco($scoid)) {
154 if ($sco->parent != $target->parent) {
155 $ancestors = scorm_get_ancestors($sco);
156 $commonpos = scorm_find_common_ancestor($ancestors,$targetsco);
157 if ($commonpos !== false) {
158 if ($activitypath = array_slice($ancestors,0,$commonpos)) {
159 foreach ($activitypath as $activity) {
160 if (scorm_seq_is('active',$activity->id,$userid) && (isset($activity->choiceexit) && ($activity->choiceexit == false))) {
161 $seq->navigation = false;
162 $seq->termination = null;
163 $seq->sequencing = null;
165 $seq->exception = 'NB.2.1-8'; /// Violates control mode
170 $seq->navigation = false;
171 $seq->termination = null;
172 $seq->sequencing = null;
174 $seq->exception = 'NB.2.1-9';
178 // Current activity is active !
179 $seq->navigation = true;
180 $seq->sequencing = 'choice';
183 $seq->exception = 'NB.2.1-10'; /// Violates control mode
186 $seq->exception = 'NB.2.1-11'; /// Target activity does not exists
193 function scorm_seq_termination ($seq,$userid) {
194 if (empty($seq->currentactivity)) {
195 $seq->termination = false;
196 $seq->exception = 'TB.2.3-1';
200 $sco = $seq->currentactivity;
202 if ((($seq->termination == 'exit') || ($seq->termination == 'abandon')) && !$seq->active) {
203 $seq->termination = false;
204 $seq->exception = 'TB.2.3-2';
207 switch ($seq->termination) {
209 scorm_seq_end_attempt($sco,$userid,$seq);
210 $seq = scorm_seq_exit_action_rules($seq,$userid);
212 $exit = false;// I think this is false. Originally this was true
213 $seq = scorm_seq_post_cond_rules($seq,$userid);
214 if ($seq->termination == 'exitparent') {
215 if ($sco->parent != '/') {
216 $sco = scorm_get_parent($sco);
217 $seq->currentactivity = $sco;
218 $seq->active = scorm_seq_is('active',$sco->id,$userid);
219 scorm_seq_end_attempt($sco,$userid,$seq);
220 $exit = true;//I think it's true. Originally this was false
222 $seq->termination = false;
223 $seq->exception = 'TB.2.3-4';
227 } while (($exit == false) && ($seq->termination == 'exit'));
228 if ($seq->termination == 'exit') {
229 $seq->termination = true;
234 scorm_seq_end_attempt($sco,$userid,$seq);
236 /// Terminate Descendent Attempts Process
239 if ($ancestors = scorm_get_ancestors($sco)) {
240 foreach ($ancestors as $ancestor) {
241 scorm_seq_end_attempt($ancestor,$userid,$seq);
242 $seq->currentactivity = $ancestor;
246 $seq->active = scorm_seq_is('active',$seq->currentactivity->id,$userid);
247 $seq->termination = true;
248 $seq->sequencing = exit;
251 if (($seq->active) || ($seq->suspended)) {
252 scorm_seq_set('suspended',$sco->id,$userid);
254 if ($sco->parent != '/') {
255 $parentsco = scorm_get_parent($sco);
256 scorm_seq_set('suspended',$parentsco->id,$userid);
258 $seq->termination = false;
259 $seq->exception = 'TB.2.3-3';
263 if ($ancestors = scorm_get_ancestors($sco)) {
264 foreach ($ancestors as $ancestor) {
265 scorm_seq_set('active',$ancestor->id,$userid,false);
266 scorm_seq_set('suspended',$ancestor->id,$userid);
267 $seq->currentactivity = $ancestor;
269 $seq->termination = true;
270 $seq->sequencing = 'exit';
272 $seq->termination = false;
273 $seq->exception = 'TB.2.3-5';
277 scorm_seq_set('active',$sco->id,$userid,false);
279 $seq->termination = true;
282 if ($ancestors = scorm_get_ancestors($sco)) {
283 foreach ($ancestors as $ancestor) {
284 scorm_seq_set('active',$ancestor->id,$userid,false);
285 $seq->currentactivity = $ancestor;
287 $seq->termination = true;
288 $seq->sequencing = 'exit';
290 $seq->termination = false;
291 $seq->exception = 'TB.2.3-6';
295 $seq->termination = false;
296 $seq->exception = 'TB.2.3-7';
302 function scorm_seq_end_attempt($sco,$userid,$seq) {
305 if (scorm_is_leaf($sco)) {
306 if (!isset($sco->tracked) || ($sco->tracked == 1)) {
307 if (!scorm_seq_is('suspended',$sco->id,$userid)) {
308 if (!isset($sco->completionsetbycontent) || ($sco->completionsetbycontent == 0)) {
309 if (!scorm_seq_is('attemptprogressstatus',$sco->id,$userid,$seq->attempt)) {
310 // if (!scorm_seq_is('attemptprogressstatus',$sco->id,$userid)) {
311 scorm_seq_set('attemptprogressstatus',$sco->id,$userid);
312 scorm_seq_set('attemptcompletionstatus',$sco->id,$userid);
315 if (!isset($sco->objectivesetbycontent) || ($sco->objectivesetbycontent == 0)) {
316 if ($objectives = $DB->get_records('scorm_seq_objective', array('scoid'=>$sco->id))) {
317 foreach ($objectives as $objective) {
318 if ($objective->primaryobj) {
319 //if (!scorm_seq_objective_progress_status($sco,$userid,$objective)) {
320 if (!scorm_seq_is('objectiveprogressstatus',$sco->id,$userid)) {
321 scorm_seq_set('objectiveprogressstatus',$sco->id,$userid);
322 scorm_seq_set('objectivesatisfiedstatus',$sco->id,$userid);
331 if ($children = scorm_get_children($sco)) {
333 foreach ($children as $child) {
334 if (scorm_seq_is('suspended',$child,$userid)) {
340 scorm_seq_set('suspended',$sco,$userid);
342 scorm_seq_set('suspended',$sco,$userid,false);
346 scorm_seq_set('active',$sco,$userid,0,false);
347 scorm_seq_overall_rollup($sco,$userid);
350 function scorm_seq_is($what, $scoid, $userid, $attempt=0) {
353 /// Check if passed activity $what is active
355 if ($track = $DB->get_record('scorm_scoes_track', array('scoid'=>$scoid,'userid'=>$userid,'attempt'=>$attempt,'element'=>$what))) {
361 function scorm_seq_set($what, $scoid, $userid, $attempt=0, $value='true') {
364 $sco = scorm_get_sco($scoid);
366 /// set passed activity to active or not
367 if ($value == false) {
368 $DB->delete_record('scorm_scoes_track', array('scoid'=>$scoid,'userid'=>$userid,'attempt'=>$attempt,'element'=>$what));
370 scorm_insert_track($userid, $sco->scorm, $sco->id, 0, $what, $value);
373 // update grades in gradebook
374 $scorm = $DB->get_record('scorm', array('id'=>$sco->scorm));
375 scorm_update_grades($scorm, $userid, true);
378 function scorm_seq_exit_action_rules($seq,$userid) {
379 $sco = $seq->currentactivity;
380 $ancestors = scorm_get_ancestors($sco);
382 foreach (array_reverse($ancestors) as $ancestor) {
383 if (scorm_seq_rules_check($ancestor,'exit') != null) {
384 $exittarget = $ancestor;
388 if ($exittarget != null) {
389 $commons = array_slice($ancestors,0,scorm_find_common_ancestor($ancestors,$exittarget));
391 /// Terminate Descendent Attempts Process
393 foreach ($commons as $ancestor) {
395 scorm_seq_end_attempt($ancestor,$userid,$seq->attempt);
396 $seq->currentactivity = $ancestor;
403 function scorm_seq_post_cond_rules($seq,$userid) {
404 $sco = $seq->currentactivity;
405 if (!$seq->suspended) {
406 if ($action = scorm_seq_rules_check($sco,'post') != null) {
411 $seq->sequencing = $action;
415 $seq->termination = $action;
418 $seq->termination = 'exitall';
419 $seq->sequencing = 'retry';
427 function scorm_seq_rules_check ($sco, $action){
431 if($rules = $DB->get_records('scorm_seq_ruleconds', array('scoid'=>$sco->id,'action'=>$action))) {
432 foreach ($rules as $rule){
433 if($act = scorm_seq_rule_check($sco,$rule)){
442 function scorm_seq_rule_check ($sco, $rule){
447 $ruleconds = $DB->get_records('scorm_seq_rulecond', array('scoid'=>$sco->id,'ruleconditionsid'=>$rule->id));
448 foreach ($ruleconds as $rulecond){
449 if ($rulecond->operator = 'not') {
450 if ($rulecond->cond != 'unknown' ){
451 $rulecond->cond = 'not'.$rulecond;
454 $bag [$rule->id] = $rulecond->cond;
465 if ($rule->conditioncombination = 'all'){
466 foreach ($bag as $con){
467 $cond = $cond.' and '.$con;
472 foreach ($bag as $con){
473 $cond = $cond.' or '.$con;
480 function scorm_seq_overall_rollup($sco,$userid){//Carlos
482 if ($ancestors = scorm_get_ancestors($sco)) {
483 foreach ($ancestors as $ancestor) {
484 if(!scorm_is_leaf($ancestor)){
485 scorm_seq_measure_rollup($sco,$userid);
487 scorm_seq_objective_rollup($sco,$userid);
488 scorm_seq_activity_progress_rollup($sco,$userid);
495 /* 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*/
497 function scorm_seq_measure_rollup($sco,$userid){
500 $totalmeasure = 0; //Check if there is something similar in the database
501 $valid = false;//Same as in the last line
502 $countedmeasures = 0;//Same too
503 $targetobjective = null;
504 $readable = true;//to check if status and measure weight are readable
505 $objectives = $DB->get_records('scorm_seq_objective', array('scoid'=>$sco->id));
507 foreach ($objectives as $objective){
509 if ($objective->primaryobj == true){//Objective contributes to rollup I'm using primaryobj field, but not
510 $targetobjective = $objective;
516 if ($targetobjective != null){
517 $children = scorm_get_children($sco);
518 foreach ($children as $child){
519 $child = scorm_get_sco ($child);
520 if (!isset($child->tracked) || ($child->tracked == 1)){
522 $rolledupobjective = null;// we set the rolled up activity to undefined
523 $objectives = $DB->get_records('scorm_seq_objective', array('scoid'=>$child->id));
524 foreach ($objectives as $objective){
525 if ($objective->primaryobj == true){//Objective contributes to rollup I'm using primaryobj field, but not
526 $rolledupobjective = $objective;
530 if ($rolledupobjective != null){
531 $child = scorm_get_sco($child->id);
533 $countedmeasures = $countedmeasures + ($child->measureweight);
534 if (!scorm_seq_is('objectivemeasurestatus',$sco->id,$userid)) {
535 $normalizedmeasure = $DB->get_record('scorm_scoes_track', array('scoid'=>$child->id,'userid'=>$userid,'element'=>'objectivenormalizedmeasure'));
536 $totalmeasure = $totalmeasure + (($normalizedmeasure->value) * ($child->measureweight));
549 scorm_seq_set('objectivemeasurestatus',$sco->id,$userid,false);
553 if($countedmeasures>0){
554 scorm_seq_set('objectivemeasurestatus',$sco->id,$userid);
555 $val=$totalmeasure/$countedmeasures;
556 scorm_seq_set('objectivenormalizedmeasure',$sco->id,$userid,$val);
560 scorm_seq_set('objectivemeasurestatus',$sco->id,$userid,false);
569 function scorm_seq_objective_rollup($sco,$userid){
572 scorm_seq_objective_rollup_measure($sco,$userid);
573 scorm_seq_objective_rollup_rules($sco,$userid);
574 scorm_seq_objective_rollup_default($sco,$userid);
577 if($targetobjective->satisfiedbymeasure){
578 scorm_seq_objective_rollup_measure($sco,$userid);
581 if ((scorm_seq_rollup_rule_check($sco,$userid,'incomplete'))|| (scorm_seq_rollup_rule_check($sco,$userid,'completed'))){
582 scorm_seq_objective_rollup_rules($sco,$userid);
586 $rolluprules = $DB->get_record('scorm_seq_rolluprule', array('scoid'=>$sco->id,'userid'=>$userid));
587 foreach($rolluprules as $rolluprule){
588 $rollupruleconds = $DB->get_records('scorm_seq_rolluprulecond', array('rollupruleid'=>$rolluprule->id));
589 foreach($rollupruleconds as $rolluprulecond){
591 switch ($rolluprulecond->cond!='satisfied' && $rolluprulecond->cond!='completed' && $rolluprulecond->cond!='attempted'){
593 scorm_seq_set('objectivesatisfiedstatus',$sco->id,$userid, false);
605 function scorm_seq_objective_rollup_measure($sco,$userid){
608 $targetobjective = null;
611 $objectives = $DB->get_records('scorm_seq_objective', array('scoid'=>$sco->id));
612 foreach ($objectives as $objective){
613 if ($objective->primaryobj == true){
614 $targetobjective = $objective;
618 if ($targetobjective != null){
620 if($targetobjective->satisfiedbymeasure){
623 if (!scorm_seq_is('objectiveprogressstatus',$sco->id,$userid)) {
625 scorm_seq_set('objectiveprogressstatus',$sco->id,$userid,false);
630 if (scorm_seq_is('active',$sco->id,$userid)) {
637 $normalizedmeasure = $DB->get_record('scorm_scoes_track', array('scoid'=>$sco->id,'userid'=>$userid,'element'=>'objectivenormalizedmeasure'));
639 $sco = scorm_get_sco ($sco->id);
641 if (!$isactive || ($isactive && (!isset($sco->measuresatisfactionifactive) || $sco->measuresatisfactionifactive == true))){
642 if($normalizedmeasure->value >= $targetobjective->minnormalizedmeasure){
643 scorm_seq_set('objectiveprogressstatus',$sco->id,$userid);
644 scorm_seq_set('objectivesatisfiedstatus',$sco->id,$userid);
647 scorm_seq_set('objectiveprogressstatus',$sco->id,$userid);
648 scorm_seq_set('objectivesatisfiedstatus',$sco->id,$userid,false);
653 scorm_seq_set('objectiveprogressstatus',$sco->id,$userid,false);
662 function scorm_seq_objective_rollup_default($sco,$userid){
665 if (!(scorm_seq_rollup_rule_check($sco,$userid,'incomplete')) && !(scorm_seq_rollup_rule_check($sco,$userid,'completed'))){
667 $rolluprules = $DB->get_record('scorm_seq_rolluprule', array('scoid'=>$sco->id,'userid'=>$userid));
668 foreach($rolluprules as $rolluprule){
669 $rollupruleconds = $DB->get_records('scorm_seq_rolluprulecond', array('rollupruleid'=>$rolluprule->id));
670 foreach($rollupruleconds as $rolluprulecond){
672 if ($rolluprulecond->cond!='satisfied' && $rolluprulecond->cond!='completed' && $rolluprulecond->cond!='attempted'){
674 scorm_seq_set('objectivesatisfiedstatus',$sco->id,$userid, false);
687 function scorm_seq_objective_rollup_rules($sco,$userid){
690 $targetobjective = null;
692 $objectives = $DB->get_records('scorm_seq_objective', array('scoid'=>$sco->id));
693 foreach ($objectives as $objective){
694 if ($objective->primaryobj == true){//Objective contributes to rollup I'm using primaryobj field, but not
695 $targetobjective = $objective;
699 if ($targetobjective != null){
703 if(scorm_seq_rollup_rule_check($sco,$userid,'notsatisfied')){//with not satisfied rollup for the activity
706 scorm_seq_set('objectiveprogressstatus',$sco->id,$userid);
707 scorm_seq_set('objectivesatisfiedstatus',$sco->id,$userid,false);
709 if(scorm_seq_rollup_rule_check($sco,$userid,'satisfied')){//with satisfied rollup for the activity
710 scorm_seq_set('objectiveprogressstatus',$sco->id,$userid);
711 scorm_seq_set('objectivesatisfiedstatus',$sco->id,$userid);
718 function scorm_seq_activity_progress_rollup ($sco, $userid){
720 if(scorm_seq_rollup_rule_check($sco,$userid,'incomplete')){
721 //incomplete rollup action
722 scorm_seq_set('attemptcompletionstatus',$sco->id,$userid,false,$seq->attempt);
723 scorm_seq_set('attemptprogressstatus',$sco->id,$userid,true,$seq->attempt);
726 if(scorm_seq_rollup_rule_check($sco,$userid,'completed')){
727 //incomplete rollup action
728 scorm_seq_set('attemptcompletionstatus',$sco->id,true,$userid);
729 scorm_seq_set('attemptprogressstatus',$sco->id,true,$userid);
734 function scorm_seq_rollup_rule_check ($sco,$userid,$action){
737 if($rolluprules = $DB->get_record('scorm_seq_rolluprule', array('scoid'=>$sco->id,'userid'=>$userid,'action'=>$action))) {
739 $childrenbag = Array ();
740 $children = scorm_get_children ($sco);
742 foreach($rolluprules as $rolluprule){
744 foreach ($children as $child){
746 /*$tracked = $DB->get_records('scorm_scoes_track', array('scoid'=>$child->id,'userid'=>$userid));
747 if($tracked && $tracked->attemp != 0){*/
748 $child = scorm_get_sco ($child);
749 if (!isset($child->tracked) || ($child->tracked == 1)){
751 if(scorm_seq_check_child ($child,$action,$userid)){
753 $rollupruleconds = $DB->get_records('scorm_seq_rolluprulecond', array('rollupruleid'=>$rolluprule->id));
754 $evaluate = scorm_seq_evaluate_rollupcond($child,$rolluprule->conditioncombination,$rollupruleconds,$userid);
755 if ($evaluate=='unknown'){
756 array_push($childrenbag,'unknown');
759 if($evaluate == true){
760 array_push($childrenbag,true);
763 array_push($childrenbag,false);
772 switch ($rolluprule->childactivityset){
775 if((array_search(false,$childrenbag)===false)&&(array_search('unknown',$childrenbag)===false)){//I think I can use this condition instead equivalent to OR
781 if(array_search(true,$childrenbag)!==false){//I think I can use this condition instead equivalent to OR
787 if((array_search(true,$childrenbag)===false)&&(array_search('unknown',$childrenbag)===false)){//I think I can use this condition instead equivalent to OR
793 foreach ($childrenbag as $itm){//I think I can use this condition instead equivalent to OR
798 if($cont >= $rolluprule->minimumcount){
805 foreach ($childrenbag as $itm){//I think I can use this condition instead equivalent to OR
810 if($cont >= $rolluprule->minimumcount){
816 case 'atleastpercent':
817 foreach ($childrenbag as $itm){//I think I can use this condition instead equivalent to OR
822 if(($cont/sizeof($childrenbag)) >= $rolluprule->minimumcount){
837 function scorm_seq_evaluate_rollupcond($sco,$conditioncombination,$rollupruleconds,$userid){
842 foreach($rollupruleconds as $rolluprulecond){
844 $condit = scorm_evaluate_cond($rolluprulecond,$sco,$userid);
846 if($rule->operator=='not'){// If operator is not, negate the condition
847 if ($rule->cond != 'unknown'){
858 array_push($childrenbag,$condit);
867 foreach ($bag as $b){
869 if ($rolluprule->conditioncombination == 'all'){
902 function scorm_evaluate_condition ($rolluprulecond,$sco,$userid){
907 switch ($rolluprulecond->cond){
910 if($r=$DB->get_record('scorm_scoes_track', array('scoid'=>$sco->id,'userid'=>$userid,'element'=>'objectivesatisfiedstatus'))) {
911 if($r->value == true){
912 if ($r=$DB->get_record('scorm_scoes_track', array('scoid'=>$sco->id,'userid'=>$userid,'element'=>'objectiveprogressstatus'))) {
913 if($r->value == true){
921 case 'objectiveStatusKnown':
922 if ($r=$DB->get_record('scorm_scoes_track', array('scoid'=>$sco->id,'userid'=>$userid,'element'=>'objectiveprogressstatus'))) {
923 if($r->value == true){
929 case 'objectiveMeasureKnown':
930 if ($r = $DB->get_record('scorm_scoes_track', array('scoid'=>$sco->id,'userid'=>$userid,'element'=>'objectivemeasurestatus'))) {
931 if($r->value == true){
940 if ($r = $DB->get_record('scorm_scoes_track', array('scoid'=>$sco->id,'userid'=>$userid,'element'=>'attemptcompletionstatus'))) {
942 if ($r = $DB->get_record('scorm_scoes_track', array('scoid'=>$sco->id,'userid'=>$userid,'element'=>'attemptprogressstatus'))) {
954 if ($r = $DB->get_record('scorm_scoes_track', array('scoid'=>$sco->id,'userid'=>$userid,'element'=>'activityprogressstatus'))) {
956 if ($r = $DB->get_record('scorm_scoes_track', array('scoid'=>$sco->id,'userid'=>$userid,'element'=>'activityattemptcount'))) {
968 case 'attemptLimitExceeded':
969 if ($r = $DB->get_record('scorm_scoes_track', array('scoid'=>$sco->id,'userid'=>$userid,'element'=>'activityprogressstatus'))) {
971 if ($r = $DB->get_record('scorm_scoes_track', array('scoid'=>$sco->id,'userid'=>$userid,'element'=>'limitconditionattemptlimitcontrol'))) {
973 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')) ){
974 if($r->value >= $r2->value){
990 case 'activityProgressKnown':
992 if ($r = $DB->get_record('scorm_scoes_track', array('scoid'=>$sco->id,'userid'=>$userid,'element'=>'activityprogressstatus'))) {
994 if ($r = $DB->get_record('scorm_scoes_track', array('scoid'=>$sco->id,'userid'=>$userid,'element'=>'attemptprogressstatus'))) {
1011 function scorm_seq_check_child ($sco, $action, $userid){
1015 $sco=scorm_get_sco($sco->id);
1016 $r = $DB->get_record('scorm_scoes_track', array('scoid'=>$sco->id,'userid'=>$userid,'element'=>'activityattemptcount'));
1017 if ($action == 'satisfied' || $action == 'notsatisfied'){
1018 if (!$sco->rollupobjectivesatisfied){
1020 if (($action == 'satisfied' && $sco->requiredforsatisfied == 'ifnotsuspended') || ($action == 'notsatisfied' && $sco->requiredfornotsatisfied == 'ifnotsuspended')){
1022 if (!scorm_seq_is('activityprogressstatus',$sco->id,$userid) || ((($r->value)>0)&& !scorm_seq_is('suspended',$sco->id,$userid))){
1028 if (($action == 'satisfied' && $sco->requiredforsatisfied == 'ifattempted') || ($action == 'notsatisfied' && $sco->requiredfornotsatisfied == 'ifattempted')){
1029 if (!scorm_seq_is('activityprogressstatus',$sco->id,$userid) || (($r->value) == 0)){
1034 if (($action == 'satisfied' && $sco->requiredforsatisfied == 'ifnotskipped') || ($action == 'notsatisfied' && $sco->requiredfornotsatisfied == 'ifnotskipped')){
1035 $rulch = scorm_seq_rules_check($sco, 'skip');
1036 if ($rulch != null){
1044 if ($action == 'completed' || $action == 'incomplete'){
1045 if (!$sco->rollupprogresscompletion){
1048 if (($action == 'completed' && $sco->requiredforcompleted == 'ifnotsuspended') || ($action == 'incomplete' && $sco->requiredforincomplete == 'ifnotsuspended')){
1050 if (!scorm_seq_is('activityprogressstatus',$sco->id,$userid) || ( (($r->value)>0)&& !scorm_seq_is('suspended',$sco->id,$userid))){
1057 if (($action == 'completed' && $sco->requiredforcompleted == 'ifattempted') || ($action == 'incomplete' && $sco->requiredforincomplete == 'ifattempted')){
1058 if (!scorm_seq_is('activityprogressstatus',$sco->id,$userid) || (($r->value)==0)){
1064 if (($action == 'completed' && $sco->requiredforsatisfied == 'ifnotskipped') || ($action == 'incomplete' && $sco->requiredfornotsatisfied == 'ifnotskipped')){
1065 $rulch = scorm_seq_rules_check($sco, 'skip');
1066 if ($rulch != null){
1081 function scorm_seq_sequencing ($scoid,$userid,$seq) {
1083 switch ($seq->sequencing) {
1086 //TODO: undefined $sco!
1087 $seq = scorm_seq_start_sequencing($sco,$userid,$seq); //We'll see the parameters we have to send, this should update delivery and end
1088 $seq->sequencing = true;
1094 $seq = scorm_seq_resume_sequencing($sco,$userid,$seq); //We'll see the parameters we have to send, this should update delivery and end
1095 $seq->sequencing = true;
1102 $seq = scorm_seq_exit_sequencing($sco,$userid,$seq); //We'll see the parameters we have to send, this should update delivery and end
1103 $seq->sequencing = true;
1110 $seq = scorm_seq_retry_sequencing($sco,$userid,$seq); //We'll see the parameters we have to send, this should update delivery and end
1111 $seq->sequencing = true;
1117 $seq = scorm_seq_previous_sequencing($sco,$userid,$seq);// We'll see the parameters we have to send, this should update delivery and end
1118 $seq->sequencing = true;
1124 $seq = scorm_seq_choice_sequencing($sco,$userid,$seq);// We'll see the parameters we have to send, this should update delivery and end
1125 $seq->sequencing = true;
1132 if ($seq->exception != null){
1133 $seq->sequencing = false;
1137 $seq->sequencing= true;
1142 function scorm_seq_start_sequencing($scoid,$userid,$seq){
1145 if (!empty($seq->currentactivity)) {
1146 $seq->delivery = null;
1147 $seq->exception = 'SB.2.5-1';
1150 $sco = $DB->get_record('scorm_scoes', array('scoid'=>$scoid,'userid'=>$userid));
1151 if (($sco->parent == '/') && scorm_is_leaf($sco)) {//if the activity is the root and is leaf
1152 $seq->delivery = $sco;
1155 $ancestors = scorm_get_ancestors($sco);
1156 $ancestorsroot = array_reverse($ancestors);
1157 $res = scorm_seq_flow($ancestorsroot[0],'forward',$seq,true,$userid);
1162 //return end and exception
1167 function scorm_seq_resume_all_sequencing($scoid,$userid,$seq){
1170 if (!empty($seq->currentactivity)){
1171 $seq->delivery = null;
1172 $seq->exception = 'SB.2.6-1';
1175 $track = $DB->get_record('scorm_scoes_track', array('scoid'=>$scoid,'userid'=>$userid,'element'=>'suspendedactivity'));
1177 $seq->delivery = null;
1178 $seq->exception = 'SB.2.6-2';
1181 $seq->delivery = $DB->get_record('scorm_scoes', array('scoid'=>$scoid,'userid'=>$userid));//we assign the sco to the delivery
1185 function scorm_seq_continue_sequencing($scoid,$userid,$seq){
1186 if (empty($seq->currentactivity)) {
1187 $seq->delivery = null;
1188 $seq->exception = 'SB.2.7-1';
1191 $currentact= $seq->currentactivity;
1192 if ($currentact->parent != '/') {//if the activity is the root and is leaf
1193 $parent = scorm_get_parent ($currentact);
1195 if (!isset($parent->flow) || ($parent->flow == false)) {
1196 $seq->delivery = null;
1197 $seq->exception = 'SB.2.7-2';
1201 $res = scorm_seq_flow($currentact,'forward',$seq,false,$userid);
1206 //return end and exception
1212 function scorm_seq_previous_sequencing($scoid,$userid,$seq){
1213 if (empty($seq->currentactivity)) {
1214 $seq->delivery = null;
1215 $seq->exception = 'SB.2.8-1';
1219 $currentact= $seq->currentactivity;
1220 if ($currentact->parent != '/') {//if the activity is the root and is leaf
1221 $parent = scorm_get_parent ($activity); // TODO: undefined!!
1222 if (!isset($parent->flow) || ($parent->flow == false)) {
1223 $seq->delivery = null;
1224 $seq->exception = 'SB.2.8-2';
1228 $res = scorm_seq_flow($currentact,'backward',$seq,false,$userid);
1233 //return end and exception
1240 function scorm_seq_exit_sequencing($scoid,$userid,$seq){
1241 if (empty($seq->currentactivity)) {
1242 $seq->delivery = null;
1243 $seq->exception = 'SB.2.11-1';
1248 $seq->endsession = false;
1249 $seq->exception = 'SB.2.11-2';
1252 $currentact= $seq->currentactivity;
1253 if ($currentact->parent == '/'){
1254 $seq->endsession = true;
1258 $seq->endsession = false;
1263 function scorm_seq_retry_sequencing($scoid,$userid,$seq){
1264 if (empty($seq->currentactivity)) {
1265 $seq->delivery = null;
1266 $seq->exception = 'SB.2.10-1';
1269 if ($seq->active || $seq->suspended){
1270 $seq->delivery = null;
1271 $seq->exception = 'SB.2.10-2';
1275 if (!scorm_is_leaf($seq->currentactivity)){
1276 $res = scorm_seq_flow($seq->currentactivity,'forward',$seq,true,$userid);
1282 $seq->delivery = null;
1283 $seq->exception = 'SB.2.10-3';
1288 $seq->delivery = $seq->currentactivity;
1294 function scorm_seq_flow ($candidate,$direction,$seq,$childrenflag,$userid){
1295 //$PREVDIRECTION NOT DEFINED YET
1297 $activity=$candidate;
1299 $previdirection = null;
1300 $seq = scorm_seq_flow_tree_traversal ($activity,$direction,$childrenflag,$prevdirection,$seq,$userid); // TODO: undefined
1301 if($seq->identifiedactivity == null){//if identifies
1302 $seq->identifiedactivity = $candidate;
1303 $seq->deliverable = false;
1307 $activity = $seq->identifiedactivity;
1308 $seq = scorm_seq_flow_activity_traversal($activity,$userid,$direction,$childrenflag,$prevdirection,$seq,$userid);//
1314 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
1315 $activity = scorm_get_sco ($activity);
1316 $parent = scorm_get_parent ($activity);
1317 if (!isset($parent->flow) || ($parent->flow == false)) {
1318 $seq->deliverable = false;
1319 $seq->exception = 'SB.2.2-1';
1320 $seq->nextactivity = $activity;
1324 $rulch = scorm_seq_rules_check($sco, 'skipped'); // TODO: undefined
1325 if ($rulch != null){
1326 $seq = scorm_seq_flow_tree_traversal ($activity, $direction, false, $prevdirection, $seq,$userid);//endsession and exception
1327 if ($seq->identifiedactivity == null){
1328 $seq->deliverable = false;
1329 $seq->nextactivity = $activity;
1334 if ($prevdirection = 'backward' && $seq->traversaldir == 'backward'){
1335 $seq = scorm_seq_flow_tree_traversal ($activity,$direction,false,null,$seq,$userid);
1336 $seq = scorm_seq_flow_activity($seq->identifiedactivity, $userid, $direction, $childrenflag, $prevdirection, $seq,$userid);
1339 $seq = scorm_seq_flow_tree_traversal ($activity,$direction,false,null,$seq,$userid);
1340 $seq = scorm_seq_flow_activity($seq->identifiedactivity, $userid, $direction, $childrenflag, $prevdirection, $seq,$userid);
1346 $ch=scorm_check_activity ($activity,$userid);
1350 $seq->deliverable = false;
1351 $seq->exception = 'SB.2.2-2';
1352 $seq->nextactivity = $activity;
1357 if (!scorm_is_leaf($activity)){
1359 $seq = scorm_seq_flow_tree_traversal ($activity,$direction,true,null,$seq,$userid);
1361 if ($seq->identifiedactivity == null){
1362 $seq->deliverable = false;
1363 $seq->nextactivity = $activity;
1368 if($direction == 'backward' && $seq->traversaldir == 'forward'){
1369 $seq = scorm_seq_flow_activity($seq->identifiedactivity, $userid, 'forward', $childrenflag, 'backward', $seq,$userid);
1372 scorm_seq_flow_activity($seq->identifiedactivity, $userid, $direction, $childrenflag, null, $seq,$userid);
1379 $seq->deliverable = true;
1380 $seq->nextactivity = $activity;
1384 function scorm_seq_flow_tree_traversal ($activity,$direction,$childrenflag,$prevdirection,$seq,$userid){
1386 $revdirection = false;
1387 $parent = scorm_get_parent ($activity);
1388 $children = scorm_get_available_children ($parent);
1389 $siz = sizeof ($children);
1391 if (($prevdirection != null && $prevdirection == 'backward') && ($children[$siz-1]->id == $activity->id)){
1392 $direction = 'backward';
1393 $children[0] = $activity;
1394 $revdirection = true;
1397 if($direction = 'forward'){
1398 $ancestors = scorm_get_ancestors($activity);
1399 $ancestorsroot = array_reverse($ancestors);
1400 $preorder = scorm_get_preorder ($ancestorsroot);
1401 $siz= sizeof ($preorder);
1402 if (($activity->id == $preorder[$siz-1]->id) || (($activity->parent == '/') && !($childrenflag))){
1403 scorm_seq_terminate_descent($ancestorsroot,$userid);
1404 $seq->endsession = true;
1405 $seq->nextactivity = null;
1408 if (scorm_is_leaf ($activity) || !$childrenflag){
1409 if ($children[$siz-1]->id == $activity->id){
1411 $seq = scorm_seq_flow_tree_traversal ($parent, $direction, false, null, $seq,$userid);
1412 // I think it's not necessary to do a return in here
1415 $parent = scorm_get_parent($activity);
1416 $children = scorm_get_available_children($parent);
1417 $seq->traversaldir = $direction;
1418 $sib = scorm_get_siblings($activity);
1419 $pos = array_search($sib, $activity);
1420 if ($pos !== false) {
1421 if ($pos != sizeof ($sib)){
1422 $seq->nextactivity = $sib [$pos+1];
1426 $ch = scorm_get_children($sib[0]);
1427 $seq->nextactivity = $ch[0];
1434 if (!empty ($children)){
1435 $seq->traversaldir = $direction;
1436 $seq->nextactivity = $children[0];
1440 $seq->traversaldir = null;
1441 $seq->nextactivity = $children[0];
1442 $seq->exception = 'SB.2.1-2';
1448 if($direction = 'backward'){
1450 if ($activity->parent == '/'){
1451 $seq->traversaldir = null;
1452 $seq->nextactivity = null;
1453 $seq->exception = 'SB.2.1-3';
1456 if (scorm_is_leaf ($activity) || !$childrenflag){
1457 if (!$revdirection){
1458 if (isset($parent->forwardonly) && ($parent->forwardonly == true)) {
1459 $seq->traversaldir = null;
1460 $seq->nextactivity = null;
1461 $seq->exception = 'SB.2.1-4';
1465 if ($children[0]->id == $activity->id){
1466 $seq = scorm_seq_flow_tree_traversal ($parent, 'backward', false, null, $seq);
1470 $ancestors = scorm_get_ancestors($activity);
1471 $ancestorsroot = array_reverse ($ancestors);
1472 $preorder = scorm_get_preorder ($ancestorsroot);
1473 $pos = array_search($preorder, $children[$siz]);
1474 $preord = array_slice($preorder, 0, $pos-1);
1475 $revpreorder = array_reverse($preord);
1476 $position = array_search($revpreorder, $activity);
1477 $seq->nextactivity = $revpreorder[$pos+1];
1478 $seq->traversaldir = $direction;
1483 if (!empty($children)){
1484 $activity = scorm_get_sco($activity->id);
1485 if (isset($parent->flow) && ($parent->flow == true)) {
1486 $children = scorm_get_children ($activity);
1487 $seq->traversaldir = 'forward';
1488 $seq->nextactivity = $children[0];
1493 $children = scorm_get_children ($activity);
1494 $seq->traversaldir = 'backward';
1495 $seq->nextactivity = $children[sizeof($children)-1];
1502 $seq->traversaldir = null;
1503 $seq->nextactivity = null;
1504 $seq->exception = 'SB.2.1-2';
1513 function scorm_check_activity ($activity,$userid){
1514 $act = scorm_seq_rules_check($activity,'disabled');
1518 if(scorm_limit_cond_check ($activity,$userid)){
1526 function scorm_limit_cond_check ($activity,$userid){
1529 if (isset($activity->tracked) && ($activity->tracked == 0)){
1534 if (scorm_seq_is('active',$activity->id,$userid) || scorm_seq_is('suspended',$activity->id,$userid)){
1538 if (!isset($activity->limitcontrol) || ($activity->limitcontrol == 1)){
1539 $r = $DB->get_record('scorm_scoes_track', array('scoid'=>$activity->id,'userid'=>$userid,'element'=>'activityattemptcount'));
1540 if (scorm_seq_is('activityprogressstatus',$activity->id,$userid) && ($r->value >=$activity->limitattempt)){
1545 if (!isset($activity->limitabsdurcontrol) || ($activity->limitabsdurcontrol == 1)){
1546 $r = $DB->get_record('scorm_scoes_track', array('scoid'=>$activity->id,'userid'=>$userid,'element'=>'activityabsoluteduration'));
1547 if (scorm_seq_is('activityprogressstatus',$activity->id,$userid) && ($r->value >=$activity->limitabsduration)){
1552 if (!isset($activity->limitexpdurcontrol) || ($activity->limitexpdurcontrol == 1)){
1553 $r = $DB->get_record('scorm_scoes_track', array('scoid'=>$activity->id,'userid'=>$userid,'element'=>'activityexperiencedduration'));
1554 if (scorm_seq_is('activityprogressstatus',$activity->id,$userid) && ($r->value >=$activity->limitexpduration)){
1559 if (!isset($activity->limitattabsdurcontrol) || ($activity->limitattabsdurcontrol == 1)){
1560 $r = $DB->get_record('scorm_scoes_track', array('scoid'=>$activity->id,'userid'=>$userid,'element'=>'attemptabsoluteduration'));
1561 if (scorm_seq_is('activityprogressstatus',$activity->id,$userid) && ($r->value >=$activity->limitattabsduration)){
1566 if (!isset($activity->limitattexpdurcontrol) || ($activity->limitattexpdurcontrol == 1)){
1567 $r = $DB->get_record('scorm_scoes_track', array('scoid'=>$activity->id,'userid'=>$userid,'element'=>'attemptexperiencedduration'));
1568 if (scorm_seq_is('activityprogressstatus',$activity->id,$userid) && ($r->value >=$activity->limitattexpduration)){
1573 if (!isset($activity->limitbegincontrol) || ($activity->limitbegincontrol == 1)){
1574 $r = $DB->get_record('scorm_scoes_track', array('scoid'=>$activity->id,'userid'=>$userid,'element'=>'begintime'));
1575 if (time()>=$activity->limitbegintime){
1580 if (!isset($activity->limitbegincontrol) || ($activity->limitbegincontrol == 1)){
1581 if (time()<$activity->limitbegintime){
1586 if (!isset($activity->limitendcontrol) || ($activity->limitendcontrol == 1)){
1588 if (time()>$activity->limitendtime){
1598 function scorm_seq_choice_sequencing($sco,$userid,$seq){
1600 $avchildren = Array ();
1601 $comancestor = null;
1605 $seq->delivery = null;
1606 $seq->exception = 'SB.2.9-1';
1610 $ancestors = scorm_get_ancestors($sco);
1611 $arrpath = array_reverse($ancestors);
1612 array_push ($arrpath,$sco);//path from the root to the target
1614 foreach ($arrpath as $activity){
1616 if ($activity->parent != '/') {
1617 $avchildren = scorm_get_available_children (scorm_get_parent($activity));
1618 $position = array_search($avchildren, $activity);
1619 if ($position !== false){
1620 $seq->delivery = null;
1621 $seq->exception = 'SB.2.9-2';
1626 if (scorm_seq_rules_check($activity,'hidefromchoice' != null)){
1628 $seq->delivery = null;
1629 $seq->exception = 'SB.2.9-3';
1636 if ($sco->parent != '/') {
1637 $parent = scorm_sco_get_parent ($sco);
1638 if ( isset($parent->choice) && ($parent->choice == false)){
1639 $seq->delivery = null;
1640 $seq->exception = 'SB.2.9-4';
1645 if ($seq->currentactivity != null){
1646 $commonpos = scorm_find_common_ancestor($ancestors,$seq->currentactivity);
1647 $comancestor = $arrpath [$commonpos];
1650 $comancestor = $arrpath [0];
1653 if($seq->currentactivity === $sco) {
1657 $sib = scorm_get_siblings($seq->currentactivity);
1658 $pos = array_search($sib, $sco);
1660 if ($pos !== false){
1662 $siblings = array_slice($sib, 0, $pos-1);
1664 if (empty($siblings)){
1666 $seq->delivery = null;
1667 $seq->exception = 'SB.2.9-5';
1672 $children = scorm_get_children (scorm_get_parent ($sco));
1673 $pos1 = array_search($children, $sco);
1674 $pos2 = array_search($seq->currentactivity, $sco);
1676 $traverse = 'forward';
1679 $traverse = 'backward';
1682 foreach ($siblings as $sibling){
1683 $seq = scorm_seq_choice_activity_traversal($sibling,$userid,$seq,$traverse);
1684 if(!$seq->reachable){
1685 $seq->delivery = null;
1693 if($seq->currentactivity == null || $seq->currentactivity == $comancestor){
1694 $commonpos = scorm_find_common_ancestor($ancestors,$seq->currentactivity);
1695 $comtarget = array_slice($ancestors, 1,$commonpos-1);//path from the common ancestor to the target activity
1696 $comtarget = array_reverse($comtarget);
1698 if (empty($comtarget)){
1699 $seq->delivery = null;
1700 $seq->exception = 'SB.2.9-5';
1703 foreach ($comtarget as $act){
1704 $seq = scorm_seq_choice_activity_traversal($act,$userid,$seq,'forward');
1705 if(!$seq->reachable){
1706 $seq->delivery = null;
1709 $act = scorm_get_sco ($acti->id);
1710 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?
1711 $seq->delivery = null;
1712 $seq->exception = 'SB.2.9-6';
1720 if ($comancestor->id == $sco->id){
1722 $ancestorscurrent = scorm_get_ancestors($seq->currentactivity);
1723 $possco = array_search ($ancestorscurrent, $sco);
1724 $curtarget = array_slice($ancestorscurrent,0,$possco);//path from the current activity to the target
1726 if (empty($curtarget)){
1727 $seq->delivery = null;
1728 $seq->exception = 'SB.2.9-5';
1732 foreach ($curtarget as $activ){
1734 if ($i != sizeof($curtarget)){
1735 if ( isset($activ->choiceexit) && ($activ->choiceexit == false)){
1736 $seq->delivery = null;
1737 $seq->exception = 'SB.2.9-7';
1745 if (array_search ($ancestors, $comancestor)!== false){
1746 $ancestorscurrent = scorm_get_ancestors($seq->currentactivity);
1747 $commonpos = scorm_find_common_ancestor($ancestors,$sco);
1748 $curcommon = array_slice($ancestorscurrent,0,$commonpos-1);
1749 if(empty($curcommon)){
1750 $seq->delivery = null;
1751 $seq->exception = 'SB.2.9-5';
1755 $constrained = null;
1756 foreach ($curcommon as $acti){
1757 $acti = scorm_get_sco($acti->id);
1758 if ( isset($acti->choiceexit) && ($acti->choiceexit == false)){
1759 $seq->delivery = null;
1760 $seq->exception = 'SB.2.9-7';
1763 if ($constrained == null){
1764 if($acti->constrainchoice == true){
1765 $constrained = $acti;
1769 if ($constrained != null){
1770 $fwdir = scorm_get_preorder($constrained);
1772 if(array_search ($fwdir, $sco)!== false){
1773 $traverse = 'forward';
1776 $traverse = 'backward';
1778 $seq = scorm_seq_choice_flow ($constrained, $traverse, $seq);
1779 $actconsider = $seq->identifiedactivity;
1780 $avdescendents = Array();
1781 $avdescendents= scorm_get_available_descendents ($actconsider);
1782 if (array_search ($avdescendents, $sco) !== false && $sco->id != $actconsider->id && $constrained->id != $sco->id ){
1783 $seq->delivery = null;
1784 $seq->exception = 'SB.2.9-8';
1791 $commonpos = scorm_find_common_ancestor($ancestors,$seq->currentactivity);
1792 $comtarget = array_slice($ancestors, 1,$commonpos-1);//path from the common ancestor to the target activity
1793 $comtarget = array_reverse($comtarget);
1795 if (empty($comtarget)){
1796 $seq->delivery = null;
1797 $seq->exception = 'SB.2.9-5';
1801 $fwdir = scorm_get_preorder($seq->currentactivity);
1803 if(array_search ($fwdir, $sco)!== false){
1805 foreach ($comtarget as $act){
1806 $seq = scorm_seq_choice_activity_traversal($act,$userid,$seq,'forward');
1807 if(!$seq->reachable){
1808 $seq->delivery = null;
1811 $act = scorm_get_sco($act->id);
1812 if(scorm_seq_is('active',$act->id,$userid) && ($act->id != $comancestor->id && ($act->preventactivation == true))){
1813 $seq->delivery = null;
1814 $seq->exception = 'SB.2.9-6';
1821 foreach ($comtarget as $act){
1822 $act = scorm_get_sco($act->id);
1823 if(scorm_seq_is('active',$act->id,$userid) && ($act->id != $comancestor->id && ($act->preventactivation==true))){
1824 $seq->delivery = null;
1825 $seq->exception = 'SB.2.9-6';
1833 if(scorm_is_leaf ($sco)){
1834 $seq->delivery = $sco;
1835 $seq->exception = 'SB.2.9-6';
1839 $seq = scorm_seq_flow ($sco,'forward',$seq,true,$userid);
1840 if ($seq->deliverable == false){
1841 scorm_terminate_descendent_attempts($comancestor,$userid,$seq);
1842 scorm_seq_end_attempt($comancestor,$userid,$seq->attempt);
1843 $seq->currentactivity = $sco;
1844 $seq->delivery = null;
1845 $seq->exception = 'SB.2.9-9';
1855 function scorm_seq_choice_flow ($constrained, $traverse, $seq){
1856 $seq = scorm_seq_choice_flow_tree ($constrained, $traverse, $seq);
1857 if ($seq->identifiedactivity == null){
1858 $seq->identifiedactivity = $constrained;
1866 function scorm_seq_choice_flow_tree ($constrained, $traverse, $seq){
1868 $parent = scorm_get_parent ($constrained);
1869 if ($traverse== 'forward'){
1870 $preord = scorm_get_preorder ($constrained);
1871 if (sizeof($preorder) == 0 || (sizeof($preorder) == 0 && $preorder[0]->id = $constrained->id)){ // TODO: undefined
1872 $islast = true;//the function is the last activity available
1874 if ($constrained->parent == '/' || $islast){
1875 $seq->nextactivity = null;
1878 $avchildren = scorm_get_available_children ($parent);//available children
1879 if ($avchildren [sizeof($avchildren)-1]->id == $constrained->id){
1880 $seq = scorm_seq_choice_flow_tree ($parent, 'forward', $seq);
1885 while($i < sizeof($avchildren)){
1886 if ($avchildren [$i]->id == $constrained->id){
1887 $seq->nextactivity = $avchildren [$i+1];
1898 if ($traverse== 'backward'){
1899 if($constrained->parent == '/' ){
1900 $seq->nextactivity = null;
1904 $avchildren = scorm_get_available_children ($parent);//available children
1905 if ($avchildren [0]->id == $constrained->id){
1906 $seq = scorm_seq_choice_flow_tree ($parent, 'backward', $seq);
1910 $i=sizeof($avchildren)-1;
1912 if ($avchildren [$i]->id == $constrained->id){
1913 $seq->nextactivity = $avchildren [$i-1];
1923 function scorm_seq_choice_activity_traversal($activity,$userid,$seq,$direction){
1925 if($direction == 'forward'){
1927 $act = scorm_seq_rules_check($activity,'stopforwardtraversal');
1930 $seq->reachable = false;
1931 $seq->exception = 'SB.2.4-1';
1934 $seq->reachable = false;
1938 if($direction == 'backward'){
1939 $parentsco = scorm_get_parent($activity);
1940 if($parentsco!= null){
1941 if (isset($parentsco->forwardonly) && ($parentsco->forwardonly == true)){
1942 $seq->reachable = false;
1943 $seq->exception = 'SB.2.4-2';
1947 $seq->reachable = false;
1948 $seq->exception = 'SB.2.4-3';
1953 $seq->reachable = true;
1958 //Delivery Request Process
1960 function scorm_sequencing_delivery($scoid,$userid,$seq){
1962 if(!scorm_is_leaf ($seq->delivery)){
1963 $seq->deliveryvalid = false;
1964 $seq->exception = 'DB.1.1-1';
1967 $ancestors = scorm_get_ancestors($seq->delivery);
1968 $arrpath = array_reverse($ancestors);
1969 array_push ($arrpath,$seq->delivery);//path from the root to the target
1971 if (empty($arrpath)){
1972 $seq->deliveryvalid = false;
1973 $seq->exception = 'DB.1.1-2';
1977 foreach ($arrpath as $activity){
1978 if(scorm_check_activity ($activity,$userid)){
1979 $seq->deliveryvalid = false;
1980 $seq->exception = 'DB.1.1-3';
1985 $seq->deliveryvalid = true;
1990 function scorm_content_delivery_environment ($seq,$userid){
1993 $act = $seq->currentactivity;
1994 if(scorm_seq_is('active',$act->id,$userid)){
1995 $seq->exception = 'DB.2-1';
1998 $track = $DB->get_record('scorm_scoes_track', array('scoid'=>$act->id,'userid'=>$userid,'element'=>'suspendedactivity'));
1999 if ($track != null){
2000 $seq = scorm_clear_suspended_activity($seq->delivery, $seq);
2003 $seq = scorm_terminate_descendent_attempts ($seq->delivery,$userid,$seq);
2004 $ancestors = scorm_get_ancestors($seq->delivery);
2005 $arrpath = array_reverse($ancestors);
2006 array_push ($arrpath,$seq->delivery);
2007 foreach ($arrpath as $activity){
2008 if(!scorm_seq_is('active',$activity->id,$userid)){
2009 if(!isset($activity->tracked) || ($activity->tracked == 1)){
2010 if(!scorm_seq_is('suspended',$activity->id,$userid)){
2011 $r = $DB->get_record('scorm_scoes_track', array('scoid'=>$activity->id,'userid'=>$userid,'element'=>'activityattemptcount'));
2012 $r->value = ($r->value)+1;
2013 $DB->update_record ('scorm_scoes_track',$r);
2014 if ($r->value == 1){
2015 scorm_seq_set('activityprogressstatus', $activity->id, $userid, 'true');
2017 scorm_insert_track($userid, $activity->scorm, $activity->id, 0, 'objectiveprogressstatus', 'false');
2018 scorm_insert_track($userid, $activity->scorm, $activity->id, 0, 'objectivesatisfiedstatus', 'false');
2019 scorm_insert_track($userid, $activity->scorm, $activity->id, 0, 'objectivemeasurestatus', 'false');
2020 scorm_insert_track($userid, $activity->scorm, $activity->id, 0, 'objectivenormalizedmeasure', 0.0);
2022 scorm_insert_track($userid, $activity->scorm, $activity->id, 0, 'attemptprogressstatus', 'false');
2023 scorm_insert_track($userid, $activity->scorm, $activity->id, 0, 'attemptcompletionstatus', 'false');
2024 scorm_insert_track($userid, $activity->scorm, $activity->id, 0, 'attemptabsoluteduration', 0.0);
2025 scorm_insert_track($userid, $activity->scorm, $activity->id, 0, 'attemptexperiencedduration', 0.0);
2026 scorm_insert_track($userid, $activity->scorm, $activity->id, 0, 'attemptcompletionamount', 0.0);
2029 scorm_seq_set('active', $activity->id, $userid, 'true');
2032 $seq->delivery = $seq->currentactivity;
2033 scorm_seq_set('suspendedactivity', $activity->id, $userid, 'false');
2035 //ONCE THE DELIVERY BEGINS (How should I check that?)
2037 if(isset($activity->tracked) || ($activity->tracked == 0)){
2038 //How should I track the info and what should I do to not record the information for the activity during delivery?
2039 $atabsdur = $DB->get_record('scorm_scoes_track', array('scoid'=>$activity->id,'userid'=>$userid,'element'=>'attemptabsoluteduration'));
2040 $atexpdur = $DB->get_record('scorm_scoes_track', array('scoid'=>$activity->id,'userid'=>$userid,'element'=>'attemptexperiencedduration'));
2046 function scorm_clear_suspended_activity($act,$seq){
2048 $currentact= $seq->currentactivity;
2049 $track = $DB->get_record('scorm_scoes_track', array('scoid'=>$currentact->id,'userid'=>$userid,'element'=>'suspendedactivity')); // TODO: undefined
2050 if ($track != null){
2051 $ancestors = scorm_get_ancestors($act);
2052 $commonpos = scorm_find_common_ancestor($ancestors,$currentact);
2053 if ($commonpos !== false) {
2054 if ($activitypath = array_slice($ancestors,0,$commonpos)) {
2055 if (!empty ($activitypath)){
2057 foreach ($activitypath as $activity) {
2058 if (scorm_is_leaf($activity)){
2059 scorm_seq_set('suspended',$activity->id,$userid,false);
2062 $children = scorm_get_children($activity);
2064 foreach ($children as $child){
2065 if(scorm_seq_is('suspended',$child->id,$userid)){
2070 scorm_seq_set('suspended',$activity->id,$userid,false);
2077 scorm_seq_set('suspendedactivity',$act->id,$userid,false);
2082 function scorm_select_children_process($scoid,$userid){
2085 $sco = scorm_get_sco($scoid);
2086 if (!scorm_is_leaf($sco)){
2087 if(!scorm_seq_is('suspended',$scoid,$userid) && !scorm_seq_is('active',$scoid,$userid)){
2088 $r = $DB->get_record('scorm_scoes_track', array('scoid'=>$scoid,'userid'=>$userid,'element'=>'selectiontiming'));
2092 case 'oneachnewattempt':
2097 if(!scorm_seq_is('activityprogressstatus',$scoid,$userid)){
2098 if(scorm_seq_is('selectioncountsstatus',$scoid,$userid)){
2100 $res = $DB->get_record('scorm_scoes_track', array('scoid'=>$scoid,'userid'=>$userid,'element'=>'selectioncount'));
2101 $i = ($res->value)-1;
2102 $children = scorm_get_children ($sco);
2105 $pos = array_rand($children);
2106 array_push($childlist,$children [$pos]);
2107 array_splice($children,$pos,1);
2111 $clist = serialize ($childlist);
2112 scorm_seq_set('availablechildren', $scoid, $userid, false);
2113 scorm_seq_set('availablechildren', $scoid, $userid, $clist);
2126 function scorm_randomize_children_process($scoid,$userid){
2129 $sco = scorm_get_sco($scoid);
2130 if (!scorm_is_leaf($sco)){
2131 if(!scorm_seq_is('suspended',$scoid,$userid) && !scorm_seq_is('active',$scoid,$userid)){
2132 $r = $DB->get_record('scorm_scoes_track', array('scoid'=>$scoid,'userid'=>$userid,'element'=>'randomizationtiming'));
2140 case 'oneachnewattempt':
2142 if(!scorm_seq_is('activityprogressstatus',$scoid,$userid)){
2143 if(scorm_seq_is('randomizechildren',$scoid,$userid)){
2144 $childlist = array();
2145 $res = scorm_get_available_children($sco);
2146 $i = sizeof($res)-1;
2147 $children = $res->value;
2150 $pos = array_rand($children);
2151 array_push($childlist,$children [$pos]);
2152 array_splice($children,$pos,1);
2156 $clist = serialize ($childlist);
2157 scorm_seq_set('availablechildren', $scoid, $userid, false);
2158 scorm_seq_set('availablechildren', $scoid, $userid, $clist);
2173 function scorm_terminate_descendent_attempts ($activity,$userid,$seq){
2174 $ancestors = scorm_get_ancestors($seq->currentactivity);
2175 $commonpos = scorm_find_common_ancestor($ancestors,$activity);
2176 if ($commonpos !== false) {
2177 if ($activitypath = array_slice($ancestors,1,$commonpos-2)) {
2178 if (!empty ($activitypath)){
2180 foreach ($activitypath as $sco) {
2181 scorm_seq_end_attempt($sco,$userid,$seq->attempt);
2189 function scorm_sequencing_exception($seq){
2191 if($seq->exception != null){
2192 switch($seq->exception){
2195 echo $OUTPUT->notification("Sequencing session has already begun");
2198 echo $OUTPUT->notification("Sequencing session has not begun");
2201 echo $OUTPUT->notification("Suspended activity is not defined");
2204 echo $OUTPUT->notification("Flow Sequencing Control Model Violation");
2207 echo $OUTPUT->notification("Flow or Forward only Sequencing Control Model Violation");
2210 echo $OUTPUT->notification("No activity is previous to the root");
2213 echo $OUTPUT->notification("Unsupported Navigation Request");
2216 echo $OUTPUT->notification("Choice Exit Sequencing Control Model Violation");
2219 echo $OUTPUT->notification("No activities to consider");
2222 echo $OUTPUT->notification("Choice Sequencing Control Model Violation");
2225 echo $OUTPUT->notification("Target Activity does not exist");
2228 echo $OUTPUT->notification("Current Activity already terminated");
2231 echo $OUTPUT->notification("Undefined Navigation Request");
2235 echo $OUTPUT->notification("Current Activity already terminated");
2238 echo $OUTPUT->notification("Current Activity already terminated");
2241 echo $OUTPUT->notification("Current Activity already terminated");
2244 echo $OUTPUT->notification("Nothing to suspend; No active activities");
2247 echo $OUTPUT->notification("Nothing to abandon; No active activities");
2251 echo $OUTPUT->notification("Last activity in the tree");
2254 echo $OUTPUT->notification("Cluster has no available children");
2257 echo $OUTPUT->notification("No activity is previous to the root");
2260 echo $OUTPUT->notification("Forward Only Sequencing Control Model Violation");
2264 echo $OUTPUT->notification("Flow Sequencing Control Model Violation");
2267 echo $OUTPUT->notification("Activity unavailable");
2271 echo $OUTPUT->notification("Forward Traversal Blocked");
2274 echo $OUTPUT->notification("Forward Only Sequencing Control Model Violation");
2277 echo $OUTPUT->notification("No activity is previous to the root");
2281 echo $OUTPUT->notification("Sequencing session has already begun");
2285 echo $OUTPUT->notification("Sequencing session has already begun");
2288 echo $OUTPUT->notification("No Suspended activity is defined");
2292 echo $OUTPUT->notification("Sequencing session has not begun");
2295 echo $OUTPUT->notification("Flow Sequencing Control Model Violation");
2299 echo $OUTPUT->notification("Sequencing session has not begun");
2302 echo $OUTPUT->notification("Flow Sequencing Control Model Violation");
2306 echo $OUTPUT->notification("No target for Choice");
2309 echo $OUTPUT->notification("Target Activity does not exist or is unavailable");
2312 echo $OUTPUT->notification("Target Activity hidden from choice");
2315 echo $OUTPUT->notification("Choice Sequencing Control Model Violation");
2318 echo $OUTPUT->notification("No activities to consider");
2321 echo $OUTPUT->notification("Unable to activate target; target is not a child of the Current Activity");
2324 echo $OUTPUT->notification("Choice Exit Sequencing Control Model Violation");
2327 echo $OUTPUT->notification("Unable to choose target activity - constrained choice");
2330 echo $OUTPUT->notification("Choice Request Prevented by Flow-only Activity");
2334 echo $OUTPUT->notification("Sequencing session has not begun");
2337 echo $OUTPUT->notification("Current Activity is active or suspended");
2340 echo $OUTPUT->notification("Flow Sequencing Control Model Violation");
2344 echo $OUTPUT->notification("Sequencing session has not begun");
2347 echo $OUTPUT->notification("Current Activity has not been terminated");
2351 echo $OUTPUT->notification("Undefined Sequencing Request");
2355 echo $OUTPUT->notification("Cannot deliver a non-leaf activity");
2358 echo $OUTPUT->notification("Nothing to deliver");
2361 echo $OUTPUT->notification("Activity unavailable");
2365 echo $OUTPUT->notification("Identified activity is already active");