/**
  * Formulář pro zadání preprocessingu pomocí nominal enumeration
  * @return Form
  */
 protected function createComponentNewNominalEnumerationForm()
 {
     $form = new Form();
     $form->setTranslator($this->translator);
     $form->addText('preprocessingName', 'Preprocessing name:')->setRequired(false)->setAttribute('placeholder', $this->translate('Nominal bins'))->setAttribute('title', $this->translate('You can left this field blank, it will be filled in automatically.'))->addRule(function (TextInput $textInput) {
         $form = $textInput->getForm(true);
         $formValues = $form->getValues(true);
         $textInputValue = $textInput->value;
         //nalezení aktuálního formátu
         $miner = $this->findMinerWithCheckAccess($formValues['miner']);
         $datasourceColumn = $this->findDatasourceColumn($miner->datasource, $formValues['column']);
         $format = $datasourceColumn->format;
         $textInput->setAttribute('placeholder', $this->prepareNominalEnumerationPreprocessingName($format, $formValues));
         if ($textInputValue != '') {
             //check preprocessings
             $existingPreprocessings = $format->preprocessings;
             if (!empty($existingPreprocessings)) {
                 foreach ($existingPreprocessings as $existingPreprocessing) {
                     if ($existingPreprocessing->name == $textInput) {
                         return false;
                     }
                 }
             }
         }
         return true;
     }, 'This preprocessing name already exists. Please select a new one...')->addRule(function (TextInput $input) {
         $values = $input->getForm(true)->getValues(true);
         return count($values['valuesBins']) > 0;
     }, 'You have to input at least one bin!');
     $form->addText('attributeName', 'Create attribute with name:')->setRequired('Input attribute name!')->addRule(Form::PATTERN, 'Attribute name can contain only letters, numbers and _ and has start with a letter.', '[a-zA-Z]{1}\\w*')->addRule(function (TextInput $input) {
         //kontrola, jestli již existuje atribtu se zadaným názvem
         $values = $input->getForm(true)->getValues();
         $miner = $this->findMinerWithCheckAccess($values->miner);
         $attributes = $miner->metasource->attributes;
         if (!empty($attributes)) {
             foreach ($attributes as $attribute) {
                 if ($attribute->name == $input->value) {
                     return false;
                 }
             }
         }
         return true;
     }, 'Attribute with this name already exists!');
     $form->addHidden('column');
     $form->addHidden('miner');
     $form->addHidden('formatType');
     $form->addHidden('formatId');
     /** @var Container $valuesBins */
     $valuesBins = $form->addDynamic('valuesBins', function (Container $valuesBin) {
         $valuesBin->addText('name', 'Bin name:')->setRequired(true)->setRequired('Input bin name!')->addRule(function (TextInput $input) {
             $values = $input->parent->getValues(true);
             return count($values['values']) > 0;
         }, 'Add at least one value!')->addRule(function (TextInput $input) {
             //kontrola, jestli má každý BIN jiný název
             $values = $input->getParent()->getParent()->getValues(true);
             $inputValue = $input->getValue();
             $usesCount = 0;
             if (!empty($values)) {
                 foreach ($values as $value) {
                     if ($value['name'] == $inputValue) {
                         $usesCount++;
                     }
                 }
             }
             return $usesCount <= 1;
         }, 'This name is used for other bin!');
         /** @var Container $intervals */
         $intervals = $valuesBin->addDynamic('values', function (Container $interval) {
             $interval->addText('value')->setAttribute('readonly');
             $interval->addSubmit('remove', 'x')->setAttribute('class', 'removeValue')->setValidationScope([])->onClick[] = function (SubmitButton $submitButton) {
                 $intervals = $submitButton->parent->parent;
                 $intervals->remove($submitButton->parent, TRUE);
             };
         });
         $addValueSubmit = $valuesBin->addSubmit('addValue', 'Add value');
         $value = $valuesBin->addText('value', null, '');
         //TODO dodělat select...
         $value->addConditionOn($addValueSubmit, Form::SUBMITTED)->setRequired('Input value!')->addConditionOn($valuesBin->getForm(true)->getComponent('formatType'), Form::EQUAL, Format::DATATYPE_VALUES)->addRule(function (TextInput $input) {
             $inputValue = $input->getValue();
             $values = $input->getForm(true)->getValues(true);
             $format = $this->metaAttributesFacade->findFormat($values['formatId']);
             $values = $format->values;
             if (!empty($values)) {
                 foreach ($values as $value) {
                     if ($value->value == $inputValue) {
                         return true;
                     }
                 }
             }
             return false;
         }, 'You have to input existing value!')->elseCondition()->addRule(Form::FLOAT, 'You have to input number!')->endCondition();
         $value->addRule(function (TextInput $input) {
             $values = $input->getForm(true)->getValues(true);
             $usedValuesArr = [];
             if (!empty($values['valuesBins'])) {
                 foreach ($values['valuesBins'] as $valuesBin) {
                     if (!empty($valuesBin['values'])) {
                         foreach ($valuesBin['values'] as $value) {
                             $usedValuesArr[] = $value['value'];
                         }
                     }
                 }
             }
             return !in_array($input->value, $usedValuesArr);
         }, 'This value is already used!');
         $addValueSubmit->setValidationScope([$value])->onClick[] = function (SubmitButton $submitButton) use($intervals) {
             $values = $submitButton->getParent()->getValues(true);
             $valueItem = $submitButton->getParent()['values']->createOne();
             $valueItem->setValues(['value' => $values['value']]);
             $submitButton->getParent()->setValues(['value' => '']);
         };
         $valuesBin->addSubmit('remove', 'Remove bin')->setAttribute('class', 'removeBin')->setValidationScope([])->onClick[] = function (SubmitButton $submitButton) {
             $submitButton->getParent()->getParent()->remove($submitButton->getParent(), true);
         };
     }, 0);
     $valuesBins->addSubmit('addBin', 'Add bin')->setValidationScope([])->onClick[] = function (SubmitButton $submitButton) {
         $submitButton->getParent()->createOne();
     };
     $form->addSubmit('submitAll', 'Save preprocessing & create attribute')->onClick[] = function (SubmitButton $submitButton) {
         #region vytvoření preprocessingu
         $values = $submitButton->getForm(true)->getValues(true);
         $miner = $this->findMinerWithCheckAccess($values['miner']);
         $this->minersFacade->checkMinerMetasource($miner);
         //vytvoření preprocessingu
         $datasourceColumn = $this->findDatasourceColumn($miner->datasource, $values['column']);
         $format = $datasourceColumn->format;
         $preprocessing = new Preprocessing();
         $preprocessing->name = $values['preprocessingName'] != '' ? $values['preprocessingName'] : $this->prepareNominalEnumerationPreprocessingName($format, $values);
         $preprocessing->format = $format;
         $preprocessing->user = $this->getCurrentUser();
         $this->preprocessingsFacade->savePreprocessing($preprocessing);
         foreach ($values['valuesBins'] as $valuesBinValues) {
             $valuesBin = new ValuesBin();
             $valuesBin->format = $format;
             $valuesBin->name = $valuesBinValues['name'];
             $this->metaAttributesFacade->saveValuesBin($valuesBin);
             foreach ($valuesBinValues['values'] as $valuesValues) {
                 try {
                     $value = $this->metaAttributesFacade->findValue($format, $valuesValues['value']);
                 } catch (\Exception $e) {
                     $value = new Value();
                     $value->value = $valuesValues['value'];
                     $this->metaAttributesFacade->saveValue($value);
                 }
                 $valuesBin->addToValues($value);
             }
             $this->metaAttributesFacade->saveValuesBin($valuesBin);
             $preprocessing->addToValuesBins($valuesBin);
         }
         $this->preprocessingsFacade->savePreprocessing($preprocessing);
         //vytvoření atributu
         $attribute = new Attribute();
         $attribute->metasource = $miner->metasource;
         $attribute->datasourceColumn = $datasourceColumn;
         $attribute->name = $values['attributeName'];
         $attribute->type = $attribute->datasourceColumn->type;
         $attribute->preprocessing = $preprocessing;
         $this->minersFacade->prepareAttribute($miner, $attribute);
         $this->metasourcesFacade->saveAttribute($attribute);
         $this->minersFacade->checkMinerState($miner, $this->getCurrentUser());
         $this->redirect('reloadUI');
         #endregion vytvoření preprocessingu
     };
     $presenter = $this;
     $form->addSubmit('storno', 'storno')->setValidationScope([])->onClick[] = function (SubmitButton $submitButton) use($presenter) {
         $values = $submitButton->getForm()->getValues();
         $presenter->redirect('addAttribute', array('column' => $values->column, 'miner' => $values->miner));
     };
     return $form;
 }
 /**
  * Funkce pro načtení PMML
  * @param string|\SimpleXMLElement $pmml
  * @param int &$rulesCount = null - informace o počtu importovaných pravidel
  * @param bool $updateImportedRulesHeads=false
  * @return bool
  * @throws \Exception
  */
 public function fullParseRulesPMML($pmml, &$rulesCount = null, $updateImportedRulesHeads = false)
 {
     Debugger::log('fullParseRulesPMML start ' . time(), ILogger::DEBUG);
     if ($pmml instanceof \SimpleXMLElement) {
         $xml = $pmml;
     } else {
         $xml = simplexml_load_string($pmml);
     }
     $xml->registerXPathNamespace('guha', 'http://keg.vse.cz/ns/GUHA0.1rev1');
     $guhaAssociationModel = $xml->xpath('//guha:AssociationModel');
     $guhaAssociationModel = $guhaAssociationModel[0];
     $rulesCount = (string) $guhaAssociationModel['numberOfRules'];
     /** @var \SimpleXMLElement $associationRulesXml */
     $associationRulesXml = $guhaAssociationModel->AssociationRules;
     if (count($associationRulesXml->AssociationRule) == 0) {
         return true;
     }
     //pokud nejsou vrácena žádná pravidla, nemá smysl zpracovávat cedenty...
     #region zpracování cedentů jen s jedním subcedentem
     $dbaItems = $associationRulesXml->xpath('./DBA[count(./BARef)=1]');
     $alternativeCedentIdsArr = array();
     if (!empty($dbaItems)) {
         foreach ($dbaItems as $dbaItem) {
             $idStr = (string) $dbaItem['id'];
             $BARefStr = (string) $dbaItem->BARef;
             $alternativeCedentIdsArr[$idStr] = isset($alternativeCedentIdsArr[$BARefStr]) ? $alternativeCedentIdsArr[$BARefStr] : $BARefStr;
         }
     }
     if (!empty($alternativeCedentIdsArr)) {
         do {
             $repeat = false;
             foreach ($alternativeCedentIdsArr as $id => $referencedId) {
                 if (isset($alternativeCedentIdsArr[$referencedId])) {
                     $alternativeCedentIdsArr[$id] = $alternativeCedentIdsArr[$referencedId];
                     $repeat = true;
                 }
             }
         } while ($repeat);
     }
     #endregion
     /** @var Cedent[] $cedentsArr */
     $cedentsArr = [];
     /** @var RuleAttribute[] $ruleAttributesArr */
     $ruleAttributesArr = [];
     /** @var string[] $unprocessedIdsArr */
     $unprocessedIdsArr = [];
     /** @var ValuesBin[]|Value[] $valuesBinsArr */
     $valuesBinsArr = [];
     /** @var Attribute[] $attributesArr - pole indexované pomocí názvů atributů použitých v PMML */
     $attributesArr = $this->miner->metasource->getAttributesByNamesArr();
     #region zpracování rule attributes
     $bbaItems = $associationRulesXml->xpath('//BBA');
     if (!empty($bbaItems)) {
         foreach ($bbaItems as $bbaItem) {
             $ruleAttribute = new RuleAttribute();
             $idStr = (string) $bbaItem['id'];
             //uložení vazby na Attribute
             $attributeName = (string) $bbaItem->FieldRef;
             $valueName = (string) $bbaItem->CatRef;
             $attribute = $attributesArr[$attributeName];
             $ruleAttribute->attribute = $attribute;
             $valueItem = $attribute->preprocessing->findValue($valueName);
             if ($valueItem instanceof Value) {
                 $ruleAttribute->value = $valueItem;
             } elseif ($valueItem instanceof ValuesBin) {
                 $ruleAttribute->valuesBin = $valueItem;
             } elseif ($attribute->preprocessing->specialType == Preprocessing::SPECIALTYPE_EACHONE) {
                 //pokud jde o preprocessing each-one a nebyla nalezena příslušná hodnota v DB, tak ji uložíme
                 $value = new Value();
                 $value->format = $attribute->preprocessing->format;
                 $value->value = $valueName;
                 $this->metaAttributesFacade->saveValue($value);
                 $ruleAttribute->value = $value;
             }
             $this->rulesFacade->saveRuleAttribute($ruleAttribute);
             $ruleAttributesArr[$idStr] = $ruleAttribute;
         }
     }
     //pročištění pole s alternativními IDčky
     if (!empty($alternativeCedentIdsArr)) {
         foreach ($alternativeCedentIdsArr as $id => $alternativeId) {
             if (isset($ruleAttributesArr[$alternativeId])) {
                 unset($alternativeCedentIdsArr[$id]);
             }
         }
     }
     #endregion
     #region zpracování cedentů s více subcedenty/hodnotami
     $dbaItems = $associationRulesXml->xpath('./DBA[count(./BARef)>0]');
     if (!empty($dbaItems)) {
         do {
             foreach ($dbaItems as $dbaItem) {
                 $idStr = (string) $dbaItem['id'];
                 if (isset($cedentsArr[$idStr])) {
                     continue;
                 }
                 if (isset($alternativeCedentIdsArr[$idStr])) {
                     continue;
                 }
                 if (isset($ruleAttributesArr[$idStr])) {
                     continue;
                 }
                 $process = true;
                 foreach ($dbaItem->BARef as $BARef) {
                     $BARefStr = (string) $BARef;
                     if (isset($alternativeCedentIdsArr[$BARefStr])) {
                         $BARefStr = $alternativeCedentIdsArr[$BARefStr];
                     }
                     if (!isset($cedentsArr[$BARefStr]) && !isset($ruleAttributesArr[$BARefStr])) {
                         $unprocessedIdsArr[$BARefStr] = $BARefStr;
                         $process = false;
                     }
                 }
                 if ($process) {
                     unset($unprocessedIdsArr[$idStr]);
                     //vytvoření konkrétního cedentu...
                     $cedent = new Cedent();
                     if (isset($dbaItem['connective'])) {
                         $cedent->connective = Strings::lower((string) $dbaItem['connective']);
                     } else {
                         $cedent->connective = 'conjunction';
                     }
                     $this->rulesFacade->saveCedent($cedent);
                     $cedentsArr[$idStr] = $cedent;
                     foreach ($dbaItem->BARef as $BARef) {
                         $BARefStr = (string) $BARef;
                         if (isset($alternativeCedentIdsArr[$BARefStr])) {
                             $BARefStr = $alternativeCedentIdsArr[$BARefStr];
                         }
                         if (isset($cedentsArr[$BARefStr])) {
                             $cedent->addToCedents($cedentsArr[$BARefStr]);
                         } elseif (isset($ruleAttributesArr[$BARefStr])) {
                             $cedent->addToRuleAttributes($ruleAttributesArr[$BARefStr]);
                         }
                     }
                     $this->rulesFacade->saveCedent($cedent);
                 } else {
                     $unprocessedIdsArr[$idStr] = $idStr;
                 }
             }
         } while (!empty($unprocessedIdsArr));
     }
     #endregion
     #region association rules
     /** @var Cedent[] $topCedentsArr - pole s cedenty na vrcholné úrovni (pokud je ruleAttribute přímo na vrcholné úrovni, musí být zabalen v cedentu)*/
     $topCedentsArr = array();
     foreach ($associationRulesXml->AssociationRule as $associationRule) {
         $rule = false;
         if ($updateImportedRulesHeads) {
             try {
                 $rule = $this->rulesFacade->findRuleByPmmlImportId($this->task->taskId, (string) $associationRule['id']);
             } catch (\Exception $e) {
                 /*ignore*/
             }
         }
         if (!$rule) {
             $rule = new Rule();
         }
         $rule->task = $this->task;
         #region antecedent
         if (isset($associationRule['antecedent'])) {
             //jde o pravidlo s antecedentem
             $antecedentId = (string) $associationRule['antecedent'];
             if (isset($alternativeCedentIdsArr[$antecedentId])) {
                 $antecedentId = $alternativeCedentIdsArr[$antecedentId];
             }
             if (isset($cedentsArr[$antecedentId])) {
                 $rule->antecedent = $cedentsArr[$antecedentId];
             } else {
                 if (isset($ruleAttributesArr[$antecedentId])) {
                     if (!isset($topCedentsArr[$antecedentId])) {
                         $cedent = new Cedent();
                         $cedent->connective = 'conjunction';
                         $this->rulesFacade->saveCedent($cedent);
                         $topCedentsArr[$antecedentId] = $cedent;
                         $cedent->addToRuleAttributes($ruleAttributesArr[$antecedentId]);
                         $this->rulesFacade->saveCedent($cedent);
                     }
                     $rule->antecedent = $topCedentsArr[$antecedentId];
                 } else {
                     throw new \Exception('Import failed!');
                 }
             }
         } else {
             //jde o pravidlo bez antecedentu
             $rule->antecedent = null;
         }
         #endregion antecedent
         #region consequent
         $consequentId = (string) $associationRule['consequent'];
         if (isset($alternativeCedentIdsArr[$consequentId])) {
             $consequentId = $alternativeCedentIdsArr[$consequentId];
         }
         if (isset($cedentsArr[$consequentId])) {
             $rule->consequent = $cedentsArr[$consequentId];
         } else {
             if (isset($ruleAttributesArr[$consequentId])) {
                 if (!isset($topCedentsArr[$consequentId])) {
                     $cedent = new Cedent();
                     $cedent->connective = 'conjunction';
                     $this->rulesFacade->saveCedent($cedent);
                     $topCedentsArr[$consequentId] = $cedent;
                     $cedent->addToRuleAttributes($ruleAttributesArr[$consequentId]);
                     $this->rulesFacade->saveCedent($cedent);
                 }
                 $rule->consequent = $topCedentsArr[$consequentId];
             } else {
                 throw new \Exception('Import failed!');
             }
         }
         #endregion consequent
         $rule->text = (string) $associationRule->Text;
         $fourFtTable = $associationRule->FourFtTable;
         $rule->a = (string) $fourFtTable['a'];
         $rule->b = (string) $fourFtTable['b'];
         $rule->c = (string) $fourFtTable['c'];
         $rule->d = (string) $fourFtTable['d'];
         $this->rulesFacade->saveRule($rule);
     }
     $this->rulesFacade->calculateMissingInterestMeasures($this->task);
     #endregion association rules
     Debugger::log('fullParseRulesPMML end ' . time(), ILogger::DEBUG);
     return true;
 }