/**
  * Method called when posting the form. Saves the subscription details to the warehouse.
  * @param $args
  * @param $auth
  * @throws \exception
  */
 private static function subscribe($args, $auth)
 {
     $url = data_entry_helper::$base_url . 'index.php/services/species_alerts/register?';
     $params = array('auth_token' => $auth['write_tokens']['auth_token'], 'nonce' => $auth['write_tokens']['nonce'], 'first_name' => $_POST['first_name'], 'surname' => $_POST['surname'], 'email' => $_POST['email'], 'website_id' => $args['website_id'], 'alert_on_entry' => $_POST['species_alert:alert_on_entry'] ? 't' : 'f', 'alert_on_verify' => $_POST['species_alert:alert_on_verify'] ? 't' : 'f');
     if (!empty($_POST['species_alert:id'])) {
         $params['id'] = $_POST['species_alert:id'];
     }
     if (!empty($_POST['species_alert:taxon_list_id'])) {
         $params['taxon_list_id'] = $_POST['species_alert:taxon_list_id'];
     }
     if (!empty($_POST['species_alert:location_id'])) {
         $params['location_id'] = $_POST['species_alert:location_id'];
     }
     if (!empty($_POST['user_id'])) {
         $params['user_id'] = $_POST['user_id'];
     }
     if (!empty($_POST['taxa_taxon_list_id'])) {
         // We've got a taxa_taxon_list_id in the post data. But, it is better to subscribe via a taxon
         // meaning ID, or even better, the external key.
         $taxon = data_entry_helper::get_population_data(array('table' => 'taxa_taxon_list', 'extraParams' => $auth['read'] + array('id' => $_POST['taxa_taxon_list_id'], 'view' => 'cache')));
         if (count($taxon) !== 1) {
             throw new exception('Unable to find unique taxon when attempting to subscribe');
         }
         $taxon = $taxon[0];
         if (!empty($taxon['external_key'])) {
             $params['external_key'] = $taxon['external_key'];
         } else {
             $params['taxon_meaning_id'] = $taxon['taxon_meaning_id'];
         }
     } elseif (!empty($_POST['species_alert:external_key'])) {
         $params['external_key'] = $_POST['species_alert:external_key'];
     } elseif (!empty($_POST['species_alert:taxon_meaning_id'])) {
         $params['taxon_meaning_id'] = $_POST['species_alert:taxon_meaning_id'];
     }
     $url .= data_entry_helper::array_to_query_string($params, true);
     $result = data_entry_helper::http_post($url);
     if ($result['result']) {
         hostsite_show_message(lang::get('Your subscription has been saved.'));
     } else {
         hostsite_show_message(lang::get('There was a problem saving your subscription.'));
         if (function_exists('watchdog')) {
             watchdog('iform', 'Species alert error on save: ' . print_r($result, true));
         }
     }
 }
 private static function get_success_page($args, $auth, $sample_id)
 {
     $reload = data_entry_helper::get_reload_link_parts();
     if (isset($reload['params']['occurrence_id'])) {
         unset($reload['params']['occurrence_id']);
     }
     if (isset($reload['params']['sample_id'])) {
         unset($reload['params']['sample_id']);
     }
     $reload['params']['new'] = "1";
     $newPath = $reload['path'] . '?' . data_entry_helper::array_to_query_string($reload['params']);
     unset($reload['params']['new']);
     $reload['params']['sample_id'] = $sample_id;
     $reloadPath = $reload['path'] . '?' . data_entry_helper::array_to_query_string($reload['params']);
     $attributes = data_entry_helper::getAttributes(array('valuetable' => 'sample_attribute_value', 'attrtable' => 'sample_attribute', 'key' => 'sample_id', 'fieldprefix' => 'smpAttr', 'extraParams' => $auth['read'] + array("untranslatedCaption" => "Shore Height"), 'survey_id' => $args['survey_id'], 'sample_method_id' => $args['transect_level_sample_method_id'], 'id' => $sample_id));
     $shore = '';
     foreach ($attributes as $attribute) {
         if ($attribute['untranslatedCaption'] == 'Shore Height') {
             $shore = ' (' . $attribute['displayValue'] . ' ' . $attribute['caption'] . ')';
         }
     }
     $r = '<h1>' . lang::get('Thank you!') . '</h1>' . '<h2>' . lang::get('Your survey data is a valuable contribution to the Capturing Our Coast programme.') . '</h2>' . '<p>' . str_replace(array('{name}', '{date}', '{shore}'), array(data_entry_helper::$entity_to_load['sample:location_name'], data_entry_helper::$entity_to_load['sample:date'], $shore), lang::get('You have completed entering your data for Transect &quot;{name}&quot; {shore} on {date}. ' . 'You can now choose to do one of several different things:')) . '</p><ul>' . '<li>' . str_replace('{newpath}', $newPath, lang::get('You can enter visit details for a new Transect by clicking <a href="{newpath}">here</a>.')) . '</li>' . '<li>' . str_replace('{reloadpath}', $reloadPath, lang::get('You can go back into the Transect you have just entered, to modify the data or upload photos, by clicking <a href="{reloadpath}">here</a>.')) . '</li>' . '<li>' . lang::get('Alternatively, you can choose one of the options in the main menu above, e.g. to explore your records.') . '</li>' . '</ul>';
     return $r;
 }
 /**
  * Return the generated form output.
  * @param array $args List of parameter values passed through to the form depending on how the form has been configured.
  * This array always contains a value for language.
  * @param object $node The Drupal node object.
  * @param array $response When this form is reloading after saving a submission, contains the response from the service call.
  * Note this does not apply when redirecting (in this case the details of the saved object are in the $_GET data).
  * @return Form HTML.
  */
 public static function get_form($args, $node, $response = null)
 {
     if (!($user_id = hostsite_get_user_field('indicia_user_id'))) {
         return self::abort('Please ensure that you\'ve filled in your surname on your user profile before leaving a group.', $args);
     }
     if (empty($_GET['group_id'])) {
         return self::abort('This form must be called with a group_id in the URL parameters.', $args);
     }
     $r = '';
     $auth = data_entry_helper::get_read_write_auth($args['website_id'], $args['password']);
     $group = data_entry_helper::get_population_data(array('table' => 'group', 'extraParams' => $auth['read'] + array('id' => $_GET['group_id']), 'nocache' => true));
     if (count($group) !== 1) {
         return self::abort('The group you\'ve requested membership of does not exist.', $args);
     }
     iform_load_helpers(array('submission_builder'));
     $group = $group[0];
     // Check for an existing group user record
     $existing = data_entry_helper::get_population_data(array('table' => 'groups_user', 'extraParams' => $auth['read'] + array('group_id' => $_GET['group_id'], 'user_id' => $user_id), 'nocache' => true));
     if (count($existing) !== 1) {
         return self::abort('You are not a member of this group.', $args);
     }
     if (!empty($_POST['response']) && $_POST['response'] === lang::get('Cancel')) {
         drupal_goto($args['groups_page_path']);
     } elseif (!empty($_POST['response']) && $_POST['response'] === lang::get('Confirm')) {
         $data = array('groups_user:id' => $existing[0]['id'], 'groups_user:group_id' => $group['id'], 'groups_user:user_id' => $user_id, 'deleted' => 't');
         $wrap = submission_builder::wrap($data, 'groups_user');
         $response = data_entry_helper::forward_post_to('groups_user', $wrap, $auth['write_tokens']);
         if (isset($response['success'])) {
             hostsite_show_message("You are no longer participating in {$group['title']}!");
             drupal_goto($args['groups_page_path']);
         } else {
             return self::abort('An error occurred whilst trying to update your group membership.');
         }
     } else {
         // First access of the form. Let's get confirmation
         $reload = data_entry_helper::get_reload_link_parts();
         $reloadpath = $reload['path'] . '?' . data_entry_helper::array_to_query_string($reload['params']);
         $r = '<form action="' . $reloadpath . '" method="POST"><fieldset>';
         $r .= '<legend>' . lang::get('Confirmation') . '</legend>';
         $r .= '<input type="hidden" name="leave" value="1" />';
         $r .= '<p>' . lang::get('Are you sure you want to stop participating in {1}?', $group['title']) . '</p>';
         $r .= '<input type="submit" value="' . lang::get('Confirm') . '" name="response" />';
         $r .= '<input type="submit" value="' . lang::get('Cancel') . '" name="response" />';
         $r .= '</fieldset></form>';
     }
     return $r;
 }
 /**
  * Save button takes us to the next transect.
  */
 public static function get_redirect_on_success($values, $args)
 {
     if (!empty($values['next-zone']) && !empty($values['next-transect'])) {
         return $args['redirect_on_success'] . '?' . data_entry_helper::array_to_query_string(array('table' => 'sample', 'id' => $values['sample:parent_id'], 'zone' => $values['next-zone'], 'transect' => $values['next-transect']));
     } else {
         return $args['front_page_path'];
     }
 }
 public static function report_picker($args, $node, $readAuth)
 {
     $r = '<ul class="categories">';
     $available = self::get_reports();
     $regionTerm = self::get_region_term($args, $readAuth);
     foreach ($available as $catName => $catDef) {
         $catDef['title'] = str_replace('#main_location_layer_type#', $regionTerm, $catDef['title']);
         $catTitleDone = false;
         foreach ($catDef['reports'] as $report => $reportDef) {
             $reportDef['title'] = str_replace('#main_location_layer_type#', $regionTerm, $reportDef['title']);
             $reportDef['description'] = str_replace('#main_location_layer_type#', $regionTerm, $reportDef['description']);
             $argName = "report_{$catName}_{$report}";
             if (!empty($args[$argName]) && $args[$argName]) {
                 if (!$catTitleDone) {
                     $r .= "<li>\n";
                     $r .= "<h2>{$catDef['title']}</h2>\n<ul class=\"reports\">";
                     $catTitleDone = true;
                 }
                 $r .= "<li><h3>{$reportDef['title']}</h3><p>{$reportDef['description']}</p>";
                 $reload = data_entry_helper::get_reload_link_parts();
                 $path = $reload['path'] . '?' . data_entry_helper::array_to_query_string($reload['params'] + array('catname' => $catName, 'report' => $report));
                 $r .= '<ul class="report-outputs">';
                 foreach ($reportDef['outputs'] as $idx => $output) {
                     $outputLabel = str_replace('_', ' ', $output);
                     $r .= "<li><a class=\"link-{$output}\" href=\"{$path}&output={$output}\"/>View {$outputLabel}</a></li>";
                 }
                 $r .= '</ul>';
                 $r .= '</li>';
             }
         }
         if ($catTitleDone) {
             $r .= '</ul></li>';
         }
     }
     $r .= '</ul>';
     return $r;
 }
 /**
  * Outputs the form for mapping columns to the import fields.
  * @param array $options Options array passed to the import control.
  */
 private static function upload_mappings_form($options)
 {
     //The Shorewatch importer only supports 4326 as this is required for the occurrence sample grid reference
     //calculations to work. This can be hardcoded.
     $_POST['sample:entered_sref_system'] = 4326;
     $_SESSION['importSettingsToCarryForward'] = $_POST;
     if (!file_exists($_SESSION['uploaded_file'])) {
         return lang::get('upload_not_available');
     }
     data_entry_helper::add_resource('jquery_ui');
     $filename = basename($_SESSION['uploaded_file']);
     // If the last step was skipped because the user did not have any settings to supply, presetSettings contains the presets.
     // Otherwise we'll use the settings form content which already in $_POST so will overwrite presetSettings.
     if (isset($options['presetSettings'])) {
         $settings = array_merge($options['presetSettings'], $_POST);
     } else {
         $settings = $_POST;
     }
     // only want defaults that actually have a value - others can be set on a per-row basis by mapping to a column
     foreach ($settings as $key => $value) {
         if (empty($value)) {
             unset($settings[$key]);
         }
     }
     //The Shorewatch importer only supports 4326 as this is required for the occurrence sample grid reference
     //calculations to work. This can be hardcoded.
     $settings['sample:entered_sref_system'] = 4326;
     // cache the mappings
     $metadata = array('settings' => json_encode($settings));
     $post = array_merge($options['auth']['write_tokens'], $metadata);
     $request = data_entry_helper::$base_url . "index.php/services/import/cache_upload_metadata?uploaded_csv={$filename}";
     $response = data_entry_helper::http_post($request, $post);
     if (!isset($response['output']) || $response['output'] != 'OK') {
         return "Could not upload the settings metadata. <br/>" . print_r($response, true);
     }
     $request = data_entry_helper::$base_url . "index.php/services/import/get_import_fields/" . $options['model'];
     $request .= '?' . data_entry_helper::array_to_query_string($options['auth']['read']);
     // include survey and website information in the request if available, as this limits the availability of custom attributes
     if (!empty($settings['website_id'])) {
         $request .= '&website_id=' . trim($settings['website_id']);
     }
     if (!empty($settings['survey_id'])) {
         $request .= '&survey_id=' . trim($settings['survey_id']);
     }
     $response = data_entry_helper::http_post($request, array());
     $fields = json_decode($response['output'], true);
     if (!is_array($fields)) {
         return "curl request to {$request} failed. Response " . print_r($response, true);
     }
     $request = str_replace('get_import_fields', 'get_required_fields', $request);
     $response = data_entry_helper::http_post($request);
     $responseIds = json_decode($response['output'], true);
     if (!is_array($responseIds)) {
         return "curl request to {$request} failed. Response " . print_r($response, true);
     }
     $model_required_fields = self::expand_ids_to_fks($responseIds);
     if (!empty($settings)) {
         $preset_fields = self::expand_ids_to_fks(array_keys($settings));
     } else {
         $preset_fields = array();
     }
     if (!empty($preset_fields)) {
         $unlinked_fields = array_diff_key($fields, array_combine($preset_fields, $preset_fields));
     } else {
         $unlinked_fields = $fields;
     }
     // only use the required fields that are available for selection - the rest are handled somehow else
     $unlinked_required_fields = array_intersect($model_required_fields, array_keys($unlinked_fields));
     ini_set('auto_detect_line_endings', 1);
     $handle = fopen($_SESSION['uploaded_file'], "r");
     $columns = fgetcsv($handle, 1000, ",");
     $reload = data_entry_helper::get_reload_link_parts();
     $reloadpath = $reload['path'] . '?' . data_entry_helper::array_to_query_string($reload['params']);
     self::clear_website_survey_fields($unlinked_fields, $settings);
     self::clear_website_survey_fields($unlinked_required_fields, $settings);
     $savedFieldMappings = array();
     // Note the Shorewatch importer doesn't currently support remembered fields, so set this to false (we are reusing a lot of the import_helper code, so leave the variable in the code as it already has proven reliability).
     self::$rememberingMappings = false;
     //  if the user checked the Remember All checkbox, save it in a variable
     if (isset($savedFieldMappings['RememberAll'])) {
         $checked['RememberAll'] = 'checked';
     }
     $r = "<form method=\"post\" id=\"entry_form\" action=\"{$reloadpath}\" class=\"iform\">\n" . '<p>' . lang::get('column_mapping_instructions') . '</p>' . '<div class="ui-helper-clearfix import-mappings-table"><table class="ui-widget ui-widget-content">' . '<thead class="ui-widget-header">' . "<tr><th>Column in CSV File</th><th>Maps to attribute</th>";
     if (self::$rememberingMappings) {
         $r .= "<th id='remember-all-header' name='remember-all-header'>" . lang::get('Remember choice?') . "<br/><input type='checkbox' name='RememberAll' id='RememberAll' value='1' title='Tick all boxes to remember every column mapping next time you import.' {$checked['RememberAll']} onclick='\n           if (this.checked) {\n             \$(\".rememberField\").attr(\"checked\",\"checked\")\n           } else {\n             \$(\".rememberField\").removeAttr(\"checked\")\n           }'/></th>";
     }
     $r .= '</tr></thead><tbody>';
     foreach ($columns as $column) {
         $colFieldName = preg_replace('/[^A-Za-z0-9]/', '_', $column);
         $r .= "<tr><td>{$column}</td><td><select name=\"{$colFieldName}\" id=\"{$colFieldName}\">";
         $r .= self::get_column_options($options['model'], $unlinked_fields, $column, ' ', $savedFieldMappings);
         $r .= "</select></td></tr>\n";
     }
     $r .= '</tbody>';
     $r .= '</table>';
     $r .= '<div id="required-instructions" class="import-mappings-instructions"><h2>' . lang::get('Tasks') . '</h2><span>' . lang::get('The following database attributes must be matched to a column in your import file before you can continue') . ':</span><ul></ul><br/></div>';
     $r .= '<div id="duplicate-instructions" class="import-mappings-instructions"><span id="duplicate-instruct">' . lang::get('There are currently two or more drop-downs allocated to the same value.') . '</span><ul></ul><br/></div></div>';
     $r .= '<input type="hidden" name="import_step" value="2" />';
     $r .= '<input type="submit" name="submit" id="submit" value="' . lang::get('Upload') . '" class="ui-corner-all ui-state-default button" />';
     $r .= '</form>';
     data_entry_helper::$javascript .= "function detect_duplicate_fields() {\n      var valueStore = [];\n      var duplicateStore = [];\n      var valueStoreIndex = 0;\n      var duplicateStoreIndex = 0;\n      \$.each(\$('#entry_form select'), function(i, select) {\n        if (valueStoreIndex==0) {\n          valueStore[valueStoreIndex] = select.value;\n          valueStoreIndex++;\n        } else {\n          for(i=0; i<valueStoreIndex; i++) {\n            if (select.value==valueStore[i] && select.value != '<" . lang::get('Not imported') . ">') {\n              duplicateStore[duplicateStoreIndex] = select.value;\n              duplicateStoreIndex++;\n            }\n             \n          }\n          valueStore[valueStoreIndex] = select.value;\n          valueStoreIndex++;\n        }      \n      })\n      if (duplicateStore.length==0) {\n        DuplicateAllowsUpload = 1;\n        \$('#duplicate-instruct').css('display', 'none');\n      } else {\n        DuplicateAllowsUpload = 0;\n        \$('#duplicate-instruct').css('display', 'inline');\n      }\n    }\n";
     data_entry_helper::$javascript .= "function update_required_fields() {\n      // copy the list of required fields\n      var fields = \$.extend(true, {}, required_fields);\n      \$('#required-instructions li').remove();\n      var sampleVagueDates = [];\n      // strip out the ones we have already allocated\n      \$.each(\$('#entry_form select'), function(i, select) {\n        delete fields[select.value];\n        // special case for vague dates - if we have a complete sample vague date, then can strike out the sample:date required field\n        if (select.value.substr(0,12)=='sample:date_') {\n          sampleVagueDates.push(select.value);\n        }\n      });\n      if (sampleVagueDates.length==3) {\n        // got a full vague date, so can remove the required date field\n        delete fields['sample:date'];\n      }\n      var output = '';\n      \$.each(fields, function(field, caption) {\n        output += '<li>'+caption+'</li>';\n      });\n      if (output==='') {\n        \$('#required-instructions').css('display', 'none');\n        RequiredAllowsUpload = 1;\n      } else {\n        \$('#required-instructions').css('display', 'inline');\n        RequiredAllowsUpload = 0;\n      }\n      if (RequiredAllowsUpload == 1 && DuplicateAllowsUpload == 1) {\n        \$('#submit').attr('disabled', false);\n      } else {\n        \$('#submit').attr('disabled', true);\n      }\n      \$('#required-instructions ul').html(output);\n    }\n";
     data_entry_helper::$javascript .= "required_fields={};\n";
     foreach ($unlinked_required_fields as $field) {
         $caption = $unlinked_fields[$field];
         if (empty($caption)) {
             $tokens = explode(':', $field);
             $fieldname = $tokens[count($tokens) - 1];
             $caption = lang::get(self::leadingCaps(preg_replace(array('/^fk_/', '/_id$/'), array('', ''), $fieldname)));
         }
         $caption = self::translate_field($field, $caption);
         data_entry_helper::$javascript .= "required_fields['{$field}']='{$caption}';\n";
     }
     data_entry_helper::$javascript .= "detect_duplicate_fields();\n";
     data_entry_helper::$javascript .= "update_required_fields();\n";
     data_entry_helper::$javascript .= "\$('#entry_form select').change(function() {detect_duplicate_fields(); update_required_fields();});\n";
     return $r;
 }
