/**
  *
  * @param Report $report        	
  * @param number $limit        	
  * @param string $sort        	
  * @param string $order        	
  * @param boolean $lazy        	
  * @param boolean $active        	
  * @param boolean $silent        	
  *
  * @return ArrayCollection $data
  */
 public function generateResults(Report $report, $limit = 0, $sort = '_score', $order = 'desc', $lazy = true, $active = true, $silent = false)
 {
     $data = new ArrayCollection();
     $request = $this->getServiceLocator()->get('Request');
     $silent = $request->getQuery('debug') ? false : $silent;
     if ($report instanceof Report) {
         $agent = $report->getAgent();
         $lead_query = new \Agent\Elastica\Query\BoolQuery();
         if ($active) {
             $lead_query->addMust(new Elastica\Query\Match('active', 1));
         }
         $client = $this->getElasticaClient();
         if ($agent && $client) {
             $filters = $agent->getFilter();
             if ($filters) {
                 $lead_query = $this->applyFilters($lead_query, $filters);
             }
             $criteria = $agent->getCriteria(false);
             if ($criteria) {
                 try {
                     $query = new Elastica\Query();
                     /* @var $criterion \Agent\Entity\AgentCriterion */
                     foreach ($criteria as $i => $criterion) {
                         $lead_query = $this->buildQuery($lead_query, $criterion);
                     }
                     $query->setQuery($lead_query);
                     $size = $limit ? $limit : 1000;
                     $query->setParam('track_scores', true);
                     $query->addSort([$sort => ['order' => $order]]);
                     $query->setSize($size);
                     $results = $this->runQuery($query, $lazy, $silent);
                     $total = isset($results['total']) ? $results['total'] : false;
                     if ($total && $results['results']) {
                         foreach ($results['results'] as $result) {
                             $data->add($result);
                         }
                     }
                     if ($total > $size) {
                         $limit = $limit ?: $total;
                         for ($page = 1; $page < ceil($limit / $size); $page++) {
                             $query->setFrom($page * $size);
                             $results = $this->runQuery($query, $silent);
                             if ($results['results']) {
                                 foreach ($results as $result) {
                                     if (is_array($result)) {
                                         foreach ($result as $r) {
                                             if ($r instanceof Result) {
                                                 $data->add($r);
                                             }
                                         }
                                     } elseif ($result instanceof Result) {
                                         $data->add($result);
                                     }
                                 }
                             }
                         }
                     }
                 } catch (\Exception $e) {
                     if (!$silent) {
                         $this->getFlashMessenger()->addErrorMessage($e->getMessage());
                     }
                 }
             }
         }
     }
     return $data;
 }
 /**
  *
  * @param array $location        	
  *
  * @return Elastica\Query $localityQuery
  */
 public static function getLocalityQuery($location)
 {
     $query = new Agent\Elastica\Query\BoolQuery();
     $method = 'addMust';
     if (!isset($location['state']) && !isset($location['zip']) && !isset($location['locality'])) {
         foreach (['phone', 'ipaddress'] as $field) {
             if (isset($location[$field]) && empty($location['state'])) {
                 switch ($field) {
                     case 'ipaddress':
                         $geo = self::$geo;
                         $loc = $geo->getRecord($location['ipaddress']);
                         if ($loc instanceof Record) {
                             $state = $loc->getRegion();
                             if ($state) {
                                 $location['state'] = $state;
                             }
                         }
                         break;
                     case 'phone':
                         $phone = Helper::parse_phonenumber($location['phone'], 'array');
                         if ($phone) {
                             $state = Helper::area_code_to_state($phone[0]);
                             if ($state) {
                                 $location['state'] = $state;
                             }
                         }
                         break;
                 }
             }
         }
     }
     foreach ($location as $field => $value) {
         switch ($field) {
             case 'locality':
                 if (!isset($location['zip'])) {
                     $fields = ['latitude', 'longitude'];
                     $values = is_array($value) ? $value : explode(",", $value);
                     $latlon = count($values) == 2 ? array_combine($fields, $values) : false;
                     if ($latlon) {
                         $path = "location";
                         $nested = new Elastica\Query\Nested();
                         $nested->setPath($path);
                         $bool = new Elastica\Query\BoolQuery();
                         foreach ($latlon as $dim => $coord) {
                             $bool->addMust(new Elastica\Query\Match("{$path}.{$dim}", $coord));
                         }
                         $nested->setQuery($bool);
                         $query->addMust($nested);
                     }
                 }
                 break;
             case 'city':
                 if (!isset($location['locality'])) {
                     $query->addShould(new Elastica\Query\Match($field, $value));
                 }
                 break;
             case 'state':
                 if (!isset($location['locality'])) {
                     $fields = ['state.abbrev', 'state.full'];
                     $values = is_array($value) ? $value : [$value];
                     foreach ($values as $state) {
                         $querystring = new Elastica\Query\QueryString($state);
                         $querystring->setFields($fields);
                         $nested = new Elastica\Query\Nested();
                         $nested->setQuery($querystring);
                         $nested->setPath($field);
                         if (count($values) > 1) {
                             $query->addShould($nested);
                         } else {
                             $query->addMust($nested);
                         }
                     }
                 }
                 break;
             case 'zip':
                 $query->{$method}(new Elastica\Query\Match($field, $value));
                 break;
         }
     }
     $localityQuery = new Elastica\Query($query);
     $localityQuery->setSize(1);
     return $localityQuery;
 }
 /**
  *
  * @param BoolQuery $lead_query        	
  * @param AgentCriterion $criterion        	
  *
  * @return BoolQuery $lead_query
  */
 protected function buildQuery(BoolQuery $lead_query, AgentCriterion $criterion)
 {
     if (!$criterion->getServiceLocator()) {
         $criterion->setServiceLocator($this->getServiceLocator());
     }
     $criteria_query = false;
     $relationship = $criterion->getRelationship();
     $required = $criterion->getRequired();
     $weight = $criterion->getWeight();
     if ($relationship) {
         $value = $criterion->getValue();
         if ($value) {
             $data = $value->getData();
             $boost = $weight ? (1 - $weight) * 10 + 1 : 1;
             $abstractQuery = $relationship->getQuery();
             if ($abstractQuery) {
                 $abstractQuery->setCriterion($criterion);
                 $abstractQuery->setRelationship($relationship);
                 $request = $this->getServiceLocator()->get('Request');
                 $debug = $request->getQuery('debug');
                 if ($debug) {
                     echo "<script>console.dir(" . json_encode($data) . ");</script>\n";
                 }
                 $boolQuery = $abstractQuery->getQuery($data, null, $required, $boost);
                 if ($boolQuery) {
                     switch ($relationship->getType()) {
                         case 'location':
                             $queryClass = (new \ReflectionClass($boolQuery))->getShortName();
                             switch ($queryClass) {
                                 case 'GeoDistance':
                                     $criteria_query = $boolQuery;
                                     break;
                                 default:
                                     $criteria_query = new Elastica\Query\HasChild($boolQuery, 'value');
                                     $criteria_query->setParam('score_mode', 'avg');
                                     break;
                             }
                             break;
                         default:
                             $criteria_query = new Elastica\Query\HasChild($boolQuery, 'value');
                             $criteria_query->setParam('score_mode', 'avg');
                             break;
                     }
                     if ($required) {
                         $lead_query->addMust($criteria_query);
                     } else {
                         $lead_query->addShould($criteria_query);
                         $lead_query->setBoost($boost);
                     }
                 }
             }
         }
     }
     return $lead_query;
 }
 /**
  *
  * @param mixed $value        	
  * @param BoolQuery $query        	
  * @param integer|boolean $required        	
  * @param integer|float $boost        	
  *
  * @return BoolQuery $query
  */
 public function getQuery($value = null, $query = null, $required = null, $boost = null)
 {
     $relationship = $this->getRelationship();
     if ($relationship) {
         $attributeDesc = false;
         $criterion = $this->getCriterion();
         if ($criterion) {
             $attribute = $criterion->getAttribute();
             if ($attribute) {
                 $attributeDesc = $attribute->getAttributeDesc();
             }
         }
         if ($attributeDesc) {
             if (!isset($query)) {
                 $query = new BoolQuery();
             }
             $attribute_query = new Elastica\Query\Nested();
             $attribute_query->setPath('attribute');
             $attribute_query->setQuery(new Elastica\Query\Match('attribute.attributeDesc', $attributeDesc));
             $query->addMust($attribute_query);
         }
         $this->setQuery($query);
     }
     return $this->query;
 }