/**
  * Import discovery rules.
  *
  * @throws Exception
  */
 protected function processDiscoveryRules()
 {
     $allDiscoveryRules = $this->getFormattedDiscoveryRules();
     if (empty($allDiscoveryRules)) {
         return;
     }
     // unset rules that are related to hosts we did not process
     foreach ($allDiscoveryRules as $host => $discoveryRules) {
         if (!$this->referencer->isProcessedHost($host)) {
             unset($allDiscoveryRules[$host]);
         }
     }
     $itemsToCreate = array();
     $itemsToUpdate = array();
     foreach ($allDiscoveryRules as $host => $discoveryRules) {
         $hostid = $this->referencer->resolveHostOrTemplate($host);
         foreach ($discoveryRules as $item) {
             $item['hostid'] = $hostid;
             if (isset($item['interface_ref'])) {
                 $item['interfaceid'] = $this->referencer->interfacesCache[$hostid][$item['interface_ref']];
             }
             unset($item['item_prototypes']);
             unset($item['trigger_prototypes']);
             unset($item['graph_prototypes']);
             unset($item['host_prototypes']);
             $itemId = $this->referencer->resolveItem($hostid, $item['key_']);
             if ($itemId) {
                 $item['itemid'] = $itemId;
                 $itemsToUpdate[] = $item;
             } else {
                 $itemsToCreate[] = $item;
             }
         }
     }
     // create/update discovery rules and add processed rules to array $processedRules
     $processedRules = array();
     if ($this->options['discoveryRules']['createMissing'] && $itemsToCreate) {
         $newItemsIds = API::DiscoveryRule()->create($itemsToCreate);
         foreach ($newItemsIds['itemids'] as $inum => $itemid) {
             $item = $itemsToCreate[$inum];
             $this->referencer->addItemRef($item['hostid'], $item['key_'], $itemid);
         }
         foreach ($itemsToCreate as $item) {
             $processedRules[$item['hostid']][$item['key_']] = 1;
         }
     }
     if ($this->options['discoveryRules']['updateExisting'] && $itemsToUpdate) {
         API::DiscoveryRule()->update($itemsToUpdate);
         foreach ($itemsToUpdate as $item) {
             $processedRules[$item['hostid']][$item['key_']] = 1;
         }
     }
     // refresh discovery rules because templated ones can be inherited to host and used for prototypes
     $this->referencer->refreshItems();
     // process prototypes
     $prototypesToUpdate = array();
     $prototypesToCreate = array();
     $hostPrototypesToUpdate = array();
     $hostPrototypesToCreate = array();
     foreach ($allDiscoveryRules as $host => $discoveryRules) {
         $hostid = $this->referencer->resolveHostOrTemplate($host);
         foreach ($discoveryRules as $item) {
             // if rule was not processed we should not create/update any of its prototypes
             if (!isset($processedRules[$hostid][$item['key_']])) {
                 continue;
             }
             $item['hostid'] = $hostid;
             $itemId = $this->referencer->resolveItem($hostid, $item['key_']);
             // prototypes
             foreach ($item['item_prototypes'] as $prototype) {
                 $prototype['hostid'] = $hostid;
                 $applicationsIds = array();
                 foreach ($prototype['applications'] as $application) {
                     $applicationsIds[] = $this->referencer->resolveApplication($hostid, $application['name']);
                 }
                 $prototype['applications'] = $applicationsIds;
                 if (isset($prototype['interface_ref'])) {
                     $prototype['interfaceid'] = $this->referencer->interfacesCache[$hostid][$prototype['interface_ref']];
                 }
                 if ($prototype['valuemap']) {
                     $valueMapId = $this->referencer->resolveValueMap($prototype['valuemap']['name']);
                     if (!$valueMapId) {
                         throw new Exception(_s('Cannot find value map "%1$s" used for item prototype "%2$s" of discovery rule "%3$s" on "%4$s".', $prototype['valuemap']['name'], $prototype['name'], $item['name'], $host));
                     }
                     $prototype['valuemapid'] = $valueMapId;
                 }
                 $prototypeId = $this->referencer->resolveItem($hostid, $prototype['key_']);
                 $prototype['rule'] = array('hostid' => $hostid, 'key' => $item['key_']);
                 if ($prototypeId) {
                     $prototype['itemid'] = $prototypeId;
                     $prototypesToUpdate[] = $prototype;
                 } else {
                     $prototypesToCreate[] = $prototype;
                 }
             }
             // host prototype
             foreach ($item['host_prototypes'] as $hostPrototype) {
                 // resolve group prototypes
                 $groupLinks = array();
                 foreach ($hostPrototype['group_links'] as $groupLink) {
                     $groupId = $this->referencer->resolveGroup($groupLink['group']['name']);
                     if (!$groupId) {
                         throw new Exception(_s('Cannot find host group "%1$s" for host prototype "%2$s" of discovery rule "%3$s" on "%4$s".', $groupLink['group']['name'], $hostPrototype['name'], $item['name'], $host));
                     }
                     $groupLinks[] = array('groupid' => $groupId);
                 }
                 $hostPrototype['groupLinks'] = $groupLinks;
                 $hostPrototype['groupPrototypes'] = $hostPrototype['group_prototypes'];
                 unset($hostPrototype['group_links'], $hostPrototype['group_prototypes']);
                 // resolve templates
                 $templates = array();
                 foreach ($hostPrototype['templates'] as $template) {
                     $templateId = $this->referencer->resolveTemplate($template['name']);
                     if (!$templateId) {
                         throw new Exception(_s('Cannot find template "%1$s" for host prototype "%2$s" of discovery rule "%3$s" on "%4$s".', $template['name'], $hostPrototype['name'], $item['name'], $host));
                     }
                     $templates[] = array('templateid' => $templateId);
                 }
                 $hostPrototype['templates'] = $templates;
                 $hostPrototypeId = $this->referencer->resolveHostPrototype($hostid, $itemId, $hostPrototype['host']);
                 if ($hostPrototypeId) {
                     $hostPrototype['hostid'] = $hostPrototypeId;
                     $hostPrototypesToUpdate[] = $hostPrototype;
                 } else {
                     $hostPrototype['ruleid'] = $itemId;
                     $hostPrototypesToCreate[] = $hostPrototype;
                 }
             }
             if (isset($item['interface_ref'])) {
                 $item['interfaceid'] = $this->referencer->interfacesCache[$hostid][$item['interface_ref']];
             }
             unset($item['item_prototypes']);
             unset($item['trigger_prototypes']);
             unset($item['graph_prototypes']);
             unset($item['host_prototypes']);
             $itemsId = $this->referencer->resolveItem($hostid, $item['key_']);
             if ($itemsId) {
                 $item['itemid'] = $itemsId;
                 $itemsToUpdate[] = $item;
             } else {
                 $itemsToCreate[] = $item;
             }
         }
     }
     if ($prototypesToCreate) {
         foreach ($prototypesToCreate as &$prototype) {
             $prototype['ruleid'] = $this->referencer->resolveItem($prototype['rule']['hostid'], $prototype['rule']['key']);
         }
         unset($prototype);
         $newPrototypeIds = API::ItemPrototype()->create($prototypesToCreate);
         foreach ($newPrototypeIds['itemids'] as $inum => $itemid) {
             $item = $prototypesToCreate[$inum];
             $this->referencer->addItemRef($item['hostid'], $item['key_'], $itemid);
         }
     }
     if ($prototypesToUpdate) {
         foreach ($prototypesToCreate as &$prototype) {
             $prototype['ruleid'] = $this->referencer->resolveItem($prototype['rule']['hostid'], $prototype['rule']['key']);
         }
         unset($prototype);
         API::ItemPrototype()->update($prototypesToUpdate);
     }
     if ($hostPrototypesToCreate) {
         API::HostPrototype()->create($hostPrototypesToCreate);
     }
     if ($hostPrototypesToUpdate) {
         API::HostPrototype()->update($hostPrototypesToUpdate);
     }
     // refresh prototypes because templated ones can be inherited to host and used in triggers prototypes or graph prototypes
     $this->referencer->refreshItems();
     // first we need to create item prototypes and only then graph prototypes
     $triggersToCreate = array();
     $triggersToUpdate = array();
     $graphsToCreate = array();
     $graphsToUpdate = array();
     foreach ($allDiscoveryRules as $host => $discoveryRules) {
         $hostid = $this->referencer->resolveHostOrTemplate($host);
         foreach ($discoveryRules as $item) {
             // if rule was not processed we should not create/update any of its prototypes
             if (!isset($processedRules[$hostid][$item['key_']])) {
                 continue;
             }
             // trigger prototypes
             foreach ($item['trigger_prototypes'] as $trigger) {
                 $triggerId = $this->referencer->resolveTrigger($trigger['description'], $trigger['expression']);
                 if ($triggerId) {
                     $trigger['triggerid'] = $triggerId;
                     $triggersToUpdate[] = $trigger;
                 } else {
                     $triggersToCreate[] = $trigger;
                 }
             }
             // graph prototypes
             foreach ($item['graph_prototypes'] as $graph) {
                 $graphHostIds = array();
                 if ($graph['ymin_item_1']) {
                     $hostId = $this->referencer->resolveHostOrTemplate($graph['ymin_item_1']['host']);
                     $itemId = $hostId ? $this->referencer->resolveItem($hostId, $graph['ymin_item_1']['key']) : false;
                     if (!$itemId) {
                         throw new Exception(_s('Cannot find item "%1$s" on "%2$s" used as the Y axis MIN value for graph prototype "%3$s" of discovery rule "%4$s" on "%5$s".', $graph['ymin_item_1']['key'], $graph['ymin_item_1']['host'], $graph['name'], $item['name'], $host));
                     }
                     $graph['ymin_itemid'] = $itemId;
                 }
                 if ($graph['ymax_item_1']) {
                     $hostId = $this->referencer->resolveHostOrTemplate($graph['ymax_item_1']['host']);
                     $itemId = $hostId ? $this->referencer->resolveItem($hostId, $graph['ymax_item_1']['key']) : false;
                     if (!$itemId) {
                         throw new Exception(_s('Cannot find item "%1$s" on "%2$s" used as the Y axis MAX value for graph prototype "%3$s" of discovery rule "%4$s" on "%5$s".', $graph['ymax_item_1']['key'], $graph['ymax_item_1']['host'], $graph['name'], $item['name'], $host));
                     }
                     $graph['ymax_itemid'] = $itemId;
                 }
                 foreach ($graph['gitems'] as &$gitem) {
                     if (!($gitemHostId = $this->referencer->resolveHostOrTemplate($gitem['item']['host']))) {
                         throw new Exception(_s('Cannot find host or template "%1$s" used in graph "%2$s".', $gitem['item']['host'], $graph['name']));
                     }
                     $gitem['itemid'] = $this->referencer->resolveItem($gitemHostId, $gitem['item']['key']);
                     $graphHostIds[$gitemHostId] = $gitemHostId;
                 }
                 unset($gitem);
                 // TODO: do this for all graphs at once
                 $sql = 'SELECT g.graphid' . ' FROM graphs g,graphs_items gi,items i' . ' WHERE g.graphid=gi.graphid' . ' AND gi.itemid=i.itemid' . ' AND g.name=' . zbx_dbstr($graph['name']) . ' AND ' . dbConditionInt('i.hostid', $graphHostIds);
                 $graphExists = DBfetch(DBselect($sql));
                 if ($graphExists) {
                     $dbGraph = API::GraphPrototype()->get(array('graphids' => $graphExists['graphid'], 'output' => array('graphid'), 'editable' => true));
                     if (empty($dbGraph)) {
                         throw new Exception(_s('No permission for graph "%1$s".', $graph['name']));
                     }
                     $graph['graphid'] = $graphExists['graphid'];
                     $graphsToUpdate[] = $graph;
                 } else {
                     $graphsToCreate[] = $graph;
                 }
             }
         }
     }
     if ($triggersToCreate) {
         API::TriggerPrototype()->create($triggersToCreate);
     }
     if ($triggersToUpdate) {
         API::TriggerPrototype()->update($triggersToUpdate);
     }
     if ($graphsToCreate) {
         API::GraphPrototype()->create($graphsToCreate);
     }
     if ($graphsToUpdate) {
         API::GraphPrototype()->update($graphsToUpdate);
     }
 }
 /**
  * Import discovery rules.
  *
  * @throws Exception
  */
 protected function processDiscoveryRules()
 {
     if (!$this->options['discoveryRules']['createMissing'] && !$this->options['discoveryRules']['updateExisting']) {
         return;
     }
     $allDiscoveryRules = $this->getFormattedDiscoveryRules();
     if (!$allDiscoveryRules) {
         return;
     }
     // unset rules that are related to hosts we did not process
     foreach ($allDiscoveryRules as $host => $discoveryRules) {
         $hostId = $this->referencer->resolveHostOrTemplate($host);
         if (!$this->importedObjectContainer->isHostProcessed($hostId) && !$this->importedObjectContainer->isTemplateProcessed($hostId)) {
             unset($allDiscoveryRules[$host]);
         }
     }
     $itemsToCreate = array();
     $itemsToUpdate = array();
     foreach ($allDiscoveryRules as $host => $discoveryRules) {
         $hostId = $this->referencer->resolveHostOrTemplate($host);
         foreach ($discoveryRules as $item) {
             $item['hostid'] = $hostId;
             if (isset($item['interface_ref'])) {
                 $item['interfaceid'] = $this->referencer->interfacesCache[$hostId][$item['interface_ref']];
             }
             unset($item['item_prototypes']);
             unset($item['trigger_prototypes']);
             unset($item['graph_prototypes']);
             unset($item['host_prototypes']);
             $itemId = $this->referencer->resolveItem($hostId, $item['key_']);
             if ($itemId) {
                 $item['itemid'] = $itemId;
                 $itemsToUpdate[] = $item;
             } else {
                 $itemsToCreate[] = $item;
             }
         }
     }
     // create/update discovery rules and add processed rules to array $processedRules
     $processedRules = array();
     if ($this->options['discoveryRules']['createMissing'] && $itemsToCreate) {
         $newItemsIds = API::DiscoveryRule()->create($itemsToCreate);
         foreach ($newItemsIds['itemids'] as $inum => $itemid) {
             $item = $itemsToCreate[$inum];
             $this->referencer->addItemRef($item['hostid'], $item['key_'], $itemid);
         }
         foreach ($itemsToCreate as $item) {
             $processedRules[$item['hostid']][$item['key_']] = 1;
         }
     }
     if ($this->options['discoveryRules']['updateExisting'] && $itemsToUpdate) {
         API::DiscoveryRule()->update($itemsToUpdate);
         foreach ($itemsToUpdate as $item) {
             $processedRules[$item['hostid']][$item['key_']] = 1;
         }
     }
     // refresh discovery rules because templated ones can be inherited to host and used for prototypes
     $this->referencer->refreshItems();
     // process prototypes
     $prototypesToUpdate = array();
     $prototypesToCreate = array();
     $hostPrototypesToUpdate = array();
     $hostPrototypesToCreate = array();
     foreach ($allDiscoveryRules as $host => $discoveryRules) {
         $hostId = $this->referencer->resolveHostOrTemplate($host);
         foreach ($discoveryRules as $item) {
             // if rule was not processed we should not create/update any of its prototypes
             if (!isset($processedRules[$hostId][$item['key_']])) {
                 continue;
             }
             $item['hostid'] = $hostId;
             $itemId = $this->referencer->resolveItem($hostId, $item['key_']);
             // prototypes
             foreach ($item['item_prototypes'] as $prototype) {
                 $prototype['hostid'] = $hostId;
                 $applicationsIds = array();
                 foreach ($prototype['applications'] as $application) {
                     $applicationsIds[] = $this->referencer->resolveApplication($hostId, $application['name']);
                 }
                 $prototype['applications'] = $applicationsIds;
                 if (isset($prototype['interface_ref'])) {
                     $prototype['interfaceid'] = $this->referencer->interfacesCache[$hostId][$prototype['interface_ref']];
                 }
                 if ($prototype['valuemap']) {
                     $valueMapId = $this->referencer->resolveValueMap($prototype['valuemap']['name']);
                     if (!$valueMapId) {
                         throw new Exception(_s('Cannot find value map "%1$s" used for item prototype "%2$s" of discovery rule "%3$s" on "%4$s".', $prototype['valuemap']['name'], $prototype['name'], $item['name'], $host));
                     }
                     $prototype['valuemapid'] = $valueMapId;
                 }
                 $prototypeId = $this->referencer->resolveItem($hostId, $prototype['key_']);
                 $prototype['rule'] = array('hostid' => $hostId, 'key' => $item['key_']);
                 if ($prototypeId) {
                     $prototype['itemid'] = $prototypeId;
                     $prototypesToUpdate[] = $prototype;
                 } else {
                     $prototypesToCreate[] = $prototype;
                 }
             }
             // host prototype
             foreach ($item['host_prototypes'] as $hostPrototype) {
                 // resolve group prototypes
                 $groupLinks = array();
                 foreach ($hostPrototype['group_links'] as $groupLink) {
                     $groupId = $this->referencer->resolveGroup($groupLink['group']['name']);
                     if (!$groupId) {
                         throw new Exception(_s('Cannot find host group "%1$s" for host prototype "%2$s" of discovery rule "%3$s" on "%4$s".', $groupLink['group']['name'], $hostPrototype['name'], $item['name'], $host));
                     }
                     $groupLinks[] = array('groupid' => $groupId);
                 }
                 $hostPrototype['groupLinks'] = $groupLinks;
                 $hostPrototype['groupPrototypes'] = $hostPrototype['group_prototypes'];
                 unset($hostPrototype['group_links'], $hostPrototype['group_prototypes']);
                 // resolve templates
                 $templates = array();
                 foreach ($hostPrototype['templates'] as $template) {
                     $templateId = $this->referencer->resolveTemplate($template['name']);
                     if (!$templateId) {
                         throw new Exception(_s('Cannot find template "%1$s" for host prototype "%2$s" of discovery rule "%3$s" on "%4$s".', $template['name'], $hostPrototype['name'], $item['name'], $host));
                     }
                     $templates[] = array('templateid' => $templateId);
                 }
                 $hostPrototype['templates'] = $templates;
                 $hostPrototypeId = $this->referencer->resolveHostPrototype($hostId, $itemId, $hostPrototype['host']);
                 if ($hostPrototypeId) {
                     $hostPrototype['hostid'] = $hostPrototypeId;
                     $hostPrototypesToUpdate[] = $hostPrototype;
                 } else {
                     $hostPrototype['ruleid'] = $itemId;
                     $hostPrototypesToCreate[] = $hostPrototype;
                 }
             }
             if (isset($item['interface_ref'])) {
                 $item['interfaceid'] = $this->referencer->interfacesCache[$hostId][$item['interface_ref']];
             }
             unset($item['item_prototypes']);
             unset($item['trigger_prototypes']);
             unset($item['graph_prototypes']);
             unset($item['host_prototypes']);
             $itemsId = $this->referencer->resolveItem($hostId, $item['key_']);
             if ($itemsId) {
                 $item['itemid'] = $itemsId;
                 $itemsToUpdate[] = $item;
             } else {
                 $itemsToCreate[] = $item;
             }
         }
     }
     if ($prototypesToCreate) {
         foreach ($prototypesToCreate as &$prototype) {
             $prototype['ruleid'] = $this->referencer->resolveItem($prototype['rule']['hostid'], $prototype['rule']['key']);
         }
         unset($prototype);
         $newPrototypeIds = API::ItemPrototype()->create($prototypesToCreate);
         foreach ($newPrototypeIds['itemids'] as $inum => $itemid) {
             $item = $prototypesToCreate[$inum];
             $this->referencer->addItemRef($item['hostid'], $item['key_'], $itemid);
         }
     }
     if ($prototypesToUpdate) {
         foreach ($prototypesToCreate as &$prototype) {
             $prototype['ruleid'] = $this->referencer->resolveItem($prototype['rule']['hostid'], $prototype['rule']['key']);
         }
         unset($prototype);
         API::ItemPrototype()->update($prototypesToUpdate);
     }
     if ($hostPrototypesToCreate) {
         API::HostPrototype()->create($hostPrototypesToCreate);
     }
     if ($hostPrototypesToUpdate) {
         API::HostPrototype()->update($hostPrototypesToUpdate);
     }
     // refresh prototypes because templated ones can be inherited to host and used in triggers prototypes or graph prototypes
     $this->referencer->refreshItems();
     // first we need to create item prototypes and only then graph prototypes
     $triggersToCreate = array();
     $triggersToUpdate = array();
     $graphsToCreate = array();
     $graphsToUpdate = array();
     foreach ($allDiscoveryRules as $host => $discoveryRules) {
         $hostId = $this->referencer->resolveHostOrTemplate($host);
         foreach ($discoveryRules as $item) {
             // if rule was not processed we should not create/update any of its prototypes
             if (!isset($processedRules[$hostId][$item['key_']])) {
                 continue;
             }
             // trigger prototypes
             foreach ($item['trigger_prototypes'] as $trigger) {
                 // search for existing  items in trigger prototype expressions
                 foreach ($trigger['parsedExpressions'] as $expression) {
                     $hostId = $this->referencer->resolveHostOrTemplate($expression['host']);
                     $itemId = $hostId ? $this->referencer->resolveItem($hostId, $expression['item']) : false;
                     if (!$itemId) {
                         throw new Exception(_s('Cannot find item "%1$s" on "%2$s" used in trigger prototype "%3$s" of discovery rule "%4$s" on "%5$s".', $expression['item'], $expression['host'], $trigger['description'], $item['name'], $host));
                     }
                 }
                 $triggerId = $this->referencer->resolveTrigger($trigger['description'], $trigger['expression']);
                 if ($triggerId) {
                     $trigger['triggerid'] = $triggerId;
                     $triggersToUpdate[] = $trigger;
                 } else {
                     $triggersToCreate[] = $trigger;
                 }
             }
             // graph prototypes
             foreach ($item['graph_prototypes'] as $graph) {
                 if ($graph['ymin_item_1']) {
                     $hostId = $this->referencer->resolveHostOrTemplate($graph['ymin_item_1']['host']);
                     $itemId = $hostId ? $this->referencer->resolveItem($hostId, $graph['ymin_item_1']['key']) : false;
                     if (!$itemId) {
                         throw new Exception(_s('Cannot find item "%1$s" on "%2$s" used as the Y axis MIN value for graph prototype "%3$s" of discovery rule "%4$s" on "%5$s".', $graph['ymin_item_1']['key'], $graph['ymin_item_1']['host'], $graph['name'], $item['name'], $host));
                     }
                     $graph['ymin_itemid'] = $itemId;
                 }
                 if ($graph['ymax_item_1']) {
                     $hostId = $this->referencer->resolveHostOrTemplate($graph['ymax_item_1']['host']);
                     $itemId = $hostId ? $this->referencer->resolveItem($hostId, $graph['ymax_item_1']['key']) : false;
                     if (!$itemId) {
                         throw new Exception(_s('Cannot find item "%1$s" on "%2$s" used as the Y axis MAX value for graph prototype "%3$s" of discovery rule "%4$s" on "%5$s".', $graph['ymax_item_1']['key'], $graph['ymax_item_1']['host'], $graph['name'], $item['name'], $host));
                     }
                     $graph['ymax_itemid'] = $itemId;
                 }
                 foreach ($graph['gitems'] as &$gitem) {
                     $gitemHostId = $this->referencer->resolveHostOrTemplate($gitem['item']['host']);
                     $gitem['itemid'] = $gitemHostId ? $this->referencer->resolveItem($gitemHostId, $gitem['item']['key']) : false;
                     if (!$gitem['itemid']) {
                         throw new Exception(_s('Cannot find item "%1$s" on "%2$s" used in graph prototype "%3$s" of discovery rule "%4$s" on "%5$s".', $gitem['item']['key'], $gitem['item']['host'], $graph['name'], $item['name'], $host));
                     }
                 }
                 unset($gitem);
                 $graphId = $this->referencer->resolveGraph($gitemHostId, $graph['name']);
                 if ($graphId) {
                     $graph['graphid'] = $graphId;
                     $graphsToUpdate[] = $graph;
                 } else {
                     $graphsToCreate[] = $graph;
                 }
             }
         }
     }
     if ($triggersToCreate) {
         API::TriggerPrototype()->create($triggersToCreate);
     }
     if ($triggersToUpdate) {
         API::TriggerPrototype()->update($triggersToUpdate);
     }
     if ($graphsToCreate) {
         API::GraphPrototype()->create($graphsToCreate);
         $this->referencer->refreshGraphs();
     }
     if ($graphsToUpdate) {
         API::GraphPrototype()->update($graphsToUpdate);
     }
 }