/**
 * Code to output a standardised report filtering panel.
 *
 * Filters can be saved and loaded by each user. Additionally, filters can define permissions to a certain task, e.g. they can be used to define the
 * context within which someone can verify. In this case they provide the "outer limit" of the available records.
 * Requires a [map] control on the page. If you don't want a map, the current option is to include one anyway and use css to hide the #map-container div.
 *
 * @param array $readAuth Pass read authorisation tokens.
 * @param array $options Options array with the following possibilities:
 *   sharing - define the record sharing task that is being filtered against. Options are reporting (default), peer_review, verification, moderation, data_flow.
 *   context_id - can also be passed as URL parameter. Force the initial selection of a particular context (a record which has defines_permissions=true in the
 *   filters table. Set to "default" to select their profile verification settings when sharing=verification.
 *   filter_id - can also be passed as URL parameter. Force the initial selection of a particular filter record in the filters table.
 *   filterTypes - allows control of the list of filter panels available, e.g. to turn one off. Associative array keyed by category
 *   so that the filter panels can be grouped (use a blank key if not required). The array values are an array of or strings with a comma separated list
 *   of the filter types to included in the category - options are what, where, when, who, quality, source.
 *   filter-#name# - set the initial value of a report filter parameter #name#.
 *   allowLoad - set to false to disable the load bar at the top of the panel.
 *   allowSave - set to false to disable the save bar at the foot of the panel.
 *   presets - provide an array of preset filters to provide in the filters drop down. Choose from my-records, my-groups (uses
 *     your list of taxon groups in the user account), my-locality (uses your recording locality from the user account),
 *     my-groups-locality (uses taxon groups and recording locality from the user account), my-queried-records, queried-records,
 *     answered-records, accepted-records, not-accepted-records.
 * @param integer $website_id The current website's warehouse ID.
 * @param string $hiddenStuff Output parameter which will contain the hidden popup HTML that will be shown
 * using fancybox during filter editing. Should be appended AFTER any form element on the page as nested forms are not allowed.
 * @return string HTML for the report filter panel
 */
