MDL-45339 Libraries: Add a note to docblock of get_config, set_config, and unset_conf...
[moodle.git] / mod / scorm / datamodels / aicc.js.php
1 <?php
2 // This file is part of Moodle - http://moodle.org/
3 //
4 // Moodle is free software: you can redistribute it and/or modify
5 // it under the terms of the GNU General Public License as published by
6 // the Free Software Foundation, either version 3 of the License, or
7 // (at your option) any later version.
8 //
9 // Moodle is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12 // GNU General Public License for more details.
13 //
14 // You should have received a copy of the GNU General Public License
15 // along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
17 if (isset($userdata->status)) {
18     if ($userdata->status == '') {
19         $userdata->entry = 'ab-initio';
20     } else {
21         if (isset($userdata->{'cmi.core.exit'}) && ($userdata->{'cmi.core.exit'} == 'suspend')) {
22             $userdata->entry = 'resume';
23         } else {
24             $userdata->entry = '';
25         }
26     }
27 }
28 if (!isset($currentorg)) {
29     $currentorg = '';
30 }
31 ?>
32 //
33 // SCORM 1.2 API Implementation
34 //
35 function AICCapi() {
36     // Standard Data Type Definition
37     CMIString256 = '^.{0,255}$';
38     CMIString4096 = '^.{0,4096}$';
39     CMITime = '^([0-2]{1}[0-9]{1}):([0-5]{1}[0-9]{1}):([0-5]{1}[0-9]{1})(\.[0-9]{1,2})?$';
40     CMITimespan = '^([0-9]{2,4}):([0-9]{2}):([0-9]{2})(\.[0-9]{1,2})?$';
41     CMIInteger = '^\\d+$';
42     CMISInteger = '^-?([0-9]+)$';
43     CMIDecimal = '^-?([0-9]{0,3})(\.[0-9]{1,2})?$';
44     CMIIdentifier = '^\\w{1,255}$';
45     CMIFeedback = CMIString256; // This must be redefined
46     CMIIndex = '[._](\\d+).';
48     // Vocabulary Data Type Definition
49     CMIStatus = '^passed$|^completed$|^failed$|^incomplete$|^browsed$';
50     CMIStatus2 = '^passed$|^completed$|^failed$|^incomplete$|^browsed$|^not attempted$';
51     CMIExit = '^time-out$|^suspend$|^logout$|^$';
52     CMIType = '^true-false$|^choice$|^fill-in$|^matching$|^performance$|^sequencing$|^likert$|^numeric$';
53     CMIResult = '^correct$|^wrong$|^unanticipated$|^neutral$|^([0-9]{0,3})?(\.[0-9]{1,2})?$';
54     NAVEvent = '^previous$|^continue$';
56     // Children lists
57     cmi_children = 'core, suspend_data, launch_data, comments, objectives, student_data, student_preference, interactions';
58     core_children = 'student_id, student_name, lesson_location, credit, lesson_status, entry, score, total_time, lesson_mode, exit, session_time';
59     score_children = 'raw, min, max';
60     comments_children = 'content, location, time';
61     objectives_children = 'id, score, status';
62     student_data_children = 'attempt_number, tries, mastery_score, max_time_allowed, time_limit_action';
63     student_preference_children = 'audio, language, speed, text';
64     interactions_children = 'id, objectives, time, type, correct_responses, weighting, student_response, result, latency';
66     // Data ranges
67     score_range = '0#100';
68     audio_range = '-1#100';
69     speed_range = '-100#100';
70     weighting_range = '-100#100';
71     text_range = '-1#1';
73     // The AICC data model
74     var datamodel =  {
75         'cmi._children':{'defaultvalue':cmi_children, 'mod':'r', 'writeerror':'402'},
76         'cmi._version':{'defaultvalue':'3.4', 'mod':'r', 'writeerror':'402'},
77         'cmi.core._children':{'defaultvalue':core_children, 'mod':'r', 'writeerror':'402'},
78         'cmi.core.student_id':{'defaultvalue':'<?php echo $userdata->student_id ?>', 'mod':'r', 'writeerror':'403'},
79         'cmi.core.student_name':{'defaultvalue':'<?php echo $userdata->student_name ?>', 'mod':'r', 'writeerror':'403'},
80         'cmi.core.lesson_location':{'defaultvalue':'<?php echo isset($userdata->{'cmi.core.lesson_location'})?$userdata->{'cmi.core.lesson_location'}:'' ?>', 'format':CMIString256, 'mod':'rw', 'writeerror':'405'},
81         'cmi.core.credit':{'defaultvalue':'<?php echo $userdata->credit ?>', 'mod':'r', 'writeerror':'403'},
82         'cmi.core.lesson_status':{'defaultvalue':'<?php echo isset($userdata->{'cmi.core.lesson_status'})?$userdata->{'cmi.core.lesson_status'}:'' ?>', 'format':CMIStatus, 'mod':'rw', 'writeerror':'405'},
83         'cmi.core.exit':{'defaultvalue':'<?php echo isset($userdata->{'cmi.core.exit'})?$userdata->{'cmi.core.exit'}:'' ?>', 'format':CMIExit, 'mod':'w', 'readerror':'404', 'writeerror':'405'},
84         'cmi.core.entry':{'defaultvalue':'<?php echo $userdata->entry ?>', 'mod':'r', 'writeerror':'403'},
85         'cmi.core.score._children':{'defaultvalue':score_children, 'mod':'r', 'writeerror':'402'},
86         'cmi.core.score.raw':{'defaultvalue':'<?php echo isset($userdata->{'cmi.core.score.raw'})?$userdata->{'cmi.core.score.raw'}:'' ?>', 'format':CMIDecimal, 'range':score_range, 'mod':'rw', 'writeerror':'405'},
87         'cmi.core.score.max':{'defaultvalue':'<?php echo isset($userdata->{'cmi.core.score.max'})?$userdata->{'cmi.core.score.max'}:'' ?>', 'format':CMIDecimal, 'range':score_range, 'mod':'rw', 'writeerror':'405'},
88         'cmi.core.score.min':{'defaultvalue':'<?php echo isset($userdata->{'cmi.core.score.min'})?$userdata->{'cmi.core.score.min'}:'' ?>', 'format':CMIDecimal, 'range':score_range, 'mod':'rw', 'writeerror':'405'},
89         'cmi.core.session_time':{'format':CMITimespan, 'mod':'w', 'defaultvalue':'00:00:00', 'readerror':'404', 'writeerror':'405'},
90         'cmi.core.total_time':{'defaultvalue':'<?php echo isset($userdata->{'cmi.core.total_time'})?$userdata->{'cmi.core.total_time'}:'00:00:00' ?>', 'mod':'r', 'writeerror':'403'},
91         'cmi.core.lesson_mode':{'defaultvalue':'<?php echo $userdata->mode ?>', 'mod':'r', 'writeerror':'403'},
92         'cmi.suspend_data':{'defaultvalue':'<?php echo isset($userdata->{'cmi.suspend_data'})?$userdata->{'cmi.suspend_data'}:'' ?>', 'format':CMIString4096, 'mod':'rw', 'writeerror':'405'},
93         'cmi.launch_data':{'defaultvalue':'<?php echo isset($userdata->datafromlms)?$userdata->datafromlms:'' ?>', 'mod':'r', 'writeerror':'403'},
94         'cmi.comments':{'defaultvalue':'<?php echo isset($userdata->{'cmi.comments'})?$userdata->{'cmi.comments'}:'' ?>', 'format':CMIString4096, 'mod':'rw', 'writeerror':'405'},
95         // deprecated evaluation attributes
96         'cmi.evaluation.comments._count':{'defaultvalue':'0', 'mod':'r', 'writeerror':'402'},
97         'cmi.evaluation.comments._children':{'defaultvalue':comments_children, 'mod':'r', 'writeerror':'402'},
98         'cmi.evaluation.comments.n.content':{'defaultvalue':'', 'pattern':CMIIndex, 'format':CMIString256, 'mod':'rw', 'writeerror':'405'},
99         'cmi.evaluation.comments.n.location':{'defaultvalue':'', 'pattern':CMIIndex, 'format':CMIString256, 'mod':'rw', 'writeerror':'405'},
100         'cmi.evaluation.comments.n.time':{'defaultvalue':'', 'pattern':CMIIndex, 'format':CMITime, 'mod':'rw', 'writeerror':'405'},
101         'cmi.comments_from_lms':{'mod':'r', 'writeerror':'403'},
102         'cmi.objectives._children':{'defaultvalue':objectives_children, 'mod':'r', 'writeerror':'402'},
103         'cmi.objectives._count':{'mod':'r', 'defaultvalue':'0', 'writeerror':'402'},
104         'cmi.objectives.n.id':{'pattern':CMIIndex, 'format':CMIIdentifier, 'mod':'rw', 'writeerror':'405'},
105         'cmi.objectives.n.score._children':{'pattern':CMIIndex, 'mod':'r', 'writeerror':'402'},
106         'cmi.objectives.n.score.raw':{'defaultvalue':'', 'pattern':CMIIndex, 'format':CMIDecimal, 'range':score_range, 'mod':'rw', 'writeerror':'405'},
107         'cmi.objectives.n.score.min':{'defaultvalue':'', 'pattern':CMIIndex, 'format':CMIDecimal, 'range':score_range, 'mod':'rw', 'writeerror':'405'},
108         'cmi.objectives.n.score.max':{'defaultvalue':'', 'pattern':CMIIndex, 'format':CMIDecimal, 'range':score_range, 'mod':'rw', 'writeerror':'405'},
109         'cmi.objectives.n.status':{'pattern':CMIIndex, 'format':CMIStatus2, 'mod':'rw', 'writeerror':'405'},
110         'cmi.student_data._children':{'defaultvalue':student_data_children, 'mod':'r', 'writeerror':'402'},
111         'cmi.student_data.attempt_number':{'defaultvalue':'<?php echo isset($userdata->{'cmi.student_data.attempt_number'})?$userdata->{'cmi.student_data.attempt_number'}:'' ?>', 'mod':'r', 'writeerror':'402'},
112         'cmi.student_data.tries.n.score.raw':{'defaultvalue':'', 'pattern':CMIIndex, 'format':CMIDecimal, 'range':score_range, 'mod':'rw', 'writeerror':'405'},
113         'cmi.student_data.tries.n.score.min':{'defaultvalue':'', 'pattern':CMIIndex, 'format':CMIDecimal, 'range':score_range, 'mod':'rw', 'writeerror':'405'},
114         'cmi.student_data.tries.n.score.max':{'defaultvalue':'', 'pattern':CMIIndex, 'format':CMIDecimal, 'range':score_range, 'mod':'rw', 'writeerror':'405'},
115         'cmi.student_data.tries.n.status':{'pattern':CMIIndex, 'format':CMIStatus2, 'mod':'rw', 'writeerror':'405'},
116         'cmi.student_data.tries.n.time':{'pattern':CMIIndex, 'format':CMITime, 'mod':'rw', 'writeerror':'405'},
117         'cmi.student_data.mastery_score':{'defaultvalue':'<?php echo isset($userdata->mastery_score)?$userdata->mastery_score:'' ?>', 'mod':'r', 'writeerror':'403'},
118         'cmi.student_data.max_time_allowed':{'defaultvalue':'<?php echo isset($userdata->max_time_allowed)?$userdata->max_time_allowed:'' ?>', 'mod':'r', 'writeerror':'403'},
119         'cmi.student_data.time_limit_action':{'defaultvalue':'<?php echo isset($userdata->time_limit_action)?$userdata->time_limit_action:'' ?>', 'mod':'r', 'writeerror':'403'},
120         'cmi.student_data.tries_during_lesson':{'defaultvalue':'<?php echo isset($userdata->{'cmi.student_data.tries_during_lesson'})?$userdata->{'cmi.student_data.tries_during_lesson'}:'' ?>', 'mod':'r', 'writeerror':'402'},
121         'cmi.student_preference._children':{'defaultvalue':student_preference_children, 'mod':'r', 'writeerror':'402'},
122         'cmi.student_preference.audio':{'defaultvalue':'0', 'format':CMISInteger, 'range':audio_range, 'mod':'rw', 'writeerror':'405'},
123         'cmi.student_preference.language':{'defaultvalue':'', 'format':CMIString256, 'mod':'rw', 'writeerror':'405'},
124         'cmi.student_preference.speed':{'defaultvalue':'0', 'format':CMISInteger, 'range':speed_range, 'mod':'rw', 'writeerror':'405'},
125         'cmi.student_preference.text':{'defaultvalue':'0', 'format':CMISInteger, 'range':text_range, 'mod':'rw', 'writeerror':'405'},
126         'cmi.interactions._children':{'defaultvalue':interactions_children, 'mod':'r', 'writeerror':'402'},
127         'cmi.interactions._count':{'mod':'r', 'defaultvalue':'0', 'writeerror':'402'},
128         'cmi.interactions.n.id':{'pattern':CMIIndex, 'format':CMIIdentifier, 'mod':'w', 'readerror':'404', 'writeerror':'405'},
129         'cmi.interactions.n.objectives._count':{'pattern':CMIIndex, 'mod':'r', 'defaultvalue':'0', 'writeerror':'402'},
130         'cmi.interactions.n.objectives.n.id':{'pattern':CMIIndex, 'format':CMIIdentifier, 'mod':'w', 'readerror':'404', 'writeerror':'405'},
131         'cmi.interactions.n.time':{'pattern':CMIIndex, 'format':CMITime, 'mod':'w', 'readerror':'404', 'writeerror':'405'},
132         'cmi.interactions.n.type':{'pattern':CMIIndex, 'format':CMIType, 'mod':'w', 'readerror':'404', 'writeerror':'405'},
133         'cmi.interactions.n.correct_responses._count':{'pattern':CMIIndex, 'mod':'r', 'defaultvalue':'0', 'writeerror':'402'},
134         'cmi.interactions.n.correct_responses.n.pattern':{'pattern':CMIIndex, 'format':CMIFeedback, 'mod':'w', 'readerror':'404', 'writeerror':'405'},
135         'cmi.interactions.n.weighting':{'pattern':CMIIndex, 'format':CMIDecimal, 'range':weighting_range, 'mod':'w', 'readerror':'404', 'writeerror':'405'},
136         'cmi.interactions.n.student_response':{'pattern':CMIIndex, 'format':CMIFeedback, 'mod':'w', 'readerror':'404', 'writeerror':'405'},
137         'cmi.interactions.n.result':{'pattern':CMIIndex, 'format':CMIResult, 'mod':'w', 'readerror':'404', 'writeerror':'405'},
138         'cmi.interactions.n.latency':{'pattern':CMIIndex, 'format':CMITimespan, 'mod':'w', 'readerror':'404', 'writeerror':'405'},
139         'nav.event':{'defaultvalue':'', 'format':NAVEvent, 'mod':'w', 'readerror':'404', 'writeerror':'405'}
140     };
142     //
143     // Datamodel inizialization
144     //
145     var cmi = new Object();
146         cmi.core = new Object();
147         cmi.core.score = new Object();
148         cmi.objectives = new Object();
149         cmi.student_data = new Object();
150         cmi.student_preference = new Object();
151         cmi.interactions = new Object();
152         // deprecated evaluation attributes
153         cmi.evaluation = new Object();
154         cmi.evaluation.comments = new Object();
156     // Navigation Object
157     var nav = new Object();
159     for (element in datamodel) {
160         if (element.match(/\.n\./) == null) {
161             if ((typeof eval('datamodel["'+element+'"].defaultvalue')) != 'undefined') {
162                 eval(element+' = datamodel["'+element+'"].defaultvalue;');
163             } else {
164                 eval(element+' = "";');
165             }
166         }
167     }
169 <?php
170 $current_objective = '';
171 $count = 0;
172 $objectives = '';
173 foreach ($userdata as $element => $value) {
174     if (substr($element, 0, 14) == 'cmi.objectives') {
175         $element = preg_replace('/\.(\d+)\./', "_\$1.", $element);
176         preg_match('/\_(\d+)\./', $element, $matches);
177         if (count($matches) > 0 && $current_objective != $matches[1]) {
178             $current_objective = $matches[1];
179             $count++;
180             $end = strpos($element, $matches[1])+strlen($matches[1]);
181             $subelement = substr($element, 0, $end);
182             echo '    '.$subelement." = new Object();\n";
183             echo '    '.$subelement.".score = new Object();\n";
184             echo '    '.$subelement.".score._children = score_children;\n";
185             echo '    '.$subelement.".score.raw = '';\n";
186             echo '    '.$subelement.".score.min = '';\n";
187             echo '    '.$subelement.".score.max = '';\n";
188         }
189         echo '    '.$element.' = \''.$value."';\n";
190     }
192 if ($count > 0) {
193     echo '    cmi.objectives._count = '.$count.";\n";
195 ?>
197     if (cmi.core.lesson_status == '') {
198         cmi.core.lesson_status = 'not attempted';
199     }
201     //
202     // API Methods definition
203     //
204     var Initialized = false;
206     function LMSInitialize (param) {
207         errorCode = "0";
208         if (param == "") {
209             if (!Initialized) {
210                 Initialized = true;
211                 errorCode = "0";
212                 return "true";
213             } else {
214                 errorCode = "101";
215             }
216         } else {
217             errorCode = "201";
218         }
219         return "false";
220     }
222     function LMSFinish (param) {
223         errorCode = "0";
224         if (param == "") {
225             if (Initialized) {
226                 Initialized = false;
227                 result = StoreData(cmi,true);
228                 if (nav.event != '') {
229                     if (nav.event == 'continue') {
230                         setTimeout('mod_scorm_launch_next_sco();',500);
231                     } else {
232                         setTimeout('mod_scorm_launch_prev_sco();',500);
233                     }
234                 } else {
235                     if (<?php echo $scorm->auto ?> == 1) {
236                         setTimeout('mod_scorm_launch_next_sco();',500);
237                     }
238                 }
239                 // trigger TOC update
240                 var sURL = "<?php echo $CFG->wwwroot; ?>" + "/mod/scorm/prereqs.php?a=<?php echo $scorm->id ?>&scoid=<?php echo $scoid ?>&attempt=<?php echo $attempt ?>&mode=<?php echo $mode ?>&currentorg=<?php echo $currentorg ?>&sesskey=<?php echo sesskey(); ?>";
241                 var callback = M.mod_scorm.connectPrereqCallback;
242                 YUI().use('io-base', function(Y) {
243                     Y.on('io:complete', callback.success, Y);
244                     Y.io(sURL);
245                 });
246                 return "true";
247             } else {
248                 errorCode = "301";
249             }
250         } else {
251             errorCode = "201";
252         }
253         return "false";
254     }
256     function LMSGetValue (element) {
257         errorCode = "0";
258         if (Initialized) {
259             if (element !="") {
260                 expression = new RegExp(CMIIndex,'g');
261                 elementmodel = String(element).replace(expression,'.n.');
262                 if ((typeof eval('datamodel["'+elementmodel+'"]')) != "undefined") {
263                     if (eval('datamodel["'+elementmodel+'"].mod') != 'w') {
264                             element = String(element).replace(expression, "_$1.");
265                             elementIndexes = element.split('.');
266                         subelement = 'cmi';
267                         i = 1;
268                         while ((i < elementIndexes.length) && (typeof eval(subelement) != "undefined")) {
269                             subelement += '.'+elementIndexes[i++];
270                         }
271                         if (subelement == element) {
272                             errorCode = "0";
273                             return eval(element);
274                         } else {
275                             errorCode = "0"; // Need to check if it is the right errorCode
276                         }
277                     } else {
278                         errorCode = eval('datamodel["'+elementmodel+'"].readerror');
279                     }
280                 } else {
281                     childrenstr = '._children';
282                     countstr = '._count';
283                     if (elementmodel.substr(elementmodel.length-childrenstr.length,elementmodel.length) == childrenstr) {
284                         parentmodel = elementmodel.substr(0,elementmodel.length-childrenstr.length);
285                         if ((typeof eval('datamodel["'+parentmodel+'"]')) != "undefined") {
286                             errorCode = "202";
287                         } else {
288                             errorCode = "201";
289                         }
290                     } else if (elementmodel.substr(elementmodel.length-countstr.length,elementmodel.length) == countstr) {
291                         parentmodel = elementmodel.substr(0,elementmodel.length-countstr.length);
292                         if ((typeof eval('datamodel["'+parentmodel+'"]')) != "undefined") {
293                             errorCode = "203";
294                         } else {
295                             errorCode = "201";
296                         }
297                     } else {
298                         errorCode = "201";
299                     }
300                 }
301             } else {
302                 errorCode = "201";
303             }
304         } else {
305             errorCode = "301";
306         }
307         return "";
308     }
310     function LMSSetValue (element,value) {
311         errorCode = "0";
312         if (Initialized) {
313             if (element != "") {
314                 expression = new RegExp(CMIIndex,'g');
315                 elementmodel = String(element).replace(expression,'.n.');
316                 if ((typeof eval('datamodel["'+elementmodel+'"]')) != "undefined") {
317                     if (eval('datamodel["'+elementmodel+'"].mod') != 'r') {
318                         expression = new RegExp(eval('datamodel["'+elementmodel+'"].format'));
319                         value = value+'';
320                         matches = value.match(expression);
321                         if (matches != null) {
322                             //Create dynamic data model element
323                             if (element != elementmodel) {
324                                 elementIndexes = element.split('.');
325                                 subelement = 'cmi';
326                                 for (i=1;i < elementIndexes.length-1;i++) {
327                                     elementIndex = elementIndexes[i];
328                                     if (elementIndexes[i+1].match(/^\d+$/)) {
329                                         if ((typeof eval(subelement+'.'+elementIndex)) == "undefined") {
330                                             eval(subelement+'.'+elementIndex+' = new Object();');
331                                             eval(subelement+'.'+elementIndex+'._count = 0;');
332                                         }
333                                         if (elementIndexes[i+1] == eval(subelement+'.'+elementIndex+'._count')) {
334                                             eval(subelement+'.'+elementIndex+'._count++;');
335                                         }
336                                         if (elementIndexes[i+1] > eval(subelement+'.'+elementIndex+'._count')) {
337                                             errorCode = "201";
338                                         }
339                                         subelement = subelement.concat('.'+elementIndex+'_'+elementIndexes[i+1]);
340                                         i++;
341                                     } else {
342                                         subelement = subelement.concat('.'+elementIndex);
343                                     }
344                                     if ((typeof eval(subelement)) == "undefined") {
345                                         eval(subelement+' = new Object();');
346                                         if (subelement.substr(0,14) == 'cmi.objectives') {
347                                             eval(subelement+'.score = new Object();');
348                                             eval(subelement+'.score._children = score_children;');
349                                             eval(subelement+'.score.raw = "";');
350                                             eval(subelement+'.score.min = "";');
351                                             eval(subelement+'.score.max = "";');
352                                         }
353                                         if (subelement.substr(0,16) == 'cmi.interactions') {
354                                             eval(subelement+'.objectives = new Object();');
355                                             eval(subelement+'.objectives._count = 0;');
356                                             eval(subelement+'.correct_responses = new Object();');
357                                             eval(subelement+'.correct_responses._count = 0;');
358                                         }
359                                     }
360                                 }
361                                 element = subelement.concat('.'+elementIndexes[elementIndexes.length-1]);
362                             }
363                             //Store data
364                             if (errorCode == "0") {
365                                 if ((typeof eval('datamodel["'+elementmodel+'"].range')) != "undefined") {
366                                     range = eval('datamodel["'+elementmodel+'"].range');
367                                     ranges = range.split('#');
368                                     value = value*1.0;
369                                     if ((value >= ranges[0]) && (value <= ranges[1])) {
370                                         eval(element+'="'+value+'";');
371                                         errorCode = "0";
372                                         return "true";
373                                     } else {
374                                         errorCode = eval('datamodel["'+elementmodel+'"].writeerror');
375                                     }
376                                 } else {
377                                     if (element == 'cmi.comments') {
378                                         eval(element+'+="'+value+'";');
379                                     } else {
380                                         eval(element+'="'+value+'";');
381                                     }
382                                     errorCode = "0";
383                                     return "true";
384                                 }
385                             }
386                         } else {
387                             errorCode = eval('datamodel["'+elementmodel+'"].writeerror');
388                         }
389                     } else {
390                         errorCode = eval('datamodel["'+elementmodel+'"].writeerror');
391                     }
392                 } else {
393                     errorCode = "201"
394                 }
395             } else {
396                 errorCode = "201";
397             }
398         } else {
399             errorCode = "301";
400         }
401         return "false";
402     }
404     function LMSCommit (param) {
405         errorCode = "0";
406         if (param == "") {
407             if (Initialized) {
408                 result = StoreData(cmi,false);
409                 return "true";
410             } else {
411                 errorCode = "301";
412             }
413         } else {
414             errorCode = "201";
415         }
416         return "false";
417     }
419     function LMSGetLastError () {
420         return errorCode;
421     }
423     function LMSGetErrorString (param) {
424         if (param != "") {
425             var errorString = new Array();
426             errorString["0"] = "No error";
427             errorString["101"] = "General exception";
428             errorString["201"] = "Invalid argument error";
429             errorString["202"] = "Element cannot have children";
430             errorString["203"] = "Element not an array - cannot have count";
431             errorString["301"] = "Not initialized";
432             errorString["401"] = "Not implemented error";
433             errorString["402"] = "Invalid set value, element is a keyword";
434             errorString["403"] = "Element is read only";
435             errorString["404"] = "Element is write only";
436             errorString["405"] = "Incorrect data type";
437             return errorString[param];
438         } else {
439            return "";
440         }
441     }
443     function LMSGetDiagnostic (param) {
444         if (param == "") {
445             param = errorCode;
446         }
447         return param;
448     }
450     function AddTime (first, second) {
451         var sFirst = first.split(":");
452         var sSecond = second.split(":");
453         var cFirst = sFirst[2].split(".");
454         var cSecond = sSecond[2].split(".");
455         var change = 0;
457         FirstCents = 0;  //Cents
458         if (cFirst.length > 1) {
459             FirstCents = parseInt(cFirst[1],10);
460         }
461         SecondCents = 0;
462         if (cSecond.length > 1) {
463             SecondCents = parseInt(cSecond[1],10);
464         }
465         var cents = FirstCents + SecondCents;
466         change = Math.floor(cents / 100);
467         cents = cents - (change * 100);
468         if (Math.floor(cents) < 10) {
469             cents = "0" + cents.toString();
470         }
472         var secs = parseInt(cFirst[0],10)+parseInt(cSecond[0],10)+change;  //Seconds
473         change = Math.floor(secs / 60);
474         secs = secs - (change * 60);
475         if (Math.floor(secs) < 10) {
476             secs = "0" + secs.toString();
477         }
479         mins = parseInt(sFirst[1],10)+parseInt(sSecond[1],10)+change;   //Minutes
480         change = Math.floor(mins / 60);
481         mins = mins - (change * 60);
482         if (mins < 10) {
483             mins = "0" + mins.toString();
484         }
486         hours = parseInt(sFirst[0],10)+parseInt(sSecond[0],10)+change;  //Hours
487         if (hours < 10) {
488             hours = "0" + hours.toString();
489         }
491         if (cents != '0') {
492             return hours + ":" + mins + ":" + secs + '.' + cents;
493         } else {
494             return hours + ":" + mins + ":" + secs;
495         }
496     }
498     function TotalTime() {
499         total_time = AddTime(cmi.core.total_time, cmi.core.session_time);
500         return '&'+underscore('cmi.core.total_time')+'='+escape(total_time);
501     }
503     function CollectData(data,parent) {
504         var datastring = '';
505         for (property in data) {
506             if (typeof data[property] == 'object') {
507                 datastring += CollectData(data[property],parent+'.'+property);
508             } else {
509                 element = parent+'.'+property;
510                 expression = new RegExp(CMIIndex,'g');
511                 elementmodel = String(element).replace(expression,'.n.');
512                 if ((typeof eval('datamodel["'+elementmodel+'"]')) != "undefined") {
513                     if (eval('datamodel["'+elementmodel+'"].mod') != 'r') {
514                         elementstring = '&'+underscore(element)+'='+escape(data[property]);
515                         if ((typeof eval('datamodel["'+elementmodel+'"].defaultvalue')) != "undefined") {
516                             if (eval('datamodel["'+elementmodel+'"].defaultvalue') != data[property]) {
517                                 datastring += elementstring;
518                             }
519                         } else {
520                             datastring += elementstring;
521                         }
522                     }
523                 }
524             }
525         }
526         return datastring;
527     }
529     function StoreData(data,storetotaltime) {
530         if (storetotaltime) {
531             if (cmi.core.lesson_mode == 'normal') {
532                 if (cmi.core.credit == 'credit') {
533                     if (cmi.student_data.mastery_score != '' && cmi.core.score.raw != '') {
534                         if (cmi.core.score.raw >= cmi.student_data.mastery_score) {
535                             cmi.core.lesson_status = 'passed';
536                         } else {
537                             cmi.core.lesson_status = 'failed';
538                         }
539                     }
540                 }
541             }
542             if (cmi.core.lesson_mode == 'browse') {
543                 if (datamodel['cmi.core.lesson_status'].defaultvalue == '' && cmi.core.lesson_status == 'not attempted') {
544                     cmi.core.lesson_status = 'browsed';
545                 }
546             }
547             datastring = CollectData(data,'cmi');
548             datastring += TotalTime();
549         } else {
550             datastring = CollectData(data,'cmi');
551         }
552         datastring += '&attempt=<?php echo $attempt ?>';
553         datastring += '&scoid=<?php echo $scoid ?>';
555         //popupwin(datastring);
556         var myRequest = NewHttpReq();
557         result = DoRequest(myRequest,"<?php p($CFG->wwwroot) ?>/mod/scorm/datamodel.php","id=<?php p($id) ?>&sesskey=<?php echo sesskey() ?>"+datastring);
558         results = String(result).split('\n');
559         errorCode = results[1];
560         return results[0];
561     }
563     this.LMSInitialize = LMSInitialize;
564     this.LMSFinish = LMSFinish;
565     this.LMSGetValue = LMSGetValue;
566     this.LMSSetValue = LMSSetValue;
567     this.LMSCommit = LMSCommit;
568     this.LMSGetLastError = LMSGetLastError;
569     this.LMSGetErrorString = LMSGetErrorString;
570     this.LMSGetDiagnostic = LMSGetDiagnostic;
573 var API = new AICCapi();