private function validateSubTree(ilAssLacAbstractComposite $composite)
 {
     if ($composite->nodes[0] instanceof ilAssLacQuestionExpressionInterface && $composite->nodes[1] instanceof ilAssLacSolutionExpressionInterface) {
         $question_expression = $composite->nodes[0];
         $answer_expression = $composite->nodes[1];
         $question_index = $composite->nodes[0]->getQuestionIndex();
         $answer_index = null;
         $question = $this->object_loader->getQuestion($question_index);
         $this->checkQuestionExists($question, $question_index);
         //$this->checkQuestionIsReachable($question, $question_index);
         if ($this->isResultOfAnswerExpression($question_expression)) {
             $answer_index = $question_expression->getAnswerIndex() - 1;
             $this->checkIfAnswerIndexOfQuestionExists($question, $question_index, $answer_index);
         }
         if ($answer_expression instanceof ilAssLacNumberOfResultExpression) {
             $this->checkIfAnswerIndexOfQuestionExists($question, $question_index, $answer_expression->getNumericValue() - 1);
         }
         $this->checkAnswerExpressionExist($question->getExpressionTypes(), $answer_expression, $question_index);
         $this->checkOperatorExistForExpression($question->getOperators($answer_expression::$identifier), $answer_expression, $composite::$pattern);
         if ($answer_expression instanceof ilAssLacOrderingResultExpression && ($question instanceof assOrderingHorizontal || $question instanceof assOrderingQuestion)) {
             foreach ($answer_expression->getOrdering() as $order) {
                 $count = 0;
                 foreach ($answer_expression->getOrdering() as $element) {
                     if ($element == $order) {
                         $count++;
                     }
                 }
                 if ($count > 1) {
                     throw new ilAssLacDuplicateElement($order);
                 }
                 $this->checkIfAnswerIndexOfQuestionExists($question, $question_index, $order - 1);
             }
         }
         if ($question instanceof assClozeTest) {
             $this->validateClozeTest($answer_index, $question, $answer_expression, $question_index);
         } elseif ($answer_expression instanceof ilAssLacPercentageResultExpression && $this->isResultOfAnswerExpression($question_expression) && !$question instanceof assFormulaQuestion) {
             throw new ilAssLacExpressionNotSupportedByQuestion($answer_expression->getValue(), $question_index . "[" . ($answer_index + 1) . "]");
         }
     } elseif ($composite->nodes[0] instanceof ilAssLacAbstractOperation && $composite->nodes[1] instanceof ilAssLacExpressionInterface || $composite->nodes[0] instanceof ilAssLacExpressionInterface && $composite->nodes[1] instanceof ilAssLacAbstractOperation || $composite->nodes[0] instanceof ilAssLacSolutionExpressionInterface) {
         throw new ilAssLacUnableToParseCondition("");
     }
 }
 /**
  * @param ilAssLacAbstractComposite $composite
  *
  * @return bool
  */
 private function evaluateSubTree(ilAssLacAbstractComposite $composite)
 {
     $result = false;
     if ($composite->nodes[0] instanceof ilAssLacExpressionInterface && $composite->nodes[1] instanceof ilAssLacExpressionInterface) {
         $question = $this->object_loader->getQuestion($composite->nodes[0]->getQuestionIndex());
         $rightNode = $composite->nodes[1];
         $index = $this->isInstanceOfAnswerIndexProvidingExpression($composite) ? $composite->nodes[0]->getAnswerIndex() : null;
         $solutions = $question->getUserQuestionResult($this->activeId, $this->pass);
         if ($question instanceof assClozeTest) {
             // @todo for Thomas J.: Move to interface / implement in concrete class (req. for future releases)
             /**
              * @var $gap assClozeGap
              * @var $answer assAnswerCloze
              */
             $result = $solutions->getSolutionForKey($index);
             $gap = $question->getAvailableAnswerOptions($index - 1);
             if ($rightNode instanceof ilAssLacStringResultExpression) {
                 if ($gap->getType() == 1) {
                     $answer = $gap->getItem($result['value'] - 1);
                     $solutions->removeByKey($index);
                     $solutions->addKeyValue($index, $answer->getAnswertext());
                 }
             } else {
                 if ($rightNode instanceof ilAssLacPercentageResultExpression && $composite->nodes[0] instanceof ilAssLacResultOfAnswerOfQuestionExpression) {
                     /**
                      * @var $answers assAnswerCloze[]
                      */
                     $answers = $gap->getItems();
                     $max_points = 0;
                     foreach ($answers as $answer) {
                         if ($max_points < $answer->getPoints()) {
                             $max_points = $answer->getPoints();
                         }
                     }
                     $item = null;
                     $reached_points = null;
                     // @todo for Thomas J.: Maybe handle identical scoring for every type
                     switch ($gap->getType()) {
                         case CLOZE_TEXT:
                             for ($order = 0; $order < $gap->getItemCount(); $order++) {
                                 $answer = $gap->getItem($order);
                                 $item_points = $question->getTextgapPoints($answer->getAnswertext(), $result['value'], $answer->getPoints());
                                 if ($item_points > $reached_points) {
                                     $reached_points = $item_points;
                                 }
                             }
                             break;
                         case CLOZE_NUMERIC:
                             for ($order = 0; $order < $gap->getItemCount(); $order++) {
                                 $answer = $gap->getItem($order);
                                 $item_points = $question->getNumericgapPoints($answer->getAnswertext(), $result["value"], $answer->getPoints(), $answer->getLowerBound(), $answer->getUpperBound());
                                 if ($item_points > $reached_points) {
                                     $reached_points = $item_points;
                                 }
                             }
                             break;
                         case CLOZE_SELECT:
                             if ($result['value'] != null) {
                                 $answer = $gap->getItem($result['value'] - 1);
                                 $reached_points = $answer->getPoints();
                             }
                             break;
                     }
                     $percentage = 0;
                     if ($max_points != 0 && $reached_points !== null) {
                         $percentage = (int) ($reached_points / $max_points * 100);
                     }
                     $solutions->setReachedPercentage($percentage);
                 }
             }
         }
         if ($question instanceof assFormulaQuestion && $rightNode instanceof ilAssLacPercentageResultExpression && $this->isInstanceOfAnswerIndexProvidingExpression($composite->nodes[0])) {
             // @todo for Thomas J.: Move to interface / implement in concrete class (req. for future releases)
             $result = $solutions->getSolutionForKey($index);
             $answer = $question->getAvailableAnswerOptions($index - 1);
             $unit = $solutions->getSolutionForKey($index . "_unit");
             $key = null;
             if (is_array($unit)) {
                 $key = $unit['value'];
             }
             $max_points = $answer->getPoints();
             $points = $answer->getReachedPoints($question->getVariables(), $question->getResults(), $result["value"], $key, $question->getUnitrepository()->getUnits());
             $percentage = 0;
             if ($max_points != 0) {
                 $percentage = (int) ($points / $max_points * 100);
             }
             $solutions->setReachedPercentage($percentage);
         }
         $result = $rightNode->checkResult($solutions, $composite->getPattern(), $index);
     } else {
         switch ($composite->getPattern()) {
             case "&":
                 $result = $composite->nodes[0] && $composite->nodes[1];
                 break;
             case "|":
                 $result = $composite->nodes[0] || $composite->nodes[1];
                 break;
             default:
                 $result = false;
         }
     }
     if ($composite->isNegated()) {
         return !$result;
     }
     return $result;
 }
 private function validateSolutionCompareExpression(ilAssQuestionSolutionComparisonExpression $expression, iQuestionCondition $question)
 {
     require_once 'Modules/TestQuestionPool/classes/questions/LogicalAnswerCompare/ilAssLacConditionParser.php';
     require_once 'Modules/TestQuestionPool/classes/questions/LogicalAnswerCompare/ilAssLacQuestionProvider.php';
     require_once 'Modules/TestQuestionPool/classes/questions/LogicalAnswerCompare/ilAssLacCompositeValidator.php';
     try {
         $conditionParser = new ilAssLacConditionParser();
         $conditionComposite = $conditionParser->parse($expression->getExpression());
         $questionProvider = new ilAssLacQuestionProvider();
         $questionProvider->setQuestion($question);
         $conditionValidator = new ilAssLacCompositeValidator($questionProvider);
         $conditionValidator->validate($conditionComposite);
     } catch (ilAssLacException $e) {
         if ($e instanceof ilAssLacFormAlertProvider) {
             return $e->getFormAlert($this->lng);
         }
         throw $e;
     }
     return true;
 }