public function get_filtered_listing($opts, $where_callback = null, $pre_template_callback = null)
 {
     /*
                 Are we using an index table? If so, filter differently.
     */
     if ($this->index_table !== false) {
         return $this->get_filtered_listing_from_index($opts, $where_callback, $pre_template_callback);
     }
     /*
        Otherwise, as you were.
     */
     $items = array();
     $Item = false;
     $single_mode = false;
     $where = array();
     $order = array();
     $limit = '';
     // find specific _id
     if (isset($opts['_id'])) {
         $single_mode = true;
         $Item = $this->find($opts['_id']);
     } else {
         // if not picking an _id, check for a filter
         if (isset($opts['filter']) && (isset($opts['value']) || is_array($opts['filter']))) {
             // if it's not a multi-filter, make it look like one to unify what we're working with
             if (!is_array($opts['filter']) && isset($opts['value'])) {
                 $filters = array(array('filter' => $opts['filter'], 'value' => $opts['value'], 'match' => isset($opts['match']) ? $opts['match'] : 'eq', 'match-type' => isset($opts['match-type']) ? $opts['match-type'] : 'alpha'));
                 $filter_mode = 'AND';
             } else {
                 $filters = $opts['filter'];
                 $filter_mode = 'AND';
                 if (isset($opts['match']) && strtolower($opts['match']) == 'or') {
                     $filter_mode = 'OR';
                 }
             }
             foreach ($filters as $filter) {
                 $key = $filter['filter'];
                 $val = $filter['value'];
                 $raw_value = $filter['value'];
                 if (is_numeric($val)) {
                     $val = (double) $val;
                 }
                 $value = $this->db->pdb($val);
                 $match = isset($filter['match']) ? $filter['match'] : 'eq';
                 switch ($match) {
                     case 'eq':
                     case 'is':
                     case 'exact':
                         $where[] = $key . '=' . $value;
                         break;
                     case 'neq':
                     case 'ne':
                     case 'not':
                     case '!eq':
                         $where[] = $key . '!=' . $value;
                         break;
                     case 'gt':
                         $where[] = $key . '>' . $value;
                         break;
                     case '!gt':
                         $where[] = $key . '!>' . $value;
                         break;
                     case 'gte':
                         $where[] = $key . '>=' . $value;
                         break;
                     case '!gte':
                         $where[] = $key . '!>=' . $value;
                         break;
                     case 'lt':
                         $where[] = $key . '<' . $value;
                         break;
                     case '!lt':
                         $where[] = $key . '!<' . $value;
                         break;
                     case 'lte':
                         $where[] = $key . '<=' . $value;
                         break;
                     case '!lte':
                         $where[] = $key . '!<=' . $value;
                         break;
                     case 'contains':
                         $v = str_replace('/', '\\/', $raw_value);
                         $where[] = $key . " REGEXP '[[:<:]]" . $v . "[[:>:]]'";
                         break;
                     case '!contains':
                         $v = str_replace('/', '\\/', $raw_value);
                         $where[] = $key . " NOT REGEXP '[[:<:]]" . $v . "[[:>:]]'";
                         break;
                     case 'regex':
                     case 'regexp':
                         $v = str_replace('/', '\\/', $raw_value);
                         $where[] = $key . " REGEXP '" . $v . "'";
                         break;
                     case 'between':
                     case 'betwixt':
                         $vals = explode(',', $raw_value);
                         if (PerchUtil::count($vals) == 2) {
                             $where[] = '(' . $key . '>' . trim($this->db->pdb($vals[0])) . ' AND ' . $key . '<' . trim($this->db->pdb($vals[1])) . ')';
                         }
                         break;
                     case '!between':
                     case '!betwixt':
                         $vals = explode(',', $raw_value);
                         if (PerchUtil::count($vals) == 2) {
                             $where[] = '(' . $key . '!>' . trim($this->db->pdb($vals[0])) . ' AND ' . $key . '!<' . trim($this->db->pdb($vals[1])) . ')';
                         }
                         break;
                     case 'eqbetween':
                     case 'eqbetwixt':
                         $vals = explode(',', $raw_value);
                         if (PerchUtil::count($vals) == 2) {
                             $where[] = '(' . $key . '>=' . trim($this->db->pdb($vals[0])) . ' AND ' . $key . '<=' . trim($this->db->pdb($vals[1])) . ')';
                         }
                         break;
                     case '!eqbetween':
                     case '!eqbetwixt':
                         $vals = explode(',', $raw_value);
                         if (PerchUtil::count($vals) == 2) {
                             $where[] = '(' . $key . '!>=' . trim($this->db->pdb($vals[0])) . ' AND ' . $key . '!<=' . trim($this->db->pdb($vals[1])) . ')';
                         }
                         break;
                     case 'in':
                     case 'within':
                         $vals = explode(',', $raw_value);
                         $tmp = array();
                         if (PerchUtil::count($vals)) {
                             $where[] = $key . ' IN (' . $this->db->implode_for_sql_in($vals) . ')';
                         }
                         break;
                     case '!in':
                     case '!within':
                         $vals = explode(',', $raw_value);
                         $tmp = array();
                         if (PerchUtil::count($vals)) {
                             $where[] = $key . ' NOT IN (' . $this->db->implode_for_sql_in($vals) . ')';
                         }
                         break;
                 }
             }
             $where = array(' (' . implode($where, ' ' . $filter_mode . ' ') . ') ');
         }
     }
     // sort
     if (isset($opts['sort'])) {
         $desc = false;
         if (isset($opts['sort-order']) && $opts['sort-order'] == 'DESC') {
             $desc = true;
         } else {
             $desc = false;
         }
         $order[] = $opts['sort'] . ' ' . ($desc ? 'DESC' : 'ASC');
     } else {
         $order[] = $this->default_sort_column . ' ' . $this->default_sort_direction;
     }
     if (isset($opts['sort-order']) && $opts['sort-order'] == 'RAND') {
         $order = array('RAND()');
     }
     // limit
     if (isset($opts['count'])) {
         $count = (int) $opts['count'];
         if (isset($opts['start'])) {
             $start = (int) $opts['start'] - 1 . ',';
         } else {
             $start = '';
         }
         $limit = $start . $count;
     }
     if ($single_mode) {
         $items = array($Item);
     } else {
         // Paging
         $Paging = new PerchPaging();
         if (isset($opts['pagination-var']) && $opts['pagination-var'] != '') {
             $Paging->set_qs_param($opts['pagination-var']);
         }
         if (!isset($count) || !$count || isset($opts['start']) && $opts['start'] != '') {
             $Paging->disable();
         } else {
             $Paging->set_per_page($count);
             if (isset($opts['start']) && $opts['start'] != '') {
                 $Paging->set_start_position($opts['start']);
             }
         }
         $select = $Paging->select_sql() . ' main.* ';
         $from = 'FROM ' . $this->table . ' main ';
         if (is_callable($where_callback)) {
             // load up Query object
             $Query = new PerchQuery();
             $Query->select = $select;
             $Query->from = $from;
             $Query->where = $where;
             // do callback
             $Query = $where_callback($Query);
             // retrieve
             $select = $Query->select;
             $from = $Query->from;
             $where = $Query->where;
         }
         $sql = $select . $from;
         $sql .= ' WHERE 1=1 ';
         if (count($where)) {
             $sql .= ' AND ' . implode(' AND ', $where);
         }
         if (count($order)) {
             $sql .= ' ORDER BY ' . implode(', ', $order);
         }
         if ($Paging->enabled()) {
             $sql .= ' ' . $Paging->limit_sql();
         } else {
             if ($limit != '') {
                 $sql .= ' LIMIT ' . $limit;
             }
         }
         $rows = $this->db->get_rows($sql);
         if ($Paging->enabled()) {
             $Paging->set_total($this->db->get_count($Paging->total_count_sql()));
         }
         // pre-template callback
         if (PerchUtil::count($rows) && $pre_template_callback && is_callable($pre_template_callback)) {
             $rows = $pre_template_callback($rows);
         }
         // each
         if (PerchUtil::count($rows) && isset($opts['each']) && is_callable($opts['each'])) {
             $content = array();
             foreach ($rows as $item) {
                 $tmp = $opts['each']($item);
                 $content[] = $tmp;
             }
             $rows = $content;
         }
         $items = $this->return_instances($rows);
     }
     // template
     if (is_callable($opts['template'])) {
         $callback = $opts['template'];
         $template = $callback($items);
     } else {
         $template = $opts['template'];
     }
     if (is_object($this->api)) {
         $Template = $this->api->get('Template');
         $Template->set($template, $this->namespace);
     } else {
         $Template = new PerchTemplate($template, $this->namespace);
     }
     $render_html = true;
     if (isset($opts['skip-template']) && $opts['skip-template'] == true) {
         $render_html = false;
         if (isset($opts['return-html']) && $opts['return-html'] == true) {
             $render_html = true;
         }
     }
     if ($render_html) {
         if (isset($Paging) && $Paging->enabled()) {
             $paging_array = $Paging->to_array($opts);
             // merge in paging vars
             if (PerchUtil::count($items)) {
                 foreach ($items as &$Item) {
                     foreach ($paging_array as $key => $val) {
                         $Item->squirrel($key, $val);
                     }
                 }
             }
         }
         if (PerchUtil::count($items)) {
             $html = $Template->render_group($items, true);
         } else {
             $Template->use_noresults();
             $html = $Template->render(array());
         }
     }
     if (isset($opts['skip-template']) && $opts['skip-template'] == true) {
         if ($single_mode) {
             return $Item->to_array();
         }
         $processed_vars = array();
         if (PerchUtil::count($items)) {
             foreach ($items as $Item) {
                 $processed_vars[] = $Item->to_array();
             }
         }
         $category_field_ids = $Template->find_all_tag_ids('categories');
         if (PerchUtil::count($processed_vars)) {
             foreach ($processed_vars as &$item) {
                 if (PerchUtil::count($item)) {
                     foreach ($item as $key => &$field) {
                         if (in_array($key, $category_field_ids)) {
                             $field = $this->_process_category_field($field);
                         }
                         if (is_array($field) && isset($field['processed'])) {
                             $field = $field['processed'];
                         }
                         if (is_array($field) && isset($field['_default'])) {
                             $field = $field['_default'];
                         }
                     }
                 }
             }
         }
         if (isset($opts['return-html']) && $opts['return-html'] == true) {
             $processed_vars['html'] = $html;
         }
         return $processed_vars;
     }
     if (strpos($html, '<perch:') !== false) {
         $Template = new PerchTemplate();
         $html = $Template->apply_runtime_post_processing($html);
     }
     return $html;
 }