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