Added auxiliar functions for sequencinglib.php
[moodle.git] / mod / scorm / datamodels / sequencinglib.php
CommitLineData
10fd330f 1<?php // $Id$
13458883 2require ('scormlib.php');
10fd330f 3
4function scorm_seq_evaluate($scoid,$usertracks) {
5 return true;
6}
7
8function scorm_seq_overall ($scoid,$userid,$request) {
9 $seq = scorm_seq_navigation($scoid,$userid,$request);
10 if ($seq->navigation) {
11 if ($seq->termination != null) {
12 $seq = scorm_seq_termination($scoid,$userid,$seq);
13 }
14 if ($seq->sequencing != null) {
13458883 15 // scorm_seq_sequencing($scoid,$userid,$seq);
10fd330f 16 }
17 if ($seq->target != null) {
18 // scorm_sequencing_delivery($scoid,$userid,$seq);
19 }
20 }
21 if ($seq->exception != null) {
22 // scorm_sequencing_exception($seq);
23 }
24 return 'true';
25}
26
27function scorm_seq_navigation ($scoid,$userid,$request) {
28 /// Sequencing structure
29 $seq = new stdClass();
30 $seq->currentactivity = scorm_get_sco($scoid);
13458883 31 $seq->traversaldir = null;
32 $seq->nextactivity = null;
33
34 $seq->identifiedactivity = null;
35 $seq->availablechildren = scorm_get_children ($seq->currentactivity);//Added by Carlos
36 $seq->delivery = null;
37 $seq->deliverable = false;
10fd330f 38 $seq->active = scorm_seq_is('active',$scoid,$userid);
39 $seq->suspended = scorm_seq_is('suspended',$scoid,$userid);
40 $seq->navigation = null;
41 $seq->termination = null;
42 $seq->sequencing = null;
43 $seq->target = null;
13458883 44 $seq->endsession = null;
10fd330f 45 $seq->exception = null;
f3800343 46 $seq->reachable = true;
47 $seq->prevact = true;
48 $seq->constrainedchoice = true;
10fd330f 49
50 switch ($request) {
51 case 'start_':
52 if (empty($seq->currentactivity)) {
53 $seq->navigation = true;
54 $seq->sequencing = 'start';
55 } else {
56 $seq->exception = 'NB.2.1-1'; /// Sequencing session already begun
57 }
58 break;
59 case 'resumeall_':
60 if (empty($seq->currentactivity)) {
13458883 61 if ($track = get_record('scorm_scoes_track','scoid',$scoid,'userid',$userid,'element','suspendedactivity')) {
10fd330f 62 $seq->navigation = true;
63 $seq->sequencing = 'resumeall';
64 } else {
65 $seq->exception = 'NB.2.1-3'; /// No suspended activity found
66 }
67 } else {
68 $seq->exception = 'NB.2.1-1'; /// Sequencing session already begun
69 }
70 break;
71 case 'continue_':
72 case 'previous_':
73 if (!empty($seq->currentactivity)) {
74 $sco = $seq->currentactivity;
75 if ($sco->parent != '/') {
76 if ($parentsco = scorm_get_parent($sco)) {
13458883 77 //BOBO'S CODE
78 /* if (isset($parentsco->flow) && ($parent->flow == true)) {//I think it's parentsco
10fd330f 79 // Current activity is active !
80 if ($request == 'continue_') {
81 $seq->navigation = true;
82 $seq->termination = 'exit';
83 $seq->sequencing = 'continue';
84 } else {
13458883 85 if (isset($parentsco->forwardonly) && ($parent->forwardonly == false)) {
10fd330f 86 $seq->navigation = true;
87 $seq->termination = 'exit';
88 $seq->sequencing = 'previous';
89 } else {
90 $seq->exception = 'NB.2.1-5'; /// Violates control mode
91 }
92 }
13458883 93 }*/
94 // CARLOS' CODE
95 if (!isset($parentsco->flow) || ($parentsco->flow == true)) {//I think it's parentsco
96 // Current activity is active !
1883612a 97 if (scorm_seq_is('active',$sco->id,$userid)) {
13458883 98 if ($request == 'continue_') {
99 $seq->navigation = true;
100 $seq->termination = 'exit';
101 $seq->sequencing = 'continue';
102 } else {
103 if (isset($parentsco->forwardonly) && ($parentsco->forwardonly == false)) {
104 $seq->navigation = true;
105 $seq->termination = 'exit';
106 $seq->sequencing = 'previous';
107 } else {
108 $seq->exception = 'NB.2.1-5'; /// Violates control mode
109 }
110 }
111 }
10fd330f 112 }
13458883 113
10fd330f 114 }
115 }
116 } else {
117 $seq->exception = 'NB.2.1-2'; /// Current activity not defined
118 }
119 break;
120 case 'forward_':
121 case 'backward_':
122 $seq->exception = 'NB.2.1-7' ; /// None to be done, behavior not defined
123 break;
124 case 'exit_':
125 case 'abandon_':
126 if (!empty($seq->currentactivity)) {
127 // Current activity is active !
128 $seq->navigation = true;
129 $seq->termination = substr($request,0,-1);
130 $seq->sequencing = 'exit';
131 } else {
132 $seq->exception = 'NB.2.1-2'; /// Current activity not defined
133 }
134 case 'exitall_':
135 case 'abandonall_':
136 case 'suspendall_':
137 if (!empty($seq->currentactivity)) {
138 $seq->navigation = true;
139 $seq->termination = substr($request,0,-1);
140 $seq->sequencing = 'exit';
141 } else {
142 $seq->exception = 'NB.2.1-2'; /// Current activity not defined
143 }
144 break;
145 default: /// {target=<STRING>}choice
146 if ($targetsco = get_record('scorm_scoes','scorm',$sco->scorm,'identifier',$request)) {
147 if ($targetsco->parent != '/') {
148 $seq->target = $request;
149 } else {
150 if ($parentsco = scorm_get_parent($targetsco)) {
13458883 151 if (!isset($parentsco->choice) || ($parent->choice == true)) {
10fd330f 152 $seq->target = $request;
153 }
154 }
155 }
156 if ($seq->target != null) {
157 if (empty($seq->currentactivity)) {
158 $seq->navigation = true;
159 $seq->sequencing = 'choice';
160 } else {
161 if (!$sco = scorm_get_sco($scoid)) {
162 return $seq;
163 }
164 if ($sco->parent != $target->parent) {
165 $ancestors = scorm_get_ancestors($sco);
166 $commonpos = scorm_find_common_ancestor($ancestors,$targetsco);
167 if ($commonpos !== false) {
168 if ($activitypath = array_slice($ancestors,0,$commonpos)) {
169 foreach ($activitypath as $activity) {
170 if (scorm_seq_is('active',$activity->id,$userid) && (isset($activity->choiceexit) && ($activity->choiceexit == false))) {
171 $seq->navigation = false;
172 $seq->termination = null;
173 $seq->sequencing = null;
174 $seq->target = null;
175 $seq->exception = 'NB.2.1-8'; /// Violates control mode
176 return $seq;
177 }
178 }
179 } else {
180 $seq->navigation = false;
181 $seq->termination = null;
182 $seq->sequencing = null;
183 $seq->target = null;
184 $seq->exception = 'NB.2.1-9';
185 }
186 }
187 }
188 // Current activity is active !
189 $seq->navigation = true;
190 $seq->sequencing = 'choice';
191 }
192 } else {
193 $seq->exception = 'NB.2.1-10'; /// Violates control mode
194 }
195 } else {
196 $seq->exception = 'NB.2.1-11'; /// Target activity does not exists
197 }
198 break;
199 }
200 return $seq;
201}
202
13458883 203function scorm_seq_termination ($seq,$userid) {
10fd330f 204 if (empty($seq->currentactivity)) {
205 $seq->termination = false;
206 $seq->exception = 'TB.2.3-1';
207 return $seq;
208 }
209
210 $sco = $seq->currentactivity;
211
212 if ((($seq->termination == 'exit') || ($seq->termination == 'abandon')) && !$seq->active) {
213 $seq->termination = false;
214 $seq->exception = 'TB.2.3-2';
215 return $seq;
216 }
217 switch ($seq->termination) {
218 case 'exit':
219 scorm_seq_end_attempt($sco,$userid);
220 $seq = scorm_seq_exit_action_rules($seq,$userid);
221 do {
13458883 222 $exit = false;// I think this is false. Originally this was true
10fd330f 223 $seq = scorm_seq_post_cond_rules($seq,$userid);
224 if ($seq->termination == 'exitparent') {
225 if ($sco->parent != '/') {
226 $sco = scorm_get_parent($sco);
227 $seq->currentactivity = $sco;
228 $seq->active = scorm_seq_is('active',$sco->id,$userid);
229 scorm_seq_end_attempt($sco,$userid);
13458883 230 $exit = true;//I think it's true. Originally this was false
10fd330f 231 } else {
232 $seq->termination = false;
233 $seq->exception = 'TB.2.3-4';
234 return $seq;
235 }
236 }
237 } while (($exit == false) && ($seq->termination == 'exit'));
238 if ($seq->termination == 'exit') {
239 $seq->termination = true;
240 return $seq;
241 }
242 case 'exitall':
243 if ($seq->active) {
244 scorm_seq_end_attempt($sco,$userid);
245 }
246 /// Terminate Descendent Attempts Process
13458883 247
248
10fd330f 249 if ($ancestors = scorm_get_ancestors($sco)) {
250 foreach ($ancestors as $ancestor) {
251 scorm_seq_end_attempt($ancestor,$userid);
252 $seq->currentactivity = $ancestor;
253 }
254 }
13458883 255
10fd330f 256 $seq->active = scorm_seq_is('active',$seq->currentactivity->id,$userid);
257 $seq->termination = true;
13458883 258 $seq->sequencing = exit;
10fd330f 259 break;
260 case 'suspendall':
261 if (($seq->active) || ($seq->suspended)) {
262 scorm_seq_set('suspended',$sco->id,$userid);
263 } else {
264 if ($sco->parent != '/') {
265 $parentsco = scorm_get_parent($sco);
266 scorm_seq_set('suspended',$parentsco->id,$userid);
267 } else {
268 $seq->termination = false;
269 $seq->exception = 'TB.2.3-3';
270 // return $seq;
271 }
272 }
273 if ($ancestors = scorm_get_ancestors($sco)) {
274 foreach ($ancestors as $ancestor) {
f3800343 275 scorm_seq_set('active',$ancestor->id,$userid,false);
10fd330f 276 scorm_seq_set('suspended',$ancestor->id,$userid);
277 $seq->currentactivity = $ancestor;
278 }
279 $seq->termination = true;
280 $seq->sequencing = 'exit';
281 } else {
282 $seq->termination = false;
283 $seq->exception = 'TB.2.3-5';
284 }
285 break;
286 case 'abandon':
f3800343 287 scorm_seq_set('active',$sco->id,$userid,false);
10fd330f 288 $seq->active = null;
289 $seq->termination = true;
290 break;
291 case 'abandonall':
292 if ($ancestors = scorm_get_ancestors($sco)) {
293 foreach ($ancestors as $ancestor) {
f3800343 294 scorm_seq_set('active',$ancestor->id,$userid,false);
10fd330f 295 $seq->currentactivity = $ancestor;
296 }
297 $seq->termination = true;
298 $seq->sequencing = 'exit';
299 } else {
300 $seq->termination = false;
301 $seq->exception = 'TB.2.3-6';
302 }
303 break;
304 default:
305 $seq->termination = false;
306 $seq->exception = 'TB.2.3-7';
307 break;
308 }
309 return $seq;
310}
311
312function scorm_seq_end_attempt($sco,$userid) {
313 if (scorm_is_leaf($sco)) {
314 if (!isset($sco->tracked) || ($sco->tracked == 1)) {
315 if (!scorm_seq_is('suspended',$sco->id,$userid)) {
316 if (!isset($sco->completionsetbycontent) || ($sco->completionsetbycontent == 0)) {
f3800343 317 // if (!scorm_seq_is('attemptprogressstatus',$sco->id,$userid,$attempt)) {
318 if (!scorm_seq_is('attemptprogressstatus',$sco->id,$userid)) {
319 scorm_seq_set('attemptprogressstatus',$sco->id,$userid);
320 scorm_seq_set('attemptcompletionstatus',$sco->id,$userid);
10fd330f 321 }
322 }
323 if (!isset($sco->objectivesetbycontent) || ($sco->objectivesetbycontent == 0)) {
f3800343 324 if ($objectives = $sco->objectives) {
10fd330f 325 foreach ($objectives as $objective) {
326 if ($objective->primary) {
327 if (!scorm_seq_objective_progress_status($sco,$userid,$objective)) {
f3800343 328 scorm_seq_set('objectiveprogressstatus',$sco->id,$userid);
329 scorm_seq_set('objectivesatisfiedstatus',$sco->id,$userid);
10fd330f 330 }
331 }
332 }
333 }
334 }
335 }
336 }
337 } else {
338 if ($children = scorm_get_children($sco)) {
339 $suspended = false;
340 foreach ($children as $child) {
341 if (scorm_seq_is('suspended',$child,$userid)) {
342 $suspended = true;
343 break;
344 }
345 }
346 if ($suspended) {
347 scorm_seq_set('suspended',$sco,$userid);
348 } else {
f3800343 349 scorm_seq_set('suspended',$sco,$userid,false);
10fd330f 350 }
351 }
352 }
353 scorm_seq_set('active',$sco,$userid,0,false);
354 scorm_seq_overall_rollup($sco,$userid);
355}
356
f3800343 357//function scorm_seq_is($what, $scoid, $userid, $attempt=0) {
358function scorm_seq_is($what, $scoid, $userid) {
10fd330f 359 /// Check if passed activity $what is active
360 $active = false;
361 if ($track = get_record('scorm_scoes_track','scoid',$scoid,'userid',$userid,'element',$what)) {
362 $active = true;
363 }
364 return $active;
365}
366
f3800343 367//function scorm_seq_set($what, $scoid, $userid, $attempt=0, $value='true') {
368function scorm_seq_set($what, $scoid, $userid, $value='true') {
10fd330f 369 /// set passed activity to active or not
370 if ($value == false) {
371 delete_record('scorm_scoes_track','scoid',$scoid,'userid',$userid,'element',$what);
372 } else {
373 $sco = scorm_get_sco($scoid);
374 scorm_insert_track($userid, $sco->scorm, $sco->id, 0, $what, $value);
375 }
376}
377
378function scorm_seq_exit_action_rules($seq,$userid) {
379 $sco = $seq->currentactivity;
380 $ancestors = scorm_get_ancestors($sco);
381 $exittarget = null;
382 foreach (array_reverse($ancestors) as $ancestor) {
383 if (scorm_seq_rules_check($ancestor,'exit') != null) {
384 $exittarget = $ancestor;
385 break;
386 }
387 }
388 if ($exittarget != null) {
389 $commons = array_slice($ancestors,0,scorm_find_common_ancestor($ancestors,$exittarget));
390
391 /// Terminate Descendent Attempts Process
392 if ($commons) {
393 foreach ($commons as $ancestor) {
13458883 394
10fd330f 395 scorm_seq_end_attempt($ancestor,$userid);
396 $seq->currentactivity = $ancestor;
397 }
398 }
399 }
400 return $seq;
401}
402
403function 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) {
407 switch($action) {
408 case 'retry':
409 case 'continue':
410 case 'previous':
411 $seq->sequencing = $action;
412 break;
413 case 'exitparent':
414 case 'exitall':
415 $seq->termination = $action;
416 break;
417 case 'retryall':
418 $seq->termination = 'exitall';
419 $seq->sequencing = 'retry';
420 break;
421 }
422 }
423 }
424 return $seq;
425}
426
13458883 427function scorm_seq_rules_check ($sco, $action){
428 $act = null;
429 if($rules = get_records('scorm_seq_ruleconds','scoid',$sco->id,'action',$action)){
430 foreach ($rules as $rule){
431 if($act = scorm_seq_rule_check($sco,$rule)){
432 return $act;
433 }
434 }
435 }
436 return $act;
437
438}
439
440function scorm_seq_rule_check ($sco, $rule){
441 $bag = Array();
442 $cond = '';
443 $ruleconds = get_records('scorm_seq_rulecond','scoid',$sco->id,'ruleconditionsid',$rule->id);
444 foreach ($ruleconds as $rulecond){
445 if ($rulecond->operator = 'not') {
446 if ($rulecond->cond != 'unknown' ){
447 $rulecond->cond = 'not'.$rulecond;
448 }
449 }
450 $bag [$rule->id] = $rulecond->cond;
451
452 }
453 if (empty($bag)){
454 $cond = 'unknown';
455 return $cond;
456 }
457
458 $size= sizeof($bag);
459 $i=0;
460
461 if ($rule->conditioncombination = 'all'){
462 foreach ($bag as $con){
463 $cond = $cond.' and '.$con;
464
465 }
466 }
467 else{
468 foreach ($bag as $con){
469 $cond = $cond.' or '.$con;
470 }
471 }
472 return $cond;
473}
474
475
476function scorm_seq_overall_rollup($sco,$userid){//Carlos
477
478 if ($ancestors = scorm_get_ancestors($sco)) {
479 foreach ($ancestors as $ancestor) {
480 if(!scorm_is_leaf($ancestor)){
481 scorm_seq_measure_rollup($sco,$userid);
482 }
483 scorm_seq_objective_rollup($sco,$userid);
484 scorm_seq_activity_progress_rollup($sco,$userid);
485
486 }
487
488 }
489}
490
491/* 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*/
492
493function scorm_seq_measure_rollup($sco,$userid){
494
495 $totalmeasure = 0; //Check if there is something similar in the database
496 $valid = false;//Same as in the last line
497 $countedmeasures = 0;//Same too
498 $targetobjective = null;
499 $readable = true;//to check if status and measure weight are readable
500 $objectives = get_records('scorm_seq_objective','scoid',$sco->id);
501
502 foreach ($objective as $objective){
503
504 if ($objective->primaryobj == true){//Objective contributes to rollup I'm using primaryobj field, but not
505 $targetobjective = $objective;
506 break;
507 }
508
509 }
510
511 if ($targetobjective != null){
512 $children = get_children($sco);
513 foreach ($children as $child){
514 $child = scorm_get_sco ($child);
b186cb9d 515 if (!isset($child->tracked) || ($child->tracked == 1)){
13458883 516 //check if we haven't done any attempt to see if this activity has been tracked
517 //it could be $child->tracked == true
518
519 $rolledupobjective = null;// we set the rolled up activity to undefined
520 $objectives = get_records('scorm_seq_objective','scoid',$child->id);
521 foreach ($objective as $objective){
522 if ($objective->primaryobj == true){//Objective contributes to rollup I'm using primaryobj field, but not
523 $rolledupobjective = $objective;
524 break;
525 }
526 }
527 if ($rolledupobjective != null){
528
529 $measureweight = get_record('scorm_scoes_track','scoid',$child->id,'userid',$userid,'element','objectivemeasureweight');
530 $countedmeasures = $countedmeasures + ($measureweight->value);
531 if (!scorm_seq_objective_measure_status($sco,$userid,$objective)) {
532 $normalizedmeasure = get_record('scorm_scoes_track','scoid',$child->id,'userid',$userid,'element','objectivenormalizedmeasure');
533 $totalmeasure = $totalmeasure + (($normalizedmeasure->value) * ($measureweight->value));
534 $valid = true;
535 }
536
537
538
539 }
540 }
541 }
542
543
544 if(!$valid){
545
f3800343 546 scorm_seq_set('objectivemeasurestatus',$sco->id,$userid,false);
13458883 547
548 }
549 else{
550 if($countedmeasures>0){
f3800343 551 scorm_seq_set('objectivemeasurestatus',$sco->id,$userid);
13458883 552 $val=$totalmeasure/$countedmeasure;
f3800343 553 scorm_seq_set('normalizedmeasure',$sco->id,$userid,$val);
13458883 554
555 }
556 else{
f3800343 557 scorm_seq_set('objectivemeasurestatus',$sco->id,$userid,false);
13458883 558
559 }
560 }
561
562 }
563
564}
565
566function scorm_seq_objective_rollup_measure($sco,$userid){
567 $targetobjective = null;
568
569
570 $objectives = get_records('scorm_seq_objective','scoid',$sco->id);
f3800343 571 foreach ($objectives as $objective){
13458883 572 if ($objective->primaryobj == true){//Objective contributes to rollup I'm using primaryobj field, but not
573 $targetobjective = $objective;
574 break;
575 }
576 }
577 if ($targetobjective != null){
578
579 if($targetobjective->satisfiedbymeasure){
580
581
582 if (!scorm_seq_objective_progress_status($sco,$userid,$targetobjective)) {
583
f3800343 584 scorm_seq_set('objectiveprogressstatus',$sco->id,$userid,false);
13458883 585
586 }
587
588 else{
589 $active = get_record('scorm_scoes_track','scoid',$sco->id,'userid',$userid,'element','active');
590 $isactive = $active->value;
591
592 $normalizedmeasure = get_record('scorm_scoes_track','scoid',$sco->id,'userid',$userid,'element','objectivenormalizedmeasure');
593
b186cb9d 594 if (!$isactive || ($isactive /*&&// measuresatisfactionif*/ )){//This condition is really odd. It's in the SeqNav.pdf on page 193, line 3.1.2.1
13458883 595 if($normalizedmeasure->value >= $targetobjective->minnormalizedmeasure){
f3800343 596 scorm_seq_set('objectiveprogressstatus',$sco->id,$userid);
597 scorm_seq_set('objectivesatisfiedstatus',$sco->id,$userid);
13458883 598 }
599 else{
f3800343 600 scorm_seq_set('objectiveprogressstatus',$sco->id,$userid);
601 scorm_seq_set('objectivesatisfiedstatus',$sco->id,$userid,false);
13458883 602 }
603 }
604 else{
f3800343 605 scorm_seq_set('objectiveprogressstatus',$sco->id,$userid,false);
13458883 606
607 }
608 }
609 }
610 }
611
612}
613
614
615function scorm_seq_objective_rollup_rules($sco,$userid){
616 $targetobjective = null;
617
618 $objectives = get_records('scorm_seq_objective','scoid',$sco->id);
619 foreach ($objective as $objective){
620 if ($objective->primaryobj == true){//Objective contributes to rollup I'm using primaryobj field, but not
621 $targetobjective = $objective;
622 break;
623 }
624 }
625 if ($targetobjective != null){
626
627
628
629 if(scorm_seq_rollup_rule_check($sco,$userid,'notsatisfied')){//with not satisfied rollup for the activity
630
631
f3800343 632 scorm_seq_set('objectiveprogressstatus',$sco->id,$userid);
633 scorm_seq_set('objectivesatisfiedstatus',$sco->id,$userid,false);
13458883 634 }
635 if(scorm_seq_rollup_rule_check($sco,$userid,'satisfied')){//with satisfied rollup for the activity
f3800343 636 scorm_seq_set('objectiveprogressstatus',$sco->id,$userid);
637 scorm_seq_set('objectivesatisfiedstatus',$sco->id,$userid);
13458883 638 }
639
640 }
641
642}
643
644function scorm_seq_activity_progress_rollup ($sco, $userid){
645
646 if(scorm_seq_rollup_rule_check($sco,$userid,'incomplete')){
647 //incomplete rollup action
f3800343 648 scorm_seq_set('attemptcompletionstatus',$sco->id,$userid,false);
649 scorm_seq_set('attemptprogressstatus',$sco->id,$userid);
13458883 650
651 }
652 if(scorm_seq_rollup_rule_check($sco,$userid,'completed')){
653 //incomplete rollup action
f3800343 654 scorm_seq_set('attemptcompletionstatus',$sco->id,$userid);
655 scorm_seq_set('attemptprogressstatus',$sco->id,$userid);
13458883 656 }
657
658}
659
660function scorm_seq_rollup_rule_check ($sco,$userid,$action){
661
662 if($rolluprules = get_record('scorm_seq_rolluprule','scoid',$sco->id,'userid',$userid,'action',$action)){
663
664 $childrenbag = Array ();
665 $children = scorm_get_children ($sco);
666
667 foreach($rolluprules as $rolluprule){
668
669
670
671 foreach ($children as $child){
672
673 /*$tracked = get_records('scorm_scoes_track','scoid',$child->id,'userid',$userid);
674 if($tracked && $tracked->attemp != 0){*/
675 $child = scorm_get_sco ($child);
676 if (!isset($child->tracked) || ($child->tracked == 1)){
677
b186cb9d 678 if(scorm_seq_check_child ($child,$action,$userid)){
13458883 679
680 $rollupruleconds = get_records('scorm_seq_rolluprulecond','rollupruleid',$rolluprule->id);
681 $evaluate = scorm_seq_evaluate_rollupcond($child,$rolluprule->conditioncombination,$rollupruleconds,$userid);
682 if ($evaluate=='unknown'){
683 array_push($childrenbag,'unknown');
684 }
685 else{
686 if($evaluate == true){
687 array_push($childrenbag,true);
688 }
689 else{
690 array_push($childrenbag,false);
691 }
692 }
693 }
694 }
695
696 }
697 $change = false;
698
699 switch ($rolluprule->childactivityset){
700
701 case 'all':
702 if((array_search(false,$childrenbag)===false)&&(array_search('unknown',$childrenbag)===false)){//I think I can use this condition instead equivalent to OR
703 $change = true;
704 }
705 break;
706
707 case 'any':
708 if(array_search(true,$childrenbag)!==false){//I think I can use this condition instead equivalent to OR
709 $change = true;
710 }
711 break;
712
713 case 'none':
714 if((array_search(true,$childrenbag)===false)&&(array_search('unknown',$childrenbag)===false)){//I think I can use this condition instead equivalent to OR
715 $change = true;
716 }
717 break;
718
719 case 'atleastcount':
720 foreach ($childrenbag as $itm){//I think I can use this condition instead equivalent to OR
721 $cont = 0;
722 if($itm === true){
723 $cont++;
724 }
725 if($cont >= $roullprule->minimumcount){
726 $change = true;
727 }
728 }
729 break;
730
731 case 'atleastcount':
732 foreach ($childrenbag as $itm){//I think I can use this condition instead equivalent to OR
733 $cont = 0;
734 if($itm === true){
735 $cont++;
736 }
737 if($cont >= $roullprule->minimumcount){
738 $change = true;
739 }
740 }
741 break;
742
743 case 'atleastpercent':
744 foreach ($childrenbag as $itm){//I think I can use this condition instead equivalent to OR
745 $cont = 0;
746 if($itm === true){
747 $cont++;
748 }
749 if(($cont/sizeof($childrenbag)) >= $roullprule->minimumcount){
750 $change = true;
751 }
752 }
753 break;
754 }
755 if ($change==true){
756 return true;
757 }
758 }
759 }
760 return false;
761}
762
763
764function scorm_seq_evaluate_rollupcond($sco,$conditioncombination,$rollupruleconds,$userid){
765 $bag = Array();
766 $con = "";
767 $val = false;
768 $unk = false;
769 foreach($rollupruleconds as $rolluprulecond){
770
771 $condit = scorm_evaluate_cond($rolluprulecond,$sco,$userid);
772
773 if($rule->operator=='not'){// If operator is not, negate the condition
774 if ($rule->cond != 'unknown'){
775 if ($condit){
776 $condit = false;
777 }
778 else{
779 $condit = true;
780 }
781 }
782 else{
783 $condit = 'unknown';
784 }
785 array_push($childrenbag,$condit);
786 }
787
788 }
789 if (empty($bag)){
790 return 'unknown';
791 }
792 else{
793 $i = 0;
794 foreach ($bag as $b){
795
796 if ($rolluprule->conditioncombination == 'all'){
797
798 $val = true;
799 if($b == 'unknown'){
800 $unk = true;
801 }
802 if($b === false){
803 return false;
804 }
805 }
806
807 else{
808
809 $val = false;
810
811 if($b == 'unknown'){
812 $unk = true;
813 }
814 if($b === true){
815 return true;
816 }
817 }
818
819
820 }
821 }
822 if ($unk){
823 return 'unknown';
824 }
825 return $val;
826
827}
828
829function scorm_evaluate_condition ($rolluprulecond,$sco,$userid){
830
831 $res = false;
832
833 switch ($rolluprulecond->cond){
834
835 case 'satisfied':
836 if($r=get_record('scorm_scoes_track','scoid',$sco->id,'userid',$userid,'element','objectivesatisfiedstatus')){
837 if($r->value == true){
838 if ($r=get_record('scorm_scoes_track','scoid',$sco->id,'userid',$userid,'element','objectiveprogressstatus')){
839 if($r->value == true){
840 $res= true;
841 }
842 }
843 }
844 }
845 break;
846
847 case 'objectiveStatusKnown':
848 if ($r=get_record('scorm_scoes_track','scoid',$sco->id,'userid',$userid,'element','objectiveprogressstatus')){
849 if($r->value == true){
850 $res= true;
851 }
852 }
853 break;
854
855 case 'objectiveMeasureKnown':
856 if ($r = get_record('scorm_scoes_track','scoid',$sco->id,'userid',$userid,'element','objectivemeasurestatus')){
857 if($r->value == true){
858 $res = true;
859 }
860
861 }
862
863 break;
864
865 case 'completed':
866 if ($r = get_record('scorm_scoes_track','scoid',$sco->id,'userid',$userid,'element','attemptcompletionstatus')){
867 if($r->value){
868 if ($r = get_record('scorm_scoes_track','scoid',$sco->id,'userid',$userid,'element','attemptprogressstatus')){
869 if($r->value){
870 $res = true;
871 }
872
873 }
874 }
875
876 }
877 break;
878
879 case 'attempted':
880 if ($r = get_record('scorm_scoes_track','scoid',$sco->id,'userid',$userid,'element','activityprogressstatus')){
881 if($r->value){
882 if ($r = get_record('scorm_scoes_track','scoid',$sco->id,'userid',$userid,'element','activityattemptcount')){
883 if($r->value > 0){
884 $res = true;
885 }
886
887 }
888 }
889
890 }
891 break;
892
893
894 case 'attemptLimitExceeded':
895 if ($r = get_record('scorm_scoes_track','scoid',$sco->id,'userid',$userid,'element','activityprogressstatus')){
896 if($r->value){
897 if ($r = get_record('scorm_scoes_track','scoid',$sco->id,'userid',$userid,'element','limitconditionattemptlimitcontrol')){
898 if($r->value){
899 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') ){
900 if($r->value >= $r2->value){
901 $res = true;
902 }
903
904 }
905
906 }
907
908 }
909
910 }
911
912 }
913
914 break;
915
916 case 'activityProgressKnown':
917
918 if ($r = get_record('scorm_scoes_track','scoid',$sco->id,'userid',$userid,'element','activityprogressstatus')){
919 if($r->value){
920 if ($r = get_record('scorm_scoes_track','scoid',$sco->id,'userid',$userid,'element','attemptprogressstatus')){
921 if($r->value){
922 $res = true;
923 }
924
925 }
926
927 }
928
929 }
930
931 break;
932 }
933 return $res;
934
935}
936
937function scorm_seq_check_child ($sco, $action, $userid){
938 $included = false;
939 $r = get_record('scorm_scoes_track','scoid',$sco->id,'userid',$userid,'element','activityattemptcount');
940 if ($action == 'satisfied' || $action == 'notsatisfied'){
b186cb9d 941 if (!scorm_seq_is('rollupobjectivesatisfied',$sco->id,$userid)){
13458883 942 $included = true;
b186cb9d 943 if (($action == 'satisfied' /*&& adlseqRequiredforSatisfied == 'ifNotSuspended') || ($action == 'notsatisfied' && adlseqRequiredforNotSatisfied == 'ifNotSuspended'*/)){
13458883 944
f3800343 945 if (!scorm_seq_is('activityprogressstatus',$sco->id,$userid) || ((($r->value)>0)&& !scorm_seq_is('suspended',$sco->id,$userid))){
13458883 946 $included = false;
947 }
948
949 }
950 else{
b186cb9d 951 if (($action == 'satisfied' /*&& adlseqRequiredforSatisfied == 'ifAttempted') || ($action == 'notsatisfied' && adlseqRequiredforNotSatisfied == 'ifAttempted'*/)){
952 if (!scorm_seq_is('activityprogressstatus',$sco->id,$userid) || (($r->value) == 0)){
13458883 953 $included = false;
954 }
955 }
956 else{
b186cb9d 957 if (($action == 'satisfied' /*&& adlseqRequiredforSatisfied == 'ifNotSkipped') || ($action == 'notsatisfied' && adlseqRequiredforNotSatisfied == 'ifNotSkipped'*/)){
13458883 958 $rulch = scorm_seq_rules_check($sco, 'skip');
959 if ($rulch != null){
960 $included = false;
961 }
962 }
963 }
964 }
965 }
966 }
967 if ($action == 'completed' || $action == 'incomplete'){
b186cb9d 968 if (!scorm_seq_is('rollupprogresscompletion',$sco->id,$userid)){
13458883 969 $included = true;
970
b186cb9d 971 if (($action == 'completed' /*&& adlseqRequiredForCompleted == 'ifNotSuspended') || ($action == 'incomplete' && adlseqRequiredForIncomplete == 'ifNotSuspended'*/)){
13458883 972
f3800343 973 if (!scorm_seq_is('activityprogressstatus',$sco->id,$userid) || ( (($r->value)>0)&& !scorm_seq_is('suspended',$sco->id,$userid))){
13458883 974 $included = false;
975 }
976
977 }
978 else{
979
b186cb9d 980 if (($action == 'completed' /*&& adlseqRequiredForCompleted == 'ifAttempted') || ($action == 'incomplete' && adlseqRequiredForIncomplete == 'ifAttempted'*/)){
13458883 981
f3800343 982 if (!scorm_seq_is('activityprogressstatus',$sco->id,$userid) || (($r->value)==0)){
13458883 983 $included = false;
984 }
985
986 }
987 else{
b186cb9d 988 if (($action == 'completed' /*&& adlseqRequiredforSatisfied == 'ifNotSkipped') || ($action == 'incomplete' && adlseqRequiredforNotSatisfied == 'ifNotSkipped'*/)){
13458883 989 $rulch = scorm_seq_rules_check($sco, 'skip');
990 if ($rulch != null){
991 $included = false;
992 }
993 }
994 }
995
996
997 }
998
999 }
1000 }
1001 return $included;
1002
1003
1004}
1005
1006function scorm_seq_sequencing ($scoid,$userid,$seq) {
1007
1008 switch ($seq->sequencing) {
1009
1010 case 'start':
f3800343 1011 $seq = scorm_seq_start_sequencing($sco,$userid,$seq); //We'll see the parameters we have to send, this should update delivery and end
13458883 1012 $seq->sequencing = true;
f3800343 1013
13458883 1014
1015 break;
1016
1017 case 'resumeall':
f3800343 1018 $seq = scorm_seq_resume_sequencing($sco,$userid,$seq); //We'll see the parameters we have to send, this should update delivery and end
13458883 1019 $seq->sequencing = true;
f3800343 1020
13458883 1021
1022
1023 break;
1024
1025 case 'exit':
f3800343 1026 $seq = scorm_seq_exit_sequencing($sco,$userid,$seq); //We'll see the parameters we have to send, this should update delivery and end
13458883 1027 $seq->sequencing = true;
13458883 1028
1029
1030
1031 break;
1032
1033 case 'retry':
f3800343 1034 $seq = scorm_seq_retry_sequencing($sco,$userid,$seq); //We'll see the parameters we have to send, this should update delivery and end
13458883 1035 $seq->sequencing = true;
f3800343 1036
13458883 1037
1038 break;
1039
1040 case 'previous':
f3800343 1041 $seq = scorm_seq_previous_sequencing($sco,$userid,$seq);// We'll see the parameters we have to send, this should update delivery and end
13458883 1042 $seq->sequencing = true;
1043
13458883 1044
1045 break;
1046
1047 case 'choice':
f3800343 1048 $seq = scorm_seq_choice_sequencing($sco,$userid,$seq);// We'll see the parameters we have to send, this should update delivery and end
13458883 1049 $seq->sequencing = true;
f3800343 1050
13458883 1051
1052 break;
1053
1054 }
1055
1056 if ($seq->exception != null){
1057 $seq->sequencing = false;
1058 return $seq;
1059 }
1060
1061 $seq->sequencing= true;
1062 return $seq;
1063}
1064
1065
1066function scorm_seq_start_sequencing($scoid,$userid,$seq){
1067 if (!empty($seq->currentactivity)) {
1068 $seq->delivery = null;
1069 $seq->exception = 'SB.2.5-1';
1070 return $seq;
1071 }
1072 $sco = get_record('scorm_scoes','scoid',$scoid,'userid',$userid);
1073 if (($sco->parent == '/') && scorm_is_leaf($sco)) {//if the activity is the root and is leaf
1074 $seq->delivery = $sco;
1075 }
1076 else{
1077 $ancestors = scorm_get_ancestors($sco);
1078 $ancestorsroot = array_reverse($ancestors);
b186cb9d 1079 $res = scorm_seq_flow($ancestorsroot[0],'forward',$seq,true,$userid);
13458883 1080 if($res){
f3800343 1081 return $res;
13458883 1082 }
1083 else{
1084 //return end and exception
1085 }
1086 }
1087}
1088
1089function scorm_seq_resume_all_sequencing($scoid,$userid,$seq){
1090 if (!empty($seq->currentactivity)){
1091 $seq->delivery = null;
1092 $seq->exception = 'SB.2.6-1';
1093 return $seq;
1094 }
1095 $track = get_record('scorm_scoes_track','scoid',$scoid,'userid',$userid,'element','suspendedactivity');
1096 if (!$track) {
1097 $seq->delivery = null;
1098 $seq->exception = 'SB.2.6-2';
1099 return $seq;
1100 }
1101 $seq->delivery = get_record('scorm_scoes','scoid',$scoid,'userid',$userid);//we assign the sco to the delivery
1102
1103}
1104
1105function scorm_seq_continue_sequencing($scoid,$userid,$seq){
1106 if (empty($seq->currentactivity)) {
1107 $seq->delivery = null;
1108 $seq->exception = 'SB.2.7-1';
1109 return $seq;
1110 }
1111 $currentact= $seq->currentactivity;
1112 if ($currentact->parent != '/') {//if the activity is the root and is leaf
1113 $parent = scorm_get_parent ($currentact);
1114
1115 if (isset($parent->flow) && ($parent->flow == false)) {
1116 $seq->delivery = null;
1117 $seq->exception = 'SB.2.7-2';
1118 return $seq;
1119 }
1120
1121 $res = scorm_seq_flow($currentact,'forward',$seq,false,$userid);
1122 if($res){
f3800343 1123 return $res;
13458883 1124 }
1125 else{
1126 //return end and exception
1127 }
1128
1129 }
1130}
1131
1132function scorm_seq_previous_sequencing($scoid,$userid,$seq){
1133 if (empty($seq->currentactivity)) {
1134 $seq->delivery = null;
1135 $seq->exception = 'SB.2.8-1';
1136 return $seq;
1137 }
1138
1139 $currentact= $seq->currentactivity;
1140 if ($currentact->parent != '/') {//if the activity is the root and is leaf
1141 $parent = scorm_get_parent ($activity);
1142 if (isset($parent->flow) && ($parent->flow == false)) {
1143 $seq->delivery = null;
1144 $seq->exception = 'SB.2.8-2';
1145 return $seq;
1146 }
1147
1148 $res = scorm_seq_flow($currentact,'backward',$seq,false,$userid);
1149 if($res){
f3800343 1150 return $res;
13458883 1151 }
1152 else{
1153 //return end and exception
1154 }
1155
1156 }
1157
1158}
1159
1160function scorm_seq_exit_sequencing($scoid,$userid,$seq){
1161 if (empty($seq->currentactivity)) {
1162 $seq->delivery = null;
1163 $seq->exception = 'SB.2.11-1';
1164 return $seq;
1165 }
1166
1167 if ($seq->active){
1168 $seq->endsession = false;
1169 $seq->exception = 'SB.2.11-2';
1170 return $seq;
1171 }
1172 $currentact= $seq->currentactivity;
1173 if ($currentact->parent == '/'){
1174 $seq->endsession = true;
1175 return $seq;
1176 }
1177
1178 $seq->endsession = false;
1179 return $seq;
1180}
1181
1182
1183function scorm_seq_retry_sequencing($scoid,$userid,$seq){
1184 if (empty($seq->currentactivity)) {
1185 $seq->delivery = null;
1186 $seq->exception = 'SB.2.10-1';
1187 return $seq;
1188 }
1189 if ($seq->active || $seq->suspended){
1190 $seq->delivery = null;
1191 $seq->exception = 'SB.2.10-2';
1192 return $seq;
1193 }
1194
1195 if (!scorm_is_leaf($seq->currentactivity)){
1196 $res = scorm_seq_flow($seq->currentactivity,'forward',$seq,true,$userid);
1197 if($res != null){
f3800343 1198 return $res;
13458883 1199 //return deliver
1200 }
1201 else{
1202 $seq->delivery = null;
1203 $seq->exception = 'SB.2.10-3';
1204 return $seq;
1205 }
1206 }
1207 else{
1208 $seq->delivery = $seq->currentactivity;
1209 return $seq;
1210 }
1211
1212}
1213
1214function scorm_seq_flow ($candidate,$direction,$seq,$childrenflag,$userid){
1215 //$PREVDIRECTION NOT DEFINED YET
1216
1217 $activity=$candidate;
1218 $deliverable=false;
1219 $previdirection = null;
1220 $seq = scorm_seq_flow_tree_traversal ($activity,$direction,$childrenflag,$prevdirection,$seq);
1221 if($seq->identifiedactivity == null){//if identifies
1222 $seq->identifiedactivity = $candidate;
1223 $seq->deliverable = false;
1224 }
1225 else{
1226 $activity = $seq->identifiedactivity;
1227 $seq = scorm_seq_flow_activity_traversal($activity,$userid,$direction,$childrenflag,$prevdirection,$seq);//
1228 return $seq;
1229
1230 }
1231}
1232
1233function scorm_seq_flow_activity_traversal ($activity, $userid, $direction, $childrenflag, $prevdirection, $seq){//returns the next activity on the tree, traversal direction, control returned to the LTS, (may) exception
1234 $activity = scorm_get_sco ($activity);
1235 $parent = scorm_get_parent ($activity);
1236 if (isset($parent->flow) && ($parent->flow == false)) {
1237 $seq->deliverable = false;
1238 $seq->exception = 'SB.2.2-1';
1239 $seq->nextactivity = $activity;
1240 return $seq;
1241 }
1242
1243 $rulch = scorm_seq_rules_check($sco, 'skipped');
1244 if ($rulch != null){
1245 $seq = scorm_seq_flow_tree_traversal ($activity, $direction, false, $prevdirection, $seq);//endsession and exception
1246 if ($seq->identifiedactivity == null){
1247 $seq->deliverable = false;
1248 $seq->nextactivity = $activity;
1249 return $seq;
1250 }
1251 else{
1252
1253 if ($prevdirection = 'backward' && $seq->traversaldir == 'backward'){
1254 $seq = scorm_seq_flow_tree_traversal ($activity,$direction,false,null,$seq);
1255 scorm_seq_flow_activity($seq->identifiedactivity, $userid, $direction, $childrenflag, $prevdirection, $seq);
1256 }
1257 else{
1258 $seq = scorm_seq_flow_tree_traversal ($activity,$direction,false,null,$seq);
1259 $seq = scorm_seq_flow_activity($seq->identifiedactivity, $userid, $direction, $childrenflag, $prevdirection, $seq);
1260 }
1261 return $seq;
1262 }
1263 }
1264
1265 $ch=scorm_check_activity ($activity,$userid);
1266
1267 if ($ch){
1268
1269 $seq->deliverable = false;
1270 $seq->exception = 'SB.2.2-2';
1271 $seq->nextactivity = $activity;
1272 return $seq;
1273
1274 }
1275
1276 if (!scorm_is_leaf($activity)){
1277
1278 $seq = scorm_seq_flow_tree_traversal ($activity,$direction,true,null,$seq);
1279
1280 if ($seq->identifiedactivity == null){
1281 $seq->deliverable = false;
1282 $seq->nextactivity = $activity;
1283 return $seq;
1284 }
1285
1286 else{
1287 if($direction == 'backward' && $seq->traversaldir == 'forward'){
1288 $seq = scorm_seq_flow_activity($seq->identifiedactivity, $userid, 'forward', $childrenflag, 'backward', $seq);
1289 }
1290 else{
1291 scorm_seq_flow_activity($seq->identifiedactivity, $userid, $direction, $childrenflag, null, $seq);
1292 }
1293 return $seq;
1294 }
1295
1296 }
1297
1298 $seq->deliverable = true;
1299 $seq->nextactivity = $activity;
1300 return $seq;
1301
1302}
1303function scorm_seq_flow_tree_traversal ($activity,$direction,$childrenflag,$prevdirection,$seq){
1304
1305 $revdirection = false;
1306 $parent = scorm_get_parent ($activity);
1307 $children = scorm_get_children ($parent);
1308 $siz = sizeof ($children);
1309
1310 if (($prevdirection != null && $prevdirection == 'backward') && ($children[$siz-1]->id == $activity->id)){
1311 $direction = 'backward';
1312 $children[0] = $activity;
1313 $revdirection = true;
1314 }
1315
1316 if($direction = 'forward'){
1317 $ancestors = scorm_get_ancestors($activity);
1318 $ancestorsroot = array_reverse($ancestors);
1319 $preorder = scorm_get_preorder ($ancestorsroot);
1320 $siz= sizeof ($preorder);
1321 if (($activity->id == $preorder[$siz-1]->id) || (($activity->parent == '/') && !($childrenflag))){
1322 scorm_seq_terminate_descent($ancestorsroot);
1323 $seq->endsession = true;
1324 $seq->nextactivity = null;
1325 return $seq;
1326 }
1327 if (scorm_is_leaf ($activity) || !$childrenflag){
1328 if ($children[$siz-1]->id == $activity->id){
1329
1330 $seq = scorm_seq_flow_tree_traversal ($parent, $direction, false, null, $seq);
1331 // I think it's not necessary to do a return in here
1332 }
1333 else{
1334 $parent = scorm_get_parent($activity);
1335 $children = scorm_get_children($parent);
1336 $seq->traversaldir = $direction;
f3800343 1337 $sib = scorm_get_siblings($activity);
13458883 1338 $pos = array_search($sib, $activity);
1339 if ($pos !== false) {
1340 if ($pos != sizeof ($sib)){
1341 $seq->nextactivity = $sib [$pos+1];
1342 return $seq;
1343 }
1344 else{
1345 $ch = scorm_get_children($sib[0]);
1346 $seq->nextactivity = $ch[0];
1347 return $seq;
1348 }
1349 }
1350 }
1351 }
1352 else{
1353 if (!empty ($children)){
1354 $seq->traversaldir = $direction;
1355 $seq->nextactivity = $children[0];
1356 return $seq;
1357 }
1358 else{
1359 $seq->traversaldir = null;
1360 $seq->nextactivity = $children[0];
1361 $seq->exception = 'SB.2.1-2';
1362 return $seq;
1363 }
1364 }
1365
1366 }
1367 if($direction = 'backward'){
1368
1369 if ($activity->parent == '/'){
1370 $seq->traversaldir = null;
1371 $seq->nextactivity = null;
1372 $seq->exception = 'SB.2.1-3';
1373 }
1374 if (scorm_is_leaf ($activity) || !$childrenflag){
1375 if (!$revdirection){
1376 if (isset($parent->forwardonly) && ($parent->forwardonly == true)) {
1377 $seq->traversaldir = null;
1378 $seq->nextactivity = null;
1379 $seq->exception = 'SB.2.1-4';
1380 return $seq;
1381 }
1382 }
1383 if ($children[0]->id == $activity->id){
1384 $seq = scorm_seq_flow_tree_traversal ($parent, 'backward', false, null, $seq);
1385 return $seq;
1386 }
1387 else{
1388 $ancestors = scorm_get_ancestors($activity);
1389 $ancestorsroot = array_reverse ($ancestors);
1390 $preorder = scorm_get_preorder ($ancestorsroot);
1391 $pos = array_search($preorder, $children[$siz]);
1392 $preord = array_slice($preorder, 0, $pos-1);
1393 $revpreorder = array_reverse($preord);
1394 $position = array_search($revpreorder, $activity);
1395 $seq->nextactivity = $revpreorder[$pos+1];
1396 $seq->traversaldir = $direction;
1397 return $seq;
1398 }
1399 }
1400 else{
b186cb9d 1401 if (!empty($children)){
13458883 1402 $activity = scorm_get_sco($activity->id);
1403 if (!isset($parent->flow) || ($parent->flow == true)) {
1404 $children = scorm_get_children ($activity);
1405 $seq->traversaldir = 'forward';
1406 $seq->nextactivity = $children[0];
1407 return $seq;
1408
1409 }
1410 else{
1411 $children = scorm_get_children ($activity);
1412 $seq->traversaldir = 'backward';
1413 $seq->nextactivity = $children[sizeof($children)-1];
1414 return $seq;
1415 }
1416
1417 }
1418 else{
1419
1420 $seq->traversaldir = null;
1421 $seq->nextactivity = null;
1422 $seq->exception = 'SB.2.1-2';
b186cb9d 1423 return $seq;
13458883 1424 }
1425 }
1426
1427 }
1428
1429
1430}
1431function scorm_check_activity ($activity,$userid){
1432 $act = scorm_seq_rules_check($activity,'disabled');
1433 if ($act != null){
1434 return true;
1435 }
1436 if(scorm_limit_cond_check ($activity,$userid)){
1437 return true;
1438 }
1439 return false;
1440
1441
1442}
1443
1444function scorm_limit_cond_check ($activity,$userid){
1445
1446 if (isset($activity->tracked) && ($activity->tracked == 0)){
1447
1448 return false;
1449 }
1450
1451 if (scorm_seq_is('active',$activity->id,$userid) || scorm_seq_is('suspended',$activity->id,$userid)){
1452 return false;
1453 }
1454
1455 if (!isset($activity->limitcontrol) || ($activity->limitcontrol == 1)){
1456 $r = get_record('scorm_scoes_track','scoid',$activity->id,'userid',$userid,'element','activityattemptcount');
f3800343 1457 if (scorm_seq_is('activityprogressstatus',$activity->id,$userid) && ($r->value >=$activity->limitattempt)){
13458883 1458 return true;
1459 }
1460 }
1461
1462 if (!isset($activity->limitabsdurcontrol) || ($activity->limitabsdurcontrol == 1)){
1463 $r = get_record('scorm_scoes_track','scoid',$activity->id,'userid',$userid,'element','activityabsoluteduration');
f3800343 1464 if (scorm_seq_is('activityprogressstatus',$activity->id,$userid) && ($r->value >=$activity->limitabsduration)){
13458883 1465 return true;
1466 }
1467 }
1468
1469 if (!isset($activity->limitexpdurcontrol) || ($activity->limitexpdurcontrol == 1)){
1470 $r = get_record('scorm_scoes_track','scoid',$activity->id,'userid',$userid,'element','activityexperiencedduration');
f3800343 1471 if (scorm_seq_is('activityprogressstatus',$activity->id,$userid) && ($r->value >=$activity->limitexpduration)){
13458883 1472 return true;
1473 }
1474 }
1475
1476 if (!isset($activity->limitattabsdurcontrol) || ($activity->limitattabsdurcontrol == 1)){
1477 $r = get_record('scorm_scoes_track','scoid',$activity->id,'userid',$userid,'element','attemptabsoluteduration');
f3800343 1478 if (scorm_seq_is('activityprogressstatus',$activity->id,$userid) && ($r->value >=$activity->limitattabsduration)){
13458883 1479 return true;
1480 }
1481 }
1482
1483 if (!isset($activity->limitattexpdurcontrol) || ($activity->limitattexpdurcontrol == 1)){
1484 $r = get_record('scorm_scoes_track','scoid',$activity->id,'userid',$userid,'element','attemptexperiencedduration');
f3800343 1485 if (scorm_seq_is('activityprogressstatus',$activity->id,$userid) && ($r->value >=$activity->limitattexpduration)){
13458883 1486 return true;
1487 }
1488 }
1489
1490 if (!isset($activity->limitbegincontrol) || ($activity->limitbegincontrol == 1)){
1491 $r = get_record('scorm_scoes_track','scoid',$activity->id,'userid',$userid,'element','begintime');
1492 if (time()>=$activity->limitbegintime){
1493 return true;
1494 }
1495 }
1496
1497 if (!isset($activity->limitbegincontrol) || ($activity->limitbegincontrol == 1)){
1498 if (time()<$activity->limitbegintime){
1499 return true;
1500 }
1501 }
1502
1503 if (!isset($activity->limitendcontrol) || ($activity->limitendcontrol == 1)){
1504
1505 if (time()>$activity->limitendtime){
1506 return true;
1507 }
1508 }
1509 return false;
1510
1511
f3800343 1512}
1513
1514
1515function scorm_seq_choice_sequencing($sco,$userid,$seq){
1516
1517 $avchildren = Array ();
1518 $comancestor = null;
1519 $traverse = null;
1520
1521 if ($sco == null){
1522 $seq->delivery = null;
1523 $seq->exception = 'SB.2.9-1';
b186cb9d 1524 return $seq;
f3800343 1525 }
1526
1527 $ancestors = scorm_get_ancestors($sco);
1528 $arrpath = array_reverse($ancestors);
1529 array_push ($arrpath,$sco);//path from the root to the target
1530
1531 foreach ($arrpath as $activity){
1532
1533 if ($activity->parent != '/') {
1534 $avchildren = scorm_get_available_children (scorm_get_parent($activity));
1535 $position = array_search($avchildren, $activity);
1536 if ($position !== false){
1537 $seq->delivery = null;
1538 $seq->exception = 'SB.2.9-2';
b186cb9d 1539 return $seq;
f3800343 1540 }
1541 }
1542
b186cb9d 1543 if (scorm_seq_rules_check($activity,'hidefromchoice' != null)){
f3800343 1544
1545 $seq->delivery = null;
1546 $seq->exception = 'SB.2.9-3';
b186cb9d 1547 return $seq;
f3800343 1548
1549 }
1550
1551 }
1552
1553 if ($sco->parent != '/') {
1554 $parent = scorm_sco_get_parent ($sco);
1555 if ( !get_record('scorm_scoes_track','scoid',$parentid->id,'userid',$userid,'element','sequencingcontrolchoice')){
1556 $seq->delivery = null;
1557 $seq->exception = 'SB.2.9-4';
b186cb9d 1558 return $seq;
f3800343 1559 }
1560 }
1561
1562 if ($seq->currentactivity != null){
1563 $commonpos = scorm_find_common_ancestor($ancestors,$seq->currentactivity);
1564 $comancestor = $arrpath [$commonpos];
1565 }
1566 else{
1567 $comancestor = $arrpath [0];
1568 }
1569
1570 if($seq->currentactivity === $sco) {
1571 break;
1572 }
1573
1574 $sib = scorm_get_siblings($seq->currentactivity);
1575 $pos = array_search($sib, $sco);
1576
b186cb9d 1577 if (pos !== false){
f3800343 1578
1579 $siblings = array_slice($sib, 0, $pos-1);
1580
1581 if (empty($siblings)){
1582
1583 $seq->delivery = null;
1584 $seq->exception = 'SB.2.9-5';
b186cb9d 1585 return $seq;
f3800343 1586
1587 }
1588
1589 $children = scorm_get_children (scorm_get_parent ($sco));
1590 $pos1 = array_search($children, $sco);
1591 $pos2 = array_search($seq->currentactivity, $sco);
1592 if ($pos1>$pos2){
1593 $traverse = 'forward';
1594 }
1595 else{
1596 $traverse = 'backward';
1597 }
1598
1599 foreach ($siblings as $sibling){
1600 $seq = scorm_seq_choice_activity_traversal($sibling,$userid,$seq,$traverse);
1601 if(!$seq->reachable){
1602 $seq->delivery = null;
1603 return $seq;
1604 }
1605 }
1606 break;
1607
1608 }
1609
1610 if($seq->currentactivity == null || $seq->currentactivity == $comancestor){
1611 $commonpos = scorm_find_common_ancestor($ancestors,$seq->currentactivity);
1612 $comtarget = array_slice($sib, 1,$commonpos);//path from the common ancestor to the target activity
1613 $comtarget = array_reverse($comtarget);
1614
1615 if (empty($comtarget)){
1616 $seq->delivery = null;
1617 $seq->exception = 'SB.2.9-5';
b186cb9d 1618 return $seq;
f3800343 1619 }
1620 foreach ($comtarget as $act){
1621 $seq = scorm_seq_choice_activity_traversal($act,$userid,$seq,'forward');
1622 if(!$seq->reachable){
1623 $seq->delivery = null;
1624 return $seq;
1625 }
1626
1627 if(scorm_seq_is('active',$act->id,$userid) && ($act->id != $comancestor->id && $seq->prevact)){//adlseq:can i write it like another property for the $seq object?
1628 $seq->delivery = null;
1629 $seq->exception = 'SB.2.9-6';
b186cb9d 1630 return $seq;
f3800343 1631 }
1632 }
1633 break;
1634
1635 }
1636
1637 if ($comancestor->id == $sco->id){
1638
1639 $ancestorscurrent = scorm_get_ancestors($seq->currentactivity);
1640 $possco = array_search ($ancestorscurrent, $sco);
1641 $curtarget = array_slice($ancestorscurrent,0,$possco);//path from the current activity to the target
1642
1643 if (empty($curtarget)){
1644 $seq->delivery = null;
1645 $seq->exception = 'SB.2.9-5';
b186cb9d 1646 return $seq;
f3800343 1647 }
1648 $i=0;
1649 foreach ($curtarget as $activ){
1650 $i++;
1651 if ($i != sizeof($curtarget)){
1652 if ( !get_record('scorm_scoes_track','scoid',$activ->id,'userid',$userid,'element','sequencingcontrolchoiceexit')){
1653 $seq->delivery = null;
1654 $seq->exception = 'SB.2.9-7';
b186cb9d 1655 return $seq;
f3800343 1656 }
1657 }
1658 }
1659 break;
1660 }
1661
1662 if (array_search ($ancestors, $comancestor)!== false){
1663 $ancestorscurrent = scorm_get_ancestors($seq->currentactivity);
1664 $commonpos = scorm_find_common_ancestor($ancestors,$sco);
1665 $curcommon = array_slice($ancestorscurrent,0,$commonpos-1);
1666 if(empty($curcommon)){
1667 $seq->delivery = null;
1668 $seq->exception = 'SB.2.9-5';
b186cb9d 1669 return $seq;
f3800343 1670 }
1671
1672 $constrained = null;
1673 foreach ($curcommon as $acti){
1674 if ( !get_record('scorm_scoes_track','scoid',$activ->id,'userid',$userid,'element','sequencingcontrolchoiceexit')){
1675 $seq->delivery = null;
1676 $seq->exception = 'SB.2.9-7';
b186cb9d 1677 return $seq;
f3800343 1678 }
1679 if ($constrained == null){
1680 if($seq->constrainedchoice){
1681 $constrained = $acti;//adlseq:can i write it like another property for the $seq object?
1682 }
1683 }
1684 }
1685 if ($constrained != null){
1686 $fwdir = scorm_get_preorder($constrained);
1687
1688 if(array_search ($fwdir, $sco)!== false){
1689 $traverse = 'forward';
1690 }
1691 else{
1692 $traverse = 'backward';
1693 }
1694 $seq = scorm_seq_choice_flow ($constrained, $traverse, $seq);
1695//CONTINUE 11.5.5
1696 }
1697
1698 }
1699
1700
1701
1702
13458883 1703}
1704
10fd330f 1705?>