fixed missing global
[moodle.git] / mod / scorm / datamodels / sequencinglib.php
CommitLineData
e5dd8e3b 1<?php
86996ffe 2require ($CFG->dirroot.'/mod/scorm/datamodels/scormlib.php');
10fd330f 3
4function scorm_seq_evaluate($scoid,$usertracks) {
5 return true;
6}
7
980c089b 8function scorm_seq_overall ($scoid,$userid,$request,$attempt) {
9 $seq = scorm_seq_navigation($scoid,$userid,$request,$attempt);
10fd330f 10 if ($seq->navigation) {
11 if ($seq->termination != null) {
12 $seq = scorm_seq_termination($scoid,$userid,$seq);
13 }
14 if ($seq->sequencing != null) {
6d41befd 15 $seq = scorm_seq_sequencing($scoid,$userid,$seq);
081a9b0d 16 if($seq->sequencing == 'exit'){//return the control to the LTS
17 return 'true';
18 }
10fd330f 19 }
6d41befd 20 if ($seq->delivery != null) {
21 $seq = scorm_sequencing_delivery($scoid,$userid,$seq);
081a9b0d 22 $seq = scorm_content_delivery_environment ($seq,$userid);
10fd330f 23 }
24 }
25 if ($seq->exception != null) {
6d41befd 26 $seq = scorm_sequencing_exception($seq);
10fd330f 27 }
28 return 'true';
29}
30
6d41befd 31
980c089b 32function scorm_seq_navigation ($scoid,$userid,$request,$attempt=0) {
bf347041 33 global $DB;
34
10fd330f 35 /// Sequencing structure
36 $seq = new stdClass();
37 $seq->currentactivity = scorm_get_sco($scoid);
081a9b0d 38 $seq->traversaldir = null;
39 $seq->nextactivity = null;
40 $seq->deliveryvalid = null;
41 $seq->attempt = $attempt;
e5dd8e3b 42
081a9b0d 43 $seq->identifiedactivity = null;
44 $seq->delivery = null;
45 $seq->deliverable = false;
10fd330f 46 $seq->active = scorm_seq_is('active',$scoid,$userid);
47 $seq->suspended = scorm_seq_is('suspended',$scoid,$userid);
48 $seq->navigation = null;
49 $seq->termination = null;
50 $seq->sequencing = null;
51 $seq->target = null;
081a9b0d 52 $seq->endsession = null;
10fd330f 53 $seq->exception = null;
081a9b0d 54 $seq->reachable = true;
55 $seq->prevact = true;
10fd330f 56
57 switch ($request) {
58 case 'start_':
59 if (empty($seq->currentactivity)) {
60 $seq->navigation = true;
61 $seq->sequencing = 'start';
62 } else {
63 $seq->exception = 'NB.2.1-1'; /// Sequencing session already begun
e5dd8e3b 64 }
10fd330f 65 break;
66 case 'resumeall_':
67 if (empty($seq->currentactivity)) {
bf347041 68 if ($track = $DB->get_record('scorm_scoes_track', array('scoid'=>$scoid,'userid'=>$userid,'element'=>'suspendedactivity'))) {//I think it's suspend instead of suspendedactivity
10fd330f 69 $seq->navigation = true;
70 $seq->sequencing = 'resumeall';
71 } else {
72 $seq->exception = 'NB.2.1-3'; /// No suspended activity found
73 }
74 } else {
75 $seq->exception = 'NB.2.1-1'; /// Sequencing session already begun
e5dd8e3b 76 }
10fd330f 77 break;
78 case 'continue_':
79 case 'previous_':
80 if (!empty($seq->currentactivity)) {
81 $sco = $seq->currentactivity;
82 if ($sco->parent != '/') {
83 if ($parentsco = scorm_get_parent($sco)) {
e5dd8e3b 84
081a9b0d 85 if (isset($parentsco->flow) && ($parentsco->flow == true)) {//I think it's parentsco
13458883 86 // Current activity is active !
081a9b0d 87 if (scorm_seq_is('active',$sco->id,$userid)) {
13458883 88 if ($request == 'continue_') {
89 $seq->navigation = true;
90 $seq->termination = 'exit';
91 $seq->sequencing = 'continue';
92 } else {
1536b92d 93 if (!isset($parentsco->forwardonly) || ($parentsco->forwardonly == false)) {
13458883 94 $seq->navigation = true;
95 $seq->termination = 'exit';
96 $seq->sequencing = 'previous';
97 } else {
98 $seq->exception = 'NB.2.1-5'; /// Violates control mode
99 }
100 }
081a9b0d 101 }
10fd330f 102 }
13458883 103
10fd330f 104 }
105 }
106 } else {
107 $seq->exception = 'NB.2.1-2'; /// Current activity not defined
108 }
109 break;
110 case 'forward_':
111 case 'backward_':
112 $seq->exception = 'NB.2.1-7' ; /// None to be done, behavior not defined
113 break;
114 case 'exit_':
115 case 'abandon_':
116 if (!empty($seq->currentactivity)) {
117 // Current activity is active !
118 $seq->navigation = true;
119 $seq->termination = substr($request,0,-1);
120 $seq->sequencing = 'exit';
121 } else {
122 $seq->exception = 'NB.2.1-2'; /// Current activity not defined
123 }
124 case 'exitall_':
125 case 'abandonall_':
126 case 'suspendall_':
127 if (!empty($seq->currentactivity)) {
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 break;
e5dd8e3b 135 default: /// {target=<STRING>}choice
bf347041 136 if ($targetsco = $DB->get_record('scorm_scoes', array('scorm'=>$sco->scorm,'identifier'=>$request))) {
10fd330f 137 if ($targetsco->parent != '/') {
138 $seq->target = $request;
139 } else {
140 if ($parentsco = scorm_get_parent($targetsco)) {
13458883 141 if (!isset($parentsco->choice) || ($parent->choice == true)) {
10fd330f 142 $seq->target = $request;
143 }
e5dd8e3b 144 }
10fd330f 145 }
146 if ($seq->target != null) {
147 if (empty($seq->currentactivity)) {
148 $seq->navigation = true;
149 $seq->sequencing = 'choice';
150 } else {
151 if (!$sco = scorm_get_sco($scoid)) {
152 return $seq;
153 }
154 if ($sco->parent != $target->parent) {
155 $ancestors = scorm_get_ancestors($sco);
156 $commonpos = scorm_find_common_ancestor($ancestors,$targetsco);
157 if ($commonpos !== false) {
158 if ($activitypath = array_slice($ancestors,0,$commonpos)) {
159 foreach ($activitypath as $activity) {
160 if (scorm_seq_is('active',$activity->id,$userid) && (isset($activity->choiceexit) && ($activity->choiceexit == false))) {
161 $seq->navigation = false;
162 $seq->termination = null;
163 $seq->sequencing = null;
164 $seq->target = null;
165 $seq->exception = 'NB.2.1-8'; /// Violates control mode
166 return $seq;
167 }
e5dd8e3b 168 }
10fd330f 169 } else {
170 $seq->navigation = false;
171 $seq->termination = null;
172 $seq->sequencing = null;
173 $seq->target = null;
174 $seq->exception = 'NB.2.1-9';
175 }
176 }
177 }
178 // Current activity is active !
179 $seq->navigation = true;
180 $seq->sequencing = 'choice';
181 }
182 } else {
183 $seq->exception = 'NB.2.1-10'; /// Violates control mode
184 }
185 } else {
186 $seq->exception = 'NB.2.1-11'; /// Target activity does not exists
187 }
188 break;
189 }
190 return $seq;
191}
192
13458883 193function scorm_seq_termination ($seq,$userid) {
10fd330f 194 if (empty($seq->currentactivity)) {
195 $seq->termination = false;
196 $seq->exception = 'TB.2.3-1';
197 return $seq;
198 }
199
200 $sco = $seq->currentactivity;
201
202 if ((($seq->termination == 'exit') || ($seq->termination == 'abandon')) && !$seq->active) {
203 $seq->termination = false;
204 $seq->exception = 'TB.2.3-2';
205 return $seq;
206 }
207 switch ($seq->termination) {
208 case 'exit':
980c089b 209 scorm_seq_end_attempt($sco,$userid,$seq);
10fd330f 210 $seq = scorm_seq_exit_action_rules($seq,$userid);
211 do {
13458883 212 $exit = false;// I think this is false. Originally this was true
10fd330f 213 $seq = scorm_seq_post_cond_rules($seq,$userid);
214 if ($seq->termination == 'exitparent') {
215 if ($sco->parent != '/') {
216 $sco = scorm_get_parent($sco);
217 $seq->currentactivity = $sco;
218 $seq->active = scorm_seq_is('active',$sco->id,$userid);
980c089b 219 scorm_seq_end_attempt($sco,$userid,$seq);
13458883 220 $exit = true;//I think it's true. Originally this was false
10fd330f 221 } else {
222 $seq->termination = false;
223 $seq->exception = 'TB.2.3-4';
224 return $seq;
225 }
226 }
227 } while (($exit == false) && ($seq->termination == 'exit'));
228 if ($seq->termination == 'exit') {
229 $seq->termination = true;
230 return $seq;
231 }
232 case 'exitall':
233 if ($seq->active) {
980c089b 234 scorm_seq_end_attempt($sco,$userid,$seq);
10fd330f 235 }
236 /// Terminate Descendent Attempts Process
13458883 237
e5dd8e3b
PS
238
239 if ($ancestors = scorm_get_ancestors($sco)) {
10fd330f 240 foreach ($ancestors as $ancestor) {
980c089b 241 scorm_seq_end_attempt($ancestor,$userid,$seq);
10fd330f 242 $seq->currentactivity = $ancestor;
243 }
244 }
13458883 245
10fd330f 246 $seq->active = scorm_seq_is('active',$seq->currentactivity->id,$userid);
247 $seq->termination = true;
081a9b0d 248 $seq->sequencing = exit;
10fd330f 249 break;
250 case 'suspendall':
251 if (($seq->active) || ($seq->suspended)) {
252 scorm_seq_set('suspended',$sco->id,$userid);
253 } else {
254 if ($sco->parent != '/') {
255 $parentsco = scorm_get_parent($sco);
256 scorm_seq_set('suspended',$parentsco->id,$userid);
257 } else {
258 $seq->termination = false;
259 $seq->exception = 'TB.2.3-3';
260 // return $seq;
261 }
262 }
e5dd8e3b 263 if ($ancestors = scorm_get_ancestors($sco)) {
10fd330f 264 foreach ($ancestors as $ancestor) {
f3800343 265 scorm_seq_set('active',$ancestor->id,$userid,false);
10fd330f 266 scorm_seq_set('suspended',$ancestor->id,$userid);
267 $seq->currentactivity = $ancestor;
268 }
269 $seq->termination = true;
270 $seq->sequencing = 'exit';
271 } else {
272 $seq->termination = false;
273 $seq->exception = 'TB.2.3-5';
274 }
275 break;
276 case 'abandon':
f3800343 277 scorm_seq_set('active',$sco->id,$userid,false);
10fd330f 278 $seq->active = null;
279 $seq->termination = true;
280 break;
281 case 'abandonall':
e5dd8e3b 282 if ($ancestors = scorm_get_ancestors($sco)) {
10fd330f 283 foreach ($ancestors as $ancestor) {
f3800343 284 scorm_seq_set('active',$ancestor->id,$userid,false);
10fd330f 285 $seq->currentactivity = $ancestor;
286 }
287 $seq->termination = true;
288 $seq->sequencing = 'exit';
289 } else {
290 $seq->termination = false;
291 $seq->exception = 'TB.2.3-6';
292 }
293 break;
294 default:
295 $seq->termination = false;
296 $seq->exception = 'TB.2.3-7';
297 break;
298 }
299 return $seq;
300}
301
980c089b 302function scorm_seq_end_attempt($sco,$userid,$seq) {
bf347041 303 global $DB;
304
10fd330f 305 if (scorm_is_leaf($sco)) {
306 if (!isset($sco->tracked) || ($sco->tracked == 1)) {
307 if (!scorm_seq_is('suspended',$sco->id,$userid)) {
308 if (!isset($sco->completionsetbycontent) || ($sco->completionsetbycontent == 0)) {
980c089b 309 if (!scorm_seq_is('attemptprogressstatus',$sco->id,$userid,$seq->attempt)) {
e5dd8e3b 310 // if (!scorm_seq_is('attemptprogressstatus',$sco->id,$userid)) {
f3800343 311 scorm_seq_set('attemptprogressstatus',$sco->id,$userid);
312 scorm_seq_set('attemptcompletionstatus',$sco->id,$userid);
10fd330f 313 }
314 }
315 if (!isset($sco->objectivesetbycontent) || ($sco->objectivesetbycontent == 0)) {
bf347041 316 if ($objectives = $DB->get_records('scorm_seq_objective', array('scoid'=>$sco->id))) {
10fd330f 317 foreach ($objectives as $objective) {
6d41befd 318 if ($objective->primaryobj) {
319 //if (!scorm_seq_objective_progress_status($sco,$userid,$objective)) {
980c089b 320 if (!scorm_seq_is('objectiveprogressstatus',$sco->id,$userid)) {
f3800343 321 scorm_seq_set('objectiveprogressstatus',$sco->id,$userid);
322 scorm_seq_set('objectivesatisfiedstatus',$sco->id,$userid);
10fd330f 323 }
324 }
325 }
326 }
327 }
328 }
329 }
330 } else {
331 if ($children = scorm_get_children($sco)) {
332 $suspended = false;
333 foreach ($children as $child) {
334 if (scorm_seq_is('suspended',$child,$userid)) {
335 $suspended = true;
336 break;
337 }
338 }
339 if ($suspended) {
340 scorm_seq_set('suspended',$sco,$userid);
e5dd8e3b 341 } else {
f3800343 342 scorm_seq_set('suspended',$sco,$userid,false);
10fd330f 343 }
344 }
345 }
346 scorm_seq_set('active',$sco,$userid,0,false);
347 scorm_seq_overall_rollup($sco,$userid);
348}
349
980c089b 350function scorm_seq_is($what, $scoid, $userid, $attempt=0) {
bf347041 351 global $DB;
980c089b 352
10fd330f 353 /// Check if passed activity $what is active
354 $active = false;
bf347041 355 if ($track = $DB->get_record('scorm_scoes_track', array('scoid'=>$scoid,'userid'=>$userid,'attempt'=>$attempt,'element'=>$what))) {
10fd330f 356 $active = true;
357 }
358 return $active;
359}
360
980c089b 361function scorm_seq_set($what, $scoid, $userid, $attempt=0, $value='true') {
bf347041 362 global $DB;
363
531fa830 364 $sco = scorm_get_sco($scoid);
980c089b 365
10fd330f 366 /// set passed activity to active or not
367 if ($value == false) {
bf347041 368 $DB->delete_record('scorm_scoes_track', array('scoid'=>$scoid,'userid'=>$userid,'attempt'=>$attempt,'element'=>$what));
10fd330f 369 } else {
10fd330f 370 scorm_insert_track($userid, $sco->scorm, $sco->id, 0, $what, $value);
371 }
531fa830 372
373 // update grades in gradebook
bf347041 374 $scorm = $DB->get_record('scorm', array('id'=>$sco->scorm));
531fa830 375 scorm_update_grades($scorm, $userid, true);
10fd330f 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) {
e5dd8e3b
PS
389 $commons = array_slice($ancestors,0,scorm_find_common_ancestor($ancestors,$exittarget));
390
10fd330f 391 /// Terminate Descendent Attempts Process
e5dd8e3b 392 if ($commons) {
10fd330f 393 foreach ($commons as $ancestor) {
e5dd8e3b 394
980c089b 395 scorm_seq_end_attempt($ancestor,$userid,$seq->attempt);
10fd330f 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){
bf347041 428 global $DB;
429
081a9b0d 430 $act = null;
431 if($rules = $DB->get_records('scorm_seq_ruleconds', array('scoid'=>$sco->id,'action'=>$action))) {
432 foreach ($rules as $rule){
433 if($act = scorm_seq_rule_check($sco,$rule)){
434 return $act;
435 }
436 }
437 }
438 return $act;
13458883 439
440}
441
442function scorm_seq_rule_check ($sco, $rule){
bf347041 443 global $DB;
444
081a9b0d 445 $bag = Array();
446 $cond = '';
447 $ruleconds = $DB->get_records('scorm_seq_rulecond', array('scoid'=>$sco->id,'ruleconditionsid'=>$rule->id));
448 foreach ($ruleconds as $rulecond){
449 if ($rulecond->operator = 'not') {
450 if ($rulecond->cond != 'unknown' ){
451 $rulecond->cond = 'not'.$rulecond;
452 }
453 }
454 $bag [$rule->id] = $rulecond->cond;
e5dd8e3b 455
081a9b0d 456 }
457 if (empty($bag)){
458 $cond = 'unknown';
459 return $cond;
460 }
461
462 $size= sizeof($bag);
463 $i=0;
464
465 if ($rule->conditioncombination = 'all'){
466 foreach ($bag as $con){
467 $cond = $cond.' and '.$con;
e5dd8e3b 468
081a9b0d 469 }
470 }
471 else{
472 foreach ($bag as $con){
473 $cond = $cond.' or '.$con;
474 }
475 }
476 return $cond;
13458883 477}
478
479
480function scorm_seq_overall_rollup($sco,$userid){//Carlos
481
e5dd8e3b 482 if ($ancestors = scorm_get_ancestors($sco)) {
13458883 483 foreach ($ancestors as $ancestor) {
081a9b0d 484 if(!scorm_is_leaf($ancestor)){
485 scorm_seq_measure_rollup($sco,$userid);
486 }
487 scorm_seq_objective_rollup($sco,$userid);
488 scorm_seq_activity_progress_rollup($sco,$userid);
13458883 489
490 }
491
e5dd8e3b 492 }
13458883 493}
494
495/* For this next function I have defined measure weight and measure status as records with the attempt = 0 on the scorm_scoes_track table. According to the page 89 of the SeqNav.pdf those datas give us some information about the progress of the objective*/
496
497function scorm_seq_measure_rollup($sco,$userid){
ae256fac 498 global $DB;
13458883 499
081a9b0d 500 $totalmeasure = 0; //Check if there is something similar in the database
501 $valid = false;//Same as in the last line
502 $countedmeasures = 0;//Same too
503 $targetobjective = null;
504 $readable = true;//to check if status and measure weight are readable
505 $objectives = $DB->get_records('scorm_seq_objective', array('scoid'=>$sco->id));
13458883 506
bf347041 507 foreach ($objectives as $objective){
13458883 508
e5dd8e3b 509 if ($objective->primaryobj == true){//Objective contributes to rollup I'm using primaryobj field, but not
081a9b0d 510 $targetobjective = $objective;
511 break;
512 }
13458883 513
081a9b0d 514 }
13458883 515
081a9b0d 516 if ($targetobjective != null){
517 $children = scorm_get_children($sco);
13458883 518 foreach ($children as $child){
081a9b0d 519 $child = scorm_get_sco ($child);
520 if (!isset($child->tracked) || ($child->tracked == 1)){
e5dd8e3b 521
081a9b0d 522 $rolledupobjective = null;// we set the rolled up activity to undefined
523 $objectives = $DB->get_records('scorm_seq_objective', array('scoid'=>$child->id));
bf347041 524 foreach ($objectives as $objective){
e5dd8e3b 525 if ($objective->primaryobj == true){//Objective contributes to rollup I'm using primaryobj field, but not
081a9b0d 526 $rolledupobjective = $objective;
527 break;
528 }
529 }
530 if ($rolledupobjective != null){
af8ed6dc 531 $child = scorm_get_sco($child->id);
e5dd8e3b 532
081a9b0d 533 $countedmeasures = $countedmeasures + ($child->measureweight);
534 if (!scorm_seq_is('objectivemeasurestatus',$sco->id,$userid)) {
535 $normalizedmeasure = $DB->get_record('scorm_scoes_track', array('scoid'=>$child->id,'userid'=>$userid,'element'=>'objectivenormalizedmeasure'));
536 $totalmeasure = $totalmeasure + (($normalizedmeasure->value) * ($child->measureweight));
537 $valid = true;
538 }
539
e5dd8e3b
PS
540
541
081a9b0d 542 }
543 }
544 }
545
e5dd8e3b 546
081a9b0d 547 if(!$valid){
548
549 scorm_seq_set('objectivemeasurestatus',$sco->id,$userid,false);
550
551 }
552 else{
553 if($countedmeasures>0){
554 scorm_seq_set('objectivemeasurestatus',$sco->id,$userid);
555 $val=$totalmeasure/$countedmeasures;
556 scorm_seq_set('objectivenormalizedmeasure',$sco->id,$userid,$val);
e5dd8e3b 557
081a9b0d 558 }
559 else{
560 scorm_seq_set('objectivemeasurestatus',$sco->id,$userid,false);
e5dd8e3b 561
081a9b0d 562 }
563 }
564
565 }
e5dd8e3b 566
13458883 567}
568
1536b92d 569function scorm_seq_objective_rollup($sco,$userid){
bf347041 570 global $DB;
e5dd8e3b 571
33cf55bf 572 scorm_seq_objective_rollup_measure($sco,$userid);
573 scorm_seq_objective_rollup_rules($sco,$userid);
574 scorm_seq_objective_rollup_default($sco,$userid);
1536b92d 575
33cf55bf 576/*
081a9b0d 577 if($targetobjective->satisfiedbymeasure){
578 scorm_seq_objective_rollup_measure($sco,$userid);
579 }
580 else{
581 if ((scorm_seq_rollup_rule_check($sco,$userid,'incomplete'))|| (scorm_seq_rollup_rule_check($sco,$userid,'completed'))){
582 scorm_seq_objective_rollup_rules($sco,$userid);
583 }
584 else{
1536b92d 585
bf347041 586 $rolluprules = $DB->get_record('scorm_seq_rolluprule', array('scoid'=>$sco->id,'userid'=>$userid));
1536b92d 587 foreach($rolluprules as $rolluprule){
bf347041 588 $rollupruleconds = $DB->get_records('scorm_seq_rolluprulecond', array('rollupruleid'=>$rolluprule->id));
081a9b0d 589 foreach($rollupruleconds as $rolluprulecond){
e5dd8e3b 590
1536b92d 591 switch ($rolluprulecond->cond!='satisfied' && $rolluprulecond->cond!='completed' && $rolluprulecond->cond!='attempted'){
e5dd8e3b 592
081a9b0d 593 scorm_seq_set('objectivesatisfiedstatus',$sco->id,$userid, false);
1536b92d 594
081a9b0d 595 break;
596 }
597 }
1536b92d 598
e5dd8e3b 599
081a9b0d 600 }
601 }
e5dd8e3b 602*/
1536b92d 603}
604
13458883 605function scorm_seq_objective_rollup_measure($sco,$userid){
bf347041 606 global $DB;
607
081a9b0d 608 $targetobjective = null;
e5dd8e3b 609
13458883 610
081a9b0d 611 $objectives = $DB->get_records('scorm_seq_objective', array('scoid'=>$sco->id));
f3800343 612 foreach ($objectives as $objective){
081a9b0d 613 if ($objective->primaryobj == true){
614 $targetobjective = $objective;
615 break;
616 }
617 }
618 if ($targetobjective != null){
13458883 619
081a9b0d 620 if($targetobjective->satisfiedbymeasure){
13458883 621
e5dd8e3b 622
980c089b 623 if (!scorm_seq_is('objectiveprogressstatus',$sco->id,$userid)) {
13458883 624
f3800343 625 scorm_seq_set('objectiveprogressstatus',$sco->id,$userid,false);
e5dd8e3b 626
13458883 627 }
628
081a9b0d 629 else{
630 if (scorm_seq_is('active',$sco->id,$userid)) {
631 $isactive = true;
632 }
633 else{
634 $isactive = false;
635 }
636
637 $normalizedmeasure = $DB->get_record('scorm_scoes_track', array('scoid'=>$sco->id,'userid'=>$userid,'element'=>'objectivenormalizedmeasure'));
638
639 $sco = scorm_get_sco ($sco->id);
640
641 if (!$isactive || ($isactive && (!isset($sco->measuresatisfactionifactive) || $sco->measuresatisfactionifactive == true))){
642 if($normalizedmeasure->value >= $targetobjective->minnormalizedmeasure){
643 scorm_seq_set('objectiveprogressstatus',$sco->id,$userid);
644 scorm_seq_set('objectivesatisfiedstatus',$sco->id,$userid);
645 }
646 else{
647 scorm_seq_set('objectiveprogressstatus',$sco->id,$userid);
648 scorm_seq_set('objectivesatisfiedstatus',$sco->id,$userid,false);
649 }
650 }
651 else{
652
653 scorm_seq_set('objectiveprogressstatus',$sco->id,$userid,false);
e5dd8e3b 654
081a9b0d 655 }
656 }
657 }
658 }
13458883 659
660}
661
33cf55bf 662function scorm_seq_objective_rollup_default($sco,$userid){
bf347041 663 global $DB;
664
081a9b0d 665 if (!(scorm_seq_rollup_rule_check($sco,$userid,'incomplete')) && !(scorm_seq_rollup_rule_check($sco,$userid,'completed'))){
e5dd8e3b 666
bf347041 667 $rolluprules = $DB->get_record('scorm_seq_rolluprule', array('scoid'=>$sco->id,'userid'=>$userid));
33cf55bf 668 foreach($rolluprules as $rolluprule){
bf347041 669 $rollupruleconds = $DB->get_records('scorm_seq_rolluprulecond', array('rollupruleid'=>$rolluprule->id));
081a9b0d 670 foreach($rollupruleconds as $rolluprulecond){
e5dd8e3b 671
7de38ebf 672 if ($rolluprulecond->cond!='satisfied' && $rolluprulecond->cond!='completed' && $rolluprulecond->cond!='attempted'){
e5dd8e3b 673
081a9b0d 674 scorm_seq_set('objectivesatisfiedstatus',$sco->id,$userid, false);
33cf55bf 675
081a9b0d 676 break;
677 }
678 }
33cf55bf 679
e5dd8e3b 680
33cf55bf 681 }
081a9b0d 682 }
e5dd8e3b 683
33cf55bf 684}
685
13458883 686
687function scorm_seq_objective_rollup_rules($sco,$userid){
bf347041 688 global $DB;
689
081a9b0d 690 $targetobjective = null;
13458883 691
081a9b0d 692 $objectives = $DB->get_records('scorm_seq_objective', array('scoid'=>$sco->id));
bf347041 693 foreach ($objectives as $objective){
e5dd8e3b 694 if ($objective->primaryobj == true){//Objective contributes to rollup I'm using primaryobj field, but not
081a9b0d 695 $targetobjective = $objective;
696 break;
697 }
698 }
699 if ($targetobjective != null){
13458883 700
e5dd8e3b 701
13458883 702
081a9b0d 703 if(scorm_seq_rollup_rule_check($sco,$userid,'notsatisfied')){//with not satisfied rollup for the activity
13458883 704
e5dd8e3b 705
081a9b0d 706 scorm_seq_set('objectiveprogressstatus',$sco->id,$userid);
707 scorm_seq_set('objectivesatisfiedstatus',$sco->id,$userid,false);
708 }
709 if(scorm_seq_rollup_rule_check($sco,$userid,'satisfied')){//with satisfied rollup for the activity
710 scorm_seq_set('objectiveprogressstatus',$sco->id,$userid);
711 scorm_seq_set('objectivesatisfiedstatus',$sco->id,$userid);
712 }
13458883 713
081a9b0d 714 }
13458883 715
716}
717
718function scorm_seq_activity_progress_rollup ($sco, $userid){
719
081a9b0d 720 if(scorm_seq_rollup_rule_check($sco,$userid,'incomplete')){
721 //incomplete rollup action
722 scorm_seq_set('attemptcompletionstatus',$sco->id,$userid,false,$seq->attempt);
723 scorm_seq_set('attemptprogressstatus',$sco->id,$userid,true,$seq->attempt);
13458883 724
081a9b0d 725 }
13458883 726 if(scorm_seq_rollup_rule_check($sco,$userid,'completed')){
081a9b0d 727 //incomplete rollup action
728 scorm_seq_set('attemptcompletionstatus',$sco->id,true,$userid);
729 scorm_seq_set('attemptprogressstatus',$sco->id,true,$userid);
730 }
13458883 731
732}
733
734function scorm_seq_rollup_rule_check ($sco,$userid,$action){
bf347041 735 global $DB;
13458883 736
081a9b0d 737 if($rolluprules = $DB->get_record('scorm_seq_rolluprule', array('scoid'=>$sco->id,'userid'=>$userid,'action'=>$action))) {
13458883 738
739 $childrenbag = Array ();
081a9b0d 740 $children = scorm_get_children ($sco);
13458883 741
081a9b0d 742 foreach($rolluprules as $rolluprule){
13458883 743
081a9b0d 744 foreach ($children as $child){
13458883 745
081a9b0d 746 /*$tracked = $DB->get_records('scorm_scoes_track', array('scoid'=>$child->id,'userid'=>$userid));
747 if($tracked && $tracked->attemp != 0){*/
748 $child = scorm_get_sco ($child);
749 if (!isset($child->tracked) || ($child->tracked == 1)){
13458883 750
081a9b0d 751 if(scorm_seq_check_child ($child,$action,$userid)){
13458883 752
bf347041 753 $rollupruleconds = $DB->get_records('scorm_seq_rolluprulecond', array('rollupruleid'=>$rolluprule->id));
081a9b0d 754 $evaluate = scorm_seq_evaluate_rollupcond($child,$rolluprule->conditioncombination,$rollupruleconds,$userid);
755 if ($evaluate=='unknown'){
756 array_push($childrenbag,'unknown');
757 }
758 else{
759 if($evaluate == true){
760 array_push($childrenbag,true);
761 }
762 else{
763 array_push($childrenbag,false);
764 }
765 }
766 }
767 }
e5dd8e3b 768
081a9b0d 769 }
770 $change = false;
771
772 switch ($rolluprule->childactivityset){
773
774 case 'all':
775 if((array_search(false,$childrenbag)===false)&&(array_search('unknown',$childrenbag)===false)){//I think I can use this condition instead equivalent to OR
776 $change = true;
777 }
778 break;
779
780 case 'any':
781 if(array_search(true,$childrenbag)!==false){//I think I can use this condition instead equivalent to OR
782 $change = true;
783 }
784 break;
785
786 case 'none':
787 if((array_search(true,$childrenbag)===false)&&(array_search('unknown',$childrenbag)===false)){//I think I can use this condition instead equivalent to OR
788 $change = true;
789 }
790 break;
791
792 case 'atleastcount':
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++;
797 }
798 if($cont >= $roullprule->minimumcount){
799 $change = true;
800 }
801 }
802 break;
803
804 case 'atleastcount':
805 foreach ($childrenbag as $itm){//I think I can use this condition instead equivalent to OR
806 $cont = 0;
807 if($itm === true){
808 $cont++;
809 }
810 if($cont >= $roullprule->minimumcount){
811 $change = true;
812 }
813 }
814 break;
815
816 case 'atleastpercent':
817 foreach ($childrenbag as $itm){//I think I can use this condition instead equivalent to OR
818 $cont = 0;
819 if($itm === true){
820 $cont++;
821 }
822 if(($cont/sizeof($childrenbag)) >= $roullprule->minimumcount){
823 $change = true;
824 }
825 }
826 break;
827 }
828 if ($change==true){
829 return true;
830 }
831 }
832 }
833 return false;
13458883 834}
835
836
837function scorm_seq_evaluate_rollupcond($sco,$conditioncombination,$rollupruleconds,$userid){
081a9b0d 838 $bag = Array();
13458883 839 $con = "";
081a9b0d 840 $val = false;
841 $unk = false;
13458883 842 foreach($rollupruleconds as $rolluprulecond){
843
081a9b0d 844 $condit = scorm_evaluate_cond($rolluprulecond,$sco,$userid);
845
846 if($rule->operator=='not'){// If operator is not, negate the condition
e5dd8e3b 847 if ($rule->cond != 'unknown'){
081a9b0d 848 if ($condit){
849 $condit = false;
850 }
851 else{
852 $condit = true;
853 }
854 }
855 else{
856 $condit = 'unknown';
857 }
858 array_push($childrenbag,$condit);
859 }
860
861 }
862 if (empty($bag)){
863 return 'unknown';
864 }
865 else{
866 $i = 0;
867 foreach ($bag as $b){
868
869 if ($rolluprule->conditioncombination == 'all'){
870
871 $val = true;
872 if($b == 'unknown'){
873 $unk = true;
874 }
875 if($b === false){
876 return false;
877 }
878 }
879
880 else{
13458883 881
882 $val = false;
e5dd8e3b 883
081a9b0d 884 if($b == 'unknown'){
885 $unk = true;
886 }
887 if($b === true){
888 return true;
889 }
890 }
891
892
893 }
894 }
895 if ($unk){
896 return 'unknown';
897 }
898 return $val;
13458883 899
900}
901
902function scorm_evaluate_condition ($rolluprulecond,$sco,$userid){
bf347041 903 global $DB;
e5dd8e3b 904
081a9b0d 905 $res = false;
13458883 906
907 switch ($rolluprulecond->cond){
e5dd8e3b 908
081a9b0d 909 case 'satisfied':
910 if($r=$DB->get_record('scorm_scoes_track', array('scoid'=>$sco->id,'userid'=>$userid,'element'=>'objectivesatisfiedstatus'))) {
911 if($r->value == true){
912 if ($r=$DB->get_record('scorm_scoes_track', array('scoid'=>$sco->id,'userid'=>$userid,'element'=>'objectiveprogressstatus'))) {
913 if($r->value == true){
914 $res= true;
915 }
916 }
917 }
918 }
919 break;
920
921 case 'objectiveStatusKnown':
bf347041 922 if ($r=$DB->get_record('scorm_scoes_track', array('scoid'=>$sco->id,'userid'=>$userid,'element'=>'objectiveprogressstatus'))) {
081a9b0d 923 if($r->value == true){
924 $res= true;
925 }
926 }
927 break;
928
929 case 'objectiveMeasureKnown':
930 if ($r = $DB->get_record('scorm_scoes_track', array('scoid'=>$sco->id,'userid'=>$userid,'element'=>'objectivemeasurestatus'))) {
931 if($r->value == true){
932 $res = true;
933 }
e5dd8e3b 934
081a9b0d 935 }
936
937 break;
938
939 case 'completed':
940 if ($r = $DB->get_record('scorm_scoes_track', array('scoid'=>$sco->id,'userid'=>$userid,'element'=>'attemptcompletionstatus'))) {
941 if($r->value){
942 if ($r = $DB->get_record('scorm_scoes_track', array('scoid'=>$sco->id,'userid'=>$userid,'element'=>'attemptprogressstatus'))) {
943 if($r->value){
944 $res = true;
945 }
e5dd8e3b 946
081a9b0d 947 }
948 }
e5dd8e3b 949
081a9b0d 950 }
951 break;
952
953 case 'attempted':
954 if ($r = $DB->get_record('scorm_scoes_track', array('scoid'=>$sco->id,'userid'=>$userid,'element'=>'activityprogressstatus'))) {
955 if($r->value){
956 if ($r = $DB->get_record('scorm_scoes_track', array('scoid'=>$sco->id,'userid'=>$userid,'element'=>'activityattemptcount'))) {
957 if($r->value > 0){
958 $res = true;
959 }
e5dd8e3b 960
081a9b0d 961 }
962 }
e5dd8e3b 963
081a9b0d 964 }
965 break;
e5dd8e3b 966
081a9b0d 967
968 case 'attemptLimitExceeded':
969 if ($r = $DB->get_record('scorm_scoes_track', array('scoid'=>$sco->id,'userid'=>$userid,'element'=>'activityprogressstatus'))) {
970 if($r->value){
971 if ($r = $DB->get_record('scorm_scoes_track', array('scoid'=>$sco->id,'userid'=>$userid,'element'=>'limitconditionattemptlimitcontrol'))) {
972 if($r->value){
973 if ($r = $DB->get_record('scorm_scoes_track', array('scoid'=>$sco->id,'userid'=>$userid,'element'=>'activityattemptcount')) && $r2 = $DB->get_record('scorm_scoes_track', array('scoid'=>$sco->id,'userid'=>$userid,'element'=>'limitconditionattemptlimit')) ){
974 if($r->value >= $r2->value){
975 $res = true;
976 }
e5dd8e3b 977
081a9b0d 978 }
e5dd8e3b 979
081a9b0d 980 }
e5dd8e3b 981
081a9b0d 982 }
e5dd8e3b 983
081a9b0d 984 }
e5dd8e3b 985
081a9b0d 986 }
e5dd8e3b 987
081a9b0d 988 break;
989
990 case 'activityProgressKnown':
991
992 if ($r = $DB->get_record('scorm_scoes_track', array('scoid'=>$sco->id,'userid'=>$userid,'element'=>'activityprogressstatus'))) {
993 if($r->value){
994 if ($r = $DB->get_record('scorm_scoes_track', array('scoid'=>$sco->id,'userid'=>$userid,'element'=>'attemptprogressstatus'))) {
995 if($r->value){
996 $res = true;
997 }
e5dd8e3b 998
081a9b0d 999 }
e5dd8e3b 1000
081a9b0d 1001 }
e5dd8e3b 1002
081a9b0d 1003 }
e5dd8e3b 1004
081a9b0d 1005 break;
1006 }
1007 return $res;
13458883 1008
1009}
1010
1011function scorm_seq_check_child ($sco, $action, $userid){
bf347041 1012 global $DB;
1013
081a9b0d 1014 $included = false;
1015 $sco=scorm_get_sco($sco->id);
1016 $r = $DB->get_record('scorm_scoes_track', array('scoid'=>$sco->id,'userid'=>$userid,'element'=>'activityattemptcount'));
1017 if ($action == 'satisfied' || $action == 'notsatisfied'){
1018 if (!$sco->rollupobjectivesatisfied){
1019 $included = true;
1020 if (($action == 'satisfied' && $sco->requiredforsatisfied == 'ifnotsuspended') || ($action == 'notsatisfied' && $sco->requiredfornotsatisfied == 'ifnotsuspended')){
e5dd8e3b 1021
081a9b0d 1022 if (!scorm_seq_is('activityprogressstatus',$sco->id,$userid) || ((($r->value)>0)&& !scorm_seq_is('suspended',$sco->id,$userid))){
1023 $included = false;
1024 }
1025
1026 }
1027 else{
1028 if (($action == 'satisfied' && $sco->requiredforsatisfied == 'ifattempted') || ($action == 'notsatisfied' && $sco->requiredfornotsatisfied == 'ifattempted')){
1029 if (!scorm_seq_is('activityprogressstatus',$sco->id,$userid) || (($r->value) == 0)){
1030 $included = false;
1031 }
1032 }
1033 else{
1034 if (($action == 'satisfied' && $sco->requiredforsatisfied == 'ifnotskipped') || ($action == 'notsatisfied' && $sco->requiredfornotsatisfied == 'ifnotskipped')){
1035 $rulch = scorm_seq_rules_check($sco, 'skip');
1036 if ($rulch != null){
1037 $included = false;
1038 }
1039 }
13458883 1040 }
081a9b0d 1041 }
13458883 1042 }
081a9b0d 1043 }
13458883 1044 if ($action == 'completed' || $action == 'incomplete'){
081a9b0d 1045 if (!$sco->rollupprogresscompletion){
1046 $included = true;
13458883 1047
980c089b 1048 if (($action == 'completed' && $sco->requiredforcompleted == 'ifnotsuspended') || ($action == 'incomplete' && $sco->requiredforincomplete == 'ifnotsuspended')){
13458883 1049
081a9b0d 1050 if (!scorm_seq_is('activityprogressstatus',$sco->id,$userid) || ( (($r->value)>0)&& !scorm_seq_is('suspended',$sco->id,$userid))){
1051 $included = false;
1052 }
1053
1054 }
1055 else{
e5dd8e3b 1056
081a9b0d 1057 if (($action == 'completed' && $sco->requiredforcompleted == 'ifattempted') || ($action == 'incomplete' && $sco->requiredforincomplete == 'ifattempted')){
1058 if (!scorm_seq_is('activityprogressstatus',$sco->id,$userid) || (($r->value)==0)){
1059 $included = false;
1060 }
1061
1062 }
1063 else{
1064 if (($action == 'completed' && $sco->requiredforsatisfied == 'ifnotskipped') || ($action == 'incomplete' && $sco->requiredfornotsatisfied == 'ifnotskipped')){
1065 $rulch = scorm_seq_rules_check($sco, 'skip');
1066 if ($rulch != null){
1067 $included = false;
1068 }
1069 }
1070 }
1071
1072
1073 }
1074
1075 }
1076 }
13458883 1077 return $included;
1078
1079
1080}
13458883 1081function scorm_seq_sequencing ($scoid,$userid,$seq) {
1082
1083 switch ($seq->sequencing) {
1084
1085 case 'start':
bf347041 1086 //TODO: undefined $sco!
081a9b0d 1087 $seq = scorm_seq_start_sequencing($sco,$userid,$seq); //We'll see the parameters we have to send, this should update delivery and end
1088 $seq->sequencing = true;
e5dd8e3b
PS
1089
1090
081a9b0d 1091 break;
e5dd8e3b 1092
13458883 1093 case 'resumeall':
081a9b0d 1094 $seq = scorm_seq_resume_sequencing($sco,$userid,$seq); //We'll see the parameters we have to send, this should update delivery and end
1095 $seq->sequencing = true;
e5dd8e3b
PS
1096
1097
1098
13458883 1099 break;
1100
1101 case 'exit':
081a9b0d 1102 $seq = scorm_seq_exit_sequencing($sco,$userid,$seq); //We'll see the parameters we have to send, this should update delivery and end
1103 $seq->sequencing = true;
13458883 1104
e5dd8e3b
PS
1105
1106
13458883 1107 break;
1108
1109 case 'retry':
f3800343 1110 $seq = scorm_seq_retry_sequencing($sco,$userid,$seq); //We'll see the parameters we have to send, this should update delivery and end
13458883 1111 $seq->sequencing = true;
e5dd8e3b
PS
1112
1113
13458883 1114 break;
1115
081a9b0d 1116 case 'previous':
1117 $seq = scorm_seq_previous_sequencing($sco,$userid,$seq);// We'll see the parameters we have to send, this should update delivery and end
1118 $seq->sequencing = true;
13458883 1119
e5dd8e3b 1120
13458883 1121 break;
1122
081a9b0d 1123 case 'choice':
1124 $seq = scorm_seq_choice_sequencing($sco,$userid,$seq);// We'll see the parameters we have to send, this should update delivery and end
e5dd8e3b
PS
1125 $seq->sequencing = true;
1126
1127
081a9b0d 1128 break;
13458883 1129
1130 }
1131
081a9b0d 1132 if ($seq->exception != null){
1133 $seq->sequencing = false;
1134 return $seq;
1135 }
e5dd8e3b 1136
081a9b0d 1137 $seq->sequencing= true;
13458883 1138 return $seq;
1139}
1140
1141
1142function scorm_seq_start_sequencing($scoid,$userid,$seq){
bf347041 1143 global $DB;
1144
081a9b0d 1145 if (!empty($seq->currentactivity)) {
1146 $seq->delivery = null;
1147 $seq->exception = 'SB.2.5-1';
1148 return $seq;
1149 }
1150 $sco = $DB->get_record('scorm_scoes', array('scoid'=>$scoid,'userid'=>$userid));
1151 if (($sco->parent == '/') && scorm_is_leaf($sco)) {//if the activity is the root and is leaf
1152 $seq->delivery = $sco;
1153 }
1154 else{
1155 $ancestors = scorm_get_ancestors($sco);
1156 $ancestorsroot = array_reverse($ancestors);
1157 $res = scorm_seq_flow($ancestorsroot[0],'forward',$seq,true,$userid);
1158 if($res){
1159 return $res;
1160 }
1161 else{
1162 //return end and exception
1163 }
1164 }
13458883 1165}
1166
1167function scorm_seq_resume_all_sequencing($scoid,$userid,$seq){
bf347041 1168 global $DB;
1169
081a9b0d 1170 if (!empty($seq->currentactivity)){
1171 $seq->delivery = null;
1172 $seq->exception = 'SB.2.6-1';
1173 return $seq;
1174 }
1175 $track = $DB->get_record('scorm_scoes_track', array('scoid'=>$scoid,'userid'=>$userid,'element'=>'suspendedactivity'));
13458883 1176 if (!$track) {
081a9b0d 1177 $seq->delivery = null;
1178 $seq->exception = 'SB.2.6-2';
1179 return $seq;
1180 }
1181 $seq->delivery = $DB->get_record('scorm_scoes', array('scoid'=>$scoid,'userid'=>$userid));//we assign the sco to the delivery
e5dd8e3b 1182
13458883 1183}
1184
1185function scorm_seq_continue_sequencing($scoid,$userid,$seq){
081a9b0d 1186 if (empty($seq->currentactivity)) {
1187 $seq->delivery = null;
1188 $seq->exception = 'SB.2.7-1';
1189 return $seq;
1190 }
1191 $currentact= $seq->currentactivity;
1192 if ($currentact->parent != '/') {//if the activity is the root and is leaf
1193 $parent = scorm_get_parent ($currentact);
1194
1195 if (!isset($parent->flow) || ($parent->flow == false)) {
1196 $seq->delivery = null;
1197 $seq->exception = 'SB.2.7-2';
1198 return $seq;
1199 }
1200
1201 $res = scorm_seq_flow($currentact,'forward',$seq,false,$userid);
1202 if($res){
1203 return $res;
1204 }
1205 else{
1206 //return end and exception
1207 }
1208
1209 }
1210}
1211
1212function scorm_seq_previous_sequencing($scoid,$userid,$seq){
1213 if (empty($seq->currentactivity)) {
1214 $seq->delivery = null;
1215 $seq->exception = 'SB.2.8-1';
1216 return $seq;
1217 }
e5dd8e3b 1218
081a9b0d 1219 $currentact= $seq->currentactivity;
1220 if ($currentact->parent != '/') {//if the activity is the root and is leaf
1221 $parent = scorm_get_parent ($activity); // TODO: undefined!!
1222 if (!isset($parent->flow) || ($parent->flow == false)) {
1223 $seq->delivery = null;
1224 $seq->exception = 'SB.2.8-2';
1225 return $seq;
1226 }
1227
1228 $res = scorm_seq_flow($currentact,'backward',$seq,false,$userid);
1229 if($res){
1230 return $res;
1231 }
1232 else{
1233 //return end and exception
1234 }
1235
1236 }
13458883 1237
1238}
1239
1240function scorm_seq_exit_sequencing($scoid,$userid,$seq){
081a9b0d 1241 if (empty($seq->currentactivity)) {
1242 $seq->delivery = null;
1243 $seq->exception = 'SB.2.11-1';
1244 return $seq;
1245 }
1246
1247 if ($seq->active){
1248 $seq->endsession = false;
1249 $seq->exception = 'SB.2.11-2';
1250 return $seq;
1251 }
1252 $currentact= $seq->currentactivity;
1253 if ($currentact->parent == '/'){
1254 $seq->endsession = true;
1255 return $seq;
1256 }
e5dd8e3b 1257
081a9b0d 1258 $seq->endsession = false;
1259 return $seq;
13458883 1260}
1261
1262
1263function scorm_seq_retry_sequencing($scoid,$userid,$seq){
081a9b0d 1264 if (empty($seq->currentactivity)) {
1265 $seq->delivery = null;
1266 $seq->exception = 'SB.2.10-1';
1267 return $seq;
1268 }
1269 if ($seq->active || $seq->suspended){
1270 $seq->delivery = null;
1271 $seq->exception = 'SB.2.10-2';
1272 return $seq;
1273 }
e5dd8e3b 1274
081a9b0d 1275 if (!scorm_is_leaf($seq->currentactivity)){
1276 $res = scorm_seq_flow($seq->currentactivity,'forward',$seq,true,$userid);
1277 if($res != null){
1278 return $res;
1279 //return deliver
1280 }
1281 else{
1282 $seq->delivery = null;
1283 $seq->exception = 'SB.2.10-3';
1284 return $seq;
1285 }
1286 }
1287 else{
1288 $seq->delivery = $seq->currentactivity;
1289 return $seq;
1290 }
13458883 1291
1292}
1293
1294function scorm_seq_flow ($candidate,$direction,$seq,$childrenflag,$userid){
081a9b0d 1295 //$PREVDIRECTION NOT DEFINED YET
1296
1297 $activity=$candidate;
1298 $deliverable=false;
1299 $previdirection = null;
1300 $seq = scorm_seq_flow_tree_traversal ($activity,$direction,$childrenflag,$prevdirection,$seq,$userid); // TODO: undefined
1301 if($seq->identifiedactivity == null){//if identifies
1302 $seq->identifiedactivity = $candidate;
1303 $seq->deliverable = false;
1304 return $seq;
1305 }
1306 else{
1307 $activity = $seq->identifiedactivity;
1308 $seq = scorm_seq_flow_activity_traversal($activity,$userid,$direction,$childrenflag,$prevdirection,$seq,$userid);//
1309 return $seq;
1310
1311 }
13458883 1312}
1313
6d41befd 1314function 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
13458883 1315 $activity = scorm_get_sco ($activity);
1316 $parent = scorm_get_parent ($activity);
1536b92d 1317 if (!isset($parent->flow) || ($parent->flow == false)) {
081a9b0d 1318 $seq->deliverable = false;
1319 $seq->exception = 'SB.2.2-1';
1320 $seq->nextactivity = $activity;
1321 return $seq;
1322 }
e5dd8e3b 1323
bf347041 1324 $rulch = scorm_seq_rules_check($sco, 'skipped'); // TODO: undefined
081a9b0d 1325 if ($rulch != null){
1326 $seq = scorm_seq_flow_tree_traversal ($activity, $direction, false, $prevdirection, $seq,$userid);//endsession and exception
1327 if ($seq->identifiedactivity == null){
1328 $seq->deliverable = false;
1329 $seq->nextactivity = $activity;
1330 return $seq;
1331 }
1332 else{
e5dd8e3b 1333
081a9b0d 1334 if ($prevdirection = 'backward' && $seq->traversaldir == 'backward'){
1335 $seq = scorm_seq_flow_tree_traversal ($activity,$direction,false,null,$seq,$userid);
1336 $seq = scorm_seq_flow_activity($seq->identifiedactivity, $userid, $direction, $childrenflag, $prevdirection, $seq,$userid);
1337 }
1338 else{
1339 $seq = scorm_seq_flow_tree_traversal ($activity,$direction,false,null,$seq,$userid);
1340 $seq = scorm_seq_flow_activity($seq->identifiedactivity, $userid, $direction, $childrenflag, $prevdirection, $seq,$userid);
1341 }
1342 return $seq;
1343 }
1344 }
1345
1346 $ch=scorm_check_activity ($activity,$userid);
1347
1348 if ($ch){
1349
1350 $seq->deliverable = false;
1351 $seq->exception = 'SB.2.2-2';
1352 $seq->nextactivity = $activity;
1353 return $seq;
1354
1355 }
1356
1357 if (!scorm_is_leaf($activity)){
1358
1359 $seq = scorm_seq_flow_tree_traversal ($activity,$direction,true,null,$seq,$userid);
1360
1361 if ($seq->identifiedactivity == null){
1362 $seq->deliverable = false;
1363 $seq->nextactivity = $activity;
1364 return $seq;
1365 }
1366
1367 else{
1368 if($direction == 'backward' && $seq->traversaldir == 'forward'){
1369 $seq = scorm_seq_flow_activity($seq->identifiedactivity, $userid, 'forward', $childrenflag, 'backward', $seq,$userid);
1370 }
1371 else{
1372 scorm_seq_flow_activity($seq->identifiedactivity, $userid, $direction, $childrenflag, null, $seq,$userid);
1373 }
1374 return $seq;
1375 }
1376
1377 }
13458883 1378
1379 $seq->deliverable = true;
081a9b0d 1380 $seq->nextactivity = $activity;
13458883 1381 return $seq;
1382
1383}
6d41befd 1384function scorm_seq_flow_tree_traversal ($activity,$direction,$childrenflag,$prevdirection,$seq,$userid){
13458883 1385
081a9b0d 1386 $revdirection = false;
1387 $parent = scorm_get_parent ($activity);
1388 $children = scorm_get_available_children ($parent);
1389 $siz = sizeof ($children);
13458883 1390
1391 if (($prevdirection != null && $prevdirection == 'backward') && ($children[$siz-1]->id == $activity->id)){
081a9b0d 1392 $direction = 'backward';
1393 $children[0] = $activity;
1394 $revdirection = true;
1395 }
1396
1397 if($direction = 'forward'){
1398 $ancestors = scorm_get_ancestors($activity);
1399 $ancestorsroot = array_reverse($ancestors);
1400 $preorder = scorm_get_preorder ($ancestorsroot);
1401 $siz= sizeof ($preorder);
1402 if (($activity->id == $preorder[$siz-1]->id) || (($activity->parent == '/') && !($childrenflag))){
1403 scorm_seq_terminate_descent($ancestorsroot,$userid);
1404 $seq->endsession = true;
1405 $seq->nextactivity = null;
1406 return $seq;
1407 }
1408 if (scorm_is_leaf ($activity) || !$childrenflag){
1409 if ($children[$siz-1]->id == $activity->id){
e5dd8e3b 1410
081a9b0d 1411 $seq = scorm_seq_flow_tree_traversal ($parent, $direction, false, null, $seq,$userid);
1412 // I think it's not necessary to do a return in here
1413 }
1414 else{
1415 $parent = scorm_get_parent($activity);
1416 $children = scorm_get_available_children($parent);
1417 $seq->traversaldir = $direction;
1418 $sib = scorm_get_siblings($activity);
1419 $pos = array_search($sib, $activity);
1420 if ($pos !== false) {
1421 if ($pos != sizeof ($sib)){
1422 $seq->nextactivity = $sib [$pos+1];
1423 return $seq;
1424 }
1425 else{
1426 $ch = scorm_get_children($sib[0]);
1427 $seq->nextactivity = $ch[0];
1428 return $seq;
1429 }
1430 }
1431 }
1432 }
1433 else{
1434 if (!empty ($children)){
1435 $seq->traversaldir = $direction;
13458883 1436 $seq->nextactivity = $children[0];
081a9b0d 1437 return $seq;
1438 }
1439 else{
1440 $seq->traversaldir = null;
13458883 1441 $seq->nextactivity = $children[0];
081a9b0d 1442 $seq->exception = 'SB.2.1-2';
1443 return $seq;
1444 }
1445 }
e5dd8e3b 1446
081a9b0d 1447 }
1448 if($direction = 'backward'){
e5dd8e3b 1449
081a9b0d 1450 if ($activity->parent == '/'){
1451 $seq->traversaldir = null;
13458883 1452 $seq->nextactivity = null;
081a9b0d 1453 $seq->exception = 'SB.2.1-3';
1454 return $seq;
1455 }
1456 if (scorm_is_leaf ($activity) || !$childrenflag){
1457 if (!$revdirection){
1458 if (isset($parent->forwardonly) && ($parent->forwardonly == true)) {
1459 $seq->traversaldir = null;
13458883 1460 $seq->nextactivity = null;
081a9b0d 1461 $seq->exception = 'SB.2.1-4';
1462 return $seq;
1463 }
1464 }
1465 if ($children[0]->id == $activity->id){
1466 $seq = scorm_seq_flow_tree_traversal ($parent, 'backward', false, null, $seq);
1467 return $seq;
1468 }
1469 else{
1470 $ancestors = scorm_get_ancestors($activity);
1471 $ancestorsroot = array_reverse ($ancestors);
1472 $preorder = scorm_get_preorder ($ancestorsroot);
1473 $pos = array_search($preorder, $children[$siz]);
1474 $preord = array_slice($preorder, 0, $pos-1);
1475 $revpreorder = array_reverse($preord);
1476 $position = array_search($revpreorder, $activity);
1477 $seq->nextactivity = $revpreorder[$pos+1];
1478 $seq->traversaldir = $direction;
1479 return $seq;
1480 }
1481 }
1482 else{
1483 if (!empty($children)){
1484 $activity = scorm_get_sco($activity->id);
1485 if (isset($parent->flow) && ($parent->flow == true)) {
1486 $children = scorm_get_children ($activity);
1487 $seq->traversaldir = 'forward';
13458883 1488 $seq->nextactivity = $children[0];
081a9b0d 1489 return $seq;
e5dd8e3b 1490
081a9b0d 1491 }
1492 else{
1493 $children = scorm_get_children ($activity);
1494 $seq->traversaldir = 'backward';
13458883 1495 $seq->nextactivity = $children[sizeof($children)-1];
081a9b0d 1496 return $seq;
1497 }
13458883 1498
081a9b0d 1499 }
1500 else{
e5dd8e3b 1501
081a9b0d 1502 $seq->traversaldir = null;
13458883 1503 $seq->nextactivity = null;
081a9b0d 1504 $seq->exception = 'SB.2.1-2';
1505 return $seq;
1506 }
1507 }
13458883 1508
081a9b0d 1509 }
13458883 1510
1511
1512}
1513function scorm_check_activity ($activity,$userid){
081a9b0d 1514 $act = scorm_seq_rules_check($activity,'disabled');
1515 if ($act != null){
1516 return true;
1517 }
13458883 1518 if(scorm_limit_cond_check ($activity,$userid)){
081a9b0d 1519 return true;
1520 }
1521 return false;
13458883 1522
1523
1524}
1525
1526function scorm_limit_cond_check ($activity,$userid){
bf347041 1527 global $DB;
13458883 1528
1529 if (isset($activity->tracked) && ($activity->tracked == 0)){
e5dd8e3b 1530
081a9b0d 1531 return false;
1532 }
1533
1534 if (scorm_seq_is('active',$activity->id,$userid) || scorm_seq_is('suspended',$activity->id,$userid)){
1535 return false;
1536 }
1537
e5dd8e3b 1538 if (!isset($activity->limitcontrol) || ($activity->limitcontrol == 1)){
081a9b0d 1539 $r = $DB->get_record('scorm_scoes_track', array('scoid'=>$activity->id,'userid'=>$userid,'element'=>'activityattemptcount'));
1540 if (scorm_seq_is('activityprogressstatus',$activity->id,$userid) && ($r->value >=$activity->limitattempt)){
1541 return true;
1542 }
1543 }
1544
e5dd8e3b 1545 if (!isset($activity->limitabsdurcontrol) || ($activity->limitabsdurcontrol == 1)){
081a9b0d 1546 $r = $DB->get_record('scorm_scoes_track', array('scoid'=>$activity->id,'userid'=>$userid,'element'=>'activityabsoluteduration'));
1547 if (scorm_seq_is('activityprogressstatus',$activity->id,$userid) && ($r->value >=$activity->limitabsduration)){
1548 return true;
1549 }
1550 }
1551
e5dd8e3b 1552 if (!isset($activity->limitexpdurcontrol) || ($activity->limitexpdurcontrol == 1)){
081a9b0d 1553 $r = $DB->get_record('scorm_scoes_track', array('scoid'=>$activity->id,'userid'=>$userid,'element'=>'activityexperiencedduration'));
1554 if (scorm_seq_is('activityprogressstatus',$activity->id,$userid) && ($r->value >=$activity->limitexpduration)){
1555 return true;
1556 }
1557 }
e5dd8e3b
PS
1558
1559 if (!isset($activity->limitattabsdurcontrol) || ($activity->limitattabsdurcontrol == 1)){
081a9b0d 1560 $r = $DB->get_record('scorm_scoes_track', array('scoid'=>$activity->id,'userid'=>$userid,'element'=>'attemptabsoluteduration'));
1561 if (scorm_seq_is('activityprogressstatus',$activity->id,$userid) && ($r->value >=$activity->limitattabsduration)){
1562 return true;
1563 }
1564 }
1565
e5dd8e3b 1566 if (!isset($activity->limitattexpdurcontrol) || ($activity->limitattexpdurcontrol == 1)){
081a9b0d 1567 $r = $DB->get_record('scorm_scoes_track', array('scoid'=>$activity->id,'userid'=>$userid,'element'=>'attemptexperiencedduration'));
1568 if (scorm_seq_is('activityprogressstatus',$activity->id,$userid) && ($r->value >=$activity->limitattexpduration)){
1569 return true;
1570 }
1571 }
1572
e5dd8e3b 1573 if (!isset($activity->limitbegincontrol) || ($activity->limitbegincontrol == 1)){
081a9b0d 1574 $r = $DB->get_record('scorm_scoes_track', array('scoid'=>$activity->id,'userid'=>$userid,'element'=>'begintime'));
1575 if (time()>=$activity->limitbegintime){
1576 return true;
1577 }
1578 }
1579
e5dd8e3b 1580 if (!isset($activity->limitbegincontrol) || ($activity->limitbegincontrol == 1)){
081a9b0d 1581 if (time()<$activity->limitbegintime){
1582 return true;
1583 }
1584 }
1585
e5dd8e3b 1586 if (!isset($activity->limitendcontrol) || ($activity->limitendcontrol == 1)){
081a9b0d 1587
1588 if (time()>$activity->limitendtime){
1589 return true;
1590 }
1591 }
1592 return false;
13458883 1593
1594
f3800343 1595}
1596
1597
1598function scorm_seq_choice_sequencing($sco,$userid,$seq){
1599
081a9b0d 1600 $avchildren = Array ();
1601 $comancestor = null;
1602 $traverse = null;
f3800343 1603
081a9b0d 1604 if ($sco == null){
1605 $seq->delivery = null;
1606 $seq->exception = 'SB.2.9-1';
1607 return $seq;
1608 }
f3800343 1609
1610 $ancestors = scorm_get_ancestors($sco);
1611 $arrpath = array_reverse($ancestors);
081a9b0d 1612 array_push ($arrpath,$sco);//path from the root to the target
f3800343 1613
081a9b0d 1614 foreach ($arrpath as $activity){
f3800343 1615
1616 if ($activity->parent != '/') {
081a9b0d 1617 $avchildren = scorm_get_available_children (scorm_get_parent($activity));
1618 $position = array_search($avchildren, $activity);
f3800343 1619 if ($position !== false){
081a9b0d 1620 $seq->delivery = null;
1621 $seq->exception = 'SB.2.9-2';
1622 return $seq;
1623 }
1624 }
f3800343 1625
081a9b0d 1626 if (scorm_seq_rules_check($activity,'hidefromchoice' != null)){
f3800343 1627
081a9b0d 1628 $seq->delivery = null;
1629 $seq->exception = 'SB.2.9-3';
1630 return $seq;
f3800343 1631
081a9b0d 1632 }
f3800343 1633
081a9b0d 1634 }
f3800343 1635
081a9b0d 1636 if ($sco->parent != '/') {
1637 $parent = scorm_sco_get_parent ($sco);
1638 if ( isset($parent->choice) && ($parent->choice == false)){
1639 $seq->delivery = null;
1640 $seq->exception = 'SB.2.9-4';
1641 return $seq;
1642 }
1643 }
f3800343 1644
081a9b0d 1645 if ($seq->currentactivity != null){
f3800343 1646 $commonpos = scorm_find_common_ancestor($ancestors,$seq->currentactivity);
081a9b0d 1647 $comancestor = $arrpath [$commonpos];
1648 }
1649 else{
1650 $comancestor = $arrpath [0];
1651 }
f3800343 1652
081a9b0d 1653 if($seq->currentactivity === $sco) {
f3800343 1654 break;
081a9b0d 1655 }
f3800343 1656
081a9b0d 1657 $sib = scorm_get_siblings($seq->currentactivity);
1658 $pos = array_search($sib, $sco);
f3800343 1659
081a9b0d 1660 if ($pos !== false){
f3800343 1661
081a9b0d 1662 $siblings = array_slice($sib, 0, $pos-1);
f3800343 1663
081a9b0d 1664 if (empty($siblings)){
f3800343 1665
081a9b0d 1666 $seq->delivery = null;
1667 $seq->exception = 'SB.2.9-5';
1668 return $seq;
f3800343 1669
081a9b0d 1670 }
e5dd8e3b 1671
081a9b0d 1672 $children = scorm_get_children (scorm_get_parent ($sco));
1673 $pos1 = array_search($children, $sco);
1674 $pos2 = array_search($seq->currentactivity, $sco);
1675 if ($pos1>$pos2){
1676 $traverse = 'forward';
1677 }
1678 else{
1679 $traverse = 'backward';
1680 }
1681
1682 foreach ($siblings as $sibling){
1683 $seq = scorm_seq_choice_activity_traversal($sibling,$userid,$seq,$traverse);
1684 if(!$seq->reachable){
1685 $seq->delivery = null;
1686 return $seq;
1687 }
1688 }
1689 break;
1690
1691 }
f3800343 1692
1693 if($seq->currentactivity == null || $seq->currentactivity == $comancestor){
081a9b0d 1694 $commonpos = scorm_find_common_ancestor($ancestors,$seq->currentactivity);
1695 $comtarget = array_slice($ancestors, 1,$commonpos-1);//path from the common ancestor to the target activity
1696 $comtarget = array_reverse($comtarget);
1697
1698 if (empty($comtarget)){
1699 $seq->delivery = null;
1700 $seq->exception = 'SB.2.9-5';
1701 return $seq;
1702 }
1703 foreach ($comtarget as $act){
1704 $seq = scorm_seq_choice_activity_traversal($act,$userid,$seq,'forward');
1705 if(!$seq->reachable){
1706 $seq->delivery = null;
1707 return $seq;
1708 }
980c089b 1709 $act = scorm_get_sco ($acti->id);
081a9b0d 1710 if(scorm_seq_is('active',$act->id,$userid) && ($act->id != $comancestor->id && $act->preventactivation)){//adlseq:can i write it like another property for the $seq object?
1711 $seq->delivery = null;
1712 $seq->exception = 'SB.2.9-6';
1713 return $seq;
1714 }
1715 }
1716 break;
f3800343 1717
081a9b0d 1718 }
f3800343 1719
081a9b0d 1720 if ($comancestor->id == $sco->id){
f3800343 1721
1722 $ancestorscurrent = scorm_get_ancestors($seq->currentactivity);
081a9b0d 1723 $possco = array_search ($ancestorscurrent, $sco);
1724 $curtarget = array_slice($ancestorscurrent,0,$possco);//path from the current activity to the target
1725
1726 if (empty($curtarget)){
1727 $seq->delivery = null;
1728 $seq->exception = 'SB.2.9-5';
1729 return $seq;
1730 }
f3800343 1731 $i=0;
081a9b0d 1732 foreach ($curtarget as $activ){
1733 $i++;
1734 if ($i != sizeof($curtarget)){
1735 if ( isset($activ->choiceexit) && ($activ->choiceexit == false)){
1736 $seq->delivery = null;
1737 $seq->exception = 'SB.2.9-7';
1738 return $seq;
1739 }
1740 }
1741 }
1742 break;
1743 }
1744
1745 if (array_search ($ancestors, $comancestor)!== false){
1746 $ancestorscurrent = scorm_get_ancestors($seq->currentactivity);
1747 $commonpos = scorm_find_common_ancestor($ancestors,$sco);
1748 $curcommon = array_slice($ancestorscurrent,0,$commonpos-1);
1749 if(empty($curcommon)){
1750 $seq->delivery = null;
1751 $seq->exception = 'SB.2.9-5';
1752 return $seq;
1753 }
1754
1755 $constrained = null;
1756 foreach ($curcommon as $acti){
1757 $acti = scorm_get_sco($acti->id);
1758 if ( isset($acti->choiceexit) && ($acti->choiceexit == false)){
1759 $seq->delivery = null;
1760 $seq->exception = 'SB.2.9-7';
1761 return $seq;
1762 }
1763 if ($constrained == null){
1764 if($acti->constrainchoice == true){
1765 $constrained = $acti;
1766 }
1767 }
1768 }
1769 if ($constrained != null){
f3800343 1770 $fwdir = scorm_get_preorder($constrained);
1771
081a9b0d 1772 if(array_search ($fwdir, $sco)!== false){
1773 $traverse = 'forward';
1774 }
1775 else{
1776 $traverse = 'backward';
1777 }
1778 $seq = scorm_seq_choice_flow ($constrained, $traverse, $seq);
1779 $actconsider = $seq->identifiedactivity;
1780 $avdescendents = Array();
1781 $avdescendents= scorm_get_available_descendents ($actconsider);
1782 if (array_search ($avdescendents, $sco) !== false && $sco->id != $actconsider->id && $constrained->id != $sco->id ){
1783 $seq->delivery = null;
1784 $seq->exception = 'SB.2.9-8';
1785 return $seq;
1786 }
6d41befd 1787
f3800343 1788//CONTINUE 11.5.5
081a9b0d 1789 }
6d41befd 1790
081a9b0d 1791 $commonpos = scorm_find_common_ancestor($ancestors,$seq->currentactivity);
1792 $comtarget = array_slice($ancestors, 1,$commonpos-1);//path from the common ancestor to the target activity
1793 $comtarget = array_reverse($comtarget);
6d41befd 1794
081a9b0d 1795 if (empty($comtarget)){
1796 $seq->delivery = null;
1797 $seq->exception = 'SB.2.9-5';
1798 return $seq;
1799 }
6d41befd 1800
081a9b0d 1801 $fwdir = scorm_get_preorder($seq->currentactivity);
6d41befd 1802
081a9b0d 1803 if(array_search ($fwdir, $sco)!== false){
6d41befd 1804
081a9b0d 1805 foreach ($comtarget as $act){
1806 $seq = scorm_seq_choice_activity_traversal($act,$userid,$seq,'forward');
1807 if(!$seq->reachable){
1808 $seq->delivery = null;
1809 return $seq;
1810 }
980c089b 1811 $act = scorm_get_sco($act->id);
081a9b0d 1812 if(scorm_seq_is('active',$act->id,$userid) && ($act->id != $comancestor->id && ($act->preventactivation == true))){
1813 $seq->delivery = null;
1814 $seq->exception = 'SB.2.9-6';
1815 return $seq;
1816 }
1817 }
1818
1819 }
1820 else{
1821 foreach ($comtarget as $act){
1822 $act = scorm_get_sco($act->id);
1823 if(scorm_seq_is('active',$act->id,$userid) && ($act->id != $comancestor->id && ($act->preventactivation==true))){
1824 $seq->delivery = null;
1825 $seq->exception = 'SB.2.9-6';
1826 return $seq;
1827 }
1828 }
1829 }
e5dd8e3b 1830 break;
081a9b0d 1831 }
1832
1833 if(scorm_is_leaf ($sco)){
1834 $seq->delivery = $sco;
1835 $seq->exception = 'SB.2.9-6';
1836 return $seq;
1837 }
f3800343 1838
6d41befd 1839 $seq = scorm_seq_flow ($sco,'forward',$seq,true,$userid);
1840 if ($seq->deliverable == false){
081a9b0d 1841 scorm_terminate_descendent_attempts($comancestor,$userid,$seq);
1842 scorm_seq_end_attempt($comancestor,$userid,$seq->attempt);
1843 $seq->currentactivity = $sco;
1844 $seq->delivery = null;
1845 $seq->exception = 'SB.2.9-9';
1846 return $seq;
1847
1848 }
1849 else{
1850 return $seq;
1851 }
e5dd8e3b 1852
13458883 1853}
1854
6d41befd 1855function scorm_seq_choice_flow ($constrained, $traverse, $seq){
081a9b0d 1856 $seq = scorm_seq_choice_flow_tree ($constrained, $traverse, $seq);
1857 if ($seq->identifiedactivity == null){
6d41befd 1858 $seq->identifiedactivity = $constrained;
081a9b0d 1859 return $seq;
1860 }
1861 else{
1862 return $seq;
1863 }
6d41befd 1864}
1865
1866function scorm_seq_choice_flow_tree ($constrained, $traverse, $seq){
081a9b0d 1867 $islast = false;
1868 $parent = scorm_get_parent ($constrained);
1869 if ($traverse== 'forward'){
1870 $preord = scorm_get_preorder ($constrained);
1871 if (sizeof($preorder) == 0 || (sizeof($preorder) == 0 && $preorder[0]->id = $constrained->id)){ // TODO: undefined
1872 $islast = true;//the function is the last activity available
1873 }
1874 if ($constrained->parent == '/' || $islast){
1875 $seq->nextactivity = null;
1876 return $seq;
1877 }
1878 $avchildren = scorm_get_available_children ($parent);//available children
1879 if ($avchildren [sizeof($avchildren)-1]->id == $constrained->id){
1880 $seq = scorm_seq_choice_flow_tree ($parent, 'forward', $seq);
1881 return $seq;
1882 }
1883 else{
1884 $i=0;
1885 while($i < sizeof($avchildren)){
1886 if ($avchildren [$i]->id == $constrained->id){
1887 $seq->nextactivity = $avchildren [$i+1];
1888 return $seq;
1889 }
1890 else{
1891 $i++;
1892 }
1893 }
1894 }
1895
1896 }
1897
1898 if ($traverse== 'backward'){
1899 if($constrained->parent == '/' ){
1900 $seq->nextactivity = null;
1901 return $seq;
1902 }
1903
1904 $avchildren = scorm_get_available_children ($parent);//available children
1905 if ($avchildren [0]->id == $constrained->id){
1906 $seq = scorm_seq_choice_flow_tree ($parent, 'backward', $seq);
1907 return $seq;
1908 }
1909 else{
1910 $i=sizeof($avchildren)-1;
1911 while($i >=0){
1912 if ($avchildren [$i]->id == $constrained->id){
1913 $seq->nextactivity = $avchildren [$i-1];
1914 return $seq;
1915 }
1916 else{
1917 $i--;
1918 }
1919 }
1920 }
1921 }
6d41befd 1922}
1923function scorm_seq_choice_activity_traversal($activity,$userid,$seq,$direction){
1924
081a9b0d 1925 if($direction == 'forward'){
1926
1927 $act = scorm_seq_rules_check($activity,'stopforwardtraversal');
1928
1929 if($act != null){
1930 $seq->reachable = false;
1931 $seq->exception = 'SB.2.4-1';
1932 return $seq;
1933 }
1934 $seq->reachable = false;
1935 return $seq;
1936 }
1937
1938 if($direction == 'backward'){
1939 $parentsco = scorm_get_parent($activity);
1940 if($parentsco!= null){
1941 if (isset($parentsco->forwardonly) && ($parentsco->forwardonly == true)){
1942 $seq->reachable = false;
1943 $seq->exception = 'SB.2.4-2';
1944 return $seq;
1945 }
1946 else{
1947 $seq->reachable = false;
1948 $seq->exception = 'SB.2.4-3';
1949 return $seq;
1950 }
1951 }
1952 }
1953 $seq->reachable = true;
1954 return $seq;
6d41befd 1955
1956}
1957
1958//Delivery Request Process
1959
1960function scorm_sequencing_delivery($scoid,$userid,$seq){
1961
081a9b0d 1962 if(!scorm_is_leaf ($seq->delivery)){
1963 $seq->deliveryvalid = false;
1964 $seq->exception = 'DB.1.1-1';
1965 return $seq;
1966 }
1967 $ancestors = scorm_get_ancestors($seq->delivery);
6d41befd 1968 $arrpath = array_reverse($ancestors);
081a9b0d 1969 array_push ($arrpath,$seq->delivery);//path from the root to the target
6d41befd 1970
081a9b0d 1971 if (empty($arrpath)){
1972 $seq->deliveryvalid = false;
1973 $seq->exception = 'DB.1.1-2';
1974 return $seq;
1975 }
6d41befd 1976
081a9b0d 1977 foreach ($arrpath as $activity){
1978 if(scorm_check_activity ($activity,$userid)){
1979 $seq->deliveryvalid = false;
1980 $seq->exception = 'DB.1.1-3';
1981 return $seq;
1982 }
1983 }
6d41befd 1984
081a9b0d 1985 $seq->deliveryvalid = true;
1986 return $seq;
6d41befd 1987
1988}
1989
1990function scorm_content_delivery_environment ($seq,$userid){
bf347041 1991 global $DB;
6d41befd 1992
081a9b0d 1993 $act = $seq->currentactivity;
1994 if(scorm_seq_is('active',$act->id,$userid)){
1995 $seq->exception = 'DB.2-1';
1996 return $seq;
1997 }
1998 $track = $DB->get_record('scorm_scoes_track', array('scoid'=>$act->id,'userid'=>$userid,'element'=>'suspendedactivity'));
1999 if ($track != null){
2000 $seq = scorm_clear_suspended_activity($seq->delivery, $seq);
2001
2002 }
2003 $seq = scorm_terminate_descendent_attempts ($seq->delivery,$userid,$seq);
2004 $ancestors = scorm_get_ancestors($seq->delivery);
6d41befd 2005 $arrpath = array_reverse($ancestors);
081a9b0d 2006 array_push ($arrpath,$seq->delivery);
2007 foreach ($arrpath as $activity){
2008 if(!scorm_seq_is('active',$activity->id,$userid)){
2009 if(!isset($activity->tracked) || ($activity->tracked == 1)){
2010 if(!scorm_seq_is('suspended',$activity->id,$userid)){
2011 $r = $DB->get_record('scorm_scoes_track', array('scoid'=>$activity->id,'userid'=>$userid,'element'=>'activityattemptcount'));
2012 $r->value = ($r->value)+1;
2013 $DB->update_record ('scorm_scoes_track',$r);
2014 if ($r->value == 1){
2015 scorm_seq_set('activityprogressstatus', $activity->id, $userid, 'true');
2016 }
2017 scorm_insert_track($userid, $activity->scorm, $activity->id, 0, 'objectiveprogressstatus', 'false');
2018 scorm_insert_track($userid, $activity->scorm, $activity->id, 0, 'objectivesatisfiedstatus', 'false');
2019 scorm_insert_track($userid, $activity->scorm, $activity->id, 0, 'objectivemeasurestatus', 'false');
2020 scorm_insert_track($userid, $activity->scorm, $activity->id, 0, 'objectivenormalizedmeasure', 0.0);
2021
2022 scorm_insert_track($userid, $activity->scorm, $activity->id, 0, 'attemptprogressstatus', 'false');
2023 scorm_insert_track($userid, $activity->scorm, $activity->id, 0, 'attemptcompletionstatus', 'false');
2024 scorm_insert_track($userid, $activity->scorm, $activity->id, 0, 'attemptabsoluteduration', 0.0);
2025 scorm_insert_track($userid, $activity->scorm, $activity->id, 0, 'attemptexperiencedduration', 0.0);
2026 scorm_insert_track($userid, $activity->scorm, $activity->id, 0, 'attemptcompletionamount', 0.0);
2027 }
2028 }
6d41befd 2029 scorm_seq_set('active', $activity->id, $userid, 'true');
081a9b0d 2030 }
2031 }
2032 $seq->delivery = $seq->currentactivity;
2033 scorm_seq_set('suspendedactivity', $activity->id, $userid, 'false');
6d41befd 2034
081a9b0d 2035 //ONCE THE DELIVERY BEGINS (How should I check that?)
6d41befd 2036
2037 if(isset($activity->tracked) || ($activity->tracked == 0)){
e5dd8e3b 2038 //How should I track the info and what should I do to not record the information for the activity during delivery?
081a9b0d 2039 $atabsdur = $DB->get_record('scorm_scoes_track', array('scoid'=>$activity->id,'userid'=>$userid,'element'=>'attemptabsoluteduration'));
2040 $atexpdur = $DB->get_record('scorm_scoes_track', array('scoid'=>$activity->id,'userid'=>$userid,'element'=>'attemptexperiencedduration'));
2041 }
2042 return $seq;
6d41befd 2043
e5dd8e3b 2044
6d41befd 2045}
2046function scorm_clear_suspended_activity($act,$seq){
bf347041 2047 global $DB;
081a9b0d 2048 $currentact= $seq->currentactivity;
2049 $track = $DB->get_record('scorm_scoes_track', array('scoid'=>$currentact->id,'userid'=>$userid,'element'=>'suspendedactivity')); // TODO: undefined
2050 if ($track != null){
2051 $ancestors = scorm_get_ancestors($act);
6d41befd 2052 $commonpos = scorm_find_common_ancestor($ancestors,$currentact);
2053 if ($commonpos !== false) {
2054 if ($activitypath = array_slice($ancestors,0,$commonpos)) {
081a9b0d 2055 if (!empty ($activitypath)){
6d41befd 2056
2057 foreach ($activitypath as $activity) {
081a9b0d 2058 if (scorm_is_leaf($activity)){
2059 scorm_seq_set('suspended',$activity->id,$userid,false);
2060 }
2061 else{
2062 $children = scorm_get_children($activity);
e5dd8e3b 2063 $bool= false;
081a9b0d 2064 foreach ($children as $child){
2065 if(scorm_seq_is('suspended',$child->id,$userid)){
2066 $bool= true;
2067 }
2068 }
6d41befd 2069 if(!$bool){
081a9b0d 2070 scorm_seq_set('suspended',$activity->id,$userid,false);
2071 }
2072 }
2073 }
2074 }
2075 }
2076 }
2077 scorm_seq_set('suspendedactivity',$act->id,$userid,false);
2078
2079 }
6d41befd 2080}
2081
2082function scorm_select_children_process($scoid,$userid){
bf347041 2083 global $DB;
6d41befd 2084
081a9b0d 2085 $sco = scorm_get_sco($scoid);
6d41befd 2086 if (!scorm_is_leaf($sco)){
081a9b0d 2087 if(!scorm_seq_is('suspended',$scoid,$userid) && !scorm_seq_is('active',$scoid,$userid)){
2088 $r = $DB->get_record('scorm_scoes_track', array('scoid'=>$scoid,'userid'=>$userid,'element'=>'selectiontiming'));
6d41befd 2089
2090 switch($r->value) {
2091
2092 case 'oneachnewattempt':
081a9b0d 2093 case 'never':
6d41befd 2094 break;
e5dd8e3b 2095
6d41befd 2096 case 'once':
2097 if(!scorm_seq_is('activityprogressstatus',$scoid,$userid)){
081a9b0d 2098 if(scorm_seq_is('selectioncountsstatus',$scoid,$userid)){
2099 $childlist = '';
2100 $res = $DB->get_record('scorm_scoes_track', array('scoid'=>$scoid,'userid'=>$userid,'element'=>'selectioncount'));
2101 $i = ($res->value)-1;
2102 $children = scorm_get_children ($sco);
2103
2104 while ($i>=0){
2105 $pos = array_rand($children);
2106 array_push($childlist,$children [$pos]);
2107 array_splice($children,$pos,1);
2108 $i--;
2109 }
2110 sort ($childlist);
2111 $clist = serialize ($childlist);
2112 scorm_seq_set('availablechildren', $scoid, $userid, false);
2113 scorm_seq_set('availablechildren', $scoid, $userid, $clist);
2114
2115
2116 }
2117 }
6d41befd 2118 break;
e5dd8e3b 2119
6d41befd 2120 }
2121
081a9b0d 2122 }
2123 }
6d41befd 2124}
2125
2126function scorm_randomize_children_process($scoid,$userid){
bf347041 2127 global $DB;
6d41befd 2128
081a9b0d 2129 $sco = scorm_get_sco($scoid);
6d41befd 2130 if (!scorm_is_leaf($sco)){
081a9b0d 2131 if(!scorm_seq_is('suspended',$scoid,$userid) && !scorm_seq_is('active',$scoid,$userid)){
2132 $r = $DB->get_record('scorm_scoes_track', array('scoid'=>$scoid,'userid'=>$userid,'element'=>'randomizationtiming'));
6d41befd 2133
2134 switch($r->value) {
2135
e5dd8e3b 2136
081a9b0d 2137 case 'never':
6d41befd 2138 break;
e5dd8e3b 2139
6d41befd 2140 case 'oneachnewattempt':
2141 case 'once':
2142 if(!scorm_seq_is('activityprogressstatus',$scoid,$userid)){
081a9b0d 2143 if(scorm_seq_is('randomizechildren',$scoid,$userid)){
2144 $childlist = array();
2145 $res = scorm_get_available_children($sco);
2146 $i = sizeof($res)-1;
2147 $children = $res->value;
2148
2149 while ($i>=0){
2150 $pos = array_rand($children);
2151 array_push($childlist,$children [$pos]);
2152 array_splice($children,$pos,1);
2153 $i--;
2154 }
e5dd8e3b 2155
081a9b0d 2156 $clist = serialize ($childlist);
2157 scorm_seq_set('availablechildren', $scoid, $userid, false);
2158 scorm_seq_set('availablechildren', $scoid, $userid, $clist);
2159
2160
2161 }
2162 }
6d41befd 2163 break;
e5dd8e3b
PS
2164
2165
2166
6d41befd 2167 }
2168
081a9b0d 2169 }
2170 }
6d41befd 2171}
2172
980c089b 2173function scorm_terminate_descendent_attempts ($activity,$userid,$seq){
081a9b0d 2174 $ancestors = scorm_get_ancestors($seq->currentactivity);
6d41befd 2175 $commonpos = scorm_find_common_ancestor($ancestors,$activity);
2176 if ($commonpos !== false) {
2177 if ($activitypath = array_slice($ancestors,1,$commonpos-2)) {
081a9b0d 2178 if (!empty ($activitypath)){
6d41befd 2179
2180 foreach ($activitypath as $sco) {
081a9b0d 2181 scorm_seq_end_attempt($sco,$userid,$seq->attempt);
e5dd8e3b 2182
081a9b0d 2183 }
2184 }
2185 }
e5dd8e3b 2186 }
6d41befd 2187}
af8ed6dc 2188
2189function scorm_sequencing_exception($seq){
6aff538a 2190 global $OUTPUT;
af8ed6dc 2191 if($seq->exception != null){
081a9b0d 2192 switch($seq->exception){
af8ed6dc 2193
081a9b0d 2194 case 'NB.2.1-1':
6aff538a 2195 echo $OUTPUT->notification("Sequencing session has already begun");
05069950 2196 break;
2197 case 'NB.2.1-2':
6aff538a 2198 echo $OUTPUT->notification("Sequencing session has not begun");
05069950 2199 break;
081a9b0d 2200 case 'NB.2.1-3':
6aff538a 2201 echo $OUTPUT->notification("Suspended activity is not defined");
05069950 2202 break;
081a9b0d 2203 case 'NB.2.1-4':
6aff538a 2204 echo $OUTPUT->notification("Flow Sequencing Control Model Violation");
05069950 2205 break;
081a9b0d 2206 case 'NB.2.1-5':
6aff538a 2207 echo $OUTPUT->notification("Flow or Forward only Sequencing Control Model Violation");
05069950 2208 break;
081a9b0d 2209 case 'NB.2.1-6':
6aff538a 2210 echo $OUTPUT->notification("No activity is previous to the root");
05069950 2211 break;
081a9b0d 2212 case 'NB.2.1-7':
6aff538a 2213 echo $OUTPUT->notification("Unsupported Navigation Request");
05069950 2214 break;
081a9b0d 2215 case 'NB.2.1-8':
6aff538a 2216 echo $OUTPUT->notification("Choice Exit Sequencing Control Model Violation");
05069950 2217 break;
081a9b0d 2218 case 'NB.2.1-9':
6aff538a 2219 echo $OUTPUT->notification("No activities to consider");
05069950 2220 break;
081a9b0d 2221 case 'NB.2.1-10':
6aff538a 2222 echo $OUTPUT->notification("Choice Sequencing Control Model Violation");
05069950 2223 break;
081a9b0d 2224 case 'NB.2.1-11':
6aff538a 2225 echo $OUTPUT->notification("Target Activity does not exist");
05069950 2226 break;
081a9b0d 2227 case 'NB.2.1-12':
6aff538a 2228 echo $OUTPUT->notification("Current Activity already terminated");
05069950 2229 break;
081a9b0d 2230 case 'NB.2.1-13':
6aff538a 2231 echo $OUTPUT->notification("Undefined Navigation Request");
05069950 2232 break;
af8ed6dc 2233
081a9b0d 2234 case 'TB.2.3-1':
6aff538a 2235 echo $OUTPUT->notification("Current Activity already terminated");
05069950 2236 break;
081a9b0d 2237 case 'TB.2.3-2':
6aff538a 2238 echo $OUTPUT->notification("Current Activity already terminated");
05069950 2239 break;
081a9b0d 2240 case 'TB.2.3-4':
6aff538a 2241 echo $OUTPUT->notification("Current Activity already terminated");
05069950 2242 break;
081a9b0d 2243 case 'TB.2.3-5':
6aff538a 2244 echo $OUTPUT->notification("Nothing to suspend; No active activities");
05069950 2245 break;
081a9b0d 2246 case 'TB.2.3-6':
6aff538a 2247 echo $OUTPUT->notification("Nothing to abandon; No active activities");
05069950 2248 break;
2249
081a9b0d 2250 case 'SB.2.1-1':
6aff538a 2251 echo $OUTPUT->notification("Last activity in the tree");
05069950 2252 break;
2253 case 'SB.2.1-2':
6aff538a 2254 echo $OUTPUT->notification("Cluster has no available children");
05069950 2255 break;
081a9b0d 2256 case 'SB.2.1-3':
6aff538a 2257 echo $OUTPUT->notification("No activity is previous to the root");
05069950 2258 break;
081a9b0d 2259 case 'SB.2.1-4':
6aff538a 2260 echo $OUTPUT->notification("Forward Only Sequencing Control Model Violation");
05069950 2261 break;
2262
081a9b0d 2263 case 'SB.2.2-1':
6aff538a 2264 echo $OUTPUT->notification("Flow Sequencing Control Model Violation");
05069950 2265 break;
081a9b0d 2266 case 'SB.2.2-2':
6aff538a 2267 echo $OUTPUT->notification("Activity unavailable");
05069950 2268 break;
2269
081a9b0d 2270 case 'SB.2.3-1':
6aff538a 2271 echo $OUTPUT->notification("Forward Traversal Blocked");
05069950 2272 break;
2273 case 'SB.2.3-2':
6aff538a 2274 echo $OUTPUT->notification("Forward Only Sequencing Control Model Violation");
05069950 2275 break;
081a9b0d 2276 case 'SB.2.3-3':
6aff538a 2277 echo $OUTPUT->notification("No activity is previous to the root");
05069950 2278 break;
2279
081a9b0d 2280 case 'SB.2.5-1':
6aff538a 2281 echo $OUTPUT->notification("Sequencing session has already begun");
05069950 2282 break;
2283
081a9b0d 2284 case 'SB.2.6-1':
6aff538a 2285 echo $OUTPUT->notification("Sequencing session has already begun");
05069950 2286 break;
081a9b0d 2287 case 'SB.2.6-2':
6aff538a 2288 echo $OUTPUT->notification("No Suspended activity is defined");
05069950 2289 break;
2290
2291 case 'SB.2.7-1':
6aff538a 2292 echo $OUTPUT->notification("Sequencing session has not begun");
05069950 2293 break;
081a9b0d 2294 case 'SB.2.7-2':
6aff538a 2295 echo $OUTPUT->notification("Flow Sequencing Control Model Violation");
05069950 2296 break;
2297
081a9b0d 2298 case 'SB.2.8-1':
6aff538a 2299 echo $OUTPUT->notification("Sequencing session has not begun");
05069950 2300 break;
081a9b0d 2301 case 'SB.2.8-2':
6aff538a 2302 echo $OUTPUT->notification("Flow Sequencing Control Model Violation");
05069950 2303 break;
2304
081a9b0d 2305 case 'SB.2.9-1':
6aff538a 2306 echo $OUTPUT->notification("No target for Choice");
05069950 2307 break;
081a9b0d 2308 case 'SB.2.9-2':
6aff538a 2309 echo $OUTPUT->notification("Target Activity does not exist or is unavailable");
05069950 2310 break;
081a9b0d 2311 case 'SB.2.9-3':
6aff538a 2312 echo $OUTPUT->notification("Target Activity hidden from choice");
05069950 2313 break;
081a9b0d 2314 case 'SB.2.9-4':
6aff538a 2315 echo $OUTPUT->notification("Choice Sequencing Control Model Violation");
05069950 2316 break;
081a9b0d 2317 case 'SB.2.9-5':
6aff538a 2318 echo $OUTPUT->notification("No activities to consider");
05069950 2319 break;
081a9b0d 2320 case 'SB.2.9-6':
6aff538a 2321 echo $OUTPUT->notification("Unable to activate target; target is not a child of the Current Activity");
05069950 2322 break;
081a9b0d 2323 case 'SB.2.9-7':
6aff538a 2324 echo $OUTPUT->notification("Choice Exit Sequencing Control Model Violation");
05069950 2325 break;
081a9b0d 2326 case 'SB.2.9-8':
6aff538a 2327 echo $OUTPUT->notification("Unable to choose target activity - constrained choice");
05069950 2328 break;
081a9b0d 2329 case 'SB.2.9-9':
6aff538a 2330 echo $OUTPUT->notification("Choice Request Prevented by Flow-only Activity");
05069950 2331 break;
2332
081a9b0d 2333 case 'SB.2.10-1':
6aff538a 2334 echo $OUTPUT->notification("Sequencing session has not begun");
05069950 2335 break;
081a9b0d 2336 case 'SB.2.10-2':
6aff538a 2337 echo $OUTPUT->notification("Current Activity is active or suspended");
05069950 2338 break;
081a9b0d 2339 case 'SB.2.10-3':
6aff538a 2340 echo $OUTPUT->notification("Flow Sequencing Control Model Violation");
05069950 2341 break;
e5dd8e3b 2342
05069950 2343 case 'SB.2.11-1':
6aff538a 2344 echo $OUTPUT->notification("Sequencing session has not begun");
05069950 2345 break;
081a9b0d 2346 case 'SB.2.11-2':
6aff538a 2347 echo $OUTPUT->notification("Current Activity has not been terminated");
05069950 2348 break;
2349
081a9b0d 2350 case 'SB.2.12-2':
6aff538a 2351 echo $OUTPUT->notification("Undefined Sequencing Request");
05069950 2352 break;
2353
081a9b0d 2354 case 'DB.1.1-1':
6aff538a 2355 echo $OUTPUT->notification("Cannot deliver a non-leaf activity");
05069950 2356 break;
081a9b0d 2357 case 'DB.1.1-2':
6aff538a 2358 echo $OUTPUT->notification("Nothing to deliver");
05069950 2359 break;
081a9b0d 2360 case 'DB.1.1-3':
6aff538a 2361 echo $OUTPUT->notification("Activity unavailable");
05069950 2362 break;
2363
081a9b0d 2364 case 'DB.2-1':
6aff538a 2365 echo $OUTPUT->notification("Identified activity is already active");
05069950 2366 break;
e5dd8e3b 2367
081a9b0d 2368 }
e5dd8e3b 2369
081a9b0d 2370 }
af8ed6dc 2371}
2372
2373
2374
6d41befd 2375
e5dd8e3b 2376