/**
  * Akce pro vytvoření nového atributu
  * @SWG\Post(
  *   tags={"Attributes"},
  *   path="/attributes",
  *   summary="Create new attribute using defined preprocessing",
  *   consumes={"application/json","application/xml"},
  *   produces={"application/json","application/xml"},
  *   security={{"apiKey":{}},{"apiKeyHeader":{}}},
  *   @SWG\Parameter(
  *     description="New attribute",
  *     name="body",
  *     required=true,
  *     @SWG\Schema(ref="#/definitions/NewAttributeInput"),
  *     in="body"
  *   ),
  *   @SWG\Response(
  *     response=201,
  *     description="Attribute created",
  *     @SWG\Schema(
  *       ref="#/definitions/AttributeResponse"
  *     )
  *   ),
  *   @SWG\Response(
  *     response=400,
  *     description="Invalid API key supplied",
  *     @SWG\Schema(ref="#/definitions/StatusResponse")
  *   )
  * )
  * @throws \InvalidArgumentException
  */
 public function actionCreate()
 {
     /** @var array $inputData */
     $inputData = $this->input->getData();
     $miner = $this->findMinerWithCheckAccess(@$inputData['miner']);
     $this->minersFacade->checkMinerMetasource($miner);
     $currentUser = $this->getCurrentUser();
     //aktualizace informace o datových sloupcích
     $this->datasourcesFacade->updateDatasourceColumns($miner->datasource, $currentUser);
     try {
         if (!empty($inputData['column'])) {
             $datasourceColumn = $this->datasourcesFacade->findDatasourceColumn($miner->datasource, @$inputData['column']);
         } else {
             $datasourceColumn = $this->datasourcesFacade->findDatasourceColumnByName($miner->datasource, @$inputData['columnName']);
         }
     } catch (\Exception $e) {
         throw new InvalidArgumentException("Datasource columns was not found: " . @$inputData['columnName']);
     }
     //inicializace formátu
     $format = $datasourceColumn->format;
     if (!$format) {
         //TODO implementovat podporu automatického mapování
         $format = $this->metaAttributesFacade->simpleCreateMetaAttributeWithFormatFromDatasourceColumn($datasourceColumn, $currentUser);
         $datasourceColumn->format = $format;
         $this->datasourcesFacade->saveDatasourceColumn($datasourceColumn);
     }
     //vytvoření nového atributu
     $attribute = new Attribute();
     $attribute->metasource = $miner->metasource;
     $attribute->datasourceColumn = $datasourceColumn;
     $attribute->name = $this->minersFacade->prepareNewAttributeName($miner, $inputData['name']);
     $attribute->type = $attribute->datasourceColumn->type;
     if (@$inputData['specialPreprocessing'] == Preprocessing::SPECIALTYPE_EACHONE) {
         $preprocessing = $this->metaAttributesFacade->findPreprocessingEachOne($datasourceColumn->format);
         $attribute->preprocessing = $preprocessing;
     } else {
         throw new \BadMethodCallException('Selected preprocessing type is not supported.');
         //FIXME je nutné nalézt příslušný preprocessing...
     }
     $attribute->active = false;
     $this->metasourcesFacade->saveAttribute($attribute);
     //inicializace preprocessingu
     $metasourceTask = $this->metasourcesFacade->startAttributesPreprocessing($miner->metasource, [$attribute]);
     while ($metasourceTask && $metasourceTask->state != MetasourceTask::STATE_DONE) {
         $metasourceTask = $this->metasourcesFacade->preprocessAttributes($metasourceTask);
     }
     //smazání předzpracovávací úlohy
     $this->metasourcesFacade->deleteMetasourceTask($metasourceTask);
     $this->setXmlMapperElements('attribute');
     $this->resource = $attribute->getDataArr();
     $this->sendResource();
 }
 /**
  * Funkce vracející formulář pro vytvoření atributu na základě vybraného sloupce a preprocessingu
  * @return Form
  */
 protected function createComponentNewAttributeForm()
 {
     $form = new Form();
     $presenter = $this;
     $form->setTranslator($this->translator);
     $form->addHidden('miner');
     $form->addHidden('column');
     $form->addHidden('preprocessing');
     $form->addText('attributeName', 'Attribute 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->addSubmit('submit', 'Create attribute')->onClick[] = function (SubmitButton $button) {
         $values = $button->form->values;
         $miner = $this->findMinerWithCheckAccess($values->miner);
         $this->minersFacade->checkMinerMetasource($miner);
         $attribute = new Attribute();
         $attribute->metasource = $miner->metasource;
         $attribute->datasourceColumn = $this->datasourcesFacade->findDatasourceColumn($miner->datasource, $values->column);
         $attribute->name = $values->attributeName;
         $attribute->type = $attribute->datasourceColumn->type;
         $attribute->preprocessing = $this->metaAttributesFacade->findPreprocessing($values->preprocessing);
         $attribute->active = false;
         $this->metasourcesFacade->saveAttribute($attribute);
         $metasourceTask = $this->metasourcesFacade->startAttributesPreprocessing($miner->metasource, [$attribute]);
         $this->redirect('preprocessingTask', ['id' => $metasourceTask->metasourceTaskId]);
     };
     $storno = $form->addSubmit('storno', 'storno');
     $storno->setValidationScope(array());
     $storno->onClick[] = function (SubmitButton $button) use($presenter) {
         //přesměrování na výběr preprocessingu
         $values = $button->form->getValues();
         $presenter->redirect('addAttribute', array('column' => $values->column, 'miner' => $values->miner));
     };
     return $form;
 }
 /**
  * Funkce pro vytvoření metaatributu a formátu na základě hodnot datového sloupce
  * @param string $metaAttributeName
  * @param string $formatName
  * @param DatasourceColumn $datasourceColumn
  * @param DbColumnValuesStatistic $columnValuesStatistic
  * @param string $formatType
  * @param bool $formatShared
  * @return Format
  */
 private function createMetaAttributeFromDatasourceColumn($metaAttributeName, $formatName, DatasourceColumn $datasourceColumn, DbColumnValuesStatistic $columnValuesStatistic, $formatType, $formatShared = false)
 {
     $metaAttribute = $this->metaAttributesFacade->findOrCreateMetaAttributeWithName($metaAttributeName);
     return $this->metaAttributesFacade->createFormatFromDatasourceColumn($metaAttribute, $formatName, $datasourceColumn, $columnValuesStatistic, $formatType, $formatShared, $this->presenter->getUser()->getId());
 }
 /**
  * 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;
 }