function report_filter_panel($readAuth, $options, $website_id, &$hiddenStuff)
{
    if (function_exists('iform_load_helpers')) {
        iform_load_helpers(array('report_helper'));
    } else {
        //When running on warehouse we don't have iform_load_helpers
        require_once DOCROOT . 'client_helpers/report_helper.php';
    }
    if (!empty($_POST['filter:sharing'])) {
        $options['sharing'] = $_POST['filter:sharing'];
    }
    $options = array_merge(array('sharing' => 'reporting', 'admin' => false, 'adminCanSetSharingTo' => array('R' => 'reporting', 'V' => 'verification'), 'allowLoad' => true, 'allowSave' => true, 'redirect_on_success' => '', 'presets' => array('my-records', 'my-queried-records', 'my-queried-or-not-accepted-records', 'my-not-reviewed-records', 'my-accepted-records', 'my-groups', 'my-locality', 'my-groups-locality'), 'entity' => 'occurrence'), $options);
    // Introduce some extra quick filters useful for verifiers.
    if ($options['sharing'] === 'verification') {
        $options['presets'] = array_merge(array('queried-records', 'answered-records', 'accepted-records', 'not-accepted-records'), $options['presets']);
    }
    if ($options['entity'] === 'sample') {
        unset($options['presets']['my-groups']);
        unset($options['presets']['my-groups-locality']);
    }
    //If in the warehouse we don't need to worry about the iform master list.
    if (function_exists('variable_get')) {
        $options = array_merge(array('taxon_list_id' => variable_get('iform_master_checklist_id', 0)), $options);
    }
    $options['sharing'] = report_filters_sharing_code_to_full_term($options['sharing']);
    $options['sharingCode'] = report_filters_full_term_to_sharing_code($options['sharing']);
    if (!preg_match('/^(reporting|peer_review|verification|data_flow|moderation)$/', $options['sharing'])) {
        return 'The @sharing option must be one of reporting, peer_review, verification, data_flow or moderation (currently ' . $options['sharing'] . ').';
    }
    report_helper::add_resource('reportfilters');
    report_helper::add_resource('validation');
    report_helper::add_resource('fancybox');
    if (function_exists('hostsite_add_library')) {
        hostsite_add_library('collapse');
    }
    $filterData = report_filters_load_existing($readAuth, $options['sharingCode']);
    $existing = '';
    $contexts = '';
    // add some preset filters in
    //If in the warehouse we don't need to worry about user specific preferences when setting up milestones.
    if (function_exists('hostsite_get_user_field')) {
        foreach ($options['presets'] as $preset) {
            $title = false;
            switch ($preset) {
                case 'my-records':
                    if (hostsite_get_user_field('id')) {
                        $title = lang::get('My records');
                    }
                    break;
                case 'my-queried-records':
                    if (hostsite_get_user_field('id')) {
                        $title = lang::get('My queried records');
                    }
                    break;
                case 'my-queried-or-not-accepted-records':
                    if (hostsite_get_user_field('id')) {
                        $title = lang::get('My not accepted or queried records');
                    }
                    break;
                case 'my-not-reviewed-records':
                    if (hostsite_get_user_field('id')) {
                        $title = lang::get('My not reviewed records');
                    }
                    break;
                case 'my-accepted-records':
                    if (hostsite_get_user_field('id')) {
                        $title = lang::get('My accepted records');
                    }
                    break;
                case 'my-groups':
                    if (hostsite_get_user_field('taxon_groups', false, true)) {
                        $title = lang::get('Records in species groups I like to record');
                    }
                    break;
                case 'my-locality':
                    if (hostsite_get_user_field('location')) {
                        $title = lang::get('Records in the locality I generally record in');
                    }
                    break;
                case 'my-groups-locality':
                    if (hostsite_get_user_field('taxon_groups', false, true) && hostsite_get_user_field('location')) {
                        $title = lang::get('Records of my species groups in my locality');
                    }
                    break;
                case 'queried-records':
                    $title = lang::get('Queried records');
                    break;
                case 'answered-records':
                    $title = lang::get('Records with answers');
                    break;
                case 'accepted-records':
                    $title = lang::get('Accepted records');
                    break;
                case 'not-accepted-records':
                    $title = lang::get('Not accepted records');
                    break;
                default:
                    throw new exception("Unsupported preset {$preset} for the filter panel");
            }
            if ($title) {
                $presetFilter = array('id' => $preset, 'title' => $title, 'defines_permissions' => 'f');
                $filterData[] = $presetFilter;
            }
        }
        if (count($options['presets'])) {
            if ($groups = hostsite_get_user_field('taxon_groups', false, true)) {
                data_entry_helper::$javascript .= "indiciaData.userPrefsTaxonGroups='" . implode(',', $groups) . "';\n";
            }
            if ($location = hostsite_get_user_field('location')) {
                data_entry_helper::$javascript .= "indiciaData.userPrefsLocation=" . $location . ";\n";
            }
        }
        $contextDefs = array();
        if ($options['sharing'] === 'verification') {
            // apply legacy verification settings from their profile
            $location_id = hostsite_get_user_field('location_expertise');
            $taxon_group_ids = hostsite_get_user_field('taxon_groups_expertise', false, true);
            $survey_ids = hostsite_get_user_field('surveys_expertise', false, true);
            if ($location_id || $taxon_group_ids || $survey_ids) {
                $selected = !empty($options['context_id']) && $options['context_id'] === 'default' ? 'selected="selected" ' : '';
                $contexts .= "<option value=\"default\" {$selected}>" . lang::get('My verification records') . "</option>";
                $def = array();
                if ($location_id) {
                    // user profile geographic limits should always be based on an indexed location.
                    $def['indexed_location_id'] = $location_id;
                }
                if ($taxon_group_ids) {
                    $def['taxon_group_list'] = implode(',', $taxon_group_ids);
                    $def['taxon_group_names'] = array();
                    $groups = data_entry_helper::get_population_data(array('table' => 'taxon_group', 'extraParams' => $readAuth + array('id' => $taxon_group_ids)));
                    foreach ($groups as $group) {
                        $def['taxon_group_names'][$group['id']] = $group['title'];
                    }
                }
                if ($survey_ids) {
                    $def['survey_list'] = implode(',', array_filter($survey_ids));
                }
                $contextDefs['default'] = $def;
            }
        }
    }
    if (!empty($_GET['context_id'])) {
        $options['context_id'] = $_GET['context_id'];
    }
    if (!empty($_GET['filter_id'])) {
        $options['filter_id'] = $_GET['filter_id'];
    }
    if (!empty($_GET['filters_user_id'])) {
        $options['filters_user_id'] = $_GET['filters_user_id'];
    }
    foreach ($filterData as $filter) {
        if ($filter['defines_permissions'] === 't') {
            $selected = !empty($options['context_id']) && $options['context_id'] == $filter['id'] ? 'selected="selected" ' : '';
            $contexts .= "<option value=\"{$filter['id']}\" {$selected}>{$filter['title']}</option>";
            $contextDefs[$filter['id']] = json_decode($filter['definition']);
        } else {
            $selected = !empty($options['filter_id']) && $options['filter_id'] == $filter['id'] ? 'selected="selected" ' : '';
            $existing .= "<option value=\"{$filter['id']}\" {$selected}>{$filter['title']}</option>";
        }
    }
    $r = '<div id="standard-params" class="ui-widget">';
    if ($options['allowSave'] && $options['admin']) {
        if (empty($_GET['filters_user_id'])) {
            // new filter to create, so sharing type can be edited
            $reload = data_entry_helper::get_reload_link_parts();
            $reloadPath = $reload['path'];
            if (count($reload['params'])) {
                $reloadPath .= '?' . data_entry_helper::array_to_query_string($reload['params']);
            }
            $r .= "<form action=\"{$reloadPath}\" method=\"post\" >";
            $r .= data_entry_helper::select(array('label' => lang::get('Select filter type'), 'fieldname' => 'filter:sharing', 'lookupValues' => $options['adminCanSetSharingTo'], 'afterControl' => '<input type="submit" value="Go"/>', 'default' => $options['sharingCode']));
            $r .= '</form>';
        } else {
            // existing filter to edit, type is therefore fixed. JS will fill these values in.
            $r .= '<p>' . lang::get('This filter is for <span id="sharing-type-label"></span>.') . '</p>';
            $r .= data_entry_helper::hidden_text(array('fieldname' => 'filter:sharing'));
        }
    }
    if ($options['allowLoad']) {
        $r .= '<div class="header ui-toolbar ui-widget-header ui-helper-clearfix"><div><span id="active-filter-label">' . lang::get('New report') . '</span></div><span class="changed" style="display:none" title="This filter has been changed">*</span>';
        $r .= '<div>';
        if ($contexts) {
            data_entry_helper::$javascript .= "indiciaData.filterContextDefs = " . json_encode($contextDefs) . ";\n";
            if (count($contextDefs) > 1) {
                $r .= '<label for="context-filter">' . lang::get('Context:') . "</label><select id=\"context-filter\">{$contexts}</select>";
            } else {
                $keys = array_keys($contextDefs);
                $r .= '<input type="hidden" id="context-filter" value="' . $keys[0] . '" />';
            }
        }
        $r .= '<label for="select-filter">' . lang::get('Filter:') . '</label><select id="select-filter"><option value="" selected="selected">' . lang::get('Select filter') . "...</option>{$existing}</select>";
        $r .= '<button type="button" id="filter-apply">' . lang::get('Apply') . '</button>';
        $r .= '<button type="button" id="filter-reset" class="disabled">' . lang::get('Reset') . '</button>';
        $r .= '<button type="button" id="filter-build">' . lang::get('Create a filter') . '</button></div>';
        $r .= '</div>';
        $r .= '<div id="filter-details" style="display: none">';
        $r .= '<img src="' . data_entry_helper::$images_path . 'nuvola/close-22px.png" width="22" height="22" alt="Close filter builder" title="Close filter builder" class="button" id="filter-done"/>' . "\n";
    } else {
        $r .= '<div id="filter-details">';
        if (!empty($options['filter_id'])) {
            $r .= "<input type=\"hidden\" id=\"select-filter\" value=\"{$options['filter_id']}\"/>";
        } elseif (!empty($options['filters_user_id'])) {
            $r .= "<input type=\"hidden\" id=\"select-filters-user\" value=\"{$options['filters_user_id']}\"/>";
        }
    }
    $r .= '<div id="filter-panes">';
    if ($options['entity'] === 'occurrence') {
        $filters = array('filter_what' => new filter_what(), 'filter_where' => new filter_where(), 'filter_when' => new filter_when(), 'filter_who' => new filter_who(), 'filter_occurrence_id' => new filter_occurrence_id(), 'filter_quality' => new filter_quality(), 'filter_source' => new filter_source());
    } elseif ($options['entity'] === 'sample') {
        $filters = array('filter_where' => new filter_where(), 'filter_when' => new filter_when(), 'filter_who' => new filter_who(), 'filter_sample_id' => new filter_sample_id(), 'filter_quality' => new filter_quality_sample(), 'filter_source' => new filter_source());
    }
    if (!empty($options['filterTypes'])) {
        $filterModules = array();
        foreach ($options['filterTypes'] as $category => $list) {
            // $list can be an array or comma separated list
            if (is_array($list)) {
                $list = implode(',', $list);
            }
            $paneNames = 'filter_' . str_replace(',', ',filter_', $list);
            $paneList = explode(',', $paneNames);
            $filterModules[$category] = array_intersect_key($filters, array_fill_keys($paneList, 1));
        }
    } else {
        $filterModules = array('' => $filters);
    }
    foreach ($filterModules as $category => $list) {
        if ($category) {
            $r .= '<fieldset class="collapsible collapsed">' . '<legend>' . '<span class="fieldset-legend">' . $category . '</span>' . '</legend>' . '<div class="fieldset-wrapper">';
        }
        foreach ($list as $moduleName => $module) {
            $r .= "<div class=\"pane\" id=\"pane-{$moduleName}\"><a class=\"fb-filter-link\" href=\"#controls-{$moduleName}\"><span class=\"pane-title\">" . $module->get_title() . '</span>';
            $r .= '<span class="filter-desc"></span></a>';
            $r .= "</div>";
        }
        if ($category) {
            $r .= '</div></fieldset>';
        }
    }
    $r .= '</div>';
    // filter panes
    $r .= '<div class="toolbar">';
    if ($options['allowSave']) {
        $r .= '<label for="filter:title">' . lang::get('Save filter as') . ':</label> <input id="filter:title" class="control-width-5"/>';
        if ($options['admin']) {
            $r .= '<br/>';
            if (empty($options['adminCanSetSharingTo'])) {
                throw new exception('Report standard params panel in admin mode so adminCanSetSharingTo option must be populated.');
            }
            $r .= data_entry_helper::autocomplete(array('label' => 'For who?', 'fieldname' => 'filters_user:user_id', 'table' => 'user', 'valueField' => 'id', 'captionField' => 'person_name', 'formatFunction' => "function(item) { return item.person_name + ' (' + item.email_address + ')'; }", 'extraParams' => $readAuth + array('view' => 'detail'), 'class' => 'control-width-5'));
            $r .= data_entry_helper::textarea(array('label' => 'Description', 'fieldname' => 'filter:description'));
        }
        $r .= '<img src="' . data_entry_helper::$images_path . 'nuvola/save-22px.png" width="22" height="22" alt="Save filter" title="Save filter" class="button" id="filter-save"/>';
        $r .= '<img src="' . data_entry_helper::$images_path . 'trash-22px.png" width="22" height="22" alt="Bin this filter" title="Bin this filter" class="button disabled" id="filter-delete"/>';
    }
    $r .= '</div></div>';
    // toolbar + clearfix
    if (!empty($options['filters_user_id'])) {
        // if we are preloading based on a filter user ID, we need to get the information now so that the sharing mode can be known
        // when loading controls
        $fu = data_entry_helper::get_population_data(array('table' => 'filters_user', 'extraParams' => $readAuth + array('id' => $options['filters_user_id']), 'caching' => false));
        if (count($fu) !== 1) {
            throw new exception('Could not find filter user record');
        }
        $options['sharing'] = report_filters_sharing_code_to_full_term($fu[0]['filter_sharing']);
    }
    report_helper::$javascript .= "indiciaData.lang={pleaseSelect:\"" . lang::get('Please select') . "\"};\n";
    // create the hidden panels required to populate the popups for setting each type of filter up.
    $hiddenStuff = '';
    foreach ($filterModules as $category => $list) {
        foreach ($list as $moduleName => $module) {
            $hiddenStuff .= "<div style=\"display: none\"><div class=\"filter-popup\" id=\"controls-{$moduleName}\"><form action=\"#\" class=\"filter-controls\"><fieldset>" . $module->get_controls($readAuth, $options) . '<button class="fb-close" type="button">Cancel</button>' . '<button class="fb-apply" type="submit">Apply</button></fieldset></form></div></div>';
            $shortName = str_replace('filter_', '', $moduleName);
            report_helper::$javascript .= "indiciaData.lang.NoDescription{$shortName}='" . lang::get('Click to Filter ' . ucfirst($shortName)) . "';\n";
        }
    }
    $r .= '</div>';
    report_helper::$js_read_tokens = $readAuth;
    report_helper::$javascript .= "indiciaData.lang.CreateAFilter='" . lang::get('Create a filter') . "';\n";
    report_helper::$javascript .= "indiciaData.lang.ModifyFilter='" . lang::get('Modify filter') . "';\n";
    report_helper::$javascript .= "indiciaData.lang.FilterReport='" . lang::get('New report') . "';\n";
    report_helper::$javascript .= "indiciaData.lang.FilterSaved='" . lang::get('The filter has been saved') . "';\n";
    report_helper::$javascript .= "indiciaData.lang.FilterDeleted='" . lang::get('The filter has been deleted') . "';\n";
    report_helper::$javascript .= "indiciaData.lang.ConfirmFilterChangedLoad='" . lang::get('Do you want to load the selected filter and lose your current changes?') . "';\n";
    report_helper::$javascript .= "indiciaData.lang.FilterExistsOverwrite='" . lang::get('A filter with that name already exists. Would you like to overwrite it?') . "';\n";
    report_helper::$javascript .= "indiciaData.lang.AutochecksFailed='" . lang::get('Automated checks failed') . "';\n";
    report_helper::$javascript .= "indiciaData.lang.AutochecksPassed='" . lang::get('Automated checks passed') . "';\n";
    report_helper::$javascript .= "indiciaData.lang.HasPhotos='" . lang::get('Records which have photos') . "';\n";
    report_helper::$javascript .= "indiciaData.lang.ConfirmFilterDelete='" . lang::get('Are you sure you want to permanently delete the {title} filter?') . "';\n";
    report_helper::$javascript .= "indiciaData.lang.MyRecords='" . lang::get('My records only') . "';\n";
    if (function_exists('iform_ajaxproxy_url')) {
        report_helper::$javascript .= "indiciaData.filterPostUrl='" . iform_ajaxproxy_url(null, 'filter') . "';\n";
        report_helper::$javascript .= "indiciaData.filterAndUserPostUrl='" . iform_ajaxproxy_url(null, 'filter_and_user') . "';\n";
    }
    report_helper::$javascript .= "indiciaData.filterSharing='" . strtoupper(substr($options['sharing'], 0, 1)) . "';\n";
    if (function_exists('hostsite_get_user_field')) {
        report_helper::$javascript .= "indiciaData.user_id='" . hostsite_get_user_field('indicia_user_id') . "';\n";
    } else {
        report_helper::$javascript .= "indiciaData.user_id='" . $_SESSION['auth_user']->id . "';\n";
    }
    if (!empty($website_id)) {
        report_helper::$javascript .= "indiciaData.website_id=" . $website_id . ";\n";
    }
    report_helper::$javascript .= "indiciaData.redirectOnSuccess='{$options['redirect_on_success']}';\n";
    // load up the filter, BEFORE any AJAX load of the grid code. First fetch any URL param overrides.
    $getParams = array();
    $optionParams = array();
    foreach ($_GET as $key => $value) {
        if (substr($key, 0, 7) === 'filter-') {
            $getParams[substr($key, 7)] = $value;
        }
    }
    foreach ($options as $key => $value) {
        if (substr($key, 0, 7) === 'filter-') {
            $optionParams[substr($key, 7)] = $value;
        }
    }
    $allParams = array_merge($optionParams, $getParams);
    if (!empty($allParams)) {
        $allParams = json_encode($allParams);
        report_helper::$onload_javascript .= "var params = {$allParams};\n";
        report_helper::$onload_javascript .= "indiciaData.filter.def=\$.extend(indiciaData.filter.def, params);\n";
        report_helper::$onload_javascript .= "indiciaData.filter.orig=\$.extend({}, params);\n";
    }
    $getParams = empty($getParams) ? '{}' : json_encode($getParams);
    if (!empty($options['filters_user_id'])) {
        report_helper::$onload_javascript .= "loadFilterUser(" . json_encode($fu[0]) . ", {$getParams});\n";
    } else {
        report_helper::$onload_javascript .= "if (\$('#select-filter').val()) {\n" . "  loadFilter(\$('#select-filter').val(), {$getParams});\n" . "} else {\n" . "  applyFilterToReports(false);\n" . "}\n";
    }
    return $r;
}