function search()
 {
     $urlSeparator = "_";
     //Used for url parameters that pass something more than just a value
     $simplesearch_custom_fields = 1;
     // Search custom fields in simple search
     $simplesearch_query_type = 'all';
     // any|all
     $min_word_chars = 3;
     // Only words with min_word_chars or higher will be used in any|all query types
     $category_ids = '';
     $criteria_ids = Sanitize::getString($this->params, 'criteria');
     $dir_id = Sanitize::getString($this->params, 'dir', '');
     $accepted_query_types = array('any', 'all', 'exact');
     $query_type = Sanitize::getString($this->params, 'query');
     $keywords = urldecode(Sanitize::getString($this->params, 'keywords'));
     $scope = Sanitize::getString($this->params, 'scope');
     $author = urldecode(Sanitize::getString($this->params, 'author'));
     $ignored_search_words = $keywords != '' ? cmsFramework::getIgnoredSearchWords() : array();
     if (!in_array($query_type, $accepted_query_types)) {
         $query_type = 'all';
         // default value if value used is not recognized
     }
     // Build search where statement for standard fields
     $wheres = array();
     # SIMPLE SEARCH
     if ($keywords != '' && $scope == '') {
         //            $scope = array("Listing.title","Listing.introtext","Listing.fulltext","Review.comments","Review.title");
         $scope = array("Listing.title", "Listing.introtext", "Listing.fulltext", "Listing.metakey");
         $words = array_unique(explode(' ', $keywords));
         // Include custom fields
         if ($simplesearch_custom_fields == 1) {
             $tbcols = $this->_db->getTableFields(array('#__jreviews_content'));
             $fields = array_keys($tbcols['#__jreviews_content']);
             $ignore = array("email", "contentid", "featured");
             // TODO: find out which fields have predefined selection values to get the searchable values instead of reference
         }
         $whereFields = array();
         foreach ($scope as $contentfield) {
             $whereContentFields = array();
             foreach ($words as $word) {
                 if (strlen($word) >= $min_word_chars && !in_array($word, $ignored_search_words)) {
                     $word = urldecode(trim($word));
                     $whereContentFields[] = " {$contentfield} LIKE " . $this->quoteLike($word);
                 }
             }
             if (!empty($whereContentFields)) {
                 $whereFields[] = " (" . implode($simplesearch_query_type == 'all' ? ') AND (' : ') OR (', $whereContentFields) . ')';
             }
         }
         if ($simplesearch_custom_fields == 1) {
             // add custom fields to where statement
             foreach ($fields as $field) {
                 $whereCustomFields = array();
                 foreach ($words as $word) {
                     $word = urldecode($word);
                     if (strlen($word) >= $min_word_chars && !in_array($word, $ignored_search_words)) {
                         if (!in_array($field, $ignore)) {
                             $whereCustomFields[] = "{$field} LIKE " . $this->quoteLike($word);
                         }
                     }
                 }
                 if (!empty($whereCustomFields) && !in_array($field, $ignore)) {
                     $whereFields[] = "\n(" . implode($simplesearch_query_type == 'all' ? ') AND (' : ') OR (', $whereCustomFields) . ')';
                 }
             }
         }
         if (!empty($whereFields)) {
             $wheres[] = "\n(" . implode(') OR (', $whereFields) . ')';
         }
     } else {
         # ADVANCED SEARCH
         // Process core content fields and reviews
         if ($keywords != '' && $scope != '') {
             $allowedContentFields = array("title", "introtext", "fulltext", "reviews", "metakey");
             $scope = explode($urlSeparator, $scope);
             $scope[] = 'metakey';
             switch ($query_type) {
                 case 'exact':
                     foreach ($scope as $contentfield) {
                         if (in_array($contentfield, $allowedContentFields)) {
                             $w = array();
                             if ($contentfield == 'reviews') {
                                 $w[] = " Review.comments LIKE " . $this->quoteLike($keywords);
                                 $w[] = " Review.title LIKE " . $this->quoteLike($keywords);
                             } else {
                                 $w[] = " Listing.{$contentfield} LIKE " . $this->quoteLike($keywords);
                             }
                             $whereContentOptions[] = "\n" . implode(' OR ', $w);
                         }
                     }
                     $wheres[] = implode(' OR ', $whereContentOptions);
                     break;
                 case 'any':
                 case 'all':
                 default:
                     $words = array_unique(explode(' ', $keywords));
                     $whereFields = array();
                     foreach ($scope as $contentfield) {
                         if (in_array($contentfield, $allowedContentFields)) {
                             $whereContentFields = array();
                             $whereReviewComment = array();
                             $whereReviewTitle = array();
                             foreach ($words as $word) {
                                 if (strlen($word) >= $min_word_chars && !in_array($word, $ignored_search_words)) {
                                     if ($contentfield == 'reviews') {
                                         $whereReviewComment[] = "Review.comments LIKE " . $this->quoteLike($word);
                                         $whereReviewTitle[] = "Review.title LIKE " . $this->quoteLike($word);
                                     } else {
                                         $whereContentFields[] = "Listing.{$contentfield} LIKE " . $this->quoteLike($word);
                                     }
                                 }
                             }
                             if ($contentfield == 'reviews') {
                                 $whereFields[] = "\n(" . implode($query_type == 'all' ? ') AND (' : ') OR (', $whereReviewTitle) . ")";
                                 $whereFields[] = "\n(" . implode($query_type == 'all' ? ') AND (' : ') OR (', $whereReviewComment) . ")";
                             } else {
                                 $whereFields[] = "\n(" . implode($query_type == 'all' ? ') AND (' : ') OR (', $whereContentFields) . ")";
                             }
                         }
                     }
                     $wheres[] = '(' . implode(') OR (', $whereFields) . ')';
                     break;
             }
         } else {
             $scope = array();
         }
         // Process author field
         if ($author && $this->Config->search_item_author) {
             $wheres[] = "( User.name LIKE " . $this->quoteLike($author) . " OR " . "\n User.username LIKE " . $this->quoteLike($author) . " OR " . "\n Listing.created_by_alias LIKE " . $this->quoteLike($author) . " )";
         }
         // Process custom fields
         $query_string = Sanitize::getString($this->passedArgs, 'url');
         if ($tag = Sanitize::getVar($this->params, 'tag')) {
             $this->click2search = true;
             // Field value underscore fix: remove extra menu parameter not removed in routes regex
             $tag['value'] = preg_replace(array('/_m[0-9]+$/', '/_m$/', '/_$/'), '', $tag['value']);
             // Below is included fix for dash to colon change in J1.5
             $query_string = 'jr_' . $tag['field'] . _PARAM_CHAR . str_replace(':', '-', $tag['value']) . '/' . $query_string;
         }
         $url_array = explode("/", $query_string);
         // Include external parameters for custom fields - this is required for components such as sh404sef
         foreach ($this->params as $varName => $varValue) {
             if (substr($varName, 0, 3) == "jr_" && false === array_search($varName . _PARAM_CHAR . $varValue, $url_array)) {
                 $url_array[] = $varName . _PARAM_CHAR . $varValue;
             }
         }
         // Get names of custom fields to eliminate queries on non-existent fields
         $customFieldsMeta = $this->_db->getTableFields(array('#__jreviews_content'));
         $customFields = is_array($customFieldsMeta['#__jreviews_content']) ? array_keys($customFieldsMeta['#__jreviews_content']) : array();
         /****************************************************************************
          * First pass of url params to get all field names and then find their types
          ****************************************************************************/
         $fieldNameArray = array();
         foreach ($url_array as $url_param) {
             $param = explode(":", $url_param);
             $key = $param[0];
             $value = Sanitize::getVar($param, '1', null);
             // '1' is the key where the value is stored in $param
             if (substr($key, 0, 3) == "jr_" && in_array($key, $customFields) && !is_null($value) && $value != '') {
                 $fieldNameArray[$key] = $value;
             }
         }
         // Find out the field type to determine whether it's an AND or OR search
         if (!empty($fieldNameArray)) {
             $query = '
                 SELECT 
                     name, type 
                 FROM 
                     #__jreviews_fields 
                 WHERE 
                     name IN (' . $this->quote(array_keys($fieldNameArray)) . ')';
             $this->_db->setQuery($query);
             $fieldTypesArray = $this->_db->loadAssocList('name');
         }
         $OR_fields = array("select", "radiobuttons");
         // Single option
         $AND_fields = array("selectmultiple", "checkboxes");
         // Multiple option
         foreach ($fieldNameArray as $key => $value) {
             $searchValues = explode($urlSeparator, $value);
             $fieldType = $fieldTypesArray[$key]['type'];
             // Process values with separator for multiple values or operators. The default separator is an underscore
             if (substr_count($value, $urlSeparator)) {
                 // Check if it is a numeric or date value
                 $allowedOperators = array("equal" => '=', "higher" => '>=', "lower" => '<=', "between" => 'between');
                 $operator = $searchValues[0];
                 $isDate = false;
                 if ($searchValues[1] == "date") {
                     $isDate = true;
                 }
                 if (in_array($operator, array_keys($allowedOperators)) && (is_numeric($searchValues[1]) || $isDate)) {
                     if ($operator == "between") {
                         if ($isDate) {
                             @($searchValues[1] = low($searchValues[2]) == 'today' ? _TODAY : $searchValues[2]);
                             @($searchValues[2] = low($searchValues[3]) == 'today' ? _TODAY : $searchValues[3]);
                         }
                         $low = is_numeric($searchValues[1]) ? $searchValues[1] : $this->quote($searchValues[1]);
                         $high = is_numeric($searchValues[2]) ? $searchValues[2] : $this->quote($searchValues[2]);
                         $wheres[] = "\n" . $key . " BETWEEN " . $low . ' AND ' . $high;
                     } else {
                         if ($searchValues[1] == "date") {
                             $searchValues[1] = low($searchValues[2]) == 'today' ? _TODAY : $searchValues[2];
                         }
                         $value = is_numeric($searchValues[1]) ? $searchValues[1] : $this->quote($searchValues[1]);
                         $wheres[] = "\n" . $key . $allowedOperators[$operator] . $value;
                     }
                 } else {
                     // This is a field with pre-defined options
                     $whereFields = array();
                     if (isset($tag) && ($key = 'jr_' . $tag['field'])) {
                         // Field value underscore fix
                         if (in_array($fieldType, $OR_fields)) {
                             $whereFields[] = " {$key} = '*" . $this->quote('*' . urldecode($value) . '*');
                         } else {
                             $whereFields[] = " {$key} LIKE " . $this->quote('%*' . urldecode($value) . '*%');
                         }
                     } elseif (!empty($searchValues)) {
                         foreach ($searchValues as $value) {
                             $searchValue = urldecode($value);
                             if (in_array($fieldType, $OR_fields)) {
                                 $whereFields[] = " {$key} = " . $this->quote('*' . $value . '*');
                             } else {
                                 $whereFields[] = " {$key} LIKE " . $this->quote('%*' . $value . '*%');
                             }
                         }
                     }
                     if (in_array($fieldType, $OR_fields)) {
                         // Single option field
                         $wheres[] = '(' . implode(') OR (', $whereFields) . ')';
                     } else {
                         // Multiple option field
                         $wheres[] = '(' . implode(') AND (', $whereFields) . ')';
                     }
                 }
             } else {
                 $value = urldecode($value);
                 $whereFields = array();
                 if (in_array($fieldType, $OR_fields)) {
                     $whereFields[] = " {$key} = " . $this->quote('*' . $value . '*');
                 } elseif (in_array($fieldType, $AND_fields)) {
                     $whereFields[] = " {$key} LIKE " . $this->quote('%*' . $value . '*%');
                 } elseif (in_array($fieldType, array('integer', 'decimal'))) {
                     // Does an exact search for numeric fields
                     $words = explode(' ', trim($value));
                     foreach ($words as $word) {
                         $whereFields[] = "{$key} = " . $this->quote($word);
                     }
                 } else {
                     $whereFields[] = " {$key} LIKE " . $this->quoteLike($value);
                 }
                 $wheres[] = " (" . implode(') AND (', $whereFields) . ")";
             }
         }
         // endforeach
     }
     $where = !empty($wheres) ? "\n (" . implode(") AND (", $wheres) . ")" : '';
     // Determine which categories to include in the queries
     if ($cat_id = Sanitize::getString($this->params, 'cat')) {
         $section_ids = array();
         $category_ids = explode($urlSeparator, $this->params['cat']);
         // Remove empty or nonpositive values from array
         if (!empty($category_ids)) {
             foreach ($category_ids as $index => $value) {
                 // Check if it's a section
                 if ($value[0] == 's' && is_numeric(substr($value, 1)) && substr($value, 1) > 0) {
                     $section_ids[] = substr($value, 1);
                     unset($category_ids[$index]);
                     // It's a section, not a category
                 } elseif (empty($value) || $value < 1 || !is_numeric($value)) {
                     unset($category_ids[$index]);
                 }
             }
         }
         $section_ids = implode(',', $section_ids);
         $category_ids = is_array($category_ids) ? implode(',', $category_ids) : $category_ids;
         $category_ids != '' and $this->params['cat'] = $category_ids;
         $section_ids != '' and $this->params['section'] = $section_ids;
     } elseif (isset($criteria_ids) && trim($criteria_ids) != '') {
         $criteria_ids = str_replace($urlSeparator, ',', $criteria_ids);
         $criteria_ids != '' and $this->params['criteria'] = $criteria_ids;
     } elseif (isset($dir_id) && trim($dir_id) != '') {
         $dir_id = str_replace($urlSeparator, ',', $dir_id);
         $dir_id != '' and $this->params['dir'] = $dir_id;
     }
     # Add search conditions to Listing model
     if ($where != '') {
         $this->Listing->conditions[] = $where;
     } elseif (empty($this->Listing->conditions) && $dir_id == '' && $category_ids == '' && $criteria_ids == '' && ($this->cmsVersion == CMS_JOOMLA15 && $section_ids == '' || $this->cmsVersion != CMS_JOOMLA15) && !Sanitize::getBool($this->Config, 'search_return_all', false)) {
         return $this->render('listings', 'listings_noresults');
     }
     return $this->listings();
 }