Merge branch 'm20_MDL-26176_cleanup' of github.com:danmarsden/moodle
[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)) {
70e36053 141 if (!isset($parentsco->choice) || ($parentsco->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 }
70e36053 154 if ($sco->parent != $targetsco->parent) {
10fd330f 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);
70e36053 347 scorm_seq_overall_rollup($sco,$userid, $seq);
10fd330f 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
70e36053 480function scorm_seq_overall_rollup($sco,$userid, $seq){//Carlos
13458883 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);
70e36053 488 scorm_seq_activity_progress_rollup($sco,$userid, $seq);
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
70e36053 718function scorm_seq_activity_progress_rollup ($sco, $userid, $seq){
13458883 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 }
1978d7aa 798 if($cont >= $rolluprule->minimumcount){
081a9b0d 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 }
1978d7aa 810 if($cont >= $rolluprule->minimumcount){
081a9b0d 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 }
1978d7aa 822 if(($cont/sizeof($childrenbag)) >= $rolluprule->minimumcount){
081a9b0d 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
020f27db 844 $condit = scorm_evaluate_condition($rolluprulecond,$sco,$userid);
081a9b0d 845
a4347c69
DM
846 if($rolluprulecond->operator=='not'){// If operator is not, negate the condition
847 if ($rolluprulecond->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
a4347c69 869 if ($rolluprulecond->conditioncombination == 'all'){
081a9b0d 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':
05923fca 1086 $seq = scorm_seq_start_sequencing($scoid,$userid,$seq); //We'll see the parameters we have to send, this should update delivery and end
081a9b0d 1087 $seq->sequencing = true;
e5dd8e3b
PS
1088
1089
081a9b0d 1090 break;
e5dd8e3b 1091
13458883 1092 case 'resumeall':
72ef83b9 1093 $seq = scorm_seq_resume_all_sequencing($scoid,$userid,$seq); //We'll see the parameters we have to send, this should update delivery and end
081a9b0d 1094 $seq->sequencing = true;
e5dd8e3b
PS
1095
1096
1097
13458883 1098 break;
1099
1100 case 'exit':
05923fca 1101 $seq = scorm_seq_exit_sequencing($scoid,$userid,$seq); //We'll see the parameters we have to send, this should update delivery and end
081a9b0d 1102 $seq->sequencing = true;
13458883 1103
e5dd8e3b
PS
1104
1105
13458883 1106 break;
1107
1108 case 'retry':
05923fca 1109 $seq = scorm_seq_retry_sequencing($scoid,$userid,$seq); //We'll see the parameters we have to send, this should update delivery and end
13458883 1110 $seq->sequencing = true;
e5dd8e3b
PS
1111
1112
13458883 1113 break;
1114
081a9b0d 1115 case 'previous':
05923fca 1116 $seq = scorm_seq_previous_sequencing($scoid,$userid,$seq);// We'll see the parameters we have to send, this should update delivery and end
081a9b0d 1117 $seq->sequencing = true;
13458883 1118
e5dd8e3b 1119
13458883 1120 break;
1121
081a9b0d 1122 case 'choice':
05923fca 1123 $seq = scorm_seq_choice_sequencing($scoid,$userid,$seq);// We'll see the parameters we have to send, this should update delivery and end
e5dd8e3b
PS
1124 $seq->sequencing = true;
1125
1126
081a9b0d 1127 break;
13458883 1128
1129 }
1130
081a9b0d 1131 if ($seq->exception != null){
1132 $seq->sequencing = false;
1133 return $seq;
1134 }
e5dd8e3b 1135
081a9b0d 1136 $seq->sequencing= true;
13458883 1137 return $seq;
1138}
1139
1140
1141function scorm_seq_start_sequencing($scoid,$userid,$seq){
bf347041 1142 global $DB;
1143
081a9b0d 1144 if (!empty($seq->currentactivity)) {
1145 $seq->delivery = null;
1146 $seq->exception = 'SB.2.5-1';
1147 return $seq;
1148 }
1149 $sco = $DB->get_record('scorm_scoes', array('scoid'=>$scoid,'userid'=>$userid));
1150 if (($sco->parent == '/') && scorm_is_leaf($sco)) {//if the activity is the root and is leaf
1151 $seq->delivery = $sco;
1152 }
1153 else{
1154 $ancestors = scorm_get_ancestors($sco);
1155 $ancestorsroot = array_reverse($ancestors);
1156 $res = scorm_seq_flow($ancestorsroot[0],'forward',$seq,true,$userid);
1157 if($res){
1158 return $res;
1159 }
1160 else{
1161 //return end and exception
1162 }
1163 }
13458883 1164}
1165
1166function scorm_seq_resume_all_sequencing($scoid,$userid,$seq){
bf347041 1167 global $DB;
1168
081a9b0d 1169 if (!empty($seq->currentactivity)){
1170 $seq->delivery = null;
1171 $seq->exception = 'SB.2.6-1';
1172 return $seq;
1173 }
1174 $track = $DB->get_record('scorm_scoes_track', array('scoid'=>$scoid,'userid'=>$userid,'element'=>'suspendedactivity'));
13458883 1175 if (!$track) {
081a9b0d 1176 $seq->delivery = null;
1177 $seq->exception = 'SB.2.6-2';
1178 return $seq;
1179 }
1180 $seq->delivery = $DB->get_record('scorm_scoes', array('scoid'=>$scoid,'userid'=>$userid));//we assign the sco to the delivery
e5dd8e3b 1181
13458883 1182}
1183
1184function scorm_seq_continue_sequencing($scoid,$userid,$seq){
081a9b0d 1185 if (empty($seq->currentactivity)) {
1186 $seq->delivery = null;
1187 $seq->exception = 'SB.2.7-1';
1188 return $seq;
1189 }
1190 $currentact= $seq->currentactivity;
1191 if ($currentact->parent != '/') {//if the activity is the root and is leaf
1192 $parent = scorm_get_parent ($currentact);
1193
1194 if (!isset($parent->flow) || ($parent->flow == false)) {
1195 $seq->delivery = null;
1196 $seq->exception = 'SB.2.7-2';
1197 return $seq;
1198 }
1199
1200 $res = scorm_seq_flow($currentact,'forward',$seq,false,$userid);
1201 if($res){
1202 return $res;
1203 }
1204 else{
1205 //return end and exception
1206 }
1207
1208 }
1209}
1210
1211function scorm_seq_previous_sequencing($scoid,$userid,$seq){
1212 if (empty($seq->currentactivity)) {
1213 $seq->delivery = null;
1214 $seq->exception = 'SB.2.8-1';
1215 return $seq;
1216 }
e5dd8e3b 1217
081a9b0d 1218 $currentact= $seq->currentactivity;
1219 if ($currentact->parent != '/') {//if the activity is the root and is leaf
a4347c69 1220 $parent = scorm_get_parent ($currentact);
081a9b0d 1221 if (!isset($parent->flow) || ($parent->flow == false)) {
1222 $seq->delivery = null;
1223 $seq->exception = 'SB.2.8-2';
1224 return $seq;
1225 }
1226
1227 $res = scorm_seq_flow($currentact,'backward',$seq,false,$userid);
1228 if($res){
1229 return $res;
1230 }
1231 else{
1232 //return end and exception
1233 }
1234
1235 }
13458883 1236
1237}
1238
1239function scorm_seq_exit_sequencing($scoid,$userid,$seq){
081a9b0d 1240 if (empty($seq->currentactivity)) {
1241 $seq->delivery = null;
1242 $seq->exception = 'SB.2.11-1';
1243 return $seq;
1244 }
1245
1246 if ($seq->active){
1247 $seq->endsession = false;
1248 $seq->exception = 'SB.2.11-2';
1249 return $seq;
1250 }
1251 $currentact= $seq->currentactivity;
1252 if ($currentact->parent == '/'){
1253 $seq->endsession = true;
1254 return $seq;
1255 }
e5dd8e3b 1256
081a9b0d 1257 $seq->endsession = false;
1258 return $seq;
13458883 1259}
1260
1261
1262function scorm_seq_retry_sequencing($scoid,$userid,$seq){
081a9b0d 1263 if (empty($seq->currentactivity)) {
1264 $seq->delivery = null;
1265 $seq->exception = 'SB.2.10-1';
1266 return $seq;
1267 }
1268 if ($seq->active || $seq->suspended){
1269 $seq->delivery = null;
1270 $seq->exception = 'SB.2.10-2';
1271 return $seq;
1272 }
e5dd8e3b 1273
081a9b0d 1274 if (!scorm_is_leaf($seq->currentactivity)){
1275 $res = scorm_seq_flow($seq->currentactivity,'forward',$seq,true,$userid);
1276 if($res != null){
1277 return $res;
1278 //return deliver
1279 }
1280 else{
1281 $seq->delivery = null;
1282 $seq->exception = 'SB.2.10-3';
1283 return $seq;
1284 }
1285 }
1286 else{
1287 $seq->delivery = $seq->currentactivity;
1288 return $seq;
1289 }
13458883 1290
1291}
1292
1293function scorm_seq_flow ($candidate,$direction,$seq,$childrenflag,$userid){
5c58d55a 1294 //TODO: $PREVDIRECTION NOT DEFINED YET
081a9b0d 1295
1296 $activity=$candidate;
5c58d55a
DM
1297 $prevdirection = null;
1298 $seq = scorm_seq_flow_tree_traversal ($activity,$direction,$childrenflag,$prevdirection,$seq,$userid);
081a9b0d 1299 if($seq->identifiedactivity == null){//if identifies
1300 $seq->identifiedactivity = $candidate;
1301 $seq->deliverable = false;
1302 return $seq;
1303 }
1304 else{
1305 $activity = $seq->identifiedactivity;
1306 $seq = scorm_seq_flow_activity_traversal($activity,$userid,$direction,$childrenflag,$prevdirection,$seq,$userid);//
1307 return $seq;
1308
1309 }
13458883 1310}
1311
6d41befd 1312function 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 1313 $activity = scorm_get_sco ($activity);
1314 $parent = scorm_get_parent ($activity);
1536b92d 1315 if (!isset($parent->flow) || ($parent->flow == false)) {
081a9b0d 1316 $seq->deliverable = false;
1317 $seq->exception = 'SB.2.2-1';
1318 $seq->nextactivity = $activity;
1319 return $seq;
1320 }
e5dd8e3b 1321
bf347041 1322 $rulch = scorm_seq_rules_check($sco, 'skipped'); // TODO: undefined
081a9b0d 1323 if ($rulch != null){
1324 $seq = scorm_seq_flow_tree_traversal ($activity, $direction, false, $prevdirection, $seq,$userid);//endsession and exception
1325 if ($seq->identifiedactivity == null){
1326 $seq->deliverable = false;
1327 $seq->nextactivity = $activity;
1328 return $seq;
1329 }
1330 else{
e5dd8e3b 1331
081a9b0d 1332 if ($prevdirection = 'backward' && $seq->traversaldir == 'backward'){
1333 $seq = scorm_seq_flow_tree_traversal ($activity,$direction,false,null,$seq,$userid);
522aafc7 1334 $seq = scorm_seq_flow_activity_traversal($seq->identifiedactivity, $userid, $direction, $childrenflag, $prevdirection, $seq,$userid);
081a9b0d 1335 }
1336 else{
1337 $seq = scorm_seq_flow_tree_traversal ($activity,$direction,false,null,$seq,$userid);
522aafc7 1338 $seq = scorm_seq_flow_activity_traversal($seq->identifiedactivity, $userid, $direction, $childrenflag, $prevdirection, $seq,$userid);
081a9b0d 1339 }
1340 return $seq;
1341 }
1342 }
1343
1344 $ch=scorm_check_activity ($activity,$userid);
1345
1346 if ($ch){
1347
1348 $seq->deliverable = false;
1349 $seq->exception = 'SB.2.2-2';
1350 $seq->nextactivity = $activity;
1351 return $seq;
1352
1353 }
1354
1355 if (!scorm_is_leaf($activity)){
1356
1357 $seq = scorm_seq_flow_tree_traversal ($activity,$direction,true,null,$seq,$userid);
1358
1359 if ($seq->identifiedactivity == null){
1360 $seq->deliverable = false;
1361 $seq->nextactivity = $activity;
1362 return $seq;
1363 }
1364
1365 else{
1366 if($direction == 'backward' && $seq->traversaldir == 'forward'){
522aafc7 1367 $seq = scorm_seq_flow_activity_traversal($seq->identifiedactivity, $userid, 'forward', $childrenflag, 'backward', $seq,$userid);
081a9b0d 1368 }
1369 else{
522aafc7 1370 scorm_seq_flow_activity_traversal($seq->identifiedactivity, $userid, $direction, $childrenflag, null, $seq,$userid);
081a9b0d 1371 }
1372 return $seq;
1373 }
1374
1375 }
13458883 1376
1377 $seq->deliverable = true;
081a9b0d 1378 $seq->nextactivity = $activity;
13458883 1379 return $seq;
1380
1381}
6d41befd 1382function scorm_seq_flow_tree_traversal ($activity,$direction,$childrenflag,$prevdirection,$seq,$userid){
13458883 1383
081a9b0d 1384 $revdirection = false;
1385 $parent = scorm_get_parent ($activity);
1386 $children = scorm_get_available_children ($parent);
1387 $siz = sizeof ($children);
13458883 1388
1389 if (($prevdirection != null && $prevdirection == 'backward') && ($children[$siz-1]->id == $activity->id)){
081a9b0d 1390 $direction = 'backward';
1391 $children[0] = $activity;
1392 $revdirection = true;
1393 }
1394
1395 if($direction = 'forward'){
1396 $ancestors = scorm_get_ancestors($activity);
1397 $ancestorsroot = array_reverse($ancestors);
1398 $preorder = scorm_get_preorder ($ancestorsroot);
1399 $siz= sizeof ($preorder);
1400 if (($activity->id == $preorder[$siz-1]->id) || (($activity->parent == '/') && !($childrenflag))){
1401 scorm_seq_terminate_descent($ancestorsroot,$userid);
1402 $seq->endsession = true;
1403 $seq->nextactivity = null;
1404 return $seq;
1405 }
1406 if (scorm_is_leaf ($activity) || !$childrenflag){
1407 if ($children[$siz-1]->id == $activity->id){
e5dd8e3b 1408
081a9b0d 1409 $seq = scorm_seq_flow_tree_traversal ($parent, $direction, false, null, $seq,$userid);
1410 // I think it's not necessary to do a return in here
1411 }
1412 else{
1413 $parent = scorm_get_parent($activity);
1414 $children = scorm_get_available_children($parent);
1415 $seq->traversaldir = $direction;
1416 $sib = scorm_get_siblings($activity);
1417 $pos = array_search($sib, $activity);
1418 if ($pos !== false) {
1419 if ($pos != sizeof ($sib)){
1420 $seq->nextactivity = $sib [$pos+1];
1421 return $seq;
1422 }
1423 else{
1424 $ch = scorm_get_children($sib[0]);
1425 $seq->nextactivity = $ch[0];
1426 return $seq;
1427 }
1428 }
1429 }
1430 }
1431 else{
1432 if (!empty ($children)){
1433 $seq->traversaldir = $direction;
13458883 1434 $seq->nextactivity = $children[0];
081a9b0d 1435 return $seq;
1436 }
1437 else{
1438 $seq->traversaldir = null;
13458883 1439 $seq->nextactivity = $children[0];
081a9b0d 1440 $seq->exception = 'SB.2.1-2';
1441 return $seq;
1442 }
1443 }
e5dd8e3b 1444
081a9b0d 1445 }
1446 if($direction = 'backward'){
e5dd8e3b 1447
081a9b0d 1448 if ($activity->parent == '/'){
1449 $seq->traversaldir = null;
13458883 1450 $seq->nextactivity = null;
081a9b0d 1451 $seq->exception = 'SB.2.1-3';
1452 return $seq;
1453 }
1454 if (scorm_is_leaf ($activity) || !$childrenflag){
1455 if (!$revdirection){
1456 if (isset($parent->forwardonly) && ($parent->forwardonly == true)) {
1457 $seq->traversaldir = null;
13458883 1458 $seq->nextactivity = null;
081a9b0d 1459 $seq->exception = 'SB.2.1-4';
1460 return $seq;
1461 }
1462 }
1463 if ($children[0]->id == $activity->id){
0be8830f 1464 $seq = scorm_seq_flow_tree_traversal ($parent, 'backward', false, null, $seq, $userid);
081a9b0d 1465 return $seq;
1466 }
1467 else{
1468 $ancestors = scorm_get_ancestors($activity);
1469 $ancestorsroot = array_reverse ($ancestors);
1470 $preorder = scorm_get_preorder ($ancestorsroot);
1471 $pos = array_search($preorder, $children[$siz]);
1472 $preord = array_slice($preorder, 0, $pos-1);
1473 $revpreorder = array_reverse($preord);
1474 $position = array_search($revpreorder, $activity);
1475 $seq->nextactivity = $revpreorder[$pos+1];
1476 $seq->traversaldir = $direction;
1477 return $seq;
1478 }
1479 }
1480 else{
1481 if (!empty($children)){
1482 $activity = scorm_get_sco($activity->id);
1483 if (isset($parent->flow) && ($parent->flow == true)) {
1484 $children = scorm_get_children ($activity);
1485 $seq->traversaldir = 'forward';
13458883 1486 $seq->nextactivity = $children[0];
081a9b0d 1487 return $seq;
e5dd8e3b 1488
081a9b0d 1489 }
1490 else{
1491 $children = scorm_get_children ($activity);
1492 $seq->traversaldir = 'backward';
13458883 1493 $seq->nextactivity = $children[sizeof($children)-1];
081a9b0d 1494 return $seq;
1495 }
13458883 1496
081a9b0d 1497 }
1498 else{
e5dd8e3b 1499
081a9b0d 1500 $seq->traversaldir = null;
13458883 1501 $seq->nextactivity = null;
081a9b0d 1502 $seq->exception = 'SB.2.1-2';
1503 return $seq;
1504 }
1505 }
13458883 1506
081a9b0d 1507 }
13458883 1508
1509
1510}
1511function scorm_check_activity ($activity,$userid){
081a9b0d 1512 $act = scorm_seq_rules_check($activity,'disabled');
1513 if ($act != null){
1514 return true;
1515 }
13458883 1516 if(scorm_limit_cond_check ($activity,$userid)){
081a9b0d 1517 return true;
1518 }
1519 return false;
13458883 1520
1521
1522}
1523
1524function scorm_limit_cond_check ($activity,$userid){
bf347041 1525 global $DB;
13458883 1526
1527 if (isset($activity->tracked) && ($activity->tracked == 0)){
e5dd8e3b 1528
081a9b0d 1529 return false;
1530 }
1531
1532 if (scorm_seq_is('active',$activity->id,$userid) || scorm_seq_is('suspended',$activity->id,$userid)){
1533 return false;
1534 }
1535
e5dd8e3b 1536 if (!isset($activity->limitcontrol) || ($activity->limitcontrol == 1)){
081a9b0d 1537 $r = $DB->get_record('scorm_scoes_track', array('scoid'=>$activity->id,'userid'=>$userid,'element'=>'activityattemptcount'));
1538 if (scorm_seq_is('activityprogressstatus',$activity->id,$userid) && ($r->value >=$activity->limitattempt)){
1539 return true;
1540 }
1541 }
1542
e5dd8e3b 1543 if (!isset($activity->limitabsdurcontrol) || ($activity->limitabsdurcontrol == 1)){
081a9b0d 1544 $r = $DB->get_record('scorm_scoes_track', array('scoid'=>$activity->id,'userid'=>$userid,'element'=>'activityabsoluteduration'));
1545 if (scorm_seq_is('activityprogressstatus',$activity->id,$userid) && ($r->value >=$activity->limitabsduration)){
1546 return true;
1547 }
1548 }
1549
e5dd8e3b 1550 if (!isset($activity->limitexpdurcontrol) || ($activity->limitexpdurcontrol == 1)){
081a9b0d 1551 $r = $DB->get_record('scorm_scoes_track', array('scoid'=>$activity->id,'userid'=>$userid,'element'=>'activityexperiencedduration'));
1552 if (scorm_seq_is('activityprogressstatus',$activity->id,$userid) && ($r->value >=$activity->limitexpduration)){
1553 return true;
1554 }
1555 }
e5dd8e3b
PS
1556
1557 if (!isset($activity->limitattabsdurcontrol) || ($activity->limitattabsdurcontrol == 1)){
081a9b0d 1558 $r = $DB->get_record('scorm_scoes_track', array('scoid'=>$activity->id,'userid'=>$userid,'element'=>'attemptabsoluteduration'));
1559 if (scorm_seq_is('activityprogressstatus',$activity->id,$userid) && ($r->value >=$activity->limitattabsduration)){
1560 return true;
1561 }
1562 }
1563
e5dd8e3b 1564 if (!isset($activity->limitattexpdurcontrol) || ($activity->limitattexpdurcontrol == 1)){
081a9b0d 1565 $r = $DB->get_record('scorm_scoes_track', array('scoid'=>$activity->id,'userid'=>$userid,'element'=>'attemptexperiencedduration'));
1566 if (scorm_seq_is('activityprogressstatus',$activity->id,$userid) && ($r->value >=$activity->limitattexpduration)){
1567 return true;
1568 }
1569 }
1570
e5dd8e3b 1571 if (!isset($activity->limitbegincontrol) || ($activity->limitbegincontrol == 1)){
081a9b0d 1572 $r = $DB->get_record('scorm_scoes_track', array('scoid'=>$activity->id,'userid'=>$userid,'element'=>'begintime'));
1573 if (time()>=$activity->limitbegintime){
1574 return true;
1575 }
1576 }
1577
e5dd8e3b 1578 if (!isset($activity->limitbegincontrol) || ($activity->limitbegincontrol == 1)){
081a9b0d 1579 if (time()<$activity->limitbegintime){
1580 return true;
1581 }
1582 }
1583
e5dd8e3b 1584 if (!isset($activity->limitendcontrol) || ($activity->limitendcontrol == 1)){
081a9b0d 1585
1586 if (time()>$activity->limitendtime){
1587 return true;
1588 }
1589 }
1590 return false;
13458883 1591
1592
f3800343 1593}
1594
1595
1596function scorm_seq_choice_sequencing($sco,$userid,$seq){
1597
081a9b0d 1598 $avchildren = Array ();
1599 $comancestor = null;
1600 $traverse = null;
f3800343 1601
081a9b0d 1602 if ($sco == null){
1603 $seq->delivery = null;
1604 $seq->exception = 'SB.2.9-1';
1605 return $seq;
1606 }
f3800343 1607
1608 $ancestors = scorm_get_ancestors($sco);
1609 $arrpath = array_reverse($ancestors);
081a9b0d 1610 array_push ($arrpath,$sco);//path from the root to the target
f3800343 1611
081a9b0d 1612 foreach ($arrpath as $activity){
f3800343 1613
1614 if ($activity->parent != '/') {
081a9b0d 1615 $avchildren = scorm_get_available_children (scorm_get_parent($activity));
1616 $position = array_search($avchildren, $activity);
f3800343 1617 if ($position !== false){
081a9b0d 1618 $seq->delivery = null;
1619 $seq->exception = 'SB.2.9-2';
1620 return $seq;
1621 }
1622 }
f3800343 1623
081a9b0d 1624 if (scorm_seq_rules_check($activity,'hidefromchoice' != null)){
f3800343 1625
081a9b0d 1626 $seq->delivery = null;
1627 $seq->exception = 'SB.2.9-3';
1628 return $seq;
f3800343 1629
081a9b0d 1630 }
f3800343 1631
081a9b0d 1632 }
f3800343 1633
081a9b0d 1634 if ($sco->parent != '/') {
1635 $parent = scorm_sco_get_parent ($sco);
1636 if ( isset($parent->choice) && ($parent->choice == false)){
1637 $seq->delivery = null;
1638 $seq->exception = 'SB.2.9-4';
1639 return $seq;
1640 }
1641 }
f3800343 1642
081a9b0d 1643 if ($seq->currentactivity != null){
f3800343 1644 $commonpos = scorm_find_common_ancestor($ancestors,$seq->currentactivity);
081a9b0d 1645 $comancestor = $arrpath [$commonpos];
1646 }
1647 else{
1648 $comancestor = $arrpath [0];
1649 }
f3800343 1650
081a9b0d 1651 if($seq->currentactivity === $sco) {
f3800343 1652 break;
081a9b0d 1653 }
f3800343 1654
081a9b0d 1655 $sib = scorm_get_siblings($seq->currentactivity);
1656 $pos = array_search($sib, $sco);
f3800343 1657
081a9b0d 1658 if ($pos !== false){
f3800343 1659
081a9b0d 1660 $siblings = array_slice($sib, 0, $pos-1);
f3800343 1661
081a9b0d 1662 if (empty($siblings)){
f3800343 1663
081a9b0d 1664 $seq->delivery = null;
1665 $seq->exception = 'SB.2.9-5';
1666 return $seq;
f3800343 1667
081a9b0d 1668 }
e5dd8e3b 1669
081a9b0d 1670 $children = scorm_get_children (scorm_get_parent ($sco));
1671 $pos1 = array_search($children, $sco);
1672 $pos2 = array_search($seq->currentactivity, $sco);
1673 if ($pos1>$pos2){
1674 $traverse = 'forward';
1675 }
1676 else{
1677 $traverse = 'backward';
1678 }
1679
1680 foreach ($siblings as $sibling){
1681 $seq = scorm_seq_choice_activity_traversal($sibling,$userid,$seq,$traverse);
1682 if(!$seq->reachable){
1683 $seq->delivery = null;
1684 return $seq;
1685 }
1686 }
1687 break;
1688
1689 }
f3800343 1690
1691 if($seq->currentactivity == null || $seq->currentactivity == $comancestor){
081a9b0d 1692 $commonpos = scorm_find_common_ancestor($ancestors,$seq->currentactivity);
1693 $comtarget = array_slice($ancestors, 1,$commonpos-1);//path from the common ancestor to the target activity
1694 $comtarget = array_reverse($comtarget);
1695
1696 if (empty($comtarget)){
1697 $seq->delivery = null;
1698 $seq->exception = 'SB.2.9-5';
1699 return $seq;
1700 }
1701 foreach ($comtarget as $act){
1702 $seq = scorm_seq_choice_activity_traversal($act,$userid,$seq,'forward');
1703 if(!$seq->reachable){
1704 $seq->delivery = null;
1705 return $seq;
1706 }
980c089b 1707 $act = scorm_get_sco ($acti->id);
081a9b0d 1708 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?
1709 $seq->delivery = null;
1710 $seq->exception = 'SB.2.9-6';
1711 return $seq;
1712 }
1713 }
1714 break;
f3800343 1715
081a9b0d 1716 }
f3800343 1717
081a9b0d 1718 if ($comancestor->id == $sco->id){
f3800343 1719
1720 $ancestorscurrent = scorm_get_ancestors($seq->currentactivity);
081a9b0d 1721 $possco = array_search ($ancestorscurrent, $sco);
1722 $curtarget = array_slice($ancestorscurrent,0,$possco);//path from the current activity to the target
1723
1724 if (empty($curtarget)){
1725 $seq->delivery = null;
1726 $seq->exception = 'SB.2.9-5';
1727 return $seq;
1728 }
f3800343 1729 $i=0;
081a9b0d 1730 foreach ($curtarget as $activ){
1731 $i++;
1732 if ($i != sizeof($curtarget)){
1733 if ( isset($activ->choiceexit) && ($activ->choiceexit == false)){
1734 $seq->delivery = null;
1735 $seq->exception = 'SB.2.9-7';
1736 return $seq;
1737 }
1738 }
1739 }
1740 break;
1741 }
1742
1743 if (array_search ($ancestors, $comancestor)!== false){
1744 $ancestorscurrent = scorm_get_ancestors($seq->currentactivity);
1745 $commonpos = scorm_find_common_ancestor($ancestors,$sco);
1746 $curcommon = array_slice($ancestorscurrent,0,$commonpos-1);
1747 if(empty($curcommon)){
1748 $seq->delivery = null;
1749 $seq->exception = 'SB.2.9-5';
1750 return $seq;
1751 }
1752
1753 $constrained = null;
1754 foreach ($curcommon as $acti){
1755 $acti = scorm_get_sco($acti->id);
1756 if ( isset($acti->choiceexit) && ($acti->choiceexit == false)){
1757 $seq->delivery = null;
1758 $seq->exception = 'SB.2.9-7';
1759 return $seq;
1760 }
1761 if ($constrained == null){
1762 if($acti->constrainchoice == true){
1763 $constrained = $acti;
1764 }
1765 }
1766 }
1767 if ($constrained != null){
f3800343 1768 $fwdir = scorm_get_preorder($constrained);
1769
081a9b0d 1770 if(array_search ($fwdir, $sco)!== false){
1771 $traverse = 'forward';
1772 }
1773 else{
1774 $traverse = 'backward';
1775 }
1776 $seq = scorm_seq_choice_flow ($constrained, $traverse, $seq);
1777 $actconsider = $seq->identifiedactivity;
1778 $avdescendents = Array();
1779 $avdescendents= scorm_get_available_descendents ($actconsider);
1780 if (array_search ($avdescendents, $sco) !== false && $sco->id != $actconsider->id && $constrained->id != $sco->id ){
1781 $seq->delivery = null;
1782 $seq->exception = 'SB.2.9-8';
1783 return $seq;
1784 }
6d41befd 1785
f3800343 1786//CONTINUE 11.5.5
081a9b0d 1787 }
6d41befd 1788
081a9b0d 1789 $commonpos = scorm_find_common_ancestor($ancestors,$seq->currentactivity);
1790 $comtarget = array_slice($ancestors, 1,$commonpos-1);//path from the common ancestor to the target activity
1791 $comtarget = array_reverse($comtarget);
6d41befd 1792
081a9b0d 1793 if (empty($comtarget)){
1794 $seq->delivery = null;
1795 $seq->exception = 'SB.2.9-5';
1796 return $seq;
1797 }
6d41befd 1798
081a9b0d 1799 $fwdir = scorm_get_preorder($seq->currentactivity);
6d41befd 1800
081a9b0d 1801 if(array_search ($fwdir, $sco)!== false){
6d41befd 1802
081a9b0d 1803 foreach ($comtarget as $act){
1804 $seq = scorm_seq_choice_activity_traversal($act,$userid,$seq,'forward');
1805 if(!$seq->reachable){
1806 $seq->delivery = null;
1807 return $seq;
1808 }
980c089b 1809 $act = scorm_get_sco($act->id);
081a9b0d 1810 if(scorm_seq_is('active',$act->id,$userid) && ($act->id != $comancestor->id && ($act->preventactivation == true))){
1811 $seq->delivery = null;
1812 $seq->exception = 'SB.2.9-6';
1813 return $seq;
1814 }
1815 }
1816
1817 }
1818 else{
1819 foreach ($comtarget as $act){
1820 $act = scorm_get_sco($act->id);
1821 if(scorm_seq_is('active',$act->id,$userid) && ($act->id != $comancestor->id && ($act->preventactivation==true))){
1822 $seq->delivery = null;
1823 $seq->exception = 'SB.2.9-6';
1824 return $seq;
1825 }
1826 }
1827 }
e5dd8e3b 1828 break;
081a9b0d 1829 }
1830
1831 if(scorm_is_leaf ($sco)){
1832 $seq->delivery = $sco;
1833 $seq->exception = 'SB.2.9-6';
1834 return $seq;
1835 }
f3800343 1836
6d41befd 1837 $seq = scorm_seq_flow ($sco,'forward',$seq,true,$userid);
1838 if ($seq->deliverable == false){
081a9b0d 1839 scorm_terminate_descendent_attempts($comancestor,$userid,$seq);
1840 scorm_seq_end_attempt($comancestor,$userid,$seq->attempt);
1841 $seq->currentactivity = $sco;
1842 $seq->delivery = null;
1843 $seq->exception = 'SB.2.9-9';
1844 return $seq;
1845
1846 }
1847 else{
1848 return $seq;
1849 }
e5dd8e3b 1850
13458883 1851}
1852
6d41befd 1853function scorm_seq_choice_flow ($constrained, $traverse, $seq){
081a9b0d 1854 $seq = scorm_seq_choice_flow_tree ($constrained, $traverse, $seq);
1855 if ($seq->identifiedactivity == null){
6d41befd 1856 $seq->identifiedactivity = $constrained;
081a9b0d 1857 return $seq;
1858 }
1859 else{
1860 return $seq;
1861 }
6d41befd 1862}
1863
1864function scorm_seq_choice_flow_tree ($constrained, $traverse, $seq){
081a9b0d 1865 $islast = false;
1866 $parent = scorm_get_parent ($constrained);
1867 if ($traverse== 'forward'){
1868 $preord = scorm_get_preorder ($constrained);
1869 if (sizeof($preorder) == 0 || (sizeof($preorder) == 0 && $preorder[0]->id = $constrained->id)){ // TODO: undefined
1870 $islast = true;//the function is the last activity available
1871 }
1872 if ($constrained->parent == '/' || $islast){
1873 $seq->nextactivity = null;
1874 return $seq;
1875 }
1876 $avchildren = scorm_get_available_children ($parent);//available children
1877 if ($avchildren [sizeof($avchildren)-1]->id == $constrained->id){
1878 $seq = scorm_seq_choice_flow_tree ($parent, 'forward', $seq);
1879 return $seq;
1880 }
1881 else{
1882 $i=0;
1883 while($i < sizeof($avchildren)){
1884 if ($avchildren [$i]->id == $constrained->id){
1885 $seq->nextactivity = $avchildren [$i+1];
1886 return $seq;
1887 }
1888 else{
1889 $i++;
1890 }
1891 }
1892 }
1893
1894 }
1895
1896 if ($traverse== 'backward'){
1897 if($constrained->parent == '/' ){
1898 $seq->nextactivity = null;
1899 return $seq;
1900 }
1901
1902 $avchildren = scorm_get_available_children ($parent);//available children
1903 if ($avchildren [0]->id == $constrained->id){
1904 $seq = scorm_seq_choice_flow_tree ($parent, 'backward', $seq);
1905 return $seq;
1906 }
1907 else{
1908 $i=sizeof($avchildren)-1;
1909 while($i >=0){
1910 if ($avchildren [$i]->id == $constrained->id){
1911 $seq->nextactivity = $avchildren [$i-1];
1912 return $seq;
1913 }
1914 else{
1915 $i--;
1916 }
1917 }
1918 }
1919 }
6d41befd 1920}
1921function scorm_seq_choice_activity_traversal($activity,$userid,$seq,$direction){
1922
081a9b0d 1923 if($direction == 'forward'){
1924
1925 $act = scorm_seq_rules_check($activity,'stopforwardtraversal');
1926
1927 if($act != null){
1928 $seq->reachable = false;
1929 $seq->exception = 'SB.2.4-1';
1930 return $seq;
1931 }
1932 $seq->reachable = false;
1933 return $seq;
1934 }
1935
1936 if($direction == 'backward'){
1937 $parentsco = scorm_get_parent($activity);
1938 if($parentsco!= null){
1939 if (isset($parentsco->forwardonly) && ($parentsco->forwardonly == true)){
1940 $seq->reachable = false;
1941 $seq->exception = 'SB.2.4-2';
1942 return $seq;
1943 }
1944 else{
1945 $seq->reachable = false;
1946 $seq->exception = 'SB.2.4-3';
1947 return $seq;
1948 }
1949 }
1950 }
1951 $seq->reachable = true;
1952 return $seq;
6d41befd 1953
1954}
1955
1956//Delivery Request Process
1957
1958function scorm_sequencing_delivery($scoid,$userid,$seq){
1959
081a9b0d 1960 if(!scorm_is_leaf ($seq->delivery)){
1961 $seq->deliveryvalid = false;
1962 $seq->exception = 'DB.1.1-1';
1963 return $seq;
1964 }
1965 $ancestors = scorm_get_ancestors($seq->delivery);
6d41befd 1966 $arrpath = array_reverse($ancestors);
081a9b0d 1967 array_push ($arrpath,$seq->delivery);//path from the root to the target
6d41befd 1968
081a9b0d 1969 if (empty($arrpath)){
1970 $seq->deliveryvalid = false;
1971 $seq->exception = 'DB.1.1-2';
1972 return $seq;
1973 }
6d41befd 1974
081a9b0d 1975 foreach ($arrpath as $activity){
1976 if(scorm_check_activity ($activity,$userid)){
1977 $seq->deliveryvalid = false;
1978 $seq->exception = 'DB.1.1-3';
1979 return $seq;
1980 }
1981 }
6d41befd 1982
081a9b0d 1983 $seq->deliveryvalid = true;
1984 return $seq;
6d41befd 1985
1986}
1987
1988function scorm_content_delivery_environment ($seq,$userid){
bf347041 1989 global $DB;
6d41befd 1990
081a9b0d 1991 $act = $seq->currentactivity;
1992 if(scorm_seq_is('active',$act->id,$userid)){
1993 $seq->exception = 'DB.2-1';
1994 return $seq;
1995 }
1996 $track = $DB->get_record('scorm_scoes_track', array('scoid'=>$act->id,'userid'=>$userid,'element'=>'suspendedactivity'));
1997 if ($track != null){
2004f2ee 1998 $seq = scorm_clear_suspended_activity($seq->delivery, $seq, $userid);
081a9b0d 1999
2000 }
2001 $seq = scorm_terminate_descendent_attempts ($seq->delivery,$userid,$seq);
2002 $ancestors = scorm_get_ancestors($seq->delivery);
6d41befd 2003 $arrpath = array_reverse($ancestors);
081a9b0d 2004 array_push ($arrpath,$seq->delivery);
2005 foreach ($arrpath as $activity){
2006 if(!scorm_seq_is('active',$activity->id,$userid)){
2007 if(!isset($activity->tracked) || ($activity->tracked == 1)){
2008 if(!scorm_seq_is('suspended',$activity->id,$userid)){
2009 $r = $DB->get_record('scorm_scoes_track', array('scoid'=>$activity->id,'userid'=>$userid,'element'=>'activityattemptcount'));
2010 $r->value = ($r->value)+1;
2011 $DB->update_record ('scorm_scoes_track',$r);
2012 if ($r->value == 1){
2013 scorm_seq_set('activityprogressstatus', $activity->id, $userid, 'true');
2014 }
2015 scorm_insert_track($userid, $activity->scorm, $activity->id, 0, 'objectiveprogressstatus', 'false');
2016 scorm_insert_track($userid, $activity->scorm, $activity->id, 0, 'objectivesatisfiedstatus', 'false');
2017 scorm_insert_track($userid, $activity->scorm, $activity->id, 0, 'objectivemeasurestatus', 'false');
2018 scorm_insert_track($userid, $activity->scorm, $activity->id, 0, 'objectivenormalizedmeasure', 0.0);
2019
2020 scorm_insert_track($userid, $activity->scorm, $activity->id, 0, 'attemptprogressstatus', 'false');
2021 scorm_insert_track($userid, $activity->scorm, $activity->id, 0, 'attemptcompletionstatus', 'false');
2022 scorm_insert_track($userid, $activity->scorm, $activity->id, 0, 'attemptabsoluteduration', 0.0);
2023 scorm_insert_track($userid, $activity->scorm, $activity->id, 0, 'attemptexperiencedduration', 0.0);
2024 scorm_insert_track($userid, $activity->scorm, $activity->id, 0, 'attemptcompletionamount', 0.0);
2025 }
2026 }
6d41befd 2027 scorm_seq_set('active', $activity->id, $userid, 'true');
081a9b0d 2028 }
2029 }
2030 $seq->delivery = $seq->currentactivity;
2031 scorm_seq_set('suspendedactivity', $activity->id, $userid, 'false');
6d41befd 2032
081a9b0d 2033 //ONCE THE DELIVERY BEGINS (How should I check that?)
6d41befd 2034
2035 if(isset($activity->tracked) || ($activity->tracked == 0)){
e5dd8e3b 2036 //How should I track the info and what should I do to not record the information for the activity during delivery?
081a9b0d 2037 $atabsdur = $DB->get_record('scorm_scoes_track', array('scoid'=>$activity->id,'userid'=>$userid,'element'=>'attemptabsoluteduration'));
2038 $atexpdur = $DB->get_record('scorm_scoes_track', array('scoid'=>$activity->id,'userid'=>$userid,'element'=>'attemptexperiencedduration'));
2039 }
2040 return $seq;
6d41befd 2041
e5dd8e3b 2042
6d41befd 2043}
2004f2ee 2044function scorm_clear_suspended_activity($act,$seq, $userid){
bf347041 2045 global $DB;
081a9b0d 2046 $currentact= $seq->currentactivity;
2047 $track = $DB->get_record('scorm_scoes_track', array('scoid'=>$currentact->id,'userid'=>$userid,'element'=>'suspendedactivity')); // TODO: undefined
2048 if ($track != null){
2049 $ancestors = scorm_get_ancestors($act);
6d41befd 2050 $commonpos = scorm_find_common_ancestor($ancestors,$currentact);
2051 if ($commonpos !== false) {
2052 if ($activitypath = array_slice($ancestors,0,$commonpos)) {
081a9b0d 2053 if (!empty ($activitypath)){
6d41befd 2054
2055 foreach ($activitypath as $activity) {
081a9b0d 2056 if (scorm_is_leaf($activity)){
2057 scorm_seq_set('suspended',$activity->id,$userid,false);
2058 }
2059 else{
2060 $children = scorm_get_children($activity);
e5dd8e3b 2061 $bool= false;
081a9b0d 2062 foreach ($children as $child){
2063 if(scorm_seq_is('suspended',$child->id,$userid)){
2064 $bool= true;
2065 }
2066 }
6d41befd 2067 if(!$bool){
081a9b0d 2068 scorm_seq_set('suspended',$activity->id,$userid,false);
2069 }
2070 }
2071 }
2072 }
2073 }
2074 }
2075 scorm_seq_set('suspendedactivity',$act->id,$userid,false);
2076
2077 }
6d41befd 2078}
2079
2080function scorm_select_children_process($scoid,$userid){
bf347041 2081 global $DB;
6d41befd 2082
081a9b0d 2083 $sco = scorm_get_sco($scoid);
6d41befd 2084 if (!scorm_is_leaf($sco)){
081a9b0d 2085 if(!scorm_seq_is('suspended',$scoid,$userid) && !scorm_seq_is('active',$scoid,$userid)){
2086 $r = $DB->get_record('scorm_scoes_track', array('scoid'=>$scoid,'userid'=>$userid,'element'=>'selectiontiming'));
6d41befd 2087
2088 switch($r->value) {
2089
2090 case 'oneachnewattempt':
081a9b0d 2091 case 'never':
6d41befd 2092 break;
e5dd8e3b 2093
6d41befd 2094 case 'once':
2095 if(!scorm_seq_is('activityprogressstatus',$scoid,$userid)){
081a9b0d 2096 if(scorm_seq_is('selectioncountsstatus',$scoid,$userid)){
2097 $childlist = '';
2098 $res = $DB->get_record('scorm_scoes_track', array('scoid'=>$scoid,'userid'=>$userid,'element'=>'selectioncount'));
2099 $i = ($res->value)-1;
2100 $children = scorm_get_children ($sco);
2101
2102 while ($i>=0){
2103 $pos = array_rand($children);
2104 array_push($childlist,$children [$pos]);
2105 array_splice($children,$pos,1);
2106 $i--;
2107 }
2108 sort ($childlist);
2109 $clist = serialize ($childlist);
2110 scorm_seq_set('availablechildren', $scoid, $userid, false);
2111 scorm_seq_set('availablechildren', $scoid, $userid, $clist);
2112
2113
2114 }
2115 }
6d41befd 2116 break;
e5dd8e3b 2117
6d41befd 2118 }
2119
081a9b0d 2120 }
2121 }
6d41befd 2122}
2123
2124function scorm_randomize_children_process($scoid,$userid){
bf347041 2125 global $DB;
6d41befd 2126
081a9b0d 2127 $sco = scorm_get_sco($scoid);
6d41befd 2128 if (!scorm_is_leaf($sco)){
081a9b0d 2129 if(!scorm_seq_is('suspended',$scoid,$userid) && !scorm_seq_is('active',$scoid,$userid)){
2130 $r = $DB->get_record('scorm_scoes_track', array('scoid'=>$scoid,'userid'=>$userid,'element'=>'randomizationtiming'));
6d41befd 2131
2132 switch($r->value) {
2133
e5dd8e3b 2134
081a9b0d 2135 case 'never':
6d41befd 2136 break;
e5dd8e3b 2137
6d41befd 2138 case 'oneachnewattempt':
2139 case 'once':
2140 if(!scorm_seq_is('activityprogressstatus',$scoid,$userid)){
081a9b0d 2141 if(scorm_seq_is('randomizechildren',$scoid,$userid)){
2142 $childlist = array();
2143 $res = scorm_get_available_children($sco);
2144 $i = sizeof($res)-1;
2145 $children = $res->value;
2146
2147 while ($i>=0){
2148 $pos = array_rand($children);
2149 array_push($childlist,$children [$pos]);
2150 array_splice($children,$pos,1);
2151 $i--;
2152 }
e5dd8e3b 2153
081a9b0d 2154 $clist = serialize ($childlist);
2155 scorm_seq_set('availablechildren', $scoid, $userid, false);
2156 scorm_seq_set('availablechildren', $scoid, $userid, $clist);
2157
2158
2159 }
2160 }
6d41befd 2161 break;
e5dd8e3b
PS
2162
2163
2164
6d41befd 2165 }
2166
081a9b0d 2167 }
2168 }
6d41befd 2169}
2170
980c089b 2171function scorm_terminate_descendent_attempts ($activity,$userid,$seq){
081a9b0d 2172 $ancestors = scorm_get_ancestors($seq->currentactivity);
6d41befd 2173 $commonpos = scorm_find_common_ancestor($ancestors,$activity);
2174 if ($commonpos !== false) {
2175 if ($activitypath = array_slice($ancestors,1,$commonpos-2)) {
081a9b0d 2176 if (!empty ($activitypath)){
6d41befd 2177
2178 foreach ($activitypath as $sco) {
081a9b0d 2179 scorm_seq_end_attempt($sco,$userid,$seq->attempt);
e5dd8e3b 2180
081a9b0d 2181 }
2182 }
2183 }
e5dd8e3b 2184 }
6d41befd 2185}
af8ed6dc 2186
2187function scorm_sequencing_exception($seq){
6aff538a 2188 global $OUTPUT;
af8ed6dc 2189 if($seq->exception != null){
081a9b0d 2190 switch($seq->exception){
af8ed6dc 2191
081a9b0d 2192 case 'NB.2.1-1':
6aff538a 2193 echo $OUTPUT->notification("Sequencing session has already begun");
05069950 2194 break;
2195 case 'NB.2.1-2':
6aff538a 2196 echo $OUTPUT->notification("Sequencing session has not begun");
05069950 2197 break;
081a9b0d 2198 case 'NB.2.1-3':
6aff538a 2199 echo $OUTPUT->notification("Suspended activity is not defined");
05069950 2200 break;
081a9b0d 2201 case 'NB.2.1-4':
6aff538a 2202 echo $OUTPUT->notification("Flow Sequencing Control Model Violation");
05069950 2203 break;
081a9b0d 2204 case 'NB.2.1-5':
6aff538a 2205 echo $OUTPUT->notification("Flow or Forward only Sequencing Control Model Violation");
05069950 2206 break;
081a9b0d 2207 case 'NB.2.1-6':
6aff538a 2208 echo $OUTPUT->notification("No activity is previous to the root");
05069950 2209 break;
081a9b0d 2210 case 'NB.2.1-7':
6aff538a 2211 echo $OUTPUT->notification("Unsupported Navigation Request");
05069950 2212 break;
081a9b0d 2213 case 'NB.2.1-8':
6aff538a 2214 echo $OUTPUT->notification("Choice Exit Sequencing Control Model Violation");
05069950 2215 break;
081a9b0d 2216 case 'NB.2.1-9':
6aff538a 2217 echo $OUTPUT->notification("No activities to consider");
05069950 2218 break;
081a9b0d 2219 case 'NB.2.1-10':
6aff538a 2220 echo $OUTPUT->notification("Choice Sequencing Control Model Violation");
05069950 2221 break;
081a9b0d 2222 case 'NB.2.1-11':
6aff538a 2223 echo $OUTPUT->notification("Target Activity does not exist");
05069950 2224 break;
081a9b0d 2225 case 'NB.2.1-12':
6aff538a 2226 echo $OUTPUT->notification("Current Activity already terminated");
05069950 2227 break;
081a9b0d 2228 case 'NB.2.1-13':
6aff538a 2229 echo $OUTPUT->notification("Undefined Navigation Request");
05069950 2230 break;
af8ed6dc 2231
081a9b0d 2232 case 'TB.2.3-1':
6aff538a 2233 echo $OUTPUT->notification("Current Activity already terminated");
05069950 2234 break;
081a9b0d 2235 case 'TB.2.3-2':
6aff538a 2236 echo $OUTPUT->notification("Current Activity already terminated");
05069950 2237 break;
081a9b0d 2238 case 'TB.2.3-4':
6aff538a 2239 echo $OUTPUT->notification("Current Activity already terminated");
05069950 2240 break;
081a9b0d 2241 case 'TB.2.3-5':
6aff538a 2242 echo $OUTPUT->notification("Nothing to suspend; No active activities");
05069950 2243 break;
081a9b0d 2244 case 'TB.2.3-6':
6aff538a 2245 echo $OUTPUT->notification("Nothing to abandon; No active activities");
05069950 2246 break;
2247
081a9b0d 2248 case 'SB.2.1-1':
6aff538a 2249 echo $OUTPUT->notification("Last activity in the tree");
05069950 2250 break;
2251 case 'SB.2.1-2':
6aff538a 2252 echo $OUTPUT->notification("Cluster has no available children");
05069950 2253 break;
081a9b0d 2254 case 'SB.2.1-3':
6aff538a 2255 echo $OUTPUT->notification("No activity is previous to the root");
05069950 2256 break;
081a9b0d 2257 case 'SB.2.1-4':
6aff538a 2258 echo $OUTPUT->notification("Forward Only Sequencing Control Model Violation");
05069950 2259 break;
2260
081a9b0d 2261 case 'SB.2.2-1':
6aff538a 2262 echo $OUTPUT->notification("Flow Sequencing Control Model Violation");
05069950 2263 break;
081a9b0d 2264 case 'SB.2.2-2':
6aff538a 2265 echo $OUTPUT->notification("Activity unavailable");
05069950 2266 break;
2267
081a9b0d 2268 case 'SB.2.3-1':
6aff538a 2269 echo $OUTPUT->notification("Forward Traversal Blocked");
05069950 2270 break;
2271 case 'SB.2.3-2':
6aff538a 2272 echo $OUTPUT->notification("Forward Only Sequencing Control Model Violation");
05069950 2273 break;
081a9b0d 2274 case 'SB.2.3-3':
6aff538a 2275 echo $OUTPUT->notification("No activity is previous to the root");
05069950 2276 break;
2277
081a9b0d 2278 case 'SB.2.5-1':
6aff538a 2279 echo $OUTPUT->notification("Sequencing session has already begun");
05069950 2280 break;
2281
081a9b0d 2282 case 'SB.2.6-1':
6aff538a 2283 echo $OUTPUT->notification("Sequencing session has already begun");
05069950 2284 break;
081a9b0d 2285 case 'SB.2.6-2':
6aff538a 2286 echo $OUTPUT->notification("No Suspended activity is defined");
05069950 2287 break;
2288
2289 case 'SB.2.7-1':
6aff538a 2290 echo $OUTPUT->notification("Sequencing session has not begun");
05069950 2291 break;
081a9b0d 2292 case 'SB.2.7-2':
6aff538a 2293 echo $OUTPUT->notification("Flow Sequencing Control Model Violation");
05069950 2294 break;
2295
081a9b0d 2296 case 'SB.2.8-1':
6aff538a 2297 echo $OUTPUT->notification("Sequencing session has not begun");
05069950 2298 break;
081a9b0d 2299 case 'SB.2.8-2':
6aff538a 2300 echo $OUTPUT->notification("Flow Sequencing Control Model Violation");
05069950 2301 break;
2302
081a9b0d 2303 case 'SB.2.9-1':
6aff538a 2304 echo $OUTPUT->notification("No target for Choice");
05069950 2305 break;
081a9b0d 2306 case 'SB.2.9-2':
6aff538a 2307 echo $OUTPUT->notification("Target Activity does not exist or is unavailable");
05069950 2308 break;
081a9b0d 2309 case 'SB.2.9-3':
6aff538a 2310 echo $OUTPUT->notification("Target Activity hidden from choice");
05069950 2311 break;
081a9b0d 2312 case 'SB.2.9-4':
6aff538a 2313 echo $OUTPUT->notification("Choice Sequencing Control Model Violation");
05069950 2314 break;
081a9b0d 2315 case 'SB.2.9-5':
6aff538a 2316 echo $OUTPUT->notification("No activities to consider");
05069950 2317 break;
081a9b0d 2318 case 'SB.2.9-6':
6aff538a 2319 echo $OUTPUT->notification("Unable to activate target; target is not a child of the Current Activity");
05069950 2320 break;
081a9b0d 2321 case 'SB.2.9-7':
6aff538a 2322 echo $OUTPUT->notification("Choice Exit Sequencing Control Model Violation");
05069950 2323 break;
081a9b0d 2324 case 'SB.2.9-8':
6aff538a 2325 echo $OUTPUT->notification("Unable to choose target activity - constrained choice");
05069950 2326 break;
081a9b0d 2327 case 'SB.2.9-9':
6aff538a 2328 echo $OUTPUT->notification("Choice Request Prevented by Flow-only Activity");
05069950 2329 break;
2330
081a9b0d 2331 case 'SB.2.10-1':
6aff538a 2332 echo $OUTPUT->notification("Sequencing session has not begun");
05069950 2333 break;
081a9b0d 2334 case 'SB.2.10-2':
6aff538a 2335 echo $OUTPUT->notification("Current Activity is active or suspended");
05069950 2336 break;
081a9b0d 2337 case 'SB.2.10-3':
6aff538a 2338 echo $OUTPUT->notification("Flow Sequencing Control Model Violation");
05069950 2339 break;
e5dd8e3b 2340
05069950 2341 case 'SB.2.11-1':
6aff538a 2342 echo $OUTPUT->notification("Sequencing session has not begun");
05069950 2343 break;
081a9b0d 2344 case 'SB.2.11-2':
6aff538a 2345 echo $OUTPUT->notification("Current Activity has not been terminated");
05069950 2346 break;
2347
081a9b0d 2348 case 'SB.2.12-2':
6aff538a 2349 echo $OUTPUT->notification("Undefined Sequencing Request");
05069950 2350 break;
2351
081a9b0d 2352 case 'DB.1.1-1':
6aff538a 2353 echo $OUTPUT->notification("Cannot deliver a non-leaf activity");
05069950 2354 break;
081a9b0d 2355 case 'DB.1.1-2':
6aff538a 2356 echo $OUTPUT->notification("Nothing to deliver");
05069950 2357 break;
081a9b0d 2358 case 'DB.1.1-3':
6aff538a 2359 echo $OUTPUT->notification("Activity unavailable");
05069950 2360 break;
2361
081a9b0d 2362 case 'DB.2-1':
6aff538a 2363 echo $OUTPUT->notification("Identified activity is already active");
05069950 2364 break;
e5dd8e3b 2365
081a9b0d 2366 }
e5dd8e3b 2367
081a9b0d 2368 }
af8ed6dc 2369}
2370
2371
2372
6d41befd 2373
e5dd8e3b 2374