/**
  * Returns HTML search form input widget for bundle specified by standard "get" bundle code (eg. <table_name>.<bundle_name> format)
  * This method handles generation of search form widgets for (1) related tables (eg. ca_places),  preferred and non-preferred labels for both the 
  * primary and related tables, and all other types of elements for related tables. If this method can't handle the bundle it will pass the request to the 
  * superclass implementation of htmlFormElementForSearch()
  *
  * @param $po_request HTTPRequest
  * @param $ps_field string
  * @param $pa_options array
  * @return string HTML text of form element. Will return null (from superclass) if it is not possible to generate an HTML form widget for the bundle.
  * 
  */
 public function htmlFormElementForSearch($po_request, $ps_field, $pa_options = null)
 {
     $vb_as_array_element = (bool) caGetOption('asArrayElement', $pa_options, false);
     $va_tmp = explode('.', $ps_field);
     switch ($va_tmp[0]) {
         case '_fulltext':
             if (!isset($pa_options['width'])) {
                 $pa_options['width'] = 30;
             }
             if (!isset($pa_options['height'])) {
                 $pa_options['height'] = 30;
             }
             if (!isset($pa_options['values'])) {
                 $pa_options['values'] = array();
             }
             if (!isset($pa_options['values']['_fulltext'])) {
                 $pa_options['values'][$ps_field] = '';
             }
             return caHTMLTextInput("_fulltext" . ($vb_as_array_element ? "[]" : ""), array('value' => $pa_options['values']['_fulltext'], 'size' => $pa_options['width'], 'class' => $pa_options['class']), $pa_options);
             break;
         case '_fieldlist':
             if (!isset($pa_options['width'])) {
                 $pa_options['width'] = 30;
             }
             if (!isset($pa_options['height'])) {
                 $pa_options['height'] = 30;
             }
             if (!isset($pa_options['values'])) {
                 $pa_options['values'] = array();
             }
             $va_filter = $va_alt_names = $va_relationship_restricted_searches = null;
             if (is_array($va_fields = preg_split("![;,]+!", caGetOption('fields', $pa_options, null))) && sizeof($va_fields)) {
                 $va_filter = $va_alt_names = $va_relationship_restricted_searches = array();
                 foreach ($va_fields as $vs_field_raw) {
                     $va_tmp = explode(':', $vs_field_raw);
                     $va_tmp2 = explode('/', $va_tmp[0]);
                     // If there's a "/" separator then this is a relationship type-restricted search (Eg. ca_entities.preferred_labels.displayname/artist:"Isamu Noguchi")
                     if (sizeof($va_tmp2) > 1) {
                         $va_relationship_restricted_searches[$va_tmp2[0]][] = $va_tmp[0];
                     } else {
                         $va_filter[] = $va_tmp2[0];
                     }
                     if (isset($va_tmp[1]) && $va_tmp[1]) {
                         $va_alt_names[$va_tmp[0]] = $va_tmp[1];
                     }
                 }
             }
             $va_options = caGetBundlesAvailableForSearch($this->tableName(), array('forSelect' => true, 'filter' => $va_filter));
             // We need to add any relationship-restricted searh qualifiers here since they're not free-standing bundles but
             // rather variants on an unqualified relationship bundle
             foreach ($va_relationship_restricted_searches as $vs_without_rel_restriction => $va_with_rel_restrictions) {
                 foreach ($va_with_rel_restrictions as $vs_with_rel_restriction) {
                     $vs_label = isset($va_alt_names[$vs_with_rel_restriction]) ? $va_alt_names[$vs_with_rel_restriction] : $vs_with_rel_restriction;
                     $va_options[$vs_label] = $vs_with_rel_restriction;
                 }
             }
             if (is_array($va_alt_names)) {
                 foreach ($va_options as $vs_l => $vs_fld) {
                     if (isset($va_alt_names[$vs_fld])) {
                         unset($va_options[$vs_l]);
                         $va_options[$va_alt_names[$vs_fld]] = $vs_fld;
                     }
                 }
             }
             if (is_array($va_filter) && sizeof($va_filter)) {
                 // reorder options to keep field list order (sigh)
                 $va_options_tmp = array();
                 foreach ($va_filter as $vs_filter) {
                     if (($vs_k = array_search($vs_filter, $va_options)) !== false) {
                         $va_options_tmp[$vs_k] = $va_options[$vs_k];
                     }
                 }
                 $va_options = $va_options_tmp;
             }
             return caHTMLSelect("_fieldlist_field" . ($vb_as_array_element ? "[]" : ""), $va_options, array('size' => $pa_options['fieldListWidth'], 'class' => $pa_options['class']), array_merge($pa_options, array('value' => $pa_options['values']['_fieldlist_field'][0]))) . caHTMLTextInput("_fieldlist_value" . ($vb_as_array_element ? "[]" : ""), array('value' => $pa_options['values']['_fieldlist_value'], 'size' => $pa_options['width'], 'class' => $pa_options['class']), $pa_options);
             break;
     }
     if (!in_array($va_tmp[0], array('created', 'modified'))) {
         switch (sizeof($va_tmp)) {
             # -------------------------------------
             case 1:
                 // table_name
                 if ($va_tmp[0] != $this->tableName()) {
                     if (!is_array($pa_options)) {
                         $pa_options = array();
                     }
                     if (!isset($pa_options['width'])) {
                         $pa_options['width'] = 30;
                     }
                     if (!isset($pa_options['values'])) {
                         $pa_options['values'] = array();
                     }
                     if (!isset($pa_options['values'][$ps_field])) {
                         $pa_options['values'][$ps_field] = '';
                     }
                     return caHTMLTextInput($ps_field . ($vb_as_array_element ? "[]" : ""), array('value' => $pa_options['values'][$ps_field], 'size' => $pa_options['width'], 'class' => $pa_options['class'], 'id' => str_replace('.', '_', $ps_field)));
                 }
                 break;
                 # -------------------------------------
             # -------------------------------------
             case 2:
                 // table_name.field_name
             // table_name.field_name
             case 3:
                 // table_name.field_name.sub_element
                 if (!($t_instance = $this->_DATAMODEL->getInstanceByTableName($va_tmp[0], true))) {
                     return null;
                 }
                 switch ($va_tmp[1]) {
                     # --------------------
                     case 'preferred_labels':
                     case 'nonpreferred_labels':
                         return caHTMLTextInput($ps_field . ($vb_as_array_element ? "[]" : ""), array('value' => $pa_options['values'][$ps_field], 'size' => $pa_options['width'], 'class' => $pa_options['class'], 'id' => str_replace('.', '_', $ps_field)));
                         break;
                         # --------------------
                     # --------------------
                     default:
                         if ($va_tmp[0] != $this->tableName()) {
                             switch (sizeof($va_tmp)) {
                                 case 1:
                                     return caHTMLTextInput($ps_field . ($vb_as_array_element ? "[]" : ""), array('value' => $pa_options['values'][$ps_field], 'size' => $pa_options['width'], 'class' => $pa_options['class'], 'id' => str_replace('.', '_', $ps_field)));
                                 case 2:
                                 case 3:
                                     if (caGetOption('select', $pa_options, false)) {
                                         $va_access = caGetOption('checkAccess', $pa_options, null);
                                         if (!($t_instance = $this->_DATAMODEL->getInstanceByTableName($va_tmp[0], true))) {
                                             return null;
                                         }
                                         $vs_label_display_field = $t_instance->getLabelDisplayField();
                                         $qr_res = call_user_func_array($va_tmp[0] . '::find', array(array('deleted' => 0, 'parent_id' => null), array('sort' => caGetOption('sort', $pa_options, $t_instance->getLabelTableName() . '.' . $vs_label_display_field), 'returnAs' => 'searchResult')));
                                         $vs_pk = $t_instance->primaryKey();
                                         $va_opts = array('-' => '');
                                         while ($qr_res->nextHit()) {
                                             if (is_array($va_access) && !in_array($qr_res->get($va_tmp[0] . '.access'), $va_access)) {
                                                 continue;
                                             }
                                             $va_opts[$qr_res->get($va_tmp[0] . ".preferred_labels.{$vs_label_display_field}")] = $qr_res->get($ps_field);
                                         }
                                         return caHTMLSelect($ps_field . ($vb_as_array_element ? "[]" : ""), $va_opts, array('value' => $pa_options['values'][$ps_field], 'class' => $pa_options['class'], 'id' => str_replace('.', '_', $ps_field)));
                                     } else {
                                         return $t_instance->htmlFormElementForSearch($po_request, $ps_field, $pa_options);
                                     }
                                     break;
                             }
                         }
                         break;
                         # --------------------
                 }
                 break;
                 # -------------------------------------
         }
     }
     return parent::htmlFormElementForSearch($po_request, $ps_field, $pa_options);
 }
 /**
  * Returns HTML search form input widget for bundle specified by standard "get" bundle code (eg. <table_name>.<bundle_name> format)
  * This method handles generation of search form widgets for (1) related tables (eg. ca_places),  preferred and non-preferred labels for both the 
  * primary and related tables, and all other types of elements for related tables. If this method can't handle the bundle it will pass the request to the 
  * superclass implementation of htmlFormElementForSearch()
  *
  * @param $po_request HTTPRequest
  * @param $ps_field string
  * @param $pa_options array
  * @return string HTML text of form element. Will return null (from superclass) if it is not possible to generate an HTML form widget for the bundle.
  * 
  */
 public function htmlFormElementForSearch($po_request, $ps_field, $pa_options = null)
 {
     $vb_as_array_element = (bool) caGetOption('asArrayElement', $pa_options, false);
     $va_tmp = explode('.', $ps_field);
     switch ($va_tmp[0]) {
         case '_fulltext':
             if (!isset($pa_options['width'])) {
                 $pa_options['width'] = 30;
             }
             if (!isset($pa_options['height'])) {
                 $pa_options['height'] = 30;
             }
             if (!isset($pa_options['values'])) {
                 $pa_options['values'] = array();
             }
             if (!isset($pa_options['values']['_fulltext'])) {
                 $pa_options['values'][$ps_field] = '';
             }
             return caHTMLTextInput("_fulltext" . ($vb_as_array_element ? "[]" : ""), array('value' => $pa_options['values']['_fulltext'], 'size' => $pa_options['width'], 'class' => $pa_options['class']), $pa_options);
             break;
         case '_fieldlist':
             if (!isset($pa_options['width'])) {
                 $pa_options['width'] = 30;
             }
             if (!isset($pa_options['height'])) {
                 $pa_options['height'] = 30;
             }
             if (!isset($pa_options['values'])) {
                 $pa_options['values'] = array();
             }
             $va_filter = $va_alt_names = $va_relationship_restricted_searches = null;
             if (is_array($va_fields = preg_split("![;,]+!", caGetOption('fields', $pa_options, null))) && sizeof($va_fields)) {
                 $va_filter = $va_alt_names = $va_relationship_restricted_searches = array();
                 foreach ($va_fields as $vs_field_raw) {
                     $va_tmp = explode(':', $vs_field_raw);
                     $va_tmp2 = explode('/', $va_tmp[0]);
                     // If there's a "/" separator then this is a relationship type-restricted search (Eg. ca_entities.preferred_labels.displayname/artist:"Isamu Noguchi")
                     if (sizeof($va_tmp2) > 1) {
                         $va_relationship_restricted_searches[$va_tmp2[0]][] = $va_tmp[0];
                     } else {
                         $va_filter[] = $va_tmp2[0];
                     }
                     if (isset($va_tmp[1]) && $va_tmp[1]) {
                         $va_alt_names[$va_tmp[0]] = $va_tmp[1];
                     }
                 }
             }
             $va_options = caGetBundlesAvailableForSearch($this->tableName(), array('forSelect' => true, 'filter' => $va_filter));
             // We need to add any relationship-restricted searh qualifiers here since they're not free-standing bundles but
             // rather variants on an unqualified relationship bundle
             foreach ($va_relationship_restricted_searches as $vs_without_rel_restriction => $va_with_rel_restrictions) {
                 foreach ($va_with_rel_restrictions as $vs_with_rel_restriction) {
                     $vs_label = isset($va_alt_names[$vs_with_rel_restriction]) ? $va_alt_names[$vs_with_rel_restriction] : $vs_with_rel_restriction;
                     $va_options[$vs_label] = $vs_with_rel_restriction;
                 }
             }
             if (is_array($va_alt_names)) {
                 foreach ($va_options as $vs_l => $vs_fld) {
                     if (isset($va_alt_names[$vs_fld])) {
                         unset($va_options[$vs_l]);
                         $va_options[$va_alt_names[$vs_fld]] = $vs_fld;
                     }
                 }
             }
             if (is_array($va_filter) && sizeof($va_filter)) {
                 // reorder options to keep field list order (sigh)
                 $va_options_tmp = array();
                 foreach ($va_filter as $vs_filter) {
                     if (($vs_k = array_search($vs_filter, $va_options)) !== false) {
                         $va_options_tmp[$vs_k] = $va_options[$vs_k];
                     }
                 }
                 $va_options = $va_options_tmp;
             }
             return caHTMLSelect("_fieldlist_field" . ($vb_as_array_element ? "[]" : ""), $va_options, array('size' => $pa_options['fieldListWidth'], 'class' => $pa_options['class']), array_merge($pa_options, array('value' => $pa_options['values']['_fieldlist_field'][0]))) . caHTMLTextInput("_fieldlist_value" . ($vb_as_array_element ? "[]" : ""), array('value' => $pa_options['values']['_fieldlist_value'], 'size' => $pa_options['width'], 'class' => $pa_options['class']), $pa_options);
             break;
     }
     if ($vs_rel_types = join(";", caGetOption('restrictToRelationshipTypes', $pa_options, array()))) {
         $vs_rel_types = "/{$vs_rel_types}";
     }
     if (!in_array($va_tmp[0], array('created', 'modified'))) {
         switch (sizeof($va_tmp)) {
             # -------------------------------------
             case 1:
                 // table_name
                 if ($va_tmp[0] != $this->tableName()) {
                     if (!is_array($pa_options)) {
                         $pa_options = array();
                     }
                     if (!isset($pa_options['width'])) {
                         $pa_options['width'] = 30;
                     }
                     if (!isset($pa_options['values'])) {
                         $pa_options['values'] = array();
                     }
                     if (!isset($pa_options['values'][$ps_field])) {
                         $pa_options['values'][$ps_field] = '';
                     }
                     return caHTMLTextInput($ps_field . $vs_rel_types . ($vb_as_array_element ? "[]" : ""), array('value' => $pa_options['values'][$ps_field], 'size' => $pa_options['width'], 'class' => $pa_options['class'], 'id' => str_replace('.', '_', $ps_field)));
                 }
                 break;
                 # -------------------------------------
             # -------------------------------------
             case 2:
                 // table_name.field_name
             // table_name.field_name
             case 3:
                 // table_name.field_name.sub_element
                 if (!($t_instance = $this->_DATAMODEL->getInstanceByTableName($va_tmp[0], true))) {
                     return null;
                 }
                 if ($va_tmp[0] != $this->tableName()) {
                     switch (sizeof($va_tmp)) {
                         case 1:
                             return caHTMLTextInput($ps_field . ($vb_as_array_element ? "[]" : ""), array('value' => $pa_options['values'][$ps_field], 'size' => $pa_options['width'], 'class' => $pa_options['class'], 'id' => str_replace('.', '_', $ps_field)));
                         case 2:
                         case 3:
                             if ($ps_render = caGetOption('render', $pa_options, null)) {
                                 switch ($ps_render) {
                                     case 'is_set':
                                         return caHTMLCheckboxInput($ps_field . $vs_rel_types, array('value' => '[SET]'));
                                         break;
                                 }
                             }
                             if (caGetOption('select', $pa_options, false)) {
                                 $va_access = caGetOption('checkAccess', $pa_options, null);
                                 if (!($t_instance = $this->_DATAMODEL->getInstanceByTableName($va_tmp[0], true))) {
                                     return null;
                                 }
                                 $vs_label_display_field = $t_instance->getLabelDisplayField();
                                 $va_find_params = array('parent_id' => null);
                                 switch ($va_tmp[0]) {
                                     case 'ca_list_items':
                                         if ($vs_list = caGetOption('list', $pa_options, null)) {
                                             if ($vn_list_id = caGetListID($vs_list)) {
                                                 $va_find_params = array('list_id' => $vn_list_id);
                                             }
                                         }
                                         break;
                                 }
                                 $qr_res = call_user_func_array($va_tmp[0] . '::find', array($va_find_params, array('sort' => caGetOption('sort', $pa_options, $t_instance->getLabelTableName() . '.' . $vs_label_display_field), 'returnAs' => 'searchResult')));
                                 $vs_pk = $t_instance->primaryKey();
                                 $va_opts = array('-' => '');
                                 $va_in_use_list = $vs_rel_pk = null;
                                 if (caGetOption('inUse', $pa_options, false)) {
                                     if (is_array($va_path = $this->_DATAMODEL->getPath($this->tableName(), $va_tmp[0]))) {
                                         $va_path = array_keys($va_path);
                                         if (sizeof($va_path) == 3) {
                                             if ($t_rel = $this->_DATAMODEL->getInstanceByTableName($va_tmp[0], true)) {
                                                 $vs_table = $this->tableName();
                                                 $vs_pk = $this->primaryKey();
                                                 $va_sql_wheres = array();
                                                 $va_sql_params = array();
                                                 if ($this->hasField('deleted')) {
                                                     $va_sql_wheres[] = "(t.deleted = 0)";
                                                 }
                                                 if ($this->hasField('access') && is_array($va_access) && sizeof($va_access)) {
                                                     $va_sql_wheres[] = "(t.access IN (?))";
                                                     $va_sql_params[] = $va_access;
                                                 }
                                                 $vs_rel_pk = $t_rel->primaryKey();
                                                 $qr_in_use = $this->getDb()->query("\n\t\t\t\t\t\t\t\t\t\t\t\t\t\tSELECT DISTINCT l.{$vs_rel_pk}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\tFROM {$va_path[1]} l\n\t\t\t\t\t\t\t\t\t\t\t\t\t\tINNER JOIN {$vs_table} AS t ON t.{$vs_pk} = l.{$vs_pk}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t" . (sizeof($va_sql_wheres) > 0 ? "WHERE " . join(" AND ", $va_sql_wheres) : "") . "\t\t\n\t\t\t\t\t\t\t\t\t\t\t\t\t", $va_sql_params);
                                                 $va_in_use_list = $qr_in_use->getAllFieldValues($vs_rel_pk);
                                             }
                                         }
                                     }
                                 }
                                 while ($qr_res->nextHit()) {
                                     if ($va_tmp[0] == 'ca_list_items' && !$qr_res->get('parent_id')) {
                                         continue;
                                     }
                                     if (is_array($va_access) && sizeof($va_access) && !in_array($qr_res->get($va_tmp[0] . '.access'), $va_access)) {
                                         continue;
                                     }
                                     if (is_array($va_in_use_list) && !in_array($vn_item_id = $qr_res->get($vs_rel_pk), $va_in_use_list)) {
                                         continue;
                                     }
                                     $va_opts[$qr_res->get($va_tmp[0] . ".preferred_labels.{$vs_label_display_field}")] = $qr_res->get($ps_field);
                                 }
                                 uksort($va_opts, "strnatcasecmp");
                                 return caHTMLSelect($ps_field . $vs_rel_types . ($vb_as_array_element ? "[]" : ""), $va_opts, array('value' => $pa_options['values'][$ps_field], 'class' => $pa_options['class'], 'id' => str_replace('.', '_', $ps_field)));
                             } else {
                                 return $t_instance->htmlFormElementForSearch($po_request, $ps_field, $pa_options);
                             }
                             break;
                     }
                 }
                 break;
                 # -------------------------------------
         }
     }
     return parent::htmlFormElementForSearch($po_request, $ps_field, $pa_options);
 }