/**
  * Add question-type specific form fields.
  *
  * @param MoodleQuickForm $mform the form being built.
  */
 protected function definition_inner($mform)
 {
     $strquestionlabel = $this->qtypeobj->comment_header($this->nonemptyanswer);
     $label = get_string("sharedwildcards", "qtype_calculated");
     $mform->addElement('hidden', 'synchronize', 0);
     $mform->addElement('hidden', 'initialcategory', 1);
     $mform->setType('synchronize', PARAM_BOOL);
     $mform->setType('initialcategory', PARAM_INT);
     $mform->addElement('hidden', 'reload', 1);
     $mform->setType('reload', PARAM_INT);
     $addfieldsname = 'updatequestion value';
     $addstring = get_string("updatecategory", "qtype_calculated");
     $mform->registerNoSubmitButton($addfieldsname);
     $this->add_per_answer_fields($mform, get_string('answerhdr', 'qtype_calculated', '{no}'), question_bank::fraction_options(), 1, 1);
     $this->add_unit_options($mform, $this);
     $this->add_unit_fields($mform, $this);
     $this->add_interactive_settings();
     $label = "<div class='mdl-align'></div><div class='mdl-align'>" . get_string('wildcardrole', 'qtype_calculatedsimple') . "</div>";
     $mform->addElement('html', "<div class='mdl-align'>&nbsp;</div>");
     // Explaining the role of datasets so other strings can be shortened.
     $mform->addElement('html', $label);
     $mform->addElement('submit', 'analyzequestion', get_string('findwildcards', 'qtype_calculatedsimple'));
     $mform->registerNoSubmitButton('analyzequestion');
     $mform->closeHeaderBefore('analyzequestion');
     $this->wizarddisplay = optional_param('analyzequestion', false, PARAM_BOOL);
     if ($this->maxnumber != -1) {
         $this->noofitems = $this->maxnumber;
     } else {
         $this->noofitems = 0;
     }
     if (!empty($this->datasetdefs)) {
         // So there are some datadefs.
         // We put them on the page.
         $key = 0;
         $mform->addElement('header', 'additemhdr', get_string('wildcardparam', 'qtype_calculatedsimple'));
         $idx = 1;
         if (!empty($this->datasetdefs)) {
             // Unnecessary test.
             $j = $this->noofitems * count($this->datasetdefs) + 1;
             //
             foreach ($this->datasetdefs as $defkey => $datasetdef) {
                 $mform->addElement('static', "na[{$j}]", get_string('param', 'qtype_calculated', $datasetdef->name));
                 $this->qtypeobj->custom_generator_tools_part($mform, $idx, $j);
                 $mform->addElement('hidden', "datasetdef[{$idx}]");
                 $mform->setType("datasetdef[{$idx}]", PARAM_RAW);
                 $mform->addElement('hidden', "defoptions[{$idx}]");
                 $mform->setType("defoptions[{$idx}]", PARAM_RAW);
                 $idx++;
                 $mform->addElement('static', "divider[{$j}]", '', '<hr />');
                 $j++;
             }
         }
         // This should be done before the elements are created and stored as $this->formdata.
         // Fill out all data sets and also the fields for the next item to add.
         /*Here we do already the values error analysis so that
          * we could force all wild cards values display if there is an error in values.
          * as using a , in a number */
         $this->numbererrors = array();
         if (!empty($this->datasetdefs)) {
             $j = $this->noofitems * count($this->datasetdefs);
             for ($itemnumber = $this->noofitems; $itemnumber >= 1; $itemnumber--) {
                 $data = array();
                 $numbererrors = array();
                 $comment = new stdClass();
                 $comment->stranswers = array();
                 $comment->outsidelimit = false;
                 $comment->answers = array();
                 foreach ($this->datasetdefs as $defid => $datasetdef) {
                     if (isset($datasetdef->items[$itemnumber])) {
                         $this->formdata["definition[{$j}]"] = $defid;
                         $this->formdata["itemid[{$j}]"] = $datasetdef->items[$itemnumber]->id;
                         $data[$datasetdef->name] = $datasetdef->items[$itemnumber]->value;
                         $this->formdata["number[{$j}]"] = $number = $datasetdef->items[$itemnumber]->value;
                         if (!is_numeric($number)) {
                             $a = new stdClass();
                             $a->name = '{' . $datasetdef->name . '}';
                             $a->value = $datasetdef->items[$itemnumber]->value;
                             if (stristr($number, ',')) {
                                 $this->numbererrors["number[{$j}]"] = get_string('nocommaallowed', 'qtype_calculated');
                                 $numbererrors .= $this->numbererrors['number[' . $j . ']'] . "<br />";
                             } else {
                                 $this->numbererrors["number[{$j}]"] = get_string('notvalidnumber', 'qtype_calculated', $a);
                                 $numbererrors .= $this->numbererrors['number[' . $j . ']'] . "<br />";
                             }
                         } else {
                             if (stristr($number, 'x')) {
                                 // Hexa will pass the test.
                                 $a = new stdClass();
                                 $a->name = '{' . $datasetdef->name . '}';
                                 $a->value = $datasetdef->items[$itemnumber]->value;
                                 $this->numbererrors['number[' . $j . ']'] = get_string('hexanotallowed', 'qtype_calculated', $a);
                                 $numbererrors .= $this->numbererrors['number[' . $j . ']'] . "<br />";
                             } else {
                                 if (is_nan($number)) {
                                     $a = new stdClass();
                                     $a->name = '{' . $datasetdef->name . '}';
                                     $a->value = $datasetdef->items[$itemnumber]->value;
                                     $this->numbererrors["number[{$j}]"] = get_string('notvalidnumber', 'qtype_calculated', $a);
                                     $numbererrors .= $this->numbererrors['number[' . $j . ']'] . "<br />";
                                 }
                             }
                         }
                     }
                     $j--;
                 }
                 if ($this->noofitems != 0) {
                     if (empty($numbererrors)) {
                         if (!isset($this->question->id)) {
                             $this->question->id = 0;
                         }
                         $this->question->questiontext = !empty($this->question->questiontext) ? $this->question->questiontext : '';
                         $comment = $this->qtypeobj->comment_on_datasetitems($this->qtypeobj, $this->question->id, $this->question->questiontext, $this->nonemptyanswer, $data, $itemnumber);
                         if ($comment->outsidelimit) {
                             $this->outsidelimit = $comment->outsidelimit;
                         }
                         $totalcomment = '';
                         foreach ($this->nonemptyanswer as $key => $answer) {
                             $totalcomment .= $comment->stranswers[$key] . '<br/>';
                         }
                         $this->formdata['answercomment[' . $itemnumber . ']'] = $totalcomment;
                     }
                 }
             }
             $this->formdata['selectdelete'] = '1';
             $this->formdata['selectadd'] = '1';
             $j = $this->noofitems * count($this->datasetdefs) + 1;
             $data = array();
             // Data for comment_on_datasetitems later.
             $idx = 1;
             foreach ($this->datasetdefs as $defid => $datasetdef) {
                 $this->formdata["datasetdef[{$idx}]"] = $defid;
                 $idx++;
             }
             $this->formdata = $this->qtypeobj->custom_generator_set_data($this->datasetdefs, $this->formdata);
         }
         $addoptions = array();
         $addoptions['1'] = '1';
         for ($i = 10; $i <= 100; $i += 10) {
             $addoptions["{$i}"] = "{$i}";
         }
         $showoptions = array();
         $showoptions['1'] = '1';
         $showoptions['2'] = '2';
         $showoptions['5'] = '5';
         for ($i = 10; $i <= 100; $i += 10) {
             $showoptions["{$i}"] = "{$i}";
         }
         $mform->closeHeaderBefore('additemhdr');
         $addgrp = array();
         $addgrp[] = $mform->createElement('submit', 'addbutton', get_string('generatenewitemsset', 'qtype_calculatedsimple'));
         $addgrp[] = $mform->createElement('select', "selectadd", '', $addoptions);
         $addgrp[] = $mform->createElement('static', "stat", '', get_string('newsetwildcardvalues', 'qtype_calculatedsimple'));
         $mform->addGroup($addgrp, 'addgrp', '', '   ', false);
         $mform->registerNoSubmitButton('addbutton');
         $mform->closeHeaderBefore('addgrp');
         $addgrp1 = array();
         $addgrp1[] = $mform->createElement('submit', 'showbutton', get_string('showitems', 'qtype_calculatedsimple'));
         $addgrp1[] = $mform->createElement('select', "selectshow", '', $showoptions);
         $addgrp1[] = $mform->createElement('static', "stat", '', get_string('setwildcardvalues', 'qtype_calculatedsimple'));
         $mform->addGroup($addgrp1, 'addgrp1', '', '   ', false);
         $mform->registerNoSubmitButton('showbutton');
         $mform->closeHeaderBefore('addgrp1');
         $mform->addElement('static', "divideradd", '', '');
         if ($this->noofitems == 0) {
             $mform->addElement('static', 'warningnoitems', '', '<span class="error">' . get_string('youmustaddatleastonevalue', 'qtype_calculatedsimple') . '</span>');
             $mform->closeHeaderBefore('warningnoitems');
         } else {
             $mform->addElement('header', 'additemhdr1', get_string('wildcardvalues', 'qtype_calculatedsimple'));
             $mform->closeHeaderBefore('additemhdr1');
             if (!empty($this->numbererrors) || $this->outsidelimit) {
                 $mform->addElement('static', "alert", '', '<span class="error">' . get_string('useadvance', 'qtype_calculatedsimple') . '</span>');
             }
             $mform->addElement('submit', 'updatedatasets', get_string('updatewildcardvalues', 'qtype_calculatedsimple'));
             $mform->registerNoSubmitButton('updatedatasets');
             $mform->setAdvanced("updatedatasets", true);
             // ...--------------------------------------------------------------.
             $j = $this->noofitems * count($this->datasetdefs);
             $k = optional_param('selectshow', 1, PARAM_INT);
             for ($i = $this->noofitems; $i >= 1; $i--) {
                 foreach ($this->datasetdefs as $defkey => $datasetdef) {
                     if ($k > 0 || $this->outsidelimit || !empty($this->numbererrors)) {
                         $mform->addElement('text', "number[{$j}]", get_string('wildcard', 'qtype_calculatedsimple', $datasetdef->name));
                         $mform->setAdvanced("number[{$j}]", true);
                         if (!empty($this->numbererrors['number[' . $j . ']'])) {
                             $mform->addElement('static', "numbercomment[{$j}]", '', '<span class="error">' . $this->numbererrors['number[' . $j . ']'] . '</span>');
                             $mform->setAdvanced("numbercomment[{$j}]", true);
                         }
                     } else {
                         $mform->addElement('hidden', "number[{$j}]", get_string('wildcard', 'qtype_calculatedsimple', $datasetdef->name));
                     }
                     $mform->setType("number[{$j}]", PARAM_RAW);
                     // This parameter will be validated in validation().
                     $mform->addElement('hidden', "itemid[{$j}]");
                     $mform->setType("itemid[{$j}]", PARAM_INT);
                     $mform->addElement('hidden', "definition[{$j}]");
                     $mform->setType("definition[{$j}]", PARAM_NOTAGS);
                     $j--;
                 }
                 if (!empty($strquestionlabel) && ($k > 0 || $this->outsidelimit || !empty($this->numbererrors))) {
                     $mform->addElement('static', "answercomment[{$i}]", "<b>" . get_string('setno', 'qtype_calculatedsimple', $i) . "</b>&nbsp;&nbsp;" . $strquestionlabel);
                 }
                 if ($k > 0 || $this->outsidelimit || !empty($this->numbererrors)) {
                     $mform->addElement('static', "divider1[{$j}]", '', '<hr />');
                 }
                 $k--;
             }
         }
     } else {
         $mform->addElement('static', 'warningnowildcards', '', '<span class="error">' . get_string('atleastonewildcard', 'qtype_calculatedsimple') . '</span>');
         $mform->closeHeaderBefore('warningnowildcards');
     }
     // ...----------------------------------------------------------------------.
     // Non standard name for button element needed so not using add_action_buttons.
     // Hidden elements.
     $mform->addElement('hidden', 'id');
     $mform->setType('id', PARAM_INT);
     $mform->addElement('hidden', 'courseid');
     $mform->setType('courseid', PARAM_INT);
     $mform->setDefault('courseid', 0);
     $mform->addElement('hidden', 'cmid');
     $mform->setType('cmid', PARAM_INT);
     $mform->setDefault('cmid', 0);
     if (!empty($this->question->id)) {
         if ($this->question->formoptions->cansaveasnew) {
             $mform->addElement('header', 'additemhdr', get_string('converttocalculated', 'qtype_calculatedsimple'));
             $mform->closeHeaderBefore('additemhdr');
             $mform->addElement('checkbox', 'convert', '', get_string('willconverttocalculated', 'qtype_calculatedsimple'));
             $mform->setDefault('convert', 0);
         }
     }
 }
 function validation($data, $files)
 {
     $errors = parent::validation($data, $files);
     //verifying for errors in {=...} in question text;
     $qtext = "";
     $qtextremaining = $data['questiontext'];
     $possibledatasets = $this->qtypeobj->find_dataset_names($data['questiontext']);
     foreach ($possibledatasets as $name => $value) {
         $qtextremaining = str_replace('{' . $name . '}', '1', $qtextremaining);
     }
     while (preg_match('~\\{=([^[:space:]}]*)}~', $qtextremaining, $regs1)) {
         $qtextsplits = explode($regs1[0], $qtextremaining, 2);
         $qtext = $qtext . $qtextsplits[0];
         $qtextremaining = $qtextsplits[1];
         if (!empty($regs1[1]) && ($formulaerrors = qtype_calculated_find_formula_errors($regs1[1]))) {
             if (!isset($errors['questiontext'])) {
                 $errors['questiontext'] = $formulaerrors . ':' . $regs1[1];
             } else {
                 $errors['questiontext'] .= '<br/>' . $formulaerrors . ':' . $regs1[1];
             }
         }
     }
     $answers = $data['answer'];
     $answercount = 0;
     $maxgrade = false;
     $possibledatasets = $this->qtypeobj->find_dataset_names($data['questiontext']);
     $mandatorydatasets = array();
     foreach ($answers as $key => $answer) {
         $mandatorydatasets += $this->qtypeobj->find_dataset_names($answer);
     }
     if (count($mandatorydatasets) == 0) {
         foreach ($answers as $key => $answer) {
             $errors['answer[' . $key . ']'] = get_string('atleastonewildcard', 'qtype_datasetdependent');
         }
     }
     foreach ($answers as $key => $answer) {
         //check no of choices
         // the * for everykind of answer not actually implemented
         $trimmedanswer = trim($answer);
         if ($trimmedanswer != '' || $answercount == 0) {
             $eqerror = qtype_calculated_find_formula_errors($trimmedanswer);
             if (FALSE !== $eqerror) {
                 $errors['answer[' . $key . ']'] = $eqerror;
             }
         }
         if ($trimmedanswer != '') {
             if ('2' == $data['correctanswerformat'][$key] && '0' == $data['correctanswerlength'][$key]) {
                 $errors['correctanswerlength[' . $key . ']'] = get_string('zerosignificantfiguresnotallowed', 'quiz');
             }
             if (!is_numeric($data['tolerance'][$key])) {
                 $errors['tolerance[' . $key . ']'] = get_string('mustbenumeric', 'qtype_calculated');
             }
             if ($data['fraction'][$key] == 1) {
                 $maxgrade = true;
             }
             $answercount++;
         }
         //check grades
         //TODO how should grade checking work here??
         /*if ($answer != '') {
               if ($data['fraction'][$key] > 0) {
                   $totalfraction += $data['fraction'][$key];
               }
               if ($data['fraction'][$key] > $maxfraction) {
                   $maxfraction = $data['fraction'][$key];
               }
           }*/
     }
     //grade checking :
     /// Perform sanity checks on fractional grades
     /*if ( ) {
           if ($maxfraction != 1) {
               $maxfraction = $maxfraction * 100;
               $errors['fraction[0]'] = get_string('errfractionsnomax', 'qtype_multichoice', $maxfraction);
           }
       } else {
           $totalfraction = round($totalfraction,2);
           if ($totalfraction != 1) {
               $totalfraction = $totalfraction * 100;
               $errors['fraction[0]'] = get_string('errfractionsaddwrong', 'qtype_multichoice', $totalfraction);
           }
       }*/
     $units = $data['unit'];
     if (count($units)) {
         foreach ($units as $key => $unit) {
             if (is_numeric($unit)) {
                 $errors['unit[' . $key . ']'] = get_string('mustnotbenumeric', 'qtype_calculated');
             }
             $trimmedunit = trim($unit);
             $trimmedmultiplier = trim($data['multiplier'][$key]);
             if (!empty($trimmedunit)) {
                 if (empty($trimmedmultiplier)) {
                     $errors['multiplier[' . $key . ']'] = get_string('youmustenteramultiplierhere', 'qtype_calculated');
                 }
                 if (!is_numeric($trimmedmultiplier)) {
                     $errors['multiplier[' . $key . ']'] = get_string('mustbenumeric', 'qtype_calculated');
                 }
             }
         }
     }
     if ($answercount == 0) {
         $errors['answer[0]'] = get_string('atleastoneanswer', 'qtype_calculated');
     }
     if ($maxgrade == false) {
         $errors['fraction[0]'] = get_string('fractionsnomax', 'question');
     }
     if (isset($data['backtoquiz']) && $this->noofitems == 0) {
         $errors['warning'] = get_string('warning', 'mnet');
     }
     if ($this->outsidelimit) {
         //   if(!isset($errors['warning'])) $errors['warning']=' ';
         $errors['outsidelimits'] = get_string('oneanswertrueansweroutsidelimits', 'qtype_calculated');
     }
     /*Here we use the already done the error analysis so that 
      * we could force all wild cards values display if there is an error in values.
      * as using a , in a number */
     $numbers = $data['number'];
     foreach ($numbers as $key => $number) {
         if (!is_numeric($number)) {
             if (stristr($number, ',')) {
                 $errors['number[' . $key . ']'] = get_string('notvalidnumber', 'qtype_datasetdependent');
             } else {
                 $errors['number[' . $key . ']'] = get_string('notvalidnumber', 'qtype_datasetdependent');
             }
         } else {
             if (stristr($number, 'x')) {
                 $errors['number[' . $key . ']'] = get_string('notvalidnumber', 'qtype_datasetdependent');
             } else {
                 if (is_nan($number)) {
                     $errors['number[' . $key . ']'] = get_string('notvalidnumber', 'qtype_datasetdependent');
                 }
             }
         }
     }
     if ($this->noofitems == 0) {
         $errors['warning'] = get_string('warning', 'mnet');
     }
     return $errors;
 }