Automatic installer.php lang files by installer_builder (20070726)
[moodle-linuxchix.git] / mod / scorm / datamodels / sequencinglib.php
blobea5b94da1fd5fb73f31bd69f668958e0f4d2b872
1 <?php // $Id$
2 require ('scormlib.php');
4 function scorm_seq_evaluate($scoid,$usertracks) {
5 return true;
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
17 return 'true';
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);
28 return 'true';
32 function scorm_seq_navigation ($scoid,$userid,$request,$attempt=0) {
33 /// Sequencing structure
34 $seq = new stdClass();
35 $seq->currentactivity = scorm_get_sco($scoid);
36 $seq->traversaldir = null;
37 $seq->nextactivity = null;
38 $seq->deliveryvalid = null;
39 $seq->attempt = $attempt;
41 $seq->identifiedactivity = null;
42 $seq->delivery = null;
43 $seq->deliverable = false;
44 $seq->active = scorm_seq_is('active',$scoid,$userid);
45 $seq->suspended = scorm_seq_is('suspended',$scoid,$userid);
46 $seq->navigation = null;
47 $seq->termination = null;
48 $seq->sequencing = null;
49 $seq->target = null;
50 $seq->endsession = null;
51 $seq->exception = null;
52 $seq->reachable = true;
53 $seq->prevact = true;
55 switch ($request) {
56 case 'start_':
57 if (empty($seq->currentactivity)) {
58 $seq->navigation = true;
59 $seq->sequencing = 'start';
60 } else {
61 $seq->exception = 'NB.2.1-1'; /// Sequencing session already begun
63 break;
64 case 'resumeall_':
65 if (empty($seq->currentactivity)) {
66 if ($track = get_record('scorm_scoes_track','scoid',$scoid,'userid',$userid,'element','suspendedactivity')) {//I think it's suspend instead of suspendedactivity
67 $seq->navigation = true;
68 $seq->sequencing = 'resumeall';
69 } else {
70 $seq->exception = 'NB.2.1-3'; /// No suspended activity found
72 } else {
73 $seq->exception = 'NB.2.1-1'; /// Sequencing session already begun
75 break;
76 case 'continue_':
77 case 'previous_':
78 if (!empty($seq->currentactivity)) {
79 $sco = $seq->currentactivity;
80 if ($sco->parent != '/') {
81 if ($parentsco = scorm_get_parent($sco)) {
83 if (isset($parentsco->flow) && ($parentsco->flow == true)) {//I think it's parentsco
84 // Current activity is active !
85 if (scorm_seq_is('active',$sco->id,$userid)) {
86 if ($request == 'continue_') {
87 $seq->navigation = true;
88 $seq->termination = 'exit';
89 $seq->sequencing = 'continue';
90 } else {
91 if (!isset($parentsco->forwardonly) || ($parentsco->forwardonly == false)) {
92 $seq->navigation = true;
93 $seq->termination = 'exit';
94 $seq->sequencing = 'previous';
95 } else {
96 $seq->exception = 'NB.2.1-5'; /// Violates control mode
104 } else {
105 $seq->exception = 'NB.2.1-2'; /// Current activity not defined
107 break;
108 case 'forward_':
109 case 'backward_':
110 $seq->exception = 'NB.2.1-7' ; /// None to be done, behavior not defined
111 break;
112 case 'exit_':
113 case 'abandon_':
114 if (!empty($seq->currentactivity)) {
115 // Current activity is active !
116 $seq->navigation = true;
117 $seq->termination = substr($request,0,-1);
118 $seq->sequencing = 'exit';
119 } else {
120 $seq->exception = 'NB.2.1-2'; /// Current activity not defined
122 case 'exitall_':
123 case 'abandonall_':
124 case 'suspendall_':
125 if (!empty($seq->currentactivity)) {
126 $seq->navigation = true;
127 $seq->termination = substr($request,0,-1);
128 $seq->sequencing = 'exit';
129 } else {
130 $seq->exception = 'NB.2.1-2'; /// Current activity not defined
132 break;
133 default: /// {target=<STRING>}choice
134 if ($targetsco = get_record('scorm_scoes','scorm',$sco->scorm,'identifier',$request)) {
135 if ($targetsco->parent != '/') {
136 $seq->target = $request;
137 } else {
138 if ($parentsco = scorm_get_parent($targetsco)) {
139 if (!isset($parentsco->choice) || ($parent->choice == true)) {
140 $seq->target = $request;
144 if ($seq->target != null) {
145 if (empty($seq->currentactivity)) {
146 $seq->navigation = true;
147 $seq->sequencing = 'choice';
148 } else {
149 if (!$sco = scorm_get_sco($scoid)) {
150 return $seq;
152 if ($sco->parent != $target->parent) {
153 $ancestors = scorm_get_ancestors($sco);
154 $commonpos = scorm_find_common_ancestor($ancestors,$targetsco);
155 if ($commonpos !== false) {
156 if ($activitypath = array_slice($ancestors,0,$commonpos)) {
157 foreach ($activitypath as $activity) {
158 if (scorm_seq_is('active',$activity->id,$userid) && (isset($activity->choiceexit) && ($activity->choiceexit == false))) {
159 $seq->navigation = false;
160 $seq->termination = null;
161 $seq->sequencing = null;
162 $seq->target = null;
163 $seq->exception = 'NB.2.1-8'; /// Violates control mode
164 return $seq;
167 } else {
168 $seq->navigation = false;
169 $seq->termination = null;
170 $seq->sequencing = null;
171 $seq->target = null;
172 $seq->exception = 'NB.2.1-9';
176 // Current activity is active !
177 $seq->navigation = true;
178 $seq->sequencing = 'choice';
180 } else {
181 $seq->exception = 'NB.2.1-10'; /// Violates control mode
183 } else {
184 $seq->exception = 'NB.2.1-11'; /// Target activity does not exists
186 break;
188 return $seq;
191 function scorm_seq_termination ($seq,$userid) {
192 if (empty($seq->currentactivity)) {
193 $seq->termination = false;
194 $seq->exception = 'TB.2.3-1';
195 return $seq;
198 $sco = $seq->currentactivity;
200 if ((($seq->termination == 'exit') || ($seq->termination == 'abandon')) && !$seq->active) {
201 $seq->termination = false;
202 $seq->exception = 'TB.2.3-2';
203 return $seq;
205 switch ($seq->termination) {
206 case 'exit':
207 scorm_seq_end_attempt($sco,$userid,$seq);
208 $seq = scorm_seq_exit_action_rules($seq,$userid);
209 do {
210 $exit = false;// I think this is false. Originally this was true
211 $seq = scorm_seq_post_cond_rules($seq,$userid);
212 if ($seq->termination == 'exitparent') {
213 if ($sco->parent != '/') {
214 $sco = scorm_get_parent($sco);
215 $seq->currentactivity = $sco;
216 $seq->active = scorm_seq_is('active',$sco->id,$userid);
217 scorm_seq_end_attempt($sco,$userid,$seq);
218 $exit = true;//I think it's true. Originally this was false
219 } else {
220 $seq->termination = false;
221 $seq->exception = 'TB.2.3-4';
222 return $seq;
225 } while (($exit == false) && ($seq->termination == 'exit'));
226 if ($seq->termination == 'exit') {
227 $seq->termination = true;
228 return $seq;
230 case 'exitall':
231 if ($seq->active) {
232 scorm_seq_end_attempt($sco,$userid,$seq);
234 /// Terminate Descendent Attempts Process
237 if ($ancestors = scorm_get_ancestors($sco)) {
238 foreach ($ancestors as $ancestor) {
239 scorm_seq_end_attempt($ancestor,$userid,$seq);
240 $seq->currentactivity = $ancestor;
244 $seq->active = scorm_seq_is('active',$seq->currentactivity->id,$userid);
245 $seq->termination = true;
246 $seq->sequencing = exit;
247 break;
248 case 'suspendall':
249 if (($seq->active) || ($seq->suspended)) {
250 scorm_seq_set('suspended',$sco->id,$userid);
251 } else {
252 if ($sco->parent != '/') {
253 $parentsco = scorm_get_parent($sco);
254 scorm_seq_set('suspended',$parentsco->id,$userid);
255 } else {
256 $seq->termination = false;
257 $seq->exception = 'TB.2.3-3';
258 // return $seq;
261 if ($ancestors = scorm_get_ancestors($sco)) {
262 foreach ($ancestors as $ancestor) {
263 scorm_seq_set('active',$ancestor->id,$userid,false);
264 scorm_seq_set('suspended',$ancestor->id,$userid);
265 $seq->currentactivity = $ancestor;
267 $seq->termination = true;
268 $seq->sequencing = 'exit';
269 } else {
270 $seq->termination = false;
271 $seq->exception = 'TB.2.3-5';
273 break;
274 case 'abandon':
275 scorm_seq_set('active',$sco->id,$userid,false);
276 $seq->active = null;
277 $seq->termination = true;
278 break;
279 case 'abandonall':
280 if ($ancestors = scorm_get_ancestors($sco)) {
281 foreach ($ancestors as $ancestor) {
282 scorm_seq_set('active',$ancestor->id,$userid,false);
283 $seq->currentactivity = $ancestor;
285 $seq->termination = true;
286 $seq->sequencing = 'exit';
287 } else {
288 $seq->termination = false;
289 $seq->exception = 'TB.2.3-6';
291 break;
292 default:
293 $seq->termination = false;
294 $seq->exception = 'TB.2.3-7';
295 break;
297 return $seq;
300 function scorm_seq_end_attempt($sco,$userid,$seq) {
301 if (scorm_is_leaf($sco)) {
302 if (!isset($sco->tracked) || ($sco->tracked == 1)) {
303 if (!scorm_seq_is('suspended',$sco->id,$userid)) {
304 if (!isset($sco->completionsetbycontent) || ($sco->completionsetbycontent == 0)) {
305 if (!scorm_seq_is('attemptprogressstatus',$sco->id,$userid,$seq->attempt)) {
306 // if (!scorm_seq_is('attemptprogressstatus',$sco->id,$userid)) {
307 scorm_seq_set('attemptprogressstatus',$sco->id,$userid);
308 scorm_seq_set('attemptcompletionstatus',$sco->id,$userid);
311 if (!isset($sco->objectivesetbycontent) || ($sco->objectivesetbycontent == 0)) {
312 if ($objectives = get_records('scorm_seq_objective','scoid',$sco->id)) {
313 foreach ($objectives as $objective) {
314 if ($objective->primaryobj) {
315 //if (!scorm_seq_objective_progress_status($sco,$userid,$objective)) {
316 if (!scorm_seq_is('objectiveprogressstatus',$sco->id,$userid)) {
317 scorm_seq_set('objectiveprogressstatus',$sco->id,$userid);
318 scorm_seq_set('objectivesatisfiedstatus',$sco->id,$userid);
326 } else {
327 if ($children = scorm_get_children($sco)) {
328 $suspended = false;
329 foreach ($children as $child) {
330 if (scorm_seq_is('suspended',$child,$userid)) {
331 $suspended = true;
332 break;
335 if ($suspended) {
336 scorm_seq_set('suspended',$sco,$userid);
337 } else {
338 scorm_seq_set('suspended',$sco,$userid,false);
342 scorm_seq_set('active',$sco,$userid,0,false);
343 scorm_seq_overall_rollup($sco,$userid);
346 function scorm_seq_is($what, $scoid, $userid, $attempt=0) {
348 /// Check if passed activity $what is active
349 $active = false;
350 if ($track = get_record('scorm_scoes_track','scoid',$scoid,'userid',$userid,'attempt',$attempt,'element',$what)) {
351 $active = true;
353 return $active;
356 function scorm_seq_set($what, $scoid, $userid, $attempt=0, $value='true') {
358 /// set passed activity to active or not
359 if ($value == false) {
360 delete_record('scorm_scoes_track','scoid',$scoid,'userid',$userid,'attempt',$attempt,'element',$what);
361 } else {
362 $sco = scorm_get_sco($scoid);
363 scorm_insert_track($userid, $sco->scorm, $sco->id, 0, $what, $value);
367 function scorm_seq_exit_action_rules($seq,$userid) {
368 $sco = $seq->currentactivity;
369 $ancestors = scorm_get_ancestors($sco);
370 $exittarget = null;
371 foreach (array_reverse($ancestors) as $ancestor) {
372 if (scorm_seq_rules_check($ancestor,'exit') != null) {
373 $exittarget = $ancestor;
374 break;
377 if ($exittarget != null) {
378 $commons = array_slice($ancestors,0,scorm_find_common_ancestor($ancestors,$exittarget));
380 /// Terminate Descendent Attempts Process
381 if ($commons) {
382 foreach ($commons as $ancestor) {
384 scorm_seq_end_attempt($ancestor,$userid,$seq->attempt);
385 $seq->currentactivity = $ancestor;
389 return $seq;
392 function scorm_seq_post_cond_rules($seq,$userid) {
393 $sco = $seq->currentactivity;
394 if (!$seq->suspended) {
395 if ($action = scorm_seq_rules_check($sco,'post') != null) {
396 switch($action) {
397 case 'retry':
398 case 'continue':
399 case 'previous':
400 $seq->sequencing = $action;
401 break;
402 case 'exitparent':
403 case 'exitall':
404 $seq->termination = $action;
405 break;
406 case 'retryall':
407 $seq->termination = 'exitall';
408 $seq->sequencing = 'retry';
409 break;
413 return $seq;
416 function scorm_seq_rules_check ($sco, $action){
417 $act = null;
418 if($rules = get_records('scorm_seq_ruleconds','scoid',$sco->id,'action',$action)){
419 foreach ($rules as $rule){
420 if($act = scorm_seq_rule_check($sco,$rule)){
421 return $act;
425 return $act;
429 function scorm_seq_rule_check ($sco, $rule){
430 $bag = Array();
431 $cond = '';
432 $ruleconds = get_records('scorm_seq_rulecond','scoid',$sco->id,'ruleconditionsid',$rule->id);
433 foreach ($ruleconds as $rulecond){
434 if ($rulecond->operator = 'not') {
435 if ($rulecond->cond != 'unknown' ){
436 $rulecond->cond = 'not'.$rulecond;
439 $bag [$rule->id] = $rulecond->cond;
442 if (empty($bag)){
443 $cond = 'unknown';
444 return $cond;
447 $size= sizeof($bag);
448 $i=0;
450 if ($rule->conditioncombination = 'all'){
451 foreach ($bag as $con){
452 $cond = $cond.' and '.$con;
456 else{
457 foreach ($bag as $con){
458 $cond = $cond.' or '.$con;
461 return $cond;
465 function scorm_seq_overall_rollup($sco,$userid){//Carlos
467 if ($ancestors = scorm_get_ancestors($sco)) {
468 foreach ($ancestors as $ancestor) {
469 if(!scorm_is_leaf($ancestor)){
470 scorm_seq_measure_rollup($sco,$userid);
472 scorm_seq_objective_rollup($sco,$userid);
473 scorm_seq_activity_progress_rollup($sco,$userid);
480 /* 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*/
482 function scorm_seq_measure_rollup($sco,$userid){
484 $totalmeasure = 0; //Check if there is something similar in the database
485 $valid = false;//Same as in the last line
486 $countedmeasures = 0;//Same too
487 $targetobjective = null;
488 $readable = true;//to check if status and measure weight are readable
489 $objectives = get_records('scorm_seq_objective','scoid',$sco->id);
491 foreach ($objective as $objective){
493 if ($objective->primaryobj == true){//Objective contributes to rollup I'm using primaryobj field, but not
494 $targetobjective = $objective;
495 break;
500 if ($targetobjective != null){
501 $children = scorm_get_children($sco);
502 foreach ($children as $child){
503 $child = scorm_get_sco ($child);
504 if (!isset($child->tracked) || ($child->tracked == 1)){
506 $rolledupobjective = null;// we set the rolled up activity to undefined
507 $objectives = get_records('scorm_seq_objective','scoid',$child->id);
508 foreach ($objective as $objective){
509 if ($objective->primaryobj == true){//Objective contributes to rollup I'm using primaryobj field, but not
510 $rolledupobjective = $objective;
511 break;
514 if ($rolledupobjective != null){
515 $child = scorm_get_sco($child->id);
517 $countedmeasures = $countedmeasures + ($child->measureweight);
518 if (!scorm_seq_is('objectivemeasurestatus',$sco->id,$userid)) {
519 $normalizedmeasure = get_record('scorm_scoes_track','scoid',$child->id,'userid',$userid,'element','objectivenormalizedmeasure');
520 $totalmeasure = $totalmeasure + (($normalizedmeasure->value) * ($child->measureweight));
521 $valid = true;
531 if(!$valid){
533 scorm_seq_set('objectivemeasurestatus',$sco->id,$userid,false);
536 else{
537 if($countedmeasures>0){
538 scorm_seq_set('objectivemeasurestatus',$sco->id,$userid);
539 $val=$totalmeasure/$countedmeasure;
540 scorm_seq_set('objectivenormalizedmeasure',$sco->id,$userid,$val);
543 else{
544 scorm_seq_set('objectivemeasurestatus',$sco->id,$userid,false);
553 function scorm_seq_objective_rollup($sco,$userid){
555 scorm_seq_objective_rollup_measure($sco,$userid);
556 scorm_seq_objective_rollup_rules($sco,$userid);
557 scorm_seq_objective_rollup_default($sco,$userid);
560 if($targetobjective->satisfiedbymeasure){
561 scorm_seq_objective_rollup_measure($sco,$userid);
563 else{
564 if ((scorm_seq_rollup_rule_check($sco,$userid,'incomplete'))|| (scorm_seq_rollup_rule_check($sco,$userid,'completed'))){
565 scorm_seq_objective_rollup_rules($sco,$userid);
567 else{
569 $rolluprules = get_record('scorm_seq_rolluprule','scoid',$sco->id,'userid',$userid);
570 foreach($rolluprules as $rolluprule){
571 $rollupruleconds = get_records('scorm_seq_rolluprulecond','rollupruleid',$rolluprule->id);
572 foreach($rollupruleconds as $rolluprulecond){
574 switch ($rolluprulecond->cond!='satisfied' && $rolluprulecond->cond!='completed' && $rolluprulecond->cond!='attempted'){
576 scorm_seq_set('objectivesatisfiedstatus',$sco->id,$userid, false);
578 break;
588 function scorm_seq_objective_rollup_measure($sco,$userid){
589 $targetobjective = null;
592 $objectives = get_records('scorm_seq_objective','scoid',$sco->id);
593 foreach ($objectives as $objective){
594 if ($objective->primaryobj == true){
595 $targetobjective = $objective;
596 break;
599 if ($targetobjective != null){
601 if($targetobjective->satisfiedbymeasure){
604 if (!scorm_seq_is('objectiveprogressstatus',$sco->id,$userid)) {
606 scorm_seq_set('objectiveprogressstatus',$sco->id,$userid,false);
610 else{
611 if (scorm_seq_is('active',$sco->id,$userid)) {
612 $isactive = true;
614 else{
615 $isactive = false;
618 $normalizedmeasure = get_record('scorm_scoes_track','scoid',$sco->id,'userid',$userid,'element','objectivenormalizedmeasure');
620 $sco = scorm_get_sco ($sco->id);
622 if (!$isactive || ($isactive && (!isset($sco->measuresatisfactionifactive) || $sco->measuresatisfactionifactive == true))){
623 if($normalizedmeasure->value >= $targetobjective->minnormalizedmeasure){
624 scorm_seq_set('objectiveprogressstatus',$sco->id,$userid);
625 scorm_seq_set('objectivesatisfiedstatus',$sco->id,$userid);
627 else{
628 scorm_seq_set('objectiveprogressstatus',$sco->id,$userid);
629 scorm_seq_set('objectivesatisfiedstatus',$sco->id,$userid,false);
632 else{
634 scorm_seq_set('objectiveprogressstatus',$sco->id,$userid,false);
643 function scorm_seq_objective_rollup_default($sco,$userid){
644 if (!(scorm_seq_rollup_rule_check($sco,$userid,'incomplete')) && !(scorm_seq_rollup_rule_check($sco,$userid,'completed'))){
646 $rolluprules = get_record('scorm_seq_rolluprule','scoid',$sco->id,'userid',$userid);
647 foreach($rolluprules as $rolluprule){
648 $rollupruleconds = get_records('scorm_seq_rolluprulecond','rollupruleid',$rolluprule->id);
649 foreach($rollupruleconds as $rolluprulecond){
651 if ($rolluprulecond->cond!='satisfied' && $rolluprulecond->cond!='completed' && $rolluprulecond->cond!='attempted'){
653 scorm_seq_set('objectivesatisfiedstatus',$sco->id,$userid, false);
655 break;
666 function scorm_seq_objective_rollup_rules($sco,$userid){
667 $targetobjective = null;
669 $objectives = get_records('scorm_seq_objective','scoid',$sco->id);
670 foreach ($objective as $objective){
671 if ($objective->primaryobj == true){//Objective contributes to rollup I'm using primaryobj field, but not
672 $targetobjective = $objective;
673 break;
676 if ($targetobjective != null){
680 if(scorm_seq_rollup_rule_check($sco,$userid,'notsatisfied')){//with not satisfied rollup for the activity
683 scorm_seq_set('objectiveprogressstatus',$sco->id,$userid);
684 scorm_seq_set('objectivesatisfiedstatus',$sco->id,$userid,false);
686 if(scorm_seq_rollup_rule_check($sco,$userid,'satisfied')){//with satisfied rollup for the activity
687 scorm_seq_set('objectiveprogressstatus',$sco->id,$userid);
688 scorm_seq_set('objectivesatisfiedstatus',$sco->id,$userid);
695 function scorm_seq_activity_progress_rollup ($sco, $userid){
697 if(scorm_seq_rollup_rule_check($sco,$userid,'incomplete')){
698 //incomplete rollup action
699 scorm_seq_set('attemptcompletionstatus',$sco->id,$userid,false,$seq->attempt);
700 scorm_seq_set('attemptprogressstatus',$sco->id,$userid,true,$seq->attempt);
703 if(scorm_seq_rollup_rule_check($sco,$userid,'completed')){
704 //incomplete rollup action
705 scorm_seq_set('attemptcompletionstatus',$sco->id,true,$userid);
706 scorm_seq_set('attemptprogressstatus',$sco->id,true,$userid);
711 function scorm_seq_rollup_rule_check ($sco,$userid,$action){
713 if($rolluprules = get_record('scorm_seq_rolluprule','scoid',$sco->id,'userid',$userid,'action',$action)){
715 $childrenbag = Array ();
716 $children = scorm_get_children ($sco);
718 foreach($rolluprules as $rolluprule){
720 foreach ($children as $child){
722 /*$tracked = get_records('scorm_scoes_track','scoid',$child->id,'userid',$userid);
723 if($tracked && $tracked->attemp != 0){*/
724 $child = scorm_get_sco ($child);
725 if (!isset($child->tracked) || ($child->tracked == 1)){
727 if(scorm_seq_check_child ($child,$action,$userid)){
729 $rollupruleconds = get_records('scorm_seq_rolluprulecond','rollupruleid',$rolluprule->id);
730 $evaluate = scorm_seq_evaluate_rollupcond($child,$rolluprule->conditioncombination,$rollupruleconds,$userid);
731 if ($evaluate=='unknown'){
732 array_push($childrenbag,'unknown');
734 else{
735 if($evaluate == true){
736 array_push($childrenbag,true);
738 else{
739 array_push($childrenbag,false);
746 $change = false;
748 switch ($rolluprule->childactivityset){
750 case 'all':
751 if((array_search(false,$childrenbag)===false)&&(array_search('unknown',$childrenbag)===false)){//I think I can use this condition instead equivalent to OR
752 $change = true;
754 break;
756 case 'any':
757 if(array_search(true,$childrenbag)!==false){//I think I can use this condition instead equivalent to OR
758 $change = true;
760 break;
762 case 'none':
763 if((array_search(true,$childrenbag)===false)&&(array_search('unknown',$childrenbag)===false)){//I think I can use this condition instead equivalent to OR
764 $change = true;
766 break;
768 case 'atleastcount':
769 foreach ($childrenbag as $itm){//I think I can use this condition instead equivalent to OR
770 $cont = 0;
771 if($itm === true){
772 $cont++;
774 if($cont >= $roullprule->minimumcount){
775 $change = true;
778 break;
780 case 'atleastcount':
781 foreach ($childrenbag as $itm){//I think I can use this condition instead equivalent to OR
782 $cont = 0;
783 if($itm === true){
784 $cont++;
786 if($cont >= $roullprule->minimumcount){
787 $change = true;
790 break;
792 case 'atleastpercent':
793 foreach ($childrenbag as $itm){//I think I can use this condition instead equivalent to OR
794 $cont = 0;
795 if($itm === true){
796 $cont++;
798 if(($cont/sizeof($childrenbag)) >= $roullprule->minimumcount){
799 $change = true;
802 break;
804 if ($change==true){
805 return true;
809 return false;
813 function scorm_seq_evaluate_rollupcond($sco,$conditioncombination,$rollupruleconds,$userid){
814 $bag = Array();
815 $con = "";
816 $val = false;
817 $unk = false;
818 foreach($rollupruleconds as $rolluprulecond){
820 $condit = scorm_evaluate_cond($rolluprulecond,$sco,$userid);
822 if($rule->operator=='not'){// If operator is not, negate the condition
823 if ($rule->cond != 'unknown'){
824 if ($condit){
825 $condit = false;
827 else{
828 $condit = true;
831 else{
832 $condit = 'unknown';
834 array_push($childrenbag,$condit);
838 if (empty($bag)){
839 return 'unknown';
841 else{
842 $i = 0;
843 foreach ($bag as $b){
845 if ($rolluprule->conditioncombination == 'all'){
847 $val = true;
848 if($b == 'unknown'){
849 $unk = true;
851 if($b === false){
852 return false;
856 else{
858 $val = false;
860 if($b == 'unknown'){
861 $unk = true;
863 if($b === true){
864 return true;
871 if ($unk){
872 return 'unknown';
874 return $val;
878 function scorm_evaluate_condition ($rolluprulecond,$sco,$userid){
880 $res = false;
882 switch ($rolluprulecond->cond){
884 case 'satisfied':
885 if($r=get_record('scorm_scoes_track','scoid',$sco->id,'userid',$userid,'element','objectivesatisfiedstatus')){
886 if($r->value == true){
887 if ($r=get_record('scorm_scoes_track','scoid',$sco->id,'userid',$userid,'element','objectiveprogressstatus')){
888 if($r->value == true){
889 $res= true;
894 break;
896 case 'objectiveStatusKnown':
897 if ($r=get_record('scorm_scoes_track','scoid',$sco->id,'userid',$userid,'element','objectiveprogressstatus')){
898 if($r->value == true){
899 $res= true;
902 break;
904 case 'objectiveMeasureKnown':
905 if ($r = get_record('scorm_scoes_track','scoid',$sco->id,'userid',$userid,'element','objectivemeasurestatus')){
906 if($r->value == true){
907 $res = true;
912 break;
914 case 'completed':
915 if ($r = get_record('scorm_scoes_track','scoid',$sco->id,'userid',$userid,'element','attemptcompletionstatus')){
916 if($r->value){
917 if ($r = get_record('scorm_scoes_track','scoid',$sco->id,'userid',$userid,'element','attemptprogressstatus')){
918 if($r->value){
919 $res = true;
926 break;
928 case 'attempted':
929 if ($r = get_record('scorm_scoes_track','scoid',$sco->id,'userid',$userid,'element','activityprogressstatus')){
930 if($r->value){
931 if ($r = get_record('scorm_scoes_track','scoid',$sco->id,'userid',$userid,'element','activityattemptcount')){
932 if($r->value > 0){
933 $res = true;
940 break;
943 case 'attemptLimitExceeded':
944 if ($r = get_record('scorm_scoes_track','scoid',$sco->id,'userid',$userid,'element','activityprogressstatus')){
945 if($r->value){
946 if ($r = get_record('scorm_scoes_track','scoid',$sco->id,'userid',$userid,'element','limitconditionattemptlimitcontrol')){
947 if($r->value){
948 if ($r = get_record('scorm_scoes_track','scoid',$sco->id,'userid',$userid,'element','activityattemptcount') && $r2 = get_record('scorm_scoes_track','scoid',$sco->id,'userid',$userid,'element','limitconditionattemptlimit') ){
949 if($r->value >= $r2->value){
950 $res = true;
963 break;
965 case 'activityProgressKnown':
967 if ($r = get_record('scorm_scoes_track','scoid',$sco->id,'userid',$userid,'element','activityprogressstatus')){
968 if($r->value){
969 if ($r = get_record('scorm_scoes_track','scoid',$sco->id,'userid',$userid,'element','attemptprogressstatus')){
970 if($r->value){
971 $res = true;
980 break;
982 return $res;
986 function scorm_seq_check_child ($sco, $action, $userid){
987 $included = false;
988 $sco=scorm_get_sco($sco->id);
989 $r = get_record('scorm_scoes_track','scoid',$sco->id,'userid',$userid,'element','activityattemptcount');
990 if ($action == 'satisfied' || $action == 'notsatisfied'){
991 if (!$sco->rollupobjectivesatisfied){
992 $included = true;
993 if (($action == 'satisfied' && $sco->requiredforsatisfied == 'ifnotsuspended') || ($action == 'notsatisfied' && $sco->requiredfornotsatisfied == 'ifnotsuspended')){
995 if (!scorm_seq_is('activityprogressstatus',$sco->id,$userid) || ((($r->value)>0)&& !scorm_seq_is('suspended',$sco->id,$userid))){
996 $included = false;
1000 else{
1001 if (($action == 'satisfied' && $sco->requiredforsatisfied == 'ifattempted') || ($action == 'notsatisfied' && $sco->requiredfornotsatisfied == 'ifattempted')){
1002 if (!scorm_seq_is('activityprogressstatus',$sco->id,$userid) || (($r->value) == 0)){
1003 $included = false;
1006 else{
1007 if (($action == 'satisfied' && $sco->requiredforsatisfied == 'ifnotskipped') || ($action == 'notsatisfied' && $sco->requiredfornotsatisfied == 'ifnotskipped')){
1008 $rulch = scorm_seq_rules_check($sco, 'skip');
1009 if ($rulch != null){
1010 $included = false;
1017 if ($action == 'completed' || $action == 'incomplete'){
1018 if (!$sco->rollupprogresscompletion){
1019 $included = true;
1021 if (($action == 'completed' && $sco->requiredforcompleted == 'ifnotsuspended') || ($action == 'incomplete' && $sco->requiredforincomplete == 'ifnotsuspended')){
1023 if (!scorm_seq_is('activityprogressstatus',$sco->id,$userid) || ( (($r->value)>0)&& !scorm_seq_is('suspended',$sco->id,$userid))){
1024 $included = false;
1028 else{
1030 if (($action == 'completed' && $sco->requiredforcompleted == 'ifattempted') || ($action == 'incomplete' && $sco->requiredforincomplete == 'ifattempted')){
1031 if (!scorm_seq_is('activityprogressstatus',$sco->id,$userid) || (($r->value)==0)){
1032 $included = false;
1036 else{
1037 if (($action == 'completed' && $sco->requiredforsatisfied == 'ifnotskipped') || ($action == 'incomplete' && $sco->requiredfornotsatisfied == 'ifnotskipped')){
1038 $rulch = scorm_seq_rules_check($sco, 'skip');
1039 if ($rulch != null){
1040 $included = false;
1050 return $included;
1054 function scorm_seq_sequencing ($scoid,$userid,$seq) {
1056 switch ($seq->sequencing) {
1058 case 'start':
1059 $seq = scorm_seq_start_sequencing($sco,$userid,$seq); //We'll see the parameters we have to send, this should update delivery and end
1060 $seq->sequencing = true;
1063 break;
1065 case 'resumeall':
1066 $seq = scorm_seq_resume_sequencing($sco,$userid,$seq); //We'll see the parameters we have to send, this should update delivery and end
1067 $seq->sequencing = true;
1071 break;
1073 case 'exit':
1074 $seq = scorm_seq_exit_sequencing($sco,$userid,$seq); //We'll see the parameters we have to send, this should update delivery and end
1075 $seq->sequencing = true;
1079 break;
1081 case 'retry':
1082 $seq = scorm_seq_retry_sequencing($sco,$userid,$seq); //We'll see the parameters we have to send, this should update delivery and end
1083 $seq->sequencing = true;
1086 break;
1088 case 'previous':
1089 $seq = scorm_seq_previous_sequencing($sco,$userid,$seq);// We'll see the parameters we have to send, this should update delivery and end
1090 $seq->sequencing = true;
1093 break;
1095 case 'choice':
1096 $seq = scorm_seq_choice_sequencing($sco,$userid,$seq);// We'll see the parameters we have to send, this should update delivery and end
1097 $seq->sequencing = true;
1100 break;
1104 if ($seq->exception != null){
1105 $seq->sequencing = false;
1106 return $seq;
1109 $seq->sequencing= true;
1110 return $seq;
1114 function scorm_seq_start_sequencing($scoid,$userid,$seq){
1115 if (!empty($seq->currentactivity)) {
1116 $seq->delivery = null;
1117 $seq->exception = 'SB.2.5-1';
1118 return $seq;
1120 $sco = get_record('scorm_scoes','scoid',$scoid,'userid',$userid);
1121 if (($sco->parent == '/') && scorm_is_leaf($sco)) {//if the activity is the root and is leaf
1122 $seq->delivery = $sco;
1124 else{
1125 $ancestors = scorm_get_ancestors($sco);
1126 $ancestorsroot = array_reverse($ancestors);
1127 $res = scorm_seq_flow($ancestorsroot[0],'forward',$seq,true,$userid);
1128 if($res){
1129 return $res;
1131 else{
1132 //return end and exception
1137 function scorm_seq_resume_all_sequencing($scoid,$userid,$seq){
1138 if (!empty($seq->currentactivity)){
1139 $seq->delivery = null;
1140 $seq->exception = 'SB.2.6-1';
1141 return $seq;
1143 $track = get_record('scorm_scoes_track','scoid',$scoid,'userid',$userid,'element','suspendedactivity');
1144 if (!$track) {
1145 $seq->delivery = null;
1146 $seq->exception = 'SB.2.6-2';
1147 return $seq;
1149 $seq->delivery = get_record('scorm_scoes','scoid',$scoid,'userid',$userid);//we assign the sco to the delivery
1153 function scorm_seq_continue_sequencing($scoid,$userid,$seq){
1154 if (empty($seq->currentactivity)) {
1155 $seq->delivery = null;
1156 $seq->exception = 'SB.2.7-1';
1157 return $seq;
1159 $currentact= $seq->currentactivity;
1160 if ($currentact->parent != '/') {//if the activity is the root and is leaf
1161 $parent = scorm_get_parent ($currentact);
1163 if (!isset($parent->flow) || ($parent->flow == false)) {
1164 $seq->delivery = null;
1165 $seq->exception = 'SB.2.7-2';
1166 return $seq;
1169 $res = scorm_seq_flow($currentact,'forward',$seq,false,$userid);
1170 if($res){
1171 return $res;
1173 else{
1174 //return end and exception
1180 function scorm_seq_previous_sequencing($scoid,$userid,$seq){
1181 if (empty($seq->currentactivity)) {
1182 $seq->delivery = null;
1183 $seq->exception = 'SB.2.8-1';
1184 return $seq;
1187 $currentact= $seq->currentactivity;
1188 if ($currentact->parent != '/') {//if the activity is the root and is leaf
1189 $parent = scorm_get_parent ($activity);
1190 if (!isset($parent->flow) || ($parent->flow == false)) {
1191 $seq->delivery = null;
1192 $seq->exception = 'SB.2.8-2';
1193 return $seq;
1196 $res = scorm_seq_flow($currentact,'backward',$seq,false,$userid);
1197 if($res){
1198 return $res;
1200 else{
1201 //return end and exception
1208 function scorm_seq_exit_sequencing($scoid,$userid,$seq){
1209 if (empty($seq->currentactivity)) {
1210 $seq->delivery = null;
1211 $seq->exception = 'SB.2.11-1';
1212 return $seq;
1215 if ($seq->active){
1216 $seq->endsession = false;
1217 $seq->exception = 'SB.2.11-2';
1218 return $seq;
1220 $currentact= $seq->currentactivity;
1221 if ($currentact->parent == '/'){
1222 $seq->endsession = true;
1223 return $seq;
1226 $seq->endsession = false;
1227 return $seq;
1231 function scorm_seq_retry_sequencing($scoid,$userid,$seq){
1232 if (empty($seq->currentactivity)) {
1233 $seq->delivery = null;
1234 $seq->exception = 'SB.2.10-1';
1235 return $seq;
1237 if ($seq->active || $seq->suspended){
1238 $seq->delivery = null;
1239 $seq->exception = 'SB.2.10-2';
1240 return $seq;
1243 if (!scorm_is_leaf($seq->currentactivity)){
1244 $res = scorm_seq_flow($seq->currentactivity,'forward',$seq,true,$userid);
1245 if($res != null){
1246 return $res;
1247 //return deliver
1249 else{
1250 $seq->delivery = null;
1251 $seq->exception = 'SB.2.10-3';
1252 return $seq;
1255 else{
1256 $seq->delivery = $seq->currentactivity;
1257 return $seq;
1262 function scorm_seq_flow ($candidate,$direction,$seq,$childrenflag,$userid){
1263 //$PREVDIRECTION NOT DEFINED YET
1265 $activity=$candidate;
1266 $deliverable=false;
1267 $previdirection = null;
1268 $seq = scorm_seq_flow_tree_traversal ($activity,$direction,$childrenflag,$prevdirection,$seq,$userid);
1269 if($seq->identifiedactivity == null){//if identifies
1270 $seq->identifiedactivity = $candidate;
1271 $seq->deliverable = false;
1272 return $seq;
1274 else{
1275 $activity = $seq->identifiedactivity;
1276 $seq = scorm_seq_flow_activity_traversal($activity,$userid,$direction,$childrenflag,$prevdirection,$seq,$userid);//
1277 return $seq;
1282 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
1283 $activity = scorm_get_sco ($activity);
1284 $parent = scorm_get_parent ($activity);
1285 if (!isset($parent->flow) || ($parent->flow == false)) {
1286 $seq->deliverable = false;
1287 $seq->exception = 'SB.2.2-1';
1288 $seq->nextactivity = $activity;
1289 return $seq;
1292 $rulch = scorm_seq_rules_check($sco, 'skipped');
1293 if ($rulch != null){
1294 $seq = scorm_seq_flow_tree_traversal ($activity, $direction, false, $prevdirection, $seq,$userid);//endsession and exception
1295 if ($seq->identifiedactivity == null){
1296 $seq->deliverable = false;
1297 $seq->nextactivity = $activity;
1298 return $seq;
1300 else{
1302 if ($prevdirection = 'backward' && $seq->traversaldir == 'backward'){
1303 $seq = scorm_seq_flow_tree_traversal ($activity,$direction,false,null,$seq,$userid);
1304 $seq = scorm_seq_flow_activity($seq->identifiedactivity, $userid, $direction, $childrenflag, $prevdirection, $seq,$userid);
1306 else{
1307 $seq = scorm_seq_flow_tree_traversal ($activity,$direction,false,null,$seq,$userid);
1308 $seq = scorm_seq_flow_activity($seq->identifiedactivity, $userid, $direction, $childrenflag, $prevdirection, $seq,$userid);
1310 return $seq;
1314 $ch=scorm_check_activity ($activity,$userid);
1316 if ($ch){
1318 $seq->deliverable = false;
1319 $seq->exception = 'SB.2.2-2';
1320 $seq->nextactivity = $activity;
1321 return $seq;
1325 if (!scorm_is_leaf($activity)){
1327 $seq = scorm_seq_flow_tree_traversal ($activity,$direction,true,null,$seq,$userid);
1329 if ($seq->identifiedactivity == null){
1330 $seq->deliverable = false;
1331 $seq->nextactivity = $activity;
1332 return $seq;
1335 else{
1336 if($direction == 'backward' && $seq->traversaldir == 'forward'){
1337 $seq = scorm_seq_flow_activity($seq->identifiedactivity, $userid, 'forward', $childrenflag, 'backward', $seq,$userid);
1339 else{
1340 scorm_seq_flow_activity($seq->identifiedactivity, $userid, $direction, $childrenflag, null, $seq,$userid);
1342 return $seq;
1347 $seq->deliverable = true;
1348 $seq->nextactivity = $activity;
1349 return $seq;
1352 function scorm_seq_flow_tree_traversal ($activity,$direction,$childrenflag,$prevdirection,$seq,$userid){
1354 $revdirection = false;
1355 $parent = scorm_get_parent ($activity);
1356 $children = scorm_get_available_children ($parent);
1357 $siz = sizeof ($children);
1359 if (($prevdirection != null && $prevdirection == 'backward') && ($children[$siz-1]->id == $activity->id)){
1360 $direction = 'backward';
1361 $children[0] = $activity;
1362 $revdirection = true;
1365 if($direction = 'forward'){
1366 $ancestors = scorm_get_ancestors($activity);
1367 $ancestorsroot = array_reverse($ancestors);
1368 $preorder = scorm_get_preorder ($ancestorsroot);
1369 $siz= sizeof ($preorder);
1370 if (($activity->id == $preorder[$siz-1]->id) || (($activity->parent == '/') && !($childrenflag))){
1371 scorm_seq_terminate_descent($ancestorsroot,$userid);
1372 $seq->endsession = true;
1373 $seq->nextactivity = null;
1374 return $seq;
1376 if (scorm_is_leaf ($activity) || !$childrenflag){
1377 if ($children[$siz-1]->id == $activity->id){
1379 $seq = scorm_seq_flow_tree_traversal ($parent, $direction, false, null, $seq,$userid);
1380 // I think it's not necessary to do a return in here
1382 else{
1383 $parent = scorm_get_parent($activity);
1384 $children = scorm_get_available_children($parent);
1385 $seq->traversaldir = $direction;
1386 $sib = scorm_get_siblings($activity);
1387 $pos = array_search($sib, $activity);
1388 if ($pos !== false) {
1389 if ($pos != sizeof ($sib)){
1390 $seq->nextactivity = $sib [$pos+1];
1391 return $seq;
1393 else{
1394 $ch = scorm_get_children($sib[0]);
1395 $seq->nextactivity = $ch[0];
1396 return $seq;
1401 else{
1402 if (!empty ($children)){
1403 $seq->traversaldir = $direction;
1404 $seq->nextactivity = $children[0];
1405 return $seq;
1407 else{
1408 $seq->traversaldir = null;
1409 $seq->nextactivity = $children[0];
1410 $seq->exception = 'SB.2.1-2';
1411 return $seq;
1416 if($direction = 'backward'){
1418 if ($activity->parent == '/'){
1419 $seq->traversaldir = null;
1420 $seq->nextactivity = null;
1421 $seq->exception = 'SB.2.1-3';
1422 return $seq;
1424 if (scorm_is_leaf ($activity) || !$childrenflag){
1425 if (!$revdirection){
1426 if (isset($parent->forwardonly) && ($parent->forwardonly == true)) {
1427 $seq->traversaldir = null;
1428 $seq->nextactivity = null;
1429 $seq->exception = 'SB.2.1-4';
1430 return $seq;
1433 if ($children[0]->id == $activity->id){
1434 $seq = scorm_seq_flow_tree_traversal ($parent, 'backward', false, null, $seq);
1435 return $seq;
1437 else{
1438 $ancestors = scorm_get_ancestors($activity);
1439 $ancestorsroot = array_reverse ($ancestors);
1440 $preorder = scorm_get_preorder ($ancestorsroot);
1441 $pos = array_search($preorder, $children[$siz]);
1442 $preord = array_slice($preorder, 0, $pos-1);
1443 $revpreorder = array_reverse($preord);
1444 $position = array_search($revpreorder, $activity);
1445 $seq->nextactivity = $revpreorder[$pos+1];
1446 $seq->traversaldir = $direction;
1447 return $seq;
1450 else{
1451 if (!empty($children)){
1452 $activity = scorm_get_sco($activity->id);
1453 if (isset($parent->flow) && ($parent->flow == true)) {
1454 $children = scorm_get_children ($activity);
1455 $seq->traversaldir = 'forward';
1456 $seq->nextactivity = $children[0];
1457 return $seq;
1460 else{
1461 $children = scorm_get_children ($activity);
1462 $seq->traversaldir = 'backward';
1463 $seq->nextactivity = $children[sizeof($children)-1];
1464 return $seq;
1468 else{
1470 $seq->traversaldir = null;
1471 $seq->nextactivity = null;
1472 $seq->exception = 'SB.2.1-2';
1473 return $seq;
1481 function scorm_check_activity ($activity,$userid){
1482 $act = scorm_seq_rules_check($activity,'disabled');
1483 if ($act != null){
1484 return true;
1486 if(scorm_limit_cond_check ($activity,$userid)){
1487 return true;
1489 return false;
1494 function scorm_limit_cond_check ($activity,$userid){
1496 if (isset($activity->tracked) && ($activity->tracked == 0)){
1498 return false;
1501 if (scorm_seq_is('active',$activity->id,$userid) || scorm_seq_is('suspended',$activity->id,$userid)){
1502 return false;
1505 if (!isset($activity->limitcontrol) || ($activity->limitcontrol == 1)){
1506 $r = get_record('scorm_scoes_track','scoid',$activity->id,'userid',$userid,'element','activityattemptcount');
1507 if (scorm_seq_is('activityprogressstatus',$activity->id,$userid) && ($r->value >=$activity->limitattempt)){
1508 return true;
1512 if (!isset($activity->limitabsdurcontrol) || ($activity->limitabsdurcontrol == 1)){
1513 $r = get_record('scorm_scoes_track','scoid',$activity->id,'userid',$userid,'element','activityabsoluteduration');
1514 if (scorm_seq_is('activityprogressstatus',$activity->id,$userid) && ($r->value >=$activity->limitabsduration)){
1515 return true;
1519 if (!isset($activity->limitexpdurcontrol) || ($activity->limitexpdurcontrol == 1)){
1520 $r = get_record('scorm_scoes_track','scoid',$activity->id,'userid',$userid,'element','activityexperiencedduration');
1521 if (scorm_seq_is('activityprogressstatus',$activity->id,$userid) && ($r->value >=$activity->limitexpduration)){
1522 return true;
1526 if (!isset($activity->limitattabsdurcontrol) || ($activity->limitattabsdurcontrol == 1)){
1527 $r = get_record('scorm_scoes_track','scoid',$activity->id,'userid',$userid,'element','attemptabsoluteduration');
1528 if (scorm_seq_is('activityprogressstatus',$activity->id,$userid) && ($r->value >=$activity->limitattabsduration)){
1529 return true;
1533 if (!isset($activity->limitattexpdurcontrol) || ($activity->limitattexpdurcontrol == 1)){
1534 $r = get_record('scorm_scoes_track','scoid',$activity->id,'userid',$userid,'element','attemptexperiencedduration');
1535 if (scorm_seq_is('activityprogressstatus',$activity->id,$userid) && ($r->value >=$activity->limitattexpduration)){
1536 return true;
1540 if (!isset($activity->limitbegincontrol) || ($activity->limitbegincontrol == 1)){
1541 $r = get_record('scorm_scoes_track','scoid',$activity->id,'userid',$userid,'element','begintime');
1542 if (time()>=$activity->limitbegintime){
1543 return true;
1547 if (!isset($activity->limitbegincontrol) || ($activity->limitbegincontrol == 1)){
1548 if (time()<$activity->limitbegintime){
1549 return true;
1553 if (!isset($activity->limitendcontrol) || ($activity->limitendcontrol == 1)){
1555 if (time()>$activity->limitendtime){
1556 return true;
1559 return false;
1565 function scorm_seq_choice_sequencing($sco,$userid,$seq){
1567 $avchildren = Array ();
1568 $comancestor = null;
1569 $traverse = null;
1571 if ($sco == null){
1572 $seq->delivery = null;
1573 $seq->exception = 'SB.2.9-1';
1574 return $seq;
1577 $ancestors = scorm_get_ancestors($sco);
1578 $arrpath = array_reverse($ancestors);
1579 array_push ($arrpath,$sco);//path from the root to the target
1581 foreach ($arrpath as $activity){
1583 if ($activity->parent != '/') {
1584 $avchildren = scorm_get_available_children (scorm_get_parent($activity));
1585 $position = array_search($avchildren, $activity);
1586 if ($position !== false){
1587 $seq->delivery = null;
1588 $seq->exception = 'SB.2.9-2';
1589 return $seq;
1593 if (scorm_seq_rules_check($activity,'hidefromchoice' != null)){
1595 $seq->delivery = null;
1596 $seq->exception = 'SB.2.9-3';
1597 return $seq;
1603 if ($sco->parent != '/') {
1604 $parent = scorm_sco_get_parent ($sco);
1605 if ( isset($parent->choice) && ($parent->choice == false)){
1606 $seq->delivery = null;
1607 $seq->exception = 'SB.2.9-4';
1608 return $seq;
1612 if ($seq->currentactivity != null){
1613 $commonpos = scorm_find_common_ancestor($ancestors,$seq->currentactivity);
1614 $comancestor = $arrpath [$commonpos];
1616 else{
1617 $comancestor = $arrpath [0];
1620 if($seq->currentactivity === $sco) {
1621 break;
1624 $sib = scorm_get_siblings($seq->currentactivity);
1625 $pos = array_search($sib, $sco);
1627 if (pos !== false){
1629 $siblings = array_slice($sib, 0, $pos-1);
1631 if (empty($siblings)){
1633 $seq->delivery = null;
1634 $seq->exception = 'SB.2.9-5';
1635 return $seq;
1639 $children = scorm_get_children (scorm_get_parent ($sco));
1640 $pos1 = array_search($children, $sco);
1641 $pos2 = array_search($seq->currentactivity, $sco);
1642 if ($pos1>$pos2){
1643 $traverse = 'forward';
1645 else{
1646 $traverse = 'backward';
1649 foreach ($siblings as $sibling){
1650 $seq = scorm_seq_choice_activity_traversal($sibling,$userid,$seq,$traverse);
1651 if(!$seq->reachable){
1652 $seq->delivery = null;
1653 return $seq;
1656 break;
1660 if($seq->currentactivity == null || $seq->currentactivity == $comancestor){
1661 $commonpos = scorm_find_common_ancestor($ancestors,$seq->currentactivity);
1662 $comtarget = array_slice($ancestors, 1,$commonpos-1);//path from the common ancestor to the target activity
1663 $comtarget = array_reverse($comtarget);
1665 if (empty($comtarget)){
1666 $seq->delivery = null;
1667 $seq->exception = 'SB.2.9-5';
1668 return $seq;
1670 foreach ($comtarget as $act){
1671 $seq = scorm_seq_choice_activity_traversal($act,$userid,$seq,'forward');
1672 if(!$seq->reachable){
1673 $seq->delivery = null;
1674 return $seq;
1676 $act = scorm_get_sco ($acti->id);
1677 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?
1678 $seq->delivery = null;
1679 $seq->exception = 'SB.2.9-6';
1680 return $seq;
1683 break;
1687 if ($comancestor->id == $sco->id){
1689 $ancestorscurrent = scorm_get_ancestors($seq->currentactivity);
1690 $possco = array_search ($ancestorscurrent, $sco);
1691 $curtarget = array_slice($ancestorscurrent,0,$possco);//path from the current activity to the target
1693 if (empty($curtarget)){
1694 $seq->delivery = null;
1695 $seq->exception = 'SB.2.9-5';
1696 return $seq;
1698 $i=0;
1699 foreach ($curtarget as $activ){
1700 $i++;
1701 if ($i != sizeof($curtarget)){
1702 if ( isset($activ->choiceexit) && ($activ->choiceexit == false)){
1703 $seq->delivery = null;
1704 $seq->exception = 'SB.2.9-7';
1705 return $seq;
1709 break;
1712 if (array_search ($ancestors, $comancestor)!== false){
1713 $ancestorscurrent = scorm_get_ancestors($seq->currentactivity);
1714 $commonpos = scorm_find_common_ancestor($ancestors,$sco);
1715 $curcommon = array_slice($ancestorscurrent,0,$commonpos-1);
1716 if(empty($curcommon)){
1717 $seq->delivery = null;
1718 $seq->exception = 'SB.2.9-5';
1719 return $seq;
1722 $constrained = null;
1723 foreach ($curcommon as $acti){
1724 $acti = scorm_get_sco($acti->id);
1725 if ( isset($acti->choiceexit) && ($acti->choiceexit == false)){
1726 $seq->delivery = null;
1727 $seq->exception = 'SB.2.9-7';
1728 return $seq;
1730 if ($constrained == null){
1731 if($acti->constrainchoice == true){
1732 $constrained = $acti;
1736 if ($constrained != null){
1737 $fwdir = scorm_get_preorder($constrained);
1739 if(array_search ($fwdir, $sco)!== false){
1740 $traverse = 'forward';
1742 else{
1743 $traverse = 'backward';
1745 $seq = scorm_seq_choice_flow ($constrained, $traverse, $seq);
1746 $actconsider = $seq->identifiedactivity;
1747 $avdescendents = Array();
1748 $avdescendents= scorm_get_available_descendents ($actconsider);
1749 if (array_search ($avdescendents, $sco) !== false && $sco->id != $actconsider->id && $constrained->id != $sco->id ){
1750 $seq->delivery = null;
1751 $seq->exception = 'SB.2.9-8';
1752 return $seq;
1755 //CONTINUE 11.5.5
1758 $commonpos = scorm_find_common_ancestor($ancestors,$seq->currentactivity);
1759 $comtarget = array_slice($ancestors, 1,$commonpos-1);//path from the common ancestor to the target activity
1760 $comtarget = array_reverse($comtarget);
1762 if (empty($comtarget)){
1763 $seq->delivery = null;
1764 $seq->exception = 'SB.2.9-5';
1765 return $seq;
1768 $fwdir = scorm_get_preorder($seq->currentactivity);
1770 if(array_search ($fwdir, $sco)!== false){
1772 foreach ($comtarget as $act){
1773 $seq = scorm_seq_choice_activity_traversal($act,$userid,$seq,'forward');
1774 if(!$seq->reachable){
1775 $seq->delivery = null;
1776 return $seq;
1778 $act = scorm_get_sco($act->id);
1779 if(scorm_seq_is('active',$act->id,$userid) && ($act->id != $comancestor->id && ($act->preventactivation == true))){
1780 $seq->delivery = null;
1781 $seq->exception = 'SB.2.9-6';
1782 return $seq;
1787 else{
1788 foreach ($comtarget as $act){
1789 $act = scorm_get_sco($act->id);
1790 if(scorm_seq_is('active',$act->id,$userid) && ($act->id != $comancestor->id && ($act->preventactivation==true))){
1791 $seq->delivery = null;
1792 $seq->exception = 'SB.2.9-6';
1793 return $seq;
1797 break;
1800 if(scorm_is_leaf ($sco)){
1801 $seq->delivery = $sco;
1802 $seq->exception = 'SB.2.9-6';
1803 return $seq;
1806 $seq = scorm_seq_flow ($sco,'forward',$seq,true,$userid);
1807 if ($seq->deliverable == false){
1808 scorm_terminate_descendent_attempts($comancestor,$userid,$seq);
1809 scorm_seq_end_attempt($comancestor,$userid,$seq->attempt);
1810 $seq->currentactivity = $sco;
1811 $seq->delivery = null;
1812 $seq->exception = 'SB.2.9-9';
1813 return $seq;
1816 else{
1817 return $seq;
1822 function scorm_seq_choice_flow ($constrained, $traverse, $seq){
1823 $seq = scorm_seq_choice_flow_tree ($constrained, $traverse, $seq);
1824 if ($seq->identifiedactivity == null){
1825 $seq->identifiedactivity = $constrained;
1826 return $seq;
1828 else{
1829 return $seq;
1833 function scorm_seq_choice_flow_tree ($constrained, $traverse, $seq){
1834 $islast = false;
1835 $parent = scorm_get_parent ($constrained);
1836 if ($traverse== 'forward'){
1837 $preord = scorm_get_preorder ($constrained);
1838 if (sizeof($preorder) == 0 || (sizeof($preorder) == 0 && $preorder[0]->id = $constrained->id)){
1839 $islast = true;//the function is the last activity available
1841 if ($constrained->parent == '/' || $islast){
1842 $seq->nextactivity = null;
1843 return $seq;
1845 $avchildren = scorm_get_available_children ($parent);//available children
1846 if ($avchildren [sizeof($avchildren)-1]->id == $constrained->id){
1847 $seq = scorm_seq_choice_flow_tree ($parent, 'forward', $seq);
1848 return $seq;
1850 else{
1851 $i=0;
1852 while(i < sizeof($avchildren)){
1853 if ($avchildren [i]->id == $constrained->id){
1854 $seq->nextactivity = $avchildren [i+1];
1855 return $seq;
1857 else{
1858 $i++;
1865 if ($traverse== 'backward'){
1866 if($constrained->parent == '/' ){
1867 $seq->nextactivity = null;
1868 return $seq;
1871 $avchildren = scorm_get_available_children ($parent);//available children
1872 if ($avchildren [0]->id == $constrained->id){
1873 $seq = scorm_seq_choice_flow_tree ($parent, 'backward', $seq);
1874 return $seq;
1876 else{
1877 $i=sizeof($avchildren)-1;
1878 while($i >=0){
1879 if ($avchildren [i]->id == $constrained->id){
1880 $seq->nextactivity = $avchildren [i-1];
1881 return $seq;
1883 else{
1884 $i--;
1890 function scorm_seq_choice_activity_traversal($activity,$userid,$seq,$direction){
1892 if($direction == 'forward'){
1894 $act = scorm_seq_rules_check($activity,'stopforwardtraversal');
1896 if($act != null){
1897 $seq->reachable = false;
1898 $seq->exception = 'SB.2.4-1';
1899 return $seq;
1901 $seq->reachable = false;
1902 return $seq;
1905 if($direction == 'backward'){
1906 $parentsco = scorm_get_parent($activity);
1907 if($parentsco!= null){
1908 if (isset($parentsco->forwardonly) && ($parentsco->forwardonly == true)){
1909 $seq->reachable = false;
1910 $seq->exception = 'SB.2.4-2';
1911 return $seq;
1913 else{
1914 $seq->reachable = false;
1915 $seq->exception = 'SB.2.4-3';
1916 return $seq;
1920 $seq->reachable = true;
1921 return $seq;
1925 //Delivery Request Process
1927 function scorm_sequencing_delivery($scoid,$userid,$seq){
1929 if(!scorm_is_leaf ($seq->delivery)){
1930 $seq->deliveryvalid = false;
1931 $seq->exception = 'DB.1.1-1';
1932 return $seq;
1934 $ancestors = scorm_get_ancestors($seq->delivery);
1935 $arrpath = array_reverse($ancestors);
1936 array_push ($arrpath,$seq->delivery);//path from the root to the target
1938 if (empty($arrpath)){
1939 $seq->deliveryvalid = false;
1940 $seq->exception = 'DB.1.1-2';
1941 return $seq;
1944 foreach ($arrpath as $activity){
1945 if(scorm_check_activity ($activity,$userid)){
1946 $seq->deliveryvalid = false;
1947 $seq->exception = 'DB.1.1-3';
1948 return $seq;
1952 $seq->deliveryvalid = true;
1953 return $seq;
1957 function scorm_content_delivery_environment ($seq,$userid){
1959 $act = $seq->currentactivity;
1960 if(scorm_seq_is('active',$act->id,$userid)){
1961 $seq->exception = 'DB.2-1';
1962 return $seq;
1964 $track = get_record('scorm_scoes_track','scoid',$act->id,'userid',$userid,'element','suspendedactivity');
1965 if ($track != null){
1966 $seq = scorm_clear_suspended_activity($seq->delivery, $seq);
1969 $seq = scorm_terminate_descendent_attempts ($seq->delivery,$userid,$seq);
1970 $ancestors = scorm_get_ancestors($seq->delivery);
1971 $arrpath = array_reverse($ancestors);
1972 array_push ($arrpath,$seq->delivery);
1973 foreach ($arrpath as $activity){
1974 if(!scorm_seq_is('active',$activity->id,$userid)){
1975 if(!isset($activity->tracked) || ($activity->tracked == 1)){
1976 if(!scorm_seq_is('suspended',$activity->id,$userid)){
1977 $r = get_record('scorm_scoes_track','scoid',$activity->id,'userid',$userid,'element','activityattemptcount');
1978 $r->value = ($r->value)+1;
1979 update_record ('scorm_scoes_track',$r);
1980 if ($r->value == 1){
1981 scorm_seq_set('activityprogressstatus', $activity->id, $userid, 'true');
1983 scorm_insert_track($userid, $activity->scorm, $activity->id, 0, 'objectiveprogressstatus', 'false');
1984 scorm_insert_track($userid, $activity->scorm, $activity->id, 0, 'objectivesatisfiedstatus', 'false');
1985 scorm_insert_track($userid, $activity->scorm, $activity->id, 0, 'objectivemeasurestatus', 'false');
1986 scorm_insert_track($userid, $activity->scorm, $activity->id, 0, 'objectivenormalizedmeasure', 0.0);
1988 scorm_insert_track($userid, $activity->scorm, $activity->id, 0, 'attemptprogressstatus', 'false');
1989 scorm_insert_track($userid, $activity->scorm, $activity->id, 0, 'attemptcompletionstatus', 'false');
1990 scorm_insert_track($userid, $activity->scorm, $activity->id, 0, 'attemptabsoluteduration', 0.0);
1991 scorm_insert_track($userid, $activity->scorm, $activity->id, 0, 'attemptexperiencedduration', 0.0);
1992 scorm_insert_track($userid, $activity->scorm, $activity->id, 0, 'attemptcompletionamount', 0.0);
1995 scorm_seq_set('active', $activity->id, $userid, 'true');
1998 $seq->delivery = $seq->currentactivity;
1999 scorm_seq_set('suspendedactivity', $activity->id, $userid, 'false');
2001 //ONCE THE DELIVERY BEGINS (How should I check that?)
2003 if(isset($activity->tracked) || ($activity->tracked == 0)){
2004 //How should I track the info and what should I do to not record the information for the activity during delivery?
2005 $atabsdur = get_record('scorm_scoes_track','scoid',$activity->id,'userid',$userid,'element','attemptabsoluteduration');
2006 $atexpdur = get_record('scorm_scoes_track','scoid',$activity->id,'userid',$userid,'element','attemptexperiencedduration');
2008 return $seq;
2012 function scorm_clear_suspended_activity($act,$seq){
2013 $currentact= $seq->currentactivity;
2014 $track = get_record('scorm_scoes_track','scoid',$currentact->id,'userid',$userid,'element','suspendedactivity');
2015 if ($track != null){
2016 $ancestors = scorm_get_ancestors($act);
2017 $commonpos = scorm_find_common_ancestor($ancestors,$currentact);
2018 if ($commonpos !== false) {
2019 if ($activitypath = array_slice($ancestors,0,$commonpos)) {
2020 if (!empty ($activitypath)){
2022 foreach ($activitypath as $activity) {
2023 if (scorm_is_leaf($activity)){
2024 scorm_seq_set('suspended',$activity->id,$userid,false);
2026 else{
2027 $children = scorm_get_children($activity);
2028 $bool= false;
2029 foreach ($children as $child){
2030 if(scorm_seq_is('suspended',$child->id,$userid)){
2031 $bool= true;
2034 if(!$bool){
2035 scorm_seq_set('suspended',$activity->id,$userid,false);
2042 scorm_seq_set('suspendedactivity',$act->id,$userid,false);
2047 function scorm_select_children_process($scoid,$userid){
2049 $sco = scorm_get_sco($scoid);
2050 if (!scorm_is_leaf($sco)){
2051 if(!scorm_seq_is('suspended',$scoid,$userid) && !scorm_seq_is('active',$scoid,$userid)){
2052 $r = get_record('scorm_scoes_track','scoid',$scoid,'userid',$userid,'element','selectiontiming');
2054 switch($r->value) {
2056 case 'oneachnewattempt':
2057 case 'never':
2058 break;
2060 case 'once':
2061 if(!scorm_seq_is('activityprogressstatus',$scoid,$userid)){
2062 if(scorm_seq_is('selectioncountsstatus',$scoid,$userid)){
2063 $childlist = '';
2064 $res = get_record('scorm_scoes_track','scoid',$scoid,'userid',$userid,'element','selectioncount');
2065 $i = ($res->value)-1;
2066 $children = scorm_get_children ($sco);
2068 while (i>=0){
2069 $pos = array_rand($children);
2070 array_push($childlist,$children [$pos]);
2071 array_splice($children,$pos,1);
2072 $i--;
2074 sort ($childlist);
2075 $clist = serialize ($childlist);
2076 scorm_seq_set('availablechildren', $scoid, $userid, false);
2077 scorm_seq_set('availablechildren', $scoid, $userid, $clist);
2082 break;
2090 function scorm_randomize_children_process($scoid,$userid){
2092 $sco = scorm_get_sco($scoid);
2093 if (!scorm_is_leaf($sco)){
2094 if(!scorm_seq_is('suspended',$scoid,$userid) && !scorm_seq_is('active',$scoid,$userid)){
2095 $r = get_record('scorm_scoes_track','scoid',$scoid,'userid',$userid,'element','randomizationtiming');
2097 switch($r->value) {
2100 case 'never':
2101 break;
2103 case 'oneachnewattempt':
2104 case 'once':
2105 if(!scorm_seq_is('activityprogressstatus',$scoid,$userid)){
2106 if(scorm_seq_is('randomizechildren',$scoid,$userid)){
2107 $childlist = array();
2108 $res = scorm_get_available_children($sco);
2109 $i = sizeof($res)-1;
2110 $children = $res->value;
2112 while (i>=0){
2113 $pos = array_rand($children);
2114 array_push($childlist,$children [$pos]);
2115 array_splice($children,$pos,1);
2116 $i--;
2119 $clist = serialize ($childlist);
2120 scorm_seq_set('availablechildren', $scoid, $userid, false);
2121 scorm_seq_set('availablechildren', $scoid, $userid, $clist);
2126 break;
2136 function scorm_terminate_descendent_attempts ($activity,$userid,$seq){
2137 $ancestors = scorm_get_ancestors($seq->currentactivity);
2138 $commonpos = scorm_find_common_ancestor($ancestors,$activity);
2139 if ($commonpos !== false) {
2140 if ($activitypath = array_slice($ancestors,1,$commonpos-2)) {
2141 if (!empty ($activitypath)){
2143 foreach ($activitypath as $sco) {
2144 scorm_seq_end_attempt($sco,$userid,$seq->attempt);
2152 function scorm_sequencing_exception($seq){
2153 if($seq->exception != null){
2154 switch($seq->exception){
2156 case 'NB.2.1-1':
2157 notify("Sequencing session has already begun");
2158 break;
2159 case 'NB.2.1-2':
2160 notify("Sequencing session has not begun");
2161 break;
2162 case 'NB.2.1-3':
2163 notify("Suspended activity is not defined");
2164 break;
2165 case 'NB.2.1-4':
2166 notify("Flow Sequencing Control Model Violation");
2167 break;
2168 case 'NB.2.1-5':
2169 notify("Flow or Forward only Sequencing Control Model Violation");
2170 break;
2171 case 'NB.2.1-6':
2172 notify("No activity is previous to the root");
2173 break;
2174 case 'NB.2.1-7':
2175 notify("Unsupported Navigation Request");
2176 break;
2177 case 'NB.2.1-8':
2178 notify("Choice Exit Sequencing Control Model Violation");
2179 break;
2180 case 'NB.2.1-9':
2181 notify("No activities to consider");
2182 break;
2183 case 'NB.2.1-10':
2184 notify("Choice Sequencing Control Model Violation");
2185 break;
2186 case 'NB.2.1-11':
2187 notify("Target Activity does not exist");
2188 break;
2189 case 'NB.2.1-12':
2190 notify("Current Activity already terminated");
2191 break;
2192 case 'NB.2.1-13':
2193 notify("Undefined Navigation Request");
2194 break;
2196 case 'TB.2.3-1':
2197 notify("Current Activity already terminated");
2198 break;
2199 case 'TB.2.3-2':
2200 notify("Current Activity already terminated");
2201 break;
2202 case 'TB.2.3-4':
2203 notify("Current Activity already terminated");
2204 break;
2205 case 'TB.2.3-5':
2206 notify("Nothing to suspend; No active activities");
2207 break;
2208 case 'TB.2.3-6':
2209 notify("Nothing to abandon; No active activities");
2210 break;
2212 case 'SB.2.1-1':
2213 notify("Last activity in the tree");
2214 break;
2215 case 'SB.2.1-2':
2216 notify("Cluster has no available children");
2217 break;
2218 case 'SB.2.1-3':
2219 notify("No activity is previous to the root");
2220 break;
2221 case 'SB.2.1-4':
2222 notify("Forward Only Sequencing Control Model Violation");
2223 break;
2225 case 'SB.2.2-1':
2226 notify("Flow Sequencing Control Model Violation");
2227 break;
2228 case 'SB.2.2-2':
2229 notify("Activity unavailable");
2230 break;
2232 case 'SB.2.3-1':
2233 notify("Forward Traversal Blocked");
2234 break;
2235 case 'SB.2.3-2':
2236 notify("Forward Only Sequencing Control Model Violation");
2237 break;
2238 case 'SB.2.3-3':
2239 notify("No activity is previous to the root");
2240 break;
2242 case 'SB.2.5-1':
2243 notify("Sequencing session has already begun");
2244 break;
2246 case 'SB.2.6-1':
2247 notify("Sequencing session has already begun");
2248 break;
2249 case 'SB.2.6-2':
2250 notify("No Suspended activity is defined");
2251 break;
2253 case 'SB.2.7-1':
2254 notify("Sequencing session has not begun");
2255 break;
2256 case 'SB.2.7-2':
2257 notify("Flow Sequencing Control Model Violation");
2258 break;
2260 case 'SB.2.8-1':
2261 notify("Sequencing session has not begun");
2262 break;
2263 case 'SB.2.8-2':
2264 notify("Flow Sequencing Control Model Violation");
2265 break;
2267 case 'SB.2.9-1':
2268 notify("No target for Choice");
2269 break;
2270 case 'SB.2.9-2':
2271 notify("Target Activity does not exist or is unavailable");
2272 break;
2273 case 'SB.2.9-3':
2274 notify("Target Activity hidden from choice");
2275 break;
2276 case 'SB.2.9-4':
2277 notify("Choice Sequencing Control Model Violation");
2278 break;
2279 case 'SB.2.9-5':
2280 notify("No activities to consider");
2281 break;
2282 case 'SB.2.9-6':
2283 notify("Unable to activate target; target is not a child of the Current Activity");
2284 break;
2285 case 'SB.2.9-7':
2286 notify("Choice Exit Sequencing Control Model Violation");
2287 break;
2288 case 'SB.2.9-8':
2289 notify("Unable to choose target activity - constrained choice");
2290 break;
2291 case 'SB.2.9-9':
2292 notify("Choice Request Prevented by Flow-only Activity");
2293 break;
2295 case 'SB.2.10-1':
2296 notify("Sequencing session has not begun");
2297 break;
2298 case 'SB.2.10-2':
2299 notify("Current Activity is active or suspended");
2300 break;
2301 case 'SB.2.10-3':
2302 notify("Flow Sequencing Control Model Violation");
2303 break;
2305 case 'SB.2.11-1':
2306 notify("Sequencing session has not begun");
2307 break;
2308 case 'SB.2.11-2':
2309 notify("Current Activity has not been terminated");
2310 break;
2312 case 'SB.2.12-2':
2313 notify("Undefined Sequencing Request");
2314 break;
2316 case 'DB.1.1-1':
2317 notify("Cannot deliver a non-leaf activity");
2318 break;
2319 case 'DB.1.1-2':
2320 notify("Nothing to deliver");
2321 break;
2322 case 'DB.1.1-3':
2323 notify("Activity unavailable");
2324 break;
2326 case 'DB.2-1':
2327 notify("Identified activity is already active");
2328 break;