/**
  * 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.
  * @todo: Implement this method 
  */
 public static function get_form($args, $node, $response = null)
 {
     global $user;
     $checks = self::check_prerequisites();
     $args = self::getArgDefaults($args);
     if ($checks !== true) {
         return $checks;
     }
     iform_load_helpers(array('map_helper'));
     data_entry_helper::add_resource('jquery_form');
     self::$ajaxFormUrl = iform_ajaxproxy_url($node, 'location');
     self::$ajaxFormSampleUrl = iform_ajaxproxy_url($node, 'sample');
     $auth = data_entry_helper::get_read_write_auth($args['website_id'], $args['password']);
     $typeTerms = array(empty($args['transect_type_term']) ? 'Transect' : $args['transect_type_term'], empty($args['section_type_term']) ? 'Section' : $args['section_type_term']);
     $settings = array('locationTypes' => helper_base::get_termlist_terms($auth, 'indicia:location_types', $typeTerms), 'locationId' => isset($_GET['id']) ? $_GET['id'] : null, 'canEditBody' => true, 'canEditSections' => true, 'canAllocBranch' => $args['managerPermission'] == "" || user_access($args['managerPermission']), 'canAllocUser' => $args['managerPermission'] == "" || user_access($args['managerPermission']));
     $settings['attributes'] = data_entry_helper::getAttributes(array('id' => $settings['locationId'], 'valuetable' => 'location_attribute_value', 'attrtable' => 'location_attribute', 'key' => 'location_id', 'fieldprefix' => 'locAttr', 'extraParams' => $auth['read'], 'survey_id' => $args['survey_id'], 'location_type_id' => $settings['locationTypes'][0]['id'], 'multiValue' => true));
     $settings['section_attributes'] = data_entry_helper::getAttributes(array('valuetable' => 'location_attribute_value', 'attrtable' => 'location_attribute', 'key' => 'location_id', 'fieldprefix' => 'locAttr', 'extraParams' => $auth['read'], 'survey_id' => $args['survey_id'], 'location_type_id' => $settings['locationTypes'][1]['id'], 'multiValue' => true));
     if ($args['allow_user_assignment']) {
         if (false == ($settings['cmsUserAttr'] = extract_cms_user_attr($settings['attributes']))) {
             return 'This form is designed to be used with the CMS User ID attribute setup for locations in the survey, or the "Allow users to be assigned to transects" option unticked.';
         }
         // keep a copy of the cms user ID attribute so we can use it later.
         self::$cmsUserAttrId = $settings['cmsUserAttr']['attributeId'];
     }
     // need to check if branch allocation is active.
     if ($args['branch_assignment_permission'] != '') {
         if (false == ($settings['branchCmsUserAttr'] = self::extract_attr($settings['attributes'], "Branch CMS User ID"))) {
             return '<br />This form is designed to be used with either<br />1) the Branch CMS User ID attribute setup for locations in the survey, or<br />2) the "Permission name for Branch Manager" option left blank.<br />';
         }
         // keep a copy of the branch cms user ID attribute so we can use it later.
         self::$branchCmsUserAttrId = $settings['branchCmsUserAttr']['attributeId'];
     }
     data_entry_helper::$javascript .= "indiciaData.sections = {};\n";
     $settings['sections'] = array();
     $settings['numSectionsAttr'] = "";
     $settings['maxSectionCount'] = $args['maxSectionCount'];
     $settings['autocalcSectionLengthAttrId'] = empty($args['autocalc_section_length_attr_id']) ? 0 : $args['autocalc_section_length_attr_id'];
     $settings['defaultSectionGridRef'] = empty($args['default_section_grid_ref']) ? 'parent' : $args['default_section_grid_ref'];
     if ($settings['locationId']) {
         data_entry_helper::load_existing_record($auth['read'], 'location', $settings['locationId']);
         $settings['walks'] = data_entry_helper::get_population_data(array('table' => 'sample', 'extraParams' => $auth['read'] + array('view' => 'detail', 'location_id' => $settings['locationId'], 'deleted' => 'f'), 'nocache' => true));
         // Work out permissions for this user: note that canAllocBranch setting effectively shows if a manager.
         if (!$settings['canAllocBranch']) {
             // Check whether I am a normal user and it is allocated to me, and also if I am a branch manager and it is allocated to me.
             $settings['canEditBody'] = false;
             $settings['canEditSections'] = false;
             if ($args['allow_user_assignment'] && count($settings['walks']) == 0 && isset($settings['cmsUserAttr']['default']) && !empty($settings['cmsUserAttr']['default'])) {
                 foreach ($settings['cmsUserAttr']['default'] as $value) {
                     // multi value
                     if ($value['default'] == $user->uid) {
                         // comparing string against int so no triple equals
                         $settings['canEditBody'] = true;
                         $settings['canEditSections'] = true;
                         break;
                     }
                 }
             }
             // If a Branch Manager and not a main manager, then can't edit the number of sections
             if ($args['branch_assignment_permission'] != '' && user_access($args['branch_assignment_permission']) && isset($settings['branchCmsUserAttr']['default']) && !empty($settings['branchCmsUserAttr']['default'])) {
                 foreach ($settings['branchCmsUserAttr']['default'] as $value) {
                     // now multi value
                     if ($value['default'] == $user->uid) {
                         // comparing string against int so no triple equals
                         $settings['canEditBody'] = true;
                         $settings['canAllocUser'] = true;
                         break;
                     }
                 }
             }
         }
         // for an admin user the defaults apply, which will be can do everything.
         // find the number of sections attribute.
         foreach ($settings['attributes'] as $attr) {
             if ($attr['caption'] === 'No. of sections') {
                 $settings['numSectionsAttr'] = $attr['fieldname'];
                 for ($i = 1; $i <= $attr['displayValue']; $i++) {
                     $settings['sections']["S{$i}"] = null;
                 }
                 $existingSectionCount = empty($attr['displayValue']) ? 1 : $attr['displayValue'];
                 data_entry_helper::$javascript .= "\$('#" . str_replace(':', '\\\\:', $attr['id']) . "').attr('min',{$existingSectionCount}).attr('max'," . $args['maxSectionCount'] . ");\n";
                 if (!$settings['canEditSections']) {
                     data_entry_helper::$javascript .= "\$('#" . str_replace(':', '\\\\:', $attr['id']) . "').attr('readonly','readonly').css('color','graytext');\n";
                 }
             }
         }
         $sections = data_entry_helper::get_population_data(array('table' => 'location', 'extraParams' => $auth['read'] + array('view' => 'detail', 'parent_id' => $settings['locationId'], 'deleted' => 'f', 'orderby' => 'id'), 'nocache' => true));
         foreach ($sections as $section) {
             $code = $section['code'];
             data_entry_helper::$javascript .= "indiciaData.sections.{$code} = {'geom':'" . $section['boundary_geom'] . "','id':'" . $section['id'] . "','sref':'" . $section['centroid_sref'] . "','system':'" . $section['centroid_sref_system'] . "'};\n";
             $settings['sections'][$code] = $section;
         }
     } else {
         // not an existing site therefore no walks. On initial save, no section data is created.
         foreach ($settings['attributes'] as $attr) {
             if ($attr['caption'] === 'No. of sections') {
                 $settings['numSectionsAttr'] = $attr['fieldname'];
                 data_entry_helper::$javascript .= "\$('#" . str_replace(':', '\\\\:', $attr['id']) . "').attr('min',1).attr('max'," . $args['maxSectionCount'] . ");\n";
             }
         }
         $settings['walks'] = array();
     }
     if ($settings['numSectionsAttr'] === '') {
         for ($i = 1; $i <= $settings['maxSectionCount']; $i++) {
             $settings['sections']["S{$i}"] = null;
         }
     }
     $r = '<div id="controls">';
     $headerOptions = array('tabs' => array('#site-details' => lang::get('Site Details')));
     if ($settings['locationId']) {
         $headerOptions['tabs']['#your-route'] = lang::get('Your Route');
         if ($args['always_show_section_details'] || count($settings['section_attributes']) > 0) {
             $headerOptions['tabs']['#section-details'] = lang::get('Section Details');
         }
     }
     if (count($headerOptions['tabs'])) {
         $r .= data_entry_helper::tab_header($headerOptions);
         data_entry_helper::enable_tabs(array('divId' => 'controls', 'style' => 'Tabs', 'progressBar' => isset($args['tabProgress']) && $args['tabProgress'] == true));
     }
     $r .= self::get_site_tab($auth, $args, $settings);
     if ($settings['locationId']) {
         $r .= self::get_your_route_tab($auth, $args, $settings);
         if ($args['always_show_section_details'] || count($settings['section_attributes']) > 0) {
             $r .= self::get_section_details_tab($auth, $args, $settings);
         }
     }
     $r .= '</div>';
     // controls
     data_entry_helper::enable_validation('input-form');
     if (function_exists('drupal_set_breadcrumb')) {
         $breadcrumb = array();
         $breadcrumb[] = l(lang::get('Home'), '<front>');
         $breadcrumb[] = l(lang::get('Sites'), $args['sites_list_path']);
         if ($settings['locationId']) {
             $breadcrumb[] = data_entry_helper::$entity_to_load['location:name'];
         } else {
             $breadcrumb[] = lang::get('New Site');
         }
         drupal_set_breadcrumb($breadcrumb);
     }
     // Inform JS where to post data to for AJAX form saving
     data_entry_helper::$javascript .= 'indiciaData.ajaxFormPostUrl="' . self::$ajaxFormUrl . "\";\n";
     data_entry_helper::$javascript .= 'indiciaData.ajaxFormPostSampleUrl="' . self::$ajaxFormSampleUrl . "\";\n";
     data_entry_helper::$javascript .= 'indiciaData.website_id="' . $args['website_id'] . "\";\n";
     data_entry_helper::$javascript .= "indiciaData.indiciaSvc = '" . data_entry_helper::$base_url . "';\n";
     data_entry_helper::$javascript .= "indiciaData.readAuth = {nonce: '" . $auth['read']['nonce'] . "', auth_token: '" . $auth['read']['auth_token'] . "'};\n";
     data_entry_helper::$javascript .= "indiciaData.currentSection = '';\n";
     data_entry_helper::$javascript .= "indiciaData.sectionTypeId = '" . $settings['locationTypes'][1]['id'] . "';\n";
     data_entry_helper::$javascript .= "indiciaData.sectionDeleteConfirm = \"" . lang::get('Are you sure you wish to delete section') . "\";\n";
     data_entry_helper::$javascript .= "indiciaData.sectionInsertConfirm = \"" . lang::get('Are you sure you wish to insert a new section after section') . "\";\n";
     data_entry_helper::$javascript .= "indiciaData.sectionChangeConfirm = \"" . lang::get('Do you wish to save the currently unsaved changes you have made to the Section Details?') . "\";\n";
     data_entry_helper::$javascript .= "indiciaData.numSectionsAttrName = \"" . $settings['numSectionsAttr'] . "\";\n";
     data_entry_helper::$javascript .= "indiciaData.maxSectionCount = \"" . $settings['maxSectionCount'] . "\";\n";
     data_entry_helper::$javascript .= "indiciaData.autocalcSectionLengthAttrId = " . $settings['autocalcSectionLengthAttrId'] . ";\n";
     data_entry_helper::$javascript .= "indiciaData.defaultSectionGridRef = '" . $settings['defaultSectionGridRef'] . "';\n";
     if ($settings['locationId']) {
         data_entry_helper::$javascript .= "selectSection('S1', true);\n";
     }
     return $r;
 }
 public static function get_occurrences_form($args, $node, $response)
 {
     global $user;
     if (!module_exists('iform_ajaxproxy')) {
         return 'This form must be used in Drupal with the Indicia AJAX Proxy module enabled.';
     }
     drupal_add_js('misc/tableheader.js');
     // for sticky heading
     data_entry_helper::add_resource('jquery_form');
     $auth = data_entry_helper::get_read_write_auth($args['website_id'], $args['password']);
     // did the parent sample previously exist? Default is no.
     $existing = false;
     $url = explode('?', $args['my_obs_page'], 2);
     $params = NULL;
     $fragment = NULL;
     // fragment is always at the end.
     if (count($url) > 1) {
         $params = explode('#', $url[1], 2);
         if (count($params) > 1) {
             $fragment = $params[1];
         }
         $params = $params[0];
     } else {
         $url = explode('#', $url[0], 2);
         if (count($url) > 1) {
             $fragment = $url[1];
         }
     }
     $args['my_obs_page'] = url($url[0], array('query' => $params, 'fragment' => $fragment, 'absolute' => TRUE));
     if (isset($_POST['sample:id'])) {
         // have just posted an edit to the existing sample
         $sampleId = $_POST['sample:id'];
         $existing = true;
         data_entry_helper::load_existing_record($auth['read'], 'sample', $sampleId);
     } else {
         if (isset($response['outer_id'])) {
             // have just posted a new sample.
             $sampleId = $response['outer_id'];
         } else {
             $sampleId = $_GET['sample_id'];
             $existing = true;
         }
     }
     $sample = data_entry_helper::get_population_data(array('table' => 'sample', 'extraParams' => $auth['read'] + array('view' => 'detail', 'id' => $sampleId, 'deleted' => 'f')));
     $sample = $sample[0];
     $date = $sample['date_start'];
     if (!function_exists('module_exists') || !module_exists('easy_login')) {
         // work out the CMS User sample ID.
         $sampleMethods = helper_base::get_termlist_terms($auth, 'indicia:sample_methods', array('Field Observation'));
         $attributes = data_entry_helper::getAttributes(array('valuetable' => 'sample_attribute_value', 'attrtable' => 'sample_attribute', 'key' => 'sample_id', 'fieldprefix' => 'smpAttr', 'extraParams' => $auth['read'], 'survey_id' => $args['survey_id'], 'sample_method_id' => $sampleMethods[0]['id']));
         if (false == ($cmsUserAttr = extract_cms_user_attr($attributes))) {
             return 'Easy Login not active: This form is designed to be used with the CMS User ID attribute setup for samples in the survey.';
         }
     }
     $allTaxonMeaningIdsAtSample = array();
     if ($existing) {
         // Only need to load the occurrences for a pre-existing sample
         $o = data_entry_helper::get_population_data(array('report' => 'reports_for_prebuilt_forms/UKBMS/ukbms_occurrences_list_for_sample', 'extraParams' => $auth['read'] + array('view' => 'detail', 'sample_id' => $sampleId, 'survey_id' => $args['survey_id'], 'date_from' => '', 'date_to' => '', 'taxon_group_id' => '', 'smpattrs' => '', 'occattrs' => $args['occurrence_attribute_ids']), 'nocache' => true));
         // build an array keyed for easy lookup
         $occurrences = array();
         $attrs = explode(',', $args['occurrence_attribute_ids']);
         if (!isset($o['error'])) {
             foreach ($o as $occurrence) {
                 if (!in_array($occurrence['taxon_meaning_id'], $allTaxonMeaningIdsAtSample)) {
                     $allTaxonMeaningIdsAtSample[] = $occurrence['taxon_meaning_id'];
                 }
                 $occurrences[$occurrence['taxon_meaning_id']] = array('ttl_id' => $occurrence['taxa_taxon_list_id'], 'ttl_id' => $occurrence['taxa_taxon_list_id'], 'preferred_ttl_id' => $occurrence['preferred_ttl_id'], 'o_id' => $occurrence['occurrence_id'], 'processed' => false);
                 foreach ($attrs as $attr) {
                     $occurrences[$occurrence['taxon_meaning_id']]['value_' . $attr] = $occurrence['attr_occurrence_' . $attr];
                     $occurrences[$occurrence['taxon_meaning_id']]['a_id_' . $attr] = $occurrence['attr_id_occurrence_' . $attr];
                 }
             }
         }
         // store it in data for JS to read when populating the grid
         data_entry_helper::$javascript .= "indiciaData.existingOccurrences = " . json_encode($occurrences) . ";\n";
     } else {
         data_entry_helper::$javascript .= "indiciaData.existingOccurrences = {};\n";
     }
     $occ_attributes = data_entry_helper::getAttributes(array('valuetable' => 'occurrence_attribute_value', 'attrtable' => 'occurrence_attribute', 'key' => 'occurrence_id', 'fieldprefix' => 'occAttr', 'extraParams' => $auth['read'], 'survey_id' => $args['survey_id'], 'multiValue' => false));
     data_entry_helper::$javascript .= "indiciaData.occurrence_totals = [];\n";
     data_entry_helper::$javascript .= "indiciaData.occurrence_attribute = [];\n";
     data_entry_helper::$javascript .= "indiciaData.occurrence_attribute_ctrl = [];\n";
     $defAttrOptions = array('extraParams' => $auth['read'] + array('orderby' => 'id'), 'suffixTemplate' => 'nosuffix');
     $occ_attributes_captions = array();
     foreach (explode(',', $args['occurrence_attribute_ids']) as $idx => $attr) {
         $occ_attributes_captions[$idx] = $occ_attributes[$attr]['caption'];
         unset($occ_attributes[$attr]['caption']);
         $ctrl = data_entry_helper::outputAttribute($occ_attributes[$attr], $defAttrOptions);
         data_entry_helper::$javascript .= "indiciaData.occurrence_totals[" . $idx . "] = [];\n";
         data_entry_helper::$javascript .= "indiciaData.occurrence_attribute[" . $idx . "] = {$attr};\n";
         data_entry_helper::$javascript .= "indiciaData.occurrence_attribute_ctrl[" . $idx . "] = jQuery('" . str_replace("\n", "", $ctrl) . "');\n";
     }
     //    $r = "<h2>".$location[0]['name']." on ".$date."</h2>\n";
     $r = '<div id="tabs">';
     $tabs = array('#grid1' => t($args['species_tab_1']));
     // tab 1 is required.
     if (isset($args['taxon_list_id_2']) && $args['taxon_list_id_2'] != '') {
         $tabs['#grid2'] = t(isset($args['species_tab_2']) && $args['species_tab_2'] != '' ? $args['species_tab_2'] : 'Species Tab 2');
     }
     if (isset($args['taxon_list_id_3']) && $args['taxon_list_id_3'] != '') {
         $tabs['#grid3'] = t(isset($args['species_tab_3']) && $args['species_tab_3'] != '' ? $args['species_tab_3'] : 'Species Tab 3');
     }
     if (isset($args['taxon_list_id_4']) && $args['taxon_list_id_4'] != '') {
         $tabs['#grid4'] = t(isset($args['species_tab_4']) && $args['species_tab_4'] != '' ? $args['species_tab_4'] : 'Species Tab 4');
     }
     $tabs['#notes'] = lang::get('Notes');
     $r .= data_entry_helper::tab_header(array('tabs' => $tabs));
     data_entry_helper::enable_tabs(array('divId' => 'tabs', 'style' => 'Tabs'));
     // will assume that first table is based on abundance count, so do totals
     $r .= '<div id="grid1"><table id="observation-input1" class="ui-widget species-grid"><thead class="table-header"><tr><th class="ui-widget-header"></th>';
     foreach (explode(',', $args['occurrence_attribute_ids']) as $idx => $attr) {
         $r .= '<th class="ui-widget-header col-' . ($idx + 1) . '">' . $occ_attributes_captions[$idx] . '</th>';
     }
     $r .= '<th class="ui-widget-header">' . lang::get('Total') . '</th></tr></thead>';
     $r .= '<tbody class="ui-widget-content occs-body"></tbody><tfoot><tr><td>Total</td>';
     foreach (explode(',', $args['occurrence_attribute_ids']) as $idx => $attr) {
         $r .= '<td class="col-' . ($idx + 1) . ' ' . ($idx % 5 == 0 ? 'first' : '') . ' col-total"></td>';
     }
     $r .= '<td class="ui-state-disabled first"></td></tr></tfoot></table><br /><a href="' . $args['my_obs_page'] . '" class="button">' . lang::get('Finish') . '</a></div>';
     $extraParams = array_merge($auth['read'], array('taxon_list_id' => $args['taxon_list_id_1'], 'preferred' => 't', 'allow_data_entry' => 't', 'view' => 'cache', 'orderby' => 'taxonomic_sort_order'));
     if (!empty($args['taxon_filter_field_1']) && !empty($args['taxon_filter_1'])) {
         $extraParams[$args['taxon_filter_field_1']] = helper_base::explode_lines($args['taxon_filter_1']);
     }
     $taxa = data_entry_helper::get_population_data(array('table' => 'taxa_taxon_list', 'extraParams' => $extraParams));
     data_entry_helper::$javascript .= "indiciaData.speciesList1List = [";
     $first = true;
     foreach ($taxa as $taxon) {
         data_entry_helper::$javascript .= ($first ? "\n" : ",\n") . "{'id':" . $taxon['id'] . ",'taxon_meaning_id':" . $taxon['taxon_meaning_id'] . ",'preferred_language_iso':'" . $taxon["preferred_language_iso"] . "','default_common_name':'" . str_replace("'", "\\'", $taxon["default_common_name"]) . "'}";
         $first = false;
     }
     data_entry_helper::$javascript .= "];\n";
     data_entry_helper::$javascript .= "indiciaData.allTaxonMeaningIdsAtSample = [" . implode(',', $allTaxonMeaningIdsAtSample) . "];\n";
     if (isset($args['taxon_list_id_2']) && $args['taxon_list_id_2'] != '') {
         $r .= '<div id="grid2"><p id="grid2-loading">' . lang::get('Loading - Please Wait') . '</p><table id="observation-input2" class="ui-widget species-grid"><thead class="table-header"><tr><th class="ui-widget-header"></th>';
         foreach (explode(',', $args['occurrence_attribute_ids']) as $idx => $attr) {
             $r .= '<th class="ui-widget-header col-' . ($idx + 1) . '">' . $occ_attributes_captions[$idx] . '</th>';
         }
         $r .= '<th class="ui-widget-header">' . lang::get('Total') . '</th></tr></thead><tbody class="ui-widget-content occs-body"></tbody><tfoot><tr><td>Total</td>';
         foreach (explode(',', $args['occurrence_attribute_ids']) as $idx => $attr) {
             $r .= '<td class="col-' . ($idx + 1) . ' ' . ($idx % 5 == 0 ? 'first' : '') . ' col-total"></td>';
         }
         $r .= '<td class="ui-state-disabled first"></td></tr></tfoot></table><br /><a href="' . $args['my_obs_page'] . '" class="button">' . lang::get('Finish') . '</a></div>';
     }
     if (isset($args['taxon_list_id_3']) && $args['taxon_list_id_3'] != '') {
         $r .= '<div id="grid3"><p id="grid3-loading">' . lang::get('Loading - Please Wait') . '</p><table id="observation-input3" class="ui-widget species-grid"><thead class="table-header"><tr><th class="ui-widget-header"></th>';
         foreach (explode(',', $args['occurrence_attribute_ids']) as $idx => $attr) {
             $r .= '<th class="ui-widget-header col-' . ($idx + 1) . '">' . $occ_attributes_captions[$idx] . '</th>';
         }
         $r .= '<th class="ui-widget-header">' . lang::get('Total') . '</th></tr></thead><tbody class="ui-widget-content occs-body"></tbody><tfoot><tr><td>Total</td>';
         foreach (explode(',', $args['occurrence_attribute_ids']) as $idx => $attr) {
             $r .= '<td class="col-' . ($idx + 1) . ' ' . ($idx % 5 == 0 ? 'first' : '') . ' col-total"></td>';
         }
         $r .= '<td class="ui-state-disabled first"></td></tr></tfoot></table><br /><a href="' . $args['my_obs_page'] . '" class="button">' . lang::get('Finish') . '</a></div>';
     }
     if (isset($args['taxon_list_id_4']) && $args['taxon_list_id_4'] != '') {
         $r .= '<div id="grid4"><p id="grid4-loading">' . lang::get('Loading - Please Wait') . '</p><table id="observation-input4" class="ui-widget species-grid"><thead class="table-header"><tr><th class="ui-widget-header"></th>';
         foreach (explode(',', $args['occurrence_attribute_ids']) as $idx => $attr) {
             $r .= '<th class="ui-widget-header col-' . ($idx + 1) . '">' . $occ_attributes_captions[$idx] . '</th>';
         }
         $r .= '<th class="ui-widget-header">' . lang::get('Total') . '</th></tr></thead><tbody class="ui-widget-content occs-body"></tbody><tfoot><tr><td>Total</td>';
         foreach (explode(',', $args['occurrence_attribute_ids']) as $idx => $attr) {
             $r .= '<td class="col-' . ($idx + 1) . ' ' . ($idx % 5 == 0 ? 'first' : '') . ' col-total"></td>';
         }
         $r .= '<td class="ui-state-disabled first"></td></tr></tfoot></table>';
         $r .= '<label for="taxonLookupControl4" class="auto-width">' . lang::get('Add species to list') . ':</label> <input id="taxonLookupControl4" name="taxonLookupControl4" >';
         $r .= '<br /><a href="' . $args['my_obs_page'] . '" class="button">' . lang::get('Finish') . '</a></div>';
     }
     // for the comment form, we want to ensure that if there is a timeout error that it reloads the
     // data as stored in the DB.
     $reload = data_entry_helper::get_reload_link_parts();
     $reload['params']['sample_id'] = $parentSampleId;
     unset($reload['params']['new']);
     $reloadPath = $reload['path'];
     if (count($reload['params'])) {
         // decode params prior to encoding to prevent double encoding.
         foreach ($reload['params'] as $key => $param) {
             $reload['params'][$key] = urldecode($param);
         }
         $reloadPath .= '?' . http_build_query($reload['params']);
     }
     // fragment is always at the end. discard this.
     $reloadPath = explode('#', $reloadPath, 2);
     $reloadPath = $reloadPath[0];
     $r .= "<div id=\"notes\"><form method=\"post\" id=\"notes_form\" action=\"" . $reloadPath . "#notes\">\n";
     $r .= $auth['write'];
     $r .= '<input type="hidden" name="sample:id" value="' . $sampleId . '" />' . '<input type="hidden" name="website_id" value="' . $args['website_id'] . '"/>' . '<input type="hidden" name="survey_id" value="' . $args['survey_id'] . '"/>' . '<input type="hidden" name="page" value="notes"/>';
     $r .= '<p class="page-notice ui-state-highlight ui-corner-all">' . lang::get('When using this page, please remember that the data is not saved to the database as you go (which is the case for the previous tabs). In order to save the data entered in this page you must click on the Submit button at the bottom of the page.') . '</p>';
     $r .= data_entry_helper::textarea(array('fieldname' => 'sample:comment', 'label' => lang::get('Notes'), 'helpText' => "Use this space to input comments about this week's walk."));
     $r .= '<input type="submit" value="' . lang::get('Submit') . '" id="save-button"/></form>';
     $r .= '<br /><a href="' . $args['my_walks_page'] . '" class="button">' . lang::get('Finish') . '</a></div></div>';
     // enable validation on the comments form in order to include the simplified ajax queuing for the autocomplete.
     data_entry_helper::enable_validation('notes_form');
     // A stub form for AJAX posting when we need to create an occurrence
     $r .= '<form style="display: none" id="occ-form" method="post" action="' . iform_ajaxproxy_url($node, 'occurrence') . '">';
     $r .= '<input name="website_id" value="' . $args['website_id'] . '"/>';
     $r .= '<input name="occurrence:id" id="occid" />';
     $r .= '<input name="occurrence:taxa_taxon_list_id" id="ttlid" />';
     $r .= '<input name="occurrence:sample_id" value="' . $sampleId . '"/>';
     $r .= '<input name="occAttr:" id="occattr"/>';
     $r .= '<input name="transaction_id" id="transaction_id"/>';
     $r .= '<input name="user_id" value="' . hostsite_get_user_field('user_id', 1) . '"/>';
     $r .= '</form>';
     // tell the Javascript where to get species from.
     data_entry_helper::add_resource('jquery_ui');
     data_entry_helper::add_resource('json');
     data_entry_helper::add_resource('autocomplete');
     data_entry_helper::$javascript .= "indiciaData.speciesList1 = " . $args['taxon_list_id_1'] . ";\n";
     if (!empty($args['taxon_filter_field_1']) && !empty($args['taxon_filter_1'])) {
         data_entry_helper::$javascript .= "indiciaData.speciesList1FilterField = '" . $args['taxon_filter_field_1'] . "';\n";
         $filterLines = helper_base::explode_lines($args['taxon_filter_1']);
         data_entry_helper::$javascript .= "indiciaData.speciesList1FilterValues = '" . json_encode($filterLines) . "';\n";
     }
     data_entry_helper::$javascript .= "indiciaData.speciesList2 = " . (isset($args['taxon_list_id_2']) && $args['taxon_list_id_2'] != "" ? $args['taxon_list_id_2'] : "-1") . ";\n";
     if (!empty($args['taxon_filter_field_2']) && !empty($args['taxon_filter_2'])) {
         data_entry_helper::$javascript .= "indiciaData.speciesList2FilterField = '" . $args['taxon_filter_field_2'] . "';\n";
         $filterLines = helper_base::explode_lines($args['taxon_filter_2']);
         data_entry_helper::$javascript .= "indiciaData.speciesList2FilterValues = " . json_encode($filterLines) . ";\n";
     }
     data_entry_helper::$javascript .= "indiciaData.speciesList3 = " . (isset($args['taxon_list_id_3']) && $args['taxon_list_id_3'] != "" ? $args['taxon_list_id_3'] : "-1") . ";\n";
     if (!empty($args['taxon_filter_field_3']) && !empty($args['taxon_filter_3'])) {
         data_entry_helper::$javascript .= "indiciaData.speciesList3FilterField = '" . $args['taxon_filter_field_3'] . "';\n";
         $filterLines = helper_base::explode_lines($args['taxon_filter_3']);
         data_entry_helper::$javascript .= "indiciaData.speciesList3FilterValues = " . json_encode($filterLines) . ";\n";
     }
     data_entry_helper::$javascript .= "indiciaData.speciesList4 = " . (isset($args['taxon_list_id_4']) && $args['taxon_list_id_4'] != "" ? $args['taxon_list_id_4'] : "-1") . ";\n";
     if (!empty($args['taxon_filter_field_4']) && !empty($args['taxon_filter_4'])) {
         data_entry_helper::$javascript .= "indiciaData.speciesList4FilterField = '" . $args['taxon_filter_field_4'] . "';\n";
         $filterLines = helper_base::explode_lines($args['taxon_filter_4']);
         data_entry_helper::$javascript .= "indiciaData.speciesList4FilterValues = " . json_encode($filterLines) . ";\n";
     }
     // allow js to do AJAX by passing in the information it needs to post forms
     data_entry_helper::$javascript .= "bindSpeciesAutocomplete(\"taxonLookupControl4\",\"table#observation-input4\",\"" . data_entry_helper::$base_url . "index.php/services/data\", indiciaData.speciesList4,\n  indiciaData.speciesList4FilterField, indiciaData.speciesList4FilterValues, {\"auth_token\" : \"" . $auth['read']['auth_token'] . "\", \"nonce\" : \"" . $auth['read']['nonce'] . "\"},\n  \"" . lang::get('LANG_Duplicate_Taxon') . "\", 25, 4);\n\n";
     data_entry_helper::$javascript .= "indiciaData.indiciaSvc = '" . data_entry_helper::$base_url . "';\n";
     data_entry_helper::$javascript .= "indiciaData.readAuth = {nonce: '" . $auth['read']['nonce'] . "', auth_token: '" . $auth['read']['auth_token'] . "'};\n";
     data_entry_helper::$javascript .= "indiciaData.sample = " . $sampleId . ";\n";
     if (function_exists('module_exists') && module_exists('easy_login')) {
         data_entry_helper::$javascript .= "indiciaData.easyLogin = true;\n";
         $userId = hostsite_get_user_field('indicia_user_id');
         if (!empty($userId)) {
             data_entry_helper::$javascript .= "indiciaData.UserID = " . $userId . ";\n";
         } else {
             return '<p>Easy Login active but could not identify user</p>';
         }
         // something is wrong
     } else {
         data_entry_helper::$javascript .= "indiciaData.easyLogin = false;\n";
         data_entry_helper::$javascript .= "indiciaData.CMSUserAttrID = " . $cmsUserAttr['attributeId'] . ";\n";
         data_entry_helper::$javascript .= "indiciaData.CMSUserID = " . $user->uid . ";\n";
     }
     // Do an AJAX population of the grid rows.
     data_entry_helper::$javascript .= "loadSpeciesList();\njQuery('#tabs').bind('tabsshow', function(event, ui) {\n    var target = ui.panel;\n    // first get rid of any previous tables\n    jQuery('table.sticky-header').remove();\n    jQuery('table.sticky-enabled thead.tableHeader-processed').removeClass('tableHeader-processed');\n    jQuery('table.sticky-enabled.tableheader-processed').removeClass('tableheader-processed');\n    jQuery('table.species-grid.sticky-enabled').removeClass('sticky-enabled');\n    var table = jQuery('#'+target.id+' table.species-grid');\n    if(table.length > 0) {\n        table.addClass('sticky-enabled');\n        if(typeof Drupal.behaviors.tableHeader == 'object') // Drupal 7\n          Drupal.behaviors.tableHeader.attach(table.parent());\n        else // Drupal6 : it is a function\n          Drupal.behaviors.tableHeader(target);\n    }\n    // remove any hanging autocomplete select list.\n    jQuery('.ac_results').hide();\n});";
     return $r;
 }
 private static function user_control($args, $readAuth, $node, &$options)
 {
     // we don't use the userID option as the user_id can be blank, and will force the parameter request if left as a blank
     global $user;
     if (!isset($args['includeUserFilter']) || !$args['includeUserFilter']) {
         return '';
     }
     // if the user is changed then we must reset the location
     $siteUrlParams = self::get_site_url_params();
     // var_dump($siteUrlParams);
     $options['extraParams']['user_id'] = $siteUrlParams[self::$userKey]['value'] == "branch" ? '' : $siteUrlParams[self::$userKey]['value'];
     $userList = array();
     if (function_exists('module_exists') && module_exists('easy_login') && function_exists('hostsite_get_user_field')) {
         $options['my_user_id'] = hostsite_get_user_field('indicia_user_id');
     } else {
         $options['my_user_id'] = $user->uid;
     }
     if (!isset($args['managerPermission']) || $args['managerPermission'] == "" || !user_access($args['managerPermission'])) {
         // user is a normal user
         $userList[$user->uid] = $user;
         // just me
     } else {
         // user is manager, so need to load the list of users they can choose to report against
         if (!($userList = self::_fetchDBCache($user->uid))) {
             $userList = array();
             if (!isset($args['userLookUp']) || !$args['userLookUp']) {
                 // look up all users, not just those that have entered data.
                 $results = db_query('SELECT uid, name FROM {users}');
                 if (version_compare(VERSION, '7', '<')) {
                     while ($result = db_fetch_object($results)) {
                         if ($result->uid) {
                             // ignore unauthorised user, uid zero
                             $account = user_load($result->uid);
                             $userList[$account->uid] = $account;
                         }
                     }
                 } else {
                     foreach ($results as $result) {
                         // DB handling is different in 7
                         if ($result->uid) {
                             // ignore unauthorised user, uid zero
                             $account = user_load($result->uid);
                             $userList[$account->uid] = $account;
                         }
                     }
                 }
             } else {
                 if (function_exists('module_exists') && module_exists('easy_login')) {
                     $sampleArgs = array('extraParams' => array_merge(array('view' => 'detail', 'website_id' => $args['website_id'], 'survey_id' => self::$siteUrlParams[self::$SurveyKey]), $readAuth), 'table' => 'sample', 'columns' => 'created_by_id');
                     $sampleList = data_entry_helper::get_population_data($sampleArgs);
                     if (isset($sampleList['error'])) {
                         return $sampleList['error'];
                     }
                     $uList = array();
                     foreach ($sampleList as $sample) {
                         $uList[intval($sample['created_by_id'])] = true;
                     }
                     // This next bit is DRUPAL specific, but we are using the Easy Login module.
                     if (count($uList) > 0) {
                         if (version_compare(VERSION, '7', '<')) {
                             $results = db_query("SELECT DISTINCT pv.uid, u.name FROM {users} u " . "JOIN {profile_values} pv ON pv.uid=u.uid " . "JOIN {profile_fields} pf ON pf.fid=pv.fid AND pf.name='profile_indicia_user_id' " . "AND pv.value IN (" . implode(',', array_keys($uList)) . ")");
                             while ($result = db_fetch_object($results)) {
                                 if ($result->uid) {
                                     $userList[$result->uid] = $result;
                                 }
                             }
                         } else {
                             // @todo: This needs optimising as in the Drupal 6 version - don't want to load ALL users
                             $results = db_query('SELECT uid, name FROM {users}');
                             foreach ($results as $result) {
                                 // DB processing is different in 7
                                 if ($result->uid) {
                                     $account = user_load($result->uid);
                                     /* this loads the field_ fields, so no need for profile_load_profile */
                                     if (isset($account->profile_indicia_user_id) && isset($uList[$account->profile_indicia_user_id]) && $uList[$account->profile_indicia_user_id]) {
                                         $userList[$account->uid] = $account;
                                     }
                                 }
                             }
                         }
                     }
                 } else {
                     // not easy login so use the CMS User ID attribute hanging off the to find which users have entered data.
                     $attrArgs = array('valuetable' => 'sample_attribute_value', 'attrtable' => 'sample_attribute', 'key' => 'sample_id', 'fieldprefix' => 'smpAttr', 'extraParams' => $readAuth, 'survey_id' => self::$siteUrlParams[self::$SurveyKey]);
                     if (isset($args['userLookUpSampleMethod']) && $args['userLookUpSampleMethod'] != "") {
                         $sampleMethods = helper_base::get_termlist_terms(array('read' => $readAuth), 'indicia:sample_methods', array(trim($args['userLookUpSampleMethod'])));
                         $attrArgs['sample_method_id'] = $sampleMethods[0]['id'];
                     }
                     $sampleAttributes = data_entry_helper::getAttributes($attrArgs, false);
                     if (false == ($cmsAttr = extract_cms_user_attr($sampleAttributes))) {
                         return lang::get('User control: CMS User ID sample attribute missing.');
                     }
                     $attrListArgs = array('extraParams' => array_merge(array('view' => 'list', 'website_id' => $args['website_id'], 'sample_attribute_id' => $cmsAttr['attributeId']), $readAuth), 'table' => 'sample_attribute_value');
                     $attrList = data_entry_helper::get_population_data($attrListArgs);
                     if (isset($attrList['error'])) {
                         return $attrList['error'];
                     }
                     foreach ($attrList as $attr) {
                         if ($attr['id'] != null) {
                             $userList[intval($attr['raw_value'])] = true;
                         }
                     }
                     // This next bit is DRUPAL specific
                     $results = db_query('SELECT uid, name FROM {users}');
                     if (version_compare(VERSION, '7', '<')) {
                         while ($result = db_fetch_object($results)) {
                             if ($result->uid && isset($userList[$result->uid]) && $userList[$result->uid]) {
                                 $userList[$account->uid] = user_load($result->uid);
                             }
                         }
                     } else {
                         foreach ($results as $result) {
                             // DB handling is different in 7
                             if ($result->uid && isset($userList[$result->uid]) && $userList[$result->uid]) {
                                 $userList[$account->uid] = user_load($result->uid);
                             }
                         }
                     }
                 }
             }
             self::_cacheResponse($user->uid, $userList);
         }
     }
     $ctrlid = 'calendar-user-select-' . $node->nid;
     $ctrl = '<label for="' . $ctrlid . '" class="user-select-label">' . lang::get('Filter by recorder') . ': </label><select id="' . $ctrlid . '" class="user-select">' . '<option value=' . $user->uid . ' class="user-select-option" ' . ($siteUrlParams[self::$userKey]['value'] == $user->uid ? 'selected="selected" ' : '') . '>' . lang::get('My data') . '</option>' . (isset($args['branchManagerPermission']) && $args['branchManagerPermission'] != "" && user_access($args['branchManagerPermission']) ? '<option value="branch" class="user-select-option" ' . ($siteUrlParams[self::$userKey]['value'] == "branch" ? 'selected="selected" ' : '') . '>' . lang::get('Branch data') . '</option>' : '') . '<option value="all" class="user-select-option" ' . ($siteUrlParams[self::$userKey]['value'] == '' ? 'selected="selected" ' : '') . '>' . lang::get('All recorders') . '</option>';
     $found = $siteUrlParams[self::$userKey]['value'] == $user->uid || isset($args['branchManagerPermission']) && $args['branchManagerPermission'] != "" && user_access($args['branchManagerPermission']) && $siteUrlParams[self::$userKey]['value'] == "branch" || $siteUrlParams[self::$userKey]['value'] == '';
     $userListArr = array();
     foreach ($userList as $id => $account) {
         // if account comes from cache, then it is an array, if from drupal an object.
         if (!is_array($account)) {
             $account = get_object_vars($account);
         }
         if ($account !== true && $id != $user->uid) {
             $userListArr[$id] = $account['name'];
         }
     }
     natcasesort($userListArr);
     foreach ($userListArr as $id => $name) {
         $ctrl .= '<option value=' . $id . ' class="user-select-option" ' . ($siteUrlParams[self::$userKey]['value'] == $id ? 'selected="selected" ' : '') . '>' . $name . '</option>';
         $found = $found || $siteUrlParams[self::$userKey]['value'] == $id;
     }
     // masquerading may produce some odd results when flipping between accounts.
     switch ($siteUrlParams[self::$userKey]['value']) {
         case '':
             $options['downloadFilePrefix'] .= lang::get('AllRecorders') . '_';
             break;
         case $user->uid:
             $options['downloadFilePrefix'] .= lang::get('MyData') . '_';
             break;
         case "branch":
             $options['downloadFilePrefix'] .= lang::get('MyBranch') . '_';
             break;
         default:
             // if account comes from cache, then it is an array, if from drupal an object.
             $account = is_array($userList[$siteUrlParams[self::$userKey]['value']]) ? $userList[$siteUrlParams[self::$userKey]['value']] : get_object_vars($userList[$siteUrlParams[self::$userKey]['value']]);
             $options['downloadFilePrefix'] .= preg_replace('/[^A-Za-z0-9]/i', '', $account['name']) . '_';
             break;
     }
     // Haven't found the selected user on the list: this means select defaults to top option which is the user themselves.
     if (!$found) {
         $siteUrlParams[self::$userKey]['value'] = $user->uid;
     }
     $ctrl .= '</select>';
     self::set_up_control_change($ctrlid, self::$userKey, array('locationID'));
     return $ctrl;
 }
 private static function user_control(&$args, $readAuth, $node, &$options)
 {
     // user filter is keyed on the CMS User ID; converted to cms_user_id/Indicia user_id pair by report_helper, if applicable.
     // we don't use the userID option as the user_id can be blank, and will force the parameter request if left as a blank
     global $user;
     $ctrl = '';
     if (!isset($args['includeUserFilter']) || !$args['includeUserFilter']) {
         return '';
     }
     // if the user is changed then we must reset the location
     $siteUrlParams = self::get_site_url_params();
     $options['user_id'] = $siteUrlParams[self::$userKey]['value'] == "branch" ? '' : $siteUrlParams[self::$userKey]['value'];
     $options['extraParams']['user_id'] = $options['user_id'];
     $userList = array();
     if (!isset($args['manager_permission']) || $args['manager_permission'] == "" || !user_access($args['manager_permission'])) {
         // user is a normal user or branch manager
         $userList[$user->uid] = $user;
         // just me
         // unset linkURL if normal user and user_id is not specified to be me: pass in flag so warning message displayed.
         // branch manager: user must be self or branch data: can use both for normal user as normal does have branch option
         // manager: access to all.
         switch ($siteUrlParams[self::$userKey]['value']) {
             case $user->uid:
                 // me so OK
             // me so OK
             case "branch":
                 // my branch so OK
                 break;
             default:
                 // all users or another user so no access to samples via links
                 unset($args['linkURL']);
                 $options['linkMessage'] = '<p>' . lang::get('In order to have the column headings as links to the data entry pages for the Visit, you must set the') . ' "' . lang::get('Filter by recorder') . '" ' . (isset($args['branch_manager_permission']) && $args['branch_manager_permission'] != "" && user_access($args['branch_manager_permission']) ? lang::get(' control to yourself or branch data.') : lang::get(' control to yourself.')) . '</p>';
         }
     } else {
         // user is manager, so need to load the list of users they can choose to report against
         if (!($userList = self::_fetchDBCache($user->uid))) {
             $userList = array();
             if (!isset($args['userLookUp']) || !$args['userLookUp']) {
                 // look up all users, not just those that have entered data.
                 $results = db_query('SELECT uid, name FROM {users}');
                 if (version_compare(VERSION, '7', '<')) {
                     while ($result = db_fetch_object($results)) {
                         if ($result->uid) {
                             // ignore unauthorised user, uid zero
                             $account = user_load($result->uid);
                             $userList[$account->uid] = $account;
                         }
                     }
                 } else {
                     foreach ($results as $result) {
                         // DB handling is different in 7
                         if ($result->uid) {
                             // ignore unauthorised user, uid zero
                             $account = user_load($result->uid);
                             $userList[$account->uid] = $account;
                         }
                     }
                 }
             } else {
                 if (function_exists('module_exists') && module_exists('easy_login')) {
                     // easy_login active: identify users who have entered data by the created_by_id on the main sample record.
                     // TODO consider whether should check only top level samples here? may not be necessary if sample_method set.
                     $sampleArgs = array('extraParams' => array_merge(array('view' => 'detail', 'website_id' => $args['website_id'], 'survey_id' => self::$siteUrlParams[self::$SurveyKey]), $readAuth), 'table' => 'sample', 'columns' => 'created_by_id');
                     if (isset($args['userLookUpSampleMethod']) && $args['userLookUpSampleMethod'] != "") {
                         $sampleMethods = helper_base::get_termlist_terms(array('read' => $readAuth), 'indicia:sample_methods', array(trim($args['userLookUpSampleMethod'])));
                         $sampleArgs['extraParams']['sample_method_id'] = $sampleMethods[0]['id'];
                     }
                     $sampleList = data_entry_helper::get_population_data($sampleArgs);
                     if (isset($sampleList['error'])) {
                         return $sampleList['error'];
                     }
                     $uList = array();
                     foreach ($sampleList as $sample) {
                         $uList[intval($sample['created_by_id'])] = true;
                     }
                     // This next bit is DRUPAL specific, but we are using the Easy Login module.
                     // get list of CMS users which match the retrieved set of Indicia User_ids.
                     if (count($uList) > 0) {
                         if (version_compare(VERSION, '7', '<')) {
                             $results = db_query("SELECT DISTINCT u.uid, u.name FROM {users} u " . "JOIN {profile_values} pv ON pv.uid=u.uid " . "JOIN {profile_fields} pf ON pf.fid=pv.fid AND pf.name='profile_indicia_user_id' " . "AND pv.value IN (" . implode(',', array_keys($uList)) . ")");
                             while ($result = db_fetch_object($results)) {
                                 if ($result->uid) {
                                     $userList[$result->uid] = $result;
                                 }
                             }
                         } else {
                             // @todo: This needs optimising as in the Drupal 6 version - don't want to load ALL users
                             $results = db_query('SELECT uid, name FROM {users}');
                             foreach ($results as $result) {
                                 // DB processing is different in 7
                                 if ($result->uid) {
                                     $account = user_load($result->uid);
                                     /* this loads the field_ fields, so no need for profile_load_profile */
                                     if (isset($account->profile_indicia_user_id) && isset($uList[$account->profile_indicia_user_id]) && $uList[$account->profile_indicia_user_id]) {
                                         $userList[$account->uid] = $account;
                                     }
                                 }
                             }
                         }
                     }
                 } else {
                     // not easy login so use the CMS User ID attribute hanging off the samples to find which users have entered data.
                     $attrArgs = array('valuetable' => 'sample_attribute_value', 'attrtable' => 'sample_attribute', 'key' => 'sample_id', 'fieldprefix' => 'smpAttr', 'extraParams' => $readAuth, 'survey_id' => self::$siteUrlParams[self::$SurveyKey]);
                     if (isset($args['userLookUpSampleMethod']) && $args['userLookUpSampleMethod'] != "") {
                         $sampleMethods = helper_base::get_termlist_terms(array('read' => $readAuth), 'indicia:sample_methods', array(trim($args['userLookUpSampleMethod'])));
                         $attrArgs['sample_method_id'] = $sampleMethods[0]['id'];
                     }
                     $sampleAttributes = data_entry_helper::getAttributes($attrArgs, false);
                     if (false == ($cmsAttr = extract_cms_user_attr($sampleAttributes))) {
                         return lang::get('User control: Looking up users who have previously entered data - non easy_login, so using CMS User ID attribute on samples: CMS User ID sample attribute missing.<br/>' . '<span style="display:none;">' . print_r($attrArgs, true) . '</span>');
                     }
                     $attrListArgs = array('extraParams' => array_merge(array('view' => 'list', 'website_id' => $args['website_id'], 'sample_attribute_id' => $cmsAttr['attributeId'], 'columns' => 'id,raw_value'), $readAuth), 'table' => 'sample_attribute_value');
                     $attrList = data_entry_helper::get_population_data($attrListArgs);
                     if (isset($attrList['error'])) {
                         return $attrList['error'];
                     }
                     foreach ($attrList as $attr) {
                         if ($attr['id'] != null) {
                             $userList[intval($attr['raw_value'])] = true;
                         }
                     }
                     // This next bit is DRUPAL specific
                     $results = db_query('SELECT uid, name FROM {users}');
                     if (version_compare(VERSION, '7', '<')) {
                         while ($result = db_fetch_object($results)) {
                             if ($result->uid && isset($userList[$result->uid]) && $userList[$result->uid]) {
                                 $userList[$account->uid] = user_load($result->uid);
                             }
                         }
                     } else {
                         foreach ($results as $result) {
                             // DB handling is different in 7
                             if ($result->uid && isset($userList[$result->uid]) && $userList[$result->uid]) {
                                 $userList[$account->uid] = user_load($result->uid);
                             }
                         }
                     }
                 }
             }
             self::_cacheResponse($user->uid, $userList);
         }
     }
     // The option values are CMS User ID, not Indicia ID.
     // This implies that $siteUrlParams[self::$userKey] is also CMS User ID.
     $ctrlid = 'calendar-user-select-' . $node->nid;
     $ctrl .= '<label for="' . $ctrlid . '" class="user-select-label">' . lang::get('Filter by recorder') . ': </label><select id="' . $ctrlid . '" class="user-select">' . '<option value=' . $user->uid . ' class="user-select-option" ' . ($siteUrlParams[self::$userKey]['value'] == $user->uid ? 'selected="selected" ' : '') . '>' . lang::get('My data') . '</option>' . (isset($args['branch_manager_permission']) && $args['branch_manager_permission'] != "" && user_access($args['branch_manager_permission']) ? '<option value="branch" class="user-select-option" ' . ($siteUrlParams[self::$userKey]['value'] == "branch" ? 'selected="selected" ' : '') . '>' . lang::get('Branch data') . '</option>' : '') . '<option value="all" class="user-select-option" ' . ($siteUrlParams[self::$userKey]['value'] == '' ? 'selected="selected" ' : '') . '>' . lang::get('All recorders') . '</option>';
     $found = $siteUrlParams[self::$userKey]['value'] == $user->uid || isset($args['branch_manager_permission']) && $args['branch_manager_permission'] != "" && user_access($args['branch_manager_permission']) && $siteUrlParams[self::$userKey]['value'] == "branch" || $siteUrlParams[self::$userKey]['value'] == '';
     $userListArr = array();
     foreach ($userList as $id => $account) {
         // if account comes from cache, then it is an array, if from drupal an object - convert.
         if (!is_array($account)) {
             $account = get_object_vars($account);
         }
         if ($account !== true && $id != $user->uid) {
             $userListArr[$id] = $account['name'];
         }
     }
     natcasesort($userListArr);
     foreach ($userListArr as $id => $name) {
         $ctrl .= '<option value=' . $id . ' class="user-select-option" ' . ($siteUrlParams[self::$userKey]['value'] == $id ? 'selected="selected" ' : '') . '>' . $name . '</option>';
         $found = $found || $siteUrlParams[self::$userKey]['value'] == $id;
     }
     // masquerading may produce some odd results when flipping between accounts.
     switch ($siteUrlParams[self::$userKey]['value']) {
         case '':
             $options['downloadFilePrefix'] .= lang::get('AllRecorders') . '_';
             break;
         case "branch":
             $options['downloadFilePrefix'] .= lang::get('MyBranch') . '_';
             // need to add user after branch so we know which branch
         // need to add user after branch so we know which branch
         default:
             // can't use "myData" as with cached reports >1 person may have same filename, but different reports. Also
             // providing explicit name makes it clearer.
             // if account comes from cache, then it is an array, if from drupal an object.
             $account = is_array($userList[$siteUrlParams[self::$userKey]['value']]) ? $userList[$siteUrlParams[self::$userKey]['value']] : get_object_vars($userList[$siteUrlParams[self::$userKey]['value']]);
             $options['downloadFilePrefix'] .= preg_replace('/[^A-Za-z0-9]/i', '', $account['name']) . '_';
             break;
     }
     // Haven't found the selected user on the list: this means select defaults to top option which is the user themselves.
     if (!$found) {
         $siteUrlParams[self::$userKey]['value'] = $user->uid;
     }
     $ctrl .= '</select>';
     self::set_up_control_change($ctrlid, self::$userKey, array('locationID'));
     return $ctrl;
 }
 public static function get_occurrences_form($args, $node, $response)
 {
     global $user;
     if (!module_exists('iform_ajaxproxy')) {
         return 'This form must be used in Drupal with the Indicia AJAX Proxy module enabled.';
     }
     drupal_add_js('misc/tableheader.js');
     // for sticky heading
     data_entry_helper::add_resource('jquery_form');
     $auth = data_entry_helper::get_read_write_auth($args['website_id'], $args['password']);
     // did the parent sample previously exist? Default is no.
     $existing = false;
     $url = explode('?', $args['my_walks_page'], 2);
     $params = NULL;
     $fragment = NULL;
     // fragment is always at the end.
     if (count($url) > 1) {
         $params = explode('#', $url[1], 2);
         if (count($params) > 1) {
             $fragment = $params[1];
         }
         $params = $params[0];
     } else {
         $url = explode('#', $url[0], 2);
         if (count($url) > 1) {
             $fragment = $url[1];
         }
     }
     $args['my_walks_page'] = url($url[0], array('query' => $params, 'fragment' => $fragment, 'absolute' => TRUE));
     if (isset($_POST['sample:id'])) {
         // have just posted an edit to the existing parent sample, so can use it to get the parent location id.
         $parentSampleId = $_POST['sample:id'];
         $existing = true;
         data_entry_helper::load_existing_record($auth['read'], 'sample', $parentSampleId);
     } else {
         if (isset($response['outer_id'])) {
             // have just posted a new parent sample, so can use it to get the parent location id.
             $parentSampleId = $response['outer_id'];
         } else {
             $parentSampleId = $_GET['sample_id'];
             $existing = true;
         }
     }
     $sample = data_entry_helper::get_population_data(array('table' => 'sample', 'extraParams' => $auth['read'] + array('view' => 'detail', 'id' => $parentSampleId, 'deleted' => 'f')));
     $sample = $sample[0];
     $parentLocId = $sample['location_id'];
     $date = $sample['date_start'];
     if (!function_exists('module_exists') || !module_exists('easy_login')) {
         // work out the CMS User sample ID.
         $sampleMethods = helper_base::get_termlist_terms($auth, 'indicia:sample_methods', array('Transect'));
         $attributes = data_entry_helper::getAttributes(array('valuetable' => 'sample_attribute_value', 'attrtable' => 'sample_attribute', 'key' => 'sample_id', 'fieldprefix' => 'smpAttr', 'extraParams' => $auth['read'], 'survey_id' => $args['survey_id'], 'sample_method_id' => $sampleMethods[0]['id']));
         if (false == ($cmsUserAttr = extract_cms_user_attr($attributes))) {
             return 'Easy Login not active: This form is designed to be used with the CMS User ID attribute setup for samples in the survey.';
         }
     }
     // find any attributes that apply to transect section samples.
     $sampleMethods = helper_base::get_termlist_terms($auth, 'indicia:sample_methods', array('Transect Section'));
     $attributes = data_entry_helper::getAttributes(array('valuetable' => 'sample_attribute_value', 'attrtable' => 'sample_attribute', 'key' => 'sample_id', 'fieldprefix' => 'smpAttr', 'extraParams' => $auth['read'], 'survey_id' => $args['survey_id'], 'sample_method_id' => $sampleMethods[0]['id'], 'multiValue' => false));
     //  the parent sample and sub-samples have already been created: can't cache in case a new section added.
     // need to specify sample_method as this must be different to those used in species map.
     // Only returns section based subsamples, not map.
     $subSamples = data_entry_helper::get_population_data(array('report' => 'library/samples/samples_list_for_parent_sample', 'extraParams' => $auth['read'] + array('sample_id' => $parentSampleId, 'date_from' => '', 'date_to' => '', 'sample_method_id' => $sampleMethods[0]['id'], 'smpattrs' => implode(',', array_keys($attributes))), 'nocache' => true));
     // transcribe the response array into a couple of forms that are useful elsewhere - one for outputting JSON so the JS knows about
     // the samples, and another for lookup of sample data by code later.
     $subSampleJson = array();
     $subSamplesByCode = array();
     foreach ($subSamples as $subSample) {
         $subSampleJson[] = '"' . $subSample['code'] . '": ' . $subSample['sample_id'];
         $subSamplesByCode[$subSample['code']] = $subSample;
     }
     data_entry_helper::$javascript .= "indiciaData.samples = { " . implode(', ', $subSampleJson) . "};\n";
     if ($existing) {
         // Only need to load the occurrences for a pre-existing sample
         $attrs = array($args['occurrence_attribute_id']);
         if (isset($args['occurrence_attribute_id_2']) && $args['occurrence_attribute_id_2'] != "") {
             $attrs[] = $args['occurrence_attribute_id_2'];
         }
         if (isset($args['occurrence_attribute_id_3']) && $args['occurrence_attribute_id_3'] != "") {
             $attrs[] = $args['occurrence_attribute_id_3'];
         }
         if (isset($args['occurrence_attribute_id_4']) && $args['occurrence_attribute_id_4'] != "") {
             $attrs[] = $args['occurrence_attribute_id_4'];
         }
         $o = data_entry_helper::get_population_data(array('report' => 'reports_for_prebuilt_forms/UKBMS/ukbms_occurrences_list_for_parent_sample', 'extraParams' => $auth['read'] + array('view' => 'detail', 'sample_id' => $parentSampleId, 'survey_id' => $args['survey_id'], 'date_from' => '', 'date_to' => '', 'taxon_group_id' => '', 'smpattrs' => '', 'occattrs' => implode(',', $attrs)), 'nocache' => true));
         // build an array keyed for easy lookup
         $occurrences = array();
         foreach ($o as $occurrence) {
             $occurrences[$occurrence['sample_id'] . ':' . $occurrence['taxon_meaning_id']] = array('ttl_id' => $occurrence['taxa_taxon_list_id'], 'taxon_meaning_id' => $occurrence['taxon_meaning_id'], 'o_id' => $occurrence['occurrence_id'], 'processed' => false);
             foreach ($attrs as $attr) {
                 $occurrences[$occurrence['sample_id'] . ':' . $occurrence['taxon_meaning_id']]['value_' . $attr] = $occurrence['attr_occurrence_' . $attr];
                 $occurrences[$occurrence['sample_id'] . ':' . $occurrence['taxon_meaning_id']]['a_id_' . $attr] = $occurrence['attr_id_occurrence_' . $attr];
             }
         }
         // store it in data for JS to read when populating the grid
         data_entry_helper::$javascript .= "indiciaData.existingOccurrences = " . json_encode($occurrences) . ";\n";
     } else {
         data_entry_helper::$javascript .= "indiciaData.existingOccurrences = {};\n";
     }
     $occ_attributes = data_entry_helper::getAttributes(array('valuetable' => 'occurrence_attribute_value', 'attrtable' => 'occurrence_attribute', 'key' => 'occurrence_id', 'fieldprefix' => 'occAttr', 'extraParams' => $auth['read'], 'survey_id' => $args['survey_id'], 'multiValue' => false));
     data_entry_helper::$javascript .= "indiciaData.occurrence_attribute = [];\n";
     data_entry_helper::$javascript .= "indiciaData.occurrence_attribute_ctrl = [];\n";
     $defAttrOptions = array('extraParams' => $auth['read'] + array('orderby' => 'id'), 'suffixTemplate' => 'nosuffix');
     foreach (array($args['occurrence_attribute_id'], isset($args['occurrence_attribute_id_2']) && $args['occurrence_attribute_id_2'] != "" ? $args['occurrence_attribute_id_2'] : $args['occurrence_attribute_id'], isset($args['occurrence_attribute_id_3']) && $args['occurrence_attribute_id_3'] != "" ? $args['occurrence_attribute_id_3'] : $args['occurrence_attribute_id'], isset($args['occurrence_attribute_id_4']) && $args['occurrence_attribute_id_4'] != "" ? $args['occurrence_attribute_id_4'] : $args['occurrence_attribute_id']) as $idx => $attr) {
         unset($occ_attributes[$attr]['caption']);
         $ctrl = data_entry_helper::outputAttribute($occ_attributes[$attr], $defAttrOptions);
         data_entry_helper::$javascript .= "indiciaData.occurrence_attribute[" . ($idx + 1) . "] = {$attr};\n";
         data_entry_helper::$javascript .= "indiciaData.occurrence_attribute_ctrl[" . ($idx + 1) . "] = jQuery('" . str_replace("\n", "", $ctrl) . "');\n";
     }
     $sections = data_entry_helper::get_population_data(array('table' => 'location', 'extraParams' => $auth['read'] + array('view' => 'detail', 'parent_id' => $parentLocId, 'deleted' => 'f'), 'nocache' => true));
     usort($sections, "ukbms_stis_sectionSort");
     $location = data_entry_helper::get_population_data(array('table' => 'location', 'extraParams' => $auth['read'] + array('view' => 'detail', 'id' => $parentLocId)));
     $r = "<h2>" . $location[0]['name'] . " on " . $date . "</h2><div id=\"tabs\">\n";
     $tabs = array('#grid1' => t($args['species_tab_1']));
     // tab 1 is required.
     if (isset($args['second_taxon_list_id']) && $args['second_taxon_list_id'] != '') {
         $tabs['#grid2'] = t(isset($args['species_tab_2']) && $args['species_tab_2'] != '' ? $args['species_tab_2'] : 'Species Tab 2');
     }
     if (isset($args['third_taxon_list_id']) && $args['third_taxon_list_id'] != '') {
         $tabs['#grid3'] = t(isset($args['species_tab_3']) && $args['species_tab_3'] != '' ? $args['species_tab_3'] : 'Species Tab 3');
     }
     if (isset($args['fourth_taxon_list_id']) && $args['fourth_taxon_list_id'] != '') {
         $tabs['#grid4'] = t(isset($args['species_tab_4']) && $args['species_tab_4'] != '' ? $args['species_tab_4'] : 'Species Tab 4');
     }
     if (isset($args['map_taxon_list_id']) && $args['map_taxon_list_id'] != '') {
         $tabs['#gridmap'] = t(isset($args['species_map_tab']) && $args['species_map_tab'] != '' ? $args['species_map_tab'] : 'Map Based Tab');
     }
     $tabs['#notes'] = lang::get('Notes');
     $r .= data_entry_helper::tab_header(array('tabs' => $tabs));
     data_entry_helper::enable_tabs(array('divId' => 'tabs', 'style' => 'Tabs'));
     $commonSelected = isset($args['start_with_common_species']) && $args['start_with_common_species'] ? 'selected="selected"' : '';
     // will assume that first table is based on abundance count, so do totals
     $r .= '<div id="grid1">' . '<label for="listSelect">' . lang::get('Use species list') . ' :</label><select id="listSelect"><option value="full">' . lang::get('All species') . '</option><option value="common"' . $commonSelected . '>' . lang::get('Common species') . '</option><option value="here">' . lang::get('Species known at this site') . '</option><option value="mine">' . lang::get('Species I have recorded') . '</option><option value="filled">' . lang::get('Species with data') . '</option></select>' . '<span id="listSelectMsg"></span>';
     $r .= '<table id="transect-input1" class="ui-widget species-grid"><thead class="table-header">';
     $r .= '<tr><th class="ui-widget-header">' . lang::get('Sections') . '</th>';
     foreach ($sections as $idx => $section) {
         $r .= '<th class="ui-widget-header col-' . ($idx + 1) . '">' . $section['code'] . '</th>';
     }
     $r .= '<th class="ui-widget-header">' . lang::get('Total') . '</th>';
     $r .= '</tr></thead>';
     $r .= '<tbody class="ui-widget-content">';
     // output rows at the top for any transect section level sample attributes
     $rowClass = '';
     foreach ($attributes as $attr) {
         $r .= '<tr ' . $rowClass . ' id="smp-' . $attr['attributeId'] . '"><td>' . $attr['caption'] . '</td>';
         $rowClass = $rowClass == '' ? 'class="alt-row"' : '';
         unset($attr['caption']);
         foreach ($sections as $idx => $section) {
             // output a cell with the attribute - tag it with a class & id to make it easy to find from JS.
             $attrOpts = array('class' => 'smp-input smpAttr-' . $section['code'], 'id' => $attr['fieldname'] . ':' . $section['code'], 'extraParams' => $auth['read']);
             // if there is an existing value, set it and also ensure the attribute name reflects the attribute value id.
             if (isset($subSamplesByCode[$section['code']])) {
                 // but have to take into account possibility that this field has been blanked out, so deleting the attribute.
                 if (isset($subSamplesByCode[$section['code']]['attr_id_sample_' . $attr['attributeId']]) && $subSamplesByCode[$section['code']]['attr_id_sample_' . $attr['attributeId']] != '') {
                     $attrOpts['fieldname'] = $attr['fieldname'] . ':' . $subSamplesByCode[$section['code']]['attr_id_sample_' . $attr['attributeId']];
                     $attr['default'] = $subSamplesByCode[$section['code']]['attr_sample_' . $attr['attributeId']];
                 } else {
                     $attr['default'] = isset($_POST[$attr['fieldname']]) ? $_POST[$attr['fieldname']] : '';
                 }
             } else {
                 $attr['default'] = isset($_POST[$attr['fieldname']]) ? $_POST[$attr['fieldname']] : '';
             }
             $r .= '<td class="col-' . ($idx + 1) . ' ' . ($idx % 5 == 0 ? 'first' : '') . '">' . data_entry_helper::outputAttribute($attr, $attrOpts) . '</td>';
         }
         $r .= '<td class="ui-state-disabled first"></td>';
         $r .= '</tr>';
     }
     $r .= '</tbody>';
     $r .= '<tbody class="ui-widget-content occs-body"></tbody>';
     $r .= '<tfoot><tr><td>Total</td>';
     foreach ($sections as $idx => $section) {
         $r .= '<td class="col-' . ($idx + 1) . ' ' . ($idx % 5 == 0 ? 'first' : '') . ' col-total"></td>';
     }
     $r .= '<td class="ui-state-disabled first"></td></tr></tfoot>';
     $r .= '</table>' . '<span id="taxonLookupControlContainer"><label for="taxonLookupControl" class="auto-width">' . lang::get('Add species to list') . ':</label> <input id="taxonLookupControl" name="taxonLookupControl" ></span>';
     $r .= '<br /><a href="' . $args['my_walks_page'] . '" class="button">' . lang::get('Finish') . '</a></div>';
     $extraParams = array_merge($auth['read'], array('taxon_list_id' => $args['taxon_list_id'], 'preferred' => 't', 'allow_data_entry' => 't', 'view' => 'cache', 'orderby' => 'taxonomic_sort_order'));
     if (!empty($args['main_taxon_filter_field']) && !empty($args['main_taxon_filter'])) {
         $extraParams[$args['main_taxon_filter_field']] = helper_base::explode_lines($args['main_taxon_filter']);
     }
     $taxa = data_entry_helper::get_population_data(array('table' => 'taxa_taxon_list', 'extraParams' => $extraParams));
     data_entry_helper::$javascript .= "indiciaData.speciesList1List = [";
     $first = true;
     foreach ($taxa as $taxon) {
         data_entry_helper::$javascript .= ($first ? "\n" : ",\n") . "{'id':" . $taxon['id'] . ",'taxon_meaning_id':" . $taxon['taxon_meaning_id'] . ",'preferred_language_iso':'" . $taxon["preferred_language_iso"] . "','default_common_name':'" . str_replace("'", "\\'", $taxon["default_common_name"]) . "'}";
         $first = false;
     }
     data_entry_helper::$javascript .= "];\n";
     if (!empty($args['common_taxon_list_id'])) {
         $extraParams = array_merge($auth['read'], array('taxon_list_id' => $args['common_taxon_list_id'], 'preferred' => 't', 'allow_data_entry' => 't', 'view' => 'cache', 'orderby' => 'taxonomic_sort_order'));
         if (!empty($args['common_taxon_filter_field']) && !empty($args['common_taxon_filter'])) {
             $extraParams[$args['common_taxon_filter_field']] = helper_base::explode_lines($args['common_taxon_filter']);
         }
         $taxa = data_entry_helper::get_population_data(array('table' => 'taxa_taxon_list', 'extraParams' => $extraParams));
         data_entry_helper::$javascript .= "indiciaData.speciesList1SubsetList = [";
         $first = true;
         foreach ($taxa as $taxon) {
             data_entry_helper::$javascript .= ($first ? "\n" : ",\n") . "{'id':" . $taxon['id'] . ",'taxon_meaning_id':" . $taxon['taxon_meaning_id'] . ",'preferred_language_iso':'" . $taxon["preferred_language_iso"] . "','default_common_name':'" . str_replace("'", "\\'", $taxon["default_common_name"]) . "'}";
             $first = false;
         }
         data_entry_helper::$javascript .= "];\n";
         $swc = isset($args['start_with_common_species']) && $args['start_with_common_species'] ? 'true' : 'false';
         data_entry_helper::$javascript .= "indiciaData.startWithCommonSpecies={$swc};\n";
     }
     $allTaxonMeaningIdsAtTransect = data_entry_helper::get_population_data(array('report' => 'reports_for_prebuilt_forms/UKBMS/ukbms_taxon_meanings_at_transect', 'extraParams' => $auth['read'] + array('location_id' => $parentLocId, 'survey_id' => $args['survey_id']), 'nocache' => true));
     data_entry_helper::$javascript .= "indiciaData.allTaxonMeaningIdsAtTransect = [";
     $first = true;
     foreach ($allTaxonMeaningIdsAtTransect as $taxon) {
         data_entry_helper::$javascript .= ($first ? "" : ",") . $taxon['taxon_meaning_id'];
         $first = false;
     }
     data_entry_helper::$javascript .= "];\n";
     if (isset($args['second_taxon_list_id']) && $args['second_taxon_list_id'] != '') {
         $isNumber = $occ_attributes[isset($args['occurrence_attribute_id_2']) && $args['occurrence_attribute_id_2'] != "" ? $args['occurrence_attribute_id_2'] : $args['occurrence_attribute_id']]["data_type"] == 'I';
         $r .= '<div id="grid2"><p id="grid2-loading">' . lang::get('Loading - Please Wait') . '</p>' . (isset($args['supress_tab_msg']) && $args['supress_tab_msg'] ? '' : '<p>' . lang::get('LANG_Tab_Msg') . '</p>') . '<table id="transect-input2" class="ui-widget species-grid"><thead class="table-header">';
         $r .= '<tr><th class="ui-widget-header">' . lang::get('Sections') . '</th>';
         foreach ($sections as $idx => $section) {
             $r .= '<th class="ui-widget-header col-' . ($idx + 1) . '">' . $section['code'] . '</th>';
         }
         $r .= ($isNumber ? '<th class="ui-widget-header">' . lang::get('Total') . '</th>' : '') . '</tr></thead>';
         // No output rows at the top for any transect section level sample attributes in second grid.
         $r .= '<tbody class="ui-widget-content occs-body"></tbody>';
         if ($isNumber) {
             $r .= '<tfoot><tr><td>Total</td>';
             foreach ($sections as $idx => $section) {
                 $r .= '<td class="col-' . ($idx + 1) . ' ' . ($idx % 5 == 0 ? 'first' : '') . ' col-total"></td>';
             }
             $r .= '<td class="ui-state-disabled first"></td></tr></tfoot>';
         }
         $r .= '</table>';
         if (!isset($args['force_second']) || !$args['force_second']) {
             $r .= '<label for="taxonLookupControl2" class="auto-width">' . lang::get('Add species to list') . ':</label> <input id="taxonLookupControl2" name="taxonLookupControl2" >';
         }
         $r .= '<br /><a href="' . $args['my_walks_page'] . '" class="button">' . lang::get('Finish') . '</a></div>';
     }
     if (isset($args['third_taxon_list_id']) && $args['third_taxon_list_id'] != '') {
         $isNumber = $occ_attributes[isset($args['occurrence_attribute_id_3']) && $args['occurrence_attribute_id_3'] != "" ? $args['occurrence_attribute_id_3'] : $args['occurrence_attribute_id']]["data_type"] == 'I';
         $r .= '<div id="grid3"><p id="grid3-loading">' . lang::get('Loading - Please Wait') . '</p>' . (isset($args['supress_tab_msg']) && $args['supress_tab_msg'] ? '' : '<p>' . lang::get('LANG_Tab_Msg') . '</p>') . '<table id="transect-input3" class="ui-widget species-grid"><thead class="table-header">';
         $r .= '<tr><th class="ui-widget-header">' . lang::get('Sections') . '</th>';
         foreach ($sections as $idx => $section) {
             $r .= '<th class="ui-widget-header col-' . ($idx + 1) . '">' . $section['code'] . '</th>';
         }
         $r .= ($isNumber ? '<th class="ui-widget-header">' . lang::get('Total') . '</th>' : '') . '</tr></thead>';
         // No output rows at the top for any transect section level sample attributes in second grid.
         $r .= '<tbody class="ui-widget-content occs-body"></tbody>';
         if ($isNumber) {
             $r .= '<tfoot><tr><td>Total</td>';
             foreach ($sections as $idx => $section) {
                 $r .= '<td class="col-' . ($idx + 1) . ' ' . ($idx % 5 == 0 ? 'first' : '') . ' col-total"></td>';
             }
             $r .= '<td class="ui-state-disabled first"></td></tr></tfoot>';
         }
         $r .= '</table>';
         if (!isset($args['force_third']) || !$args['force_third']) {
             $r .= '<label for="taxonLookupControl3" class="auto-width">' . lang::get('Add species to list') . ':</label> <input id="taxonLookupControl3" name="taxonLookupControl3" >';
         }
         $r .= '<br /><a href="' . $args['my_walks_page'] . '" class="button">' . lang::get('Finish') . '</a></div>';
     }
     if (isset($args['fourth_taxon_list_id']) && $args['fourth_taxon_list_id'] != '') {
         $isNumber = $occ_attributes[isset($args['occurrence_attribute_id_4']) && $args['occurrence_attribute_id_4'] != "" ? $args['occurrence_attribute_id_4'] : $args['occurrence_attribute_id']]["data_type"] == 'I';
         $r .= '<div id="grid4"><p id="grid4-loading">' . lang::get('Loading - Please Wait') . '</p>' . (isset($args['supress_tab_msg']) && $args['supress_tab_msg'] ? '' : '<p>' . lang::get('LANG_Tab_Msg') . '</p>') . '<table id="transect-input4" class="ui-widget species-grid"><thead class="table-header">';
         $r .= '<tr><th class="ui-widget-header">' . lang::get('Sections') . '</th>';
         foreach ($sections as $idx => $section) {
             $r .= '<th class="ui-widget-header col-' . ($idx + 1) . '">' . $section['code'] . '</th>';
         }
         $r .= ($isNumber ? '<th class="ui-widget-header">' . lang::get('Total') . '</th>' : '') . '</tr></thead>';
         // No output rows at the top for any transect section level sample attributes in second grid.
         $r .= '<tbody class="ui-widget-content occs-body"></tbody>';
         if ($isNumber) {
             $r .= '<tfoot><tr><td>Total</td>';
             foreach ($sections as $idx => $section) {
                 $r .= '<td class="col-' . ($idx + 1) . ' ' . ($idx % 5 == 0 ? 'first' : '') . ' col-total"></td>';
             }
             $r .= '<td class="ui-state-disabled first"></td></tr></tfoot>';
         }
         $r .= '</table>';
         if (!isset($args['force_fourth']) || !$args['force_fourth']) {
             $r .= '<label for="taxonLookupControl4" class="auto-width">' . lang::get('Add species to list') . ':</label> <input id="taxonLookupControl4" name="taxonLookupControl4" >';
         }
         $r .= '<br /><a href="' . $args['my_walks_page'] . '" class="button">' . lang::get('Finish') . '</a></div>';
     }
     $reloadPath = self::getReloadPath();
     if (isset($args['map_taxon_list_id']) && $args['map_taxon_list_id'] != '') {
         // TODO convert to AJAX.
         data_entry_helper::enable_validation('entry_form');
         $value = helper_base::explode_lines_key_value_pairs($args['defaults']);
         $value = isset($value['occurrence:record_status']) ? $value['occurrence:record_status'] : 'C';
         $r .= '<div id="gridmap">' . "\n" . '<form method="post" id="entry_form" action="' . $reloadPath . '">' . $auth['write'] . '<p>When using this page, please remember that the data is not saved to the database as you go (which is the case for the previous tabs). In order to save the data entered in this page you must click on the Save button at the bottom of the page.</p>' . '<input type="hidden" id="website_id" name="website_id" value="' . $args["website_id"] . '" />' . '<input type="hidden" id="survey_id" name="sample:survey_id" value="' . $args["survey_id"] . '" />' . '<input type="hidden" id="occurrence:record_status" name="occurrence:record_status" value="' . $value . '" />' . '<input type="hidden" name="sample:id" value="' . data_entry_helper::$entity_to_load['sample:id'] . '"/>' . '<input type="hidden" name="page" value="speciesmap"/>' . '<input type="hidden" name="sample:location_id" value="' . $parentLocId . '"/>';
         if (preg_match('/^(\\d{4})/', data_entry_helper::$entity_to_load['sample:date'])) {
             // Date has 4 digit year first (ISO style) - convert date to expected output format
             $d = new DateTime(data_entry_helper::$entity_to_load['sample:date']);
             data_entry_helper::$entity_to_load['sample:date'] = $d->format('d/m/Y');
         }
         $r .= '<input type="hidden" name="sample:date" value="' . data_entry_helper::$entity_to_load['sample:date'] . '"/>';
         // leave the sample_method as it is stored now.
         // Dont need the place search, as we will zoom in to the main location. TODO
         $options = iform_map_get_map_options($args, $auth["read"]);
         if (isset(data_entry_helper::$entity_to_load["sample:geom"])) {
             $options["initialFeatureWkt"] = data_entry_helper::$entity_to_load["sample:wkt"];
         }
         $options["tabDiv"] = "gridmap";
         $olOptions = iform_map_get_ol_options($args);
         if (!isset($options["standardControls"])) {
             $options["standardControls"] = array("layerSwitcher", "panZoomBar");
         }
         $r .= data_entry_helper::map_panel($options, $olOptions);
         // [species map]
         $r .= self::control_speciesmap($auth, $args, "gridmap", array());
         /**
          * The speciesmapsummary is not implemented here
          */
         $r .= '<input type="submit" class="indicia-button" id="save-button" value="' . lang::get('Save') . '" /></form></div>';
         data_entry_helper::$javascript .= "var speciesMapTabHandler = function(event, ui) {\n  if (ui.panel.id=='" . $options["tabDiv"] . "') {\n    if (indiciaData.ParentSampleLayer.features.length > 0) {\n      var bounds=indiciaData.ParentSampleLayer.getDataExtent();\n      bounds.extend(indiciaData.SubSampleLayer.getDataExtent());\n      // extend the boundary to include a buffer, so the map does not zoom too tight.\n      bounds.scale(1.2);\n      indiciaData.ParentSampleLayer.map.zoomToExtent(bounds);\n    }\n  }\n};\njQuery(jQuery('#" . $options["tabDiv"] . "').parent()).bind('tabsshow', speciesMapTabHandler);\n";
     } else {
         // enable validation on the comments form in order to include the simplified ajax queuing for the autocomplete.
         data_entry_helper::enable_validation('notes_form');
     }
     // for the comment form, we want to ensure that if there is a timeout error that it reloads the
     // data as stored in the DB.
     $reloadParts = explode('?', $reloadPath, 2);
     // fragment is always at the end. discard this.
     if (count($reloadParts) > 1) {
         $params = explode('#', $reloadParts[1], 2);
         $params = $params[0] . "&sample_id=" . $parentSampleId;
     } else {
         $reloadParts = explode('#', $reloadParts[0], 2);
         $params = "sample_id=" . $parentSampleId;
     }
     $r .= "<div id=\"notes\">\n";
     $r .= "<form method=\"post\" id=\"notes_form\" action=\"" . $reloadParts[0] . '?' . $params . "#notes\">\n";
     $r .= $auth['write'];
     $r .= '<input type="hidden" name="sample:id" value="' . $parentSampleId . '" />';
     $r .= '<input type="hidden" name="website_id" value="' . $args['website_id'] . '"/>';
     $r .= '<input type="hidden" name="survey_id" value="' . $args['survey_id'] . '"/>';
     $r .= '<input type="hidden" name="page" value="notes"/>';
     $r .= '<p  class="page-notice ui-state-highlight ui-corner-all">' . lang::get('When using this page, please remember that the data is not saved to the database as you go (which is the case for the previous tabs). In order to save the data entered in this page you must click on the Submit button at the bottom of the page.') . '</p>';
     $r .= data_entry_helper::textarea(array('fieldname' => 'sample:comment', 'label' => lang::get('Notes'), 'helpText' => "Use this space to input comments about this week's walk."));
     $r .= '<input type="submit" value="' . lang::get('Submit') . '" id="save-button"/>';
     $r .= '</form>';
     $r .= '<br /><a href="' . $args['my_walks_page'] . '" class="button">' . lang::get('Finish') . '</a>';
     $r .= '</div></div>';
     // A stub form for AJAX posting when we need to create an occurrence
     $r .= '<form style="display: none" id="occ-form" method="post" action="' . iform_ajaxproxy_url($node, 'occurrence') . '">';
     $r .= '<input name="website_id" value="' . $args['website_id'] . '"/>';
     $r .= '<input name="survey_id" value="' . $args["survey_id"] . '" />';
     $r .= '<input name="occurrence:id" id="occid" />';
     $r .= '<input name="occurrence:deleted" id="occdeleted" />';
     $r .= '<input name="occurrence:zero_abundance" id="occzero" />';
     $r .= '<input name="occurrence:taxa_taxon_list_id" id="ttlid" />';
     $r .= '<input name="occurrence:sample_id" id="occ_sampleid"/>';
     if (isset($args["sensitiveAttrID"]) && $args["sensitiveAttrID"] != "" && isset($args["sensitivityPrecision"]) && $args["sensitivityPrecision"] != "") {
         $locationTypes = helper_base::get_termlist_terms($auth, 'indicia:location_types', array(empty($args['transect_type_term']) ? 'Transect' : $args['transect_type_term']));
         $site_attributes = data_entry_helper::getAttributes(array('valuetable' => 'location_attribute_value', 'attrtable' => 'location_attribute', 'key' => 'location_id', 'fieldprefix' => 'locAttr', 'extraParams' => $auth['read'] + array('id' => $args["sensitiveAttrID"]), 'location_type_id' => $locationTypes[0]['id'], 'survey_id' => $args['survey_id'], 'id' => $parentLocId));
         $r .= '<input name="occurrence:sensitivity_precision" id="occSensitive" value="' . (count($site_attributes) > 0 && $site_attributes[$args["sensitiveAttrID"]]['default'] == "1" ? $args["sensitivityPrecision"] : '') . '"/>';
     }
     $r .= '<input name="occAttr:' . $args['occurrence_attribute_id'] . '" id="occattr"/>';
     $r .= '<input name="transaction_id" id="transaction_id"/>';
     $r .= '<input name="user_id" value="' . hostsite_get_user_field('user_id', 1) . '"/>';
     $r .= '</form>';
     // A stub form for AJAX posting when we need to update a sample
     $r .= '<form style="display: none" id="smp-form" method="post" action="' . iform_ajaxproxy_url($node, 'sample') . '">';
     $r .= '<input name="website_id" value="' . $args['website_id'] . '"/>';
     $r .= '<input name="sample:id" id="smpid" />';
     $r .= '<input name="sample:parent_id" value="' . $parentSampleId . '" />';
     $r .= '<input name="sample:survey_id" value="' . $args['survey_id'] . '" />';
     $r .= '<input name="sample:sample_method_id" value="' . $sampleMethods[0]['id'] . '" />';
     $r .= '<input name="sample:entered_sref" id="smpsref" />';
     $r .= '<input name="sample:entered_sref_system" id="smpsref_system" />';
     $r .= '<input name="sample:location_id" id="smploc" />';
     $r .= '<input name="sample:date" value="' . $date . '" />';
     // include a stub input for each transect section sample attribute
     foreach ($attributes as $attr) {
         $r .= '<input id="' . $attr['fieldname'] . '" />';
     }
     $r .= '</form>';
     // tell the Javascript where to get species from.
     // @todo handle diff species lists.
     data_entry_helper::add_resource('jquery_ui');
     data_entry_helper::add_resource('json');
     data_entry_helper::add_resource('autocomplete');
     data_entry_helper::$javascript .= "indiciaData.speciesList1 = " . $args['taxon_list_id'] . ";\n";
     if (!empty($args['main_taxon_filter_field']) && !empty($args['main_taxon_filter'])) {
         data_entry_helper::$javascript .= "indiciaData.speciesList1FilterField = '" . $args['main_taxon_filter_field'] . "';\n";
         $filterLines = helper_base::explode_lines($args['main_taxon_filter']);
         data_entry_helper::$javascript .= "indiciaData.speciesList1FilterValues = '" . json_encode($filterLines) . "';\n";
     }
     data_entry_helper::$javascript .= "bindSpeciesAutocomplete(\"taxonLookupControl\",\"table#transect-input1\",\"" . data_entry_helper::$base_url . "index.php/services/data\", \"" . $args['taxon_list_id'] . "\",\n  indiciaData.speciesList1FilterField, indiciaData.speciesList1FilterValues, {\"auth_token\" : \"" . $auth['read']['auth_token'] . "\", \"nonce\" : \"" . $auth['read']['nonce'] . "\"},\n  \"" . lang::get('LANG_Duplicate_Taxon') . "\", 25, 1);\n\nindiciaData.speciesList1Subset = " . (isset($args['common_taxon_list_id']) && $args['common_taxon_list_id'] != "" ? $args['common_taxon_list_id'] : "-1") . ";\n";
     if (!empty($args['common_taxon_filter_field']) && !empty($args['common_taxon_filter'])) {
         data_entry_helper::$javascript .= "indiciaData.speciesList1SubsetFilterField = '" . $args['common_taxon_filter_field'] . "';\n";
         $filterLines = helper_base::explode_lines($args['common_taxon_filter']);
         data_entry_helper::$javascript .= "indiciaData.speciesList1SubsetFilterValues = '" . json_encode($filterLines) . "';\n";
     }
     data_entry_helper::$javascript .= "indiciaData.speciesList2 = " . (isset($args['second_taxon_list_id']) && $args['second_taxon_list_id'] != "" ? $args['second_taxon_list_id'] : "-1") . ";\n";
     if (!empty($args['second_taxon_filter_field']) && !empty($args['second_taxon_filter'])) {
         data_entry_helper::$javascript .= "indiciaData.speciesList2FilterField = '" . $args['second_taxon_filter_field'] . "';\n";
         $filterLines = helper_base::explode_lines($args['second_taxon_filter']);
         data_entry_helper::$javascript .= "indiciaData.speciesList2FilterValues = " . json_encode($filterLines) . ";\n";
     }
     data_entry_helper::$javascript .= "indiciaData.speciesList2Force = " . (isset($args['force_second']) && $args['force_second'] ? 'true' : 'false') . ";\n";
     if (!isset($args['force_second']) || !$args['force_second']) {
         data_entry_helper::$javascript .= "bindSpeciesAutocomplete(\"taxonLookupControl2\",\"table#transect-input2\",\"" . data_entry_helper::$base_url . "index.php/services/data\", indiciaData.speciesList2,\n  indiciaData.speciesList2FilterField, indiciaData.speciesList2FilterValues, {\"auth_token\" : \"" . $auth['read']['auth_token'] . "\", \"nonce\" : \"" . $auth['read']['nonce'] . "\"},\n  \"" . lang::get('LANG_Duplicate_Taxon') . "\", 25, 2);\n\n";
     }
     data_entry_helper::$javascript .= "indiciaData.speciesList3 = " . (isset($args['third_taxon_list_id']) && $args['third_taxon_list_id'] != "" ? $args['third_taxon_list_id'] : "-1") . ";\n";
     if (!empty($args['third_taxon_filter_field']) && !empty($args['third_taxon_filter'])) {
         data_entry_helper::$javascript .= "indiciaData.speciesList3FilterField = '" . $args['third_taxon_filter_field'] . "';\n";
         $filterLines = helper_base::explode_lines($args['third_taxon_filter']);
         data_entry_helper::$javascript .= "indiciaData.speciesList3FilterValues = " . json_encode($filterLines) . ";\n";
     }
     data_entry_helper::$javascript .= "indiciaData.speciesList3Force = " . (isset($args['force_third']) && $args['force_third'] ? 'true' : 'false') . ";\n";
     if (!isset($args['force_third']) || !$args['force_third']) {
         data_entry_helper::$javascript .= "bindSpeciesAutocomplete(\"taxonLookupControl3\",\"table#transect-input3\",\"" . data_entry_helper::$base_url . "index.php/services/data\", indiciaData.speciesList3,\n    indiciaData.speciesList3FilterField, indiciaData.speciesList3FilterValues, {\"auth_token\" : \"" . $auth['read']['auth_token'] . "\", \"nonce\" : \"" . $auth['read']['nonce'] . "\"},\n    \"" . lang::get('LANG_Duplicate_Taxon') . "\", 25, 3);\n\n";
     }
     data_entry_helper::$javascript .= "indiciaData.speciesList4 = " . (isset($args['fourth_taxon_list_id']) && $args['fourth_taxon_list_id'] != "" ? $args['fourth_taxon_list_id'] : "-1") . ";\n";
     if (!empty($args['fourth_taxon_filter_field']) && !empty($args['fourth_taxon_filter'])) {
         data_entry_helper::$javascript .= "indiciaData.speciesList4FilterField = '" . $args['fourth_taxon_filter_field'] . "';\n";
         $filterLines = helper_base::explode_lines($args['fourth_taxon_filter']);
         data_entry_helper::$javascript .= "indiciaData.speciesList4FilterValues = " . json_encode($filterLines) . ";\n";
     }
     data_entry_helper::$javascript .= "indiciaData.speciesList4Force = " . (isset($args['force_fourth']) && $args['force_fourth'] ? 'true' : 'false') . ";\n";
     // allow js to do AJAX by passing in the information it needs to post forms
     if (!isset($args['force_fourth']) || !$args['force_fourth']) {
         data_entry_helper::$javascript .= "bindSpeciesAutocomplete(\"taxonLookupControl4\",\"table#transect-input4\",\"" . data_entry_helper::$base_url . "index.php/services/data\", indiciaData.speciesList4,\n  indiciaData.speciesList4FilterField, indiciaData.speciesList4FilterValues, {\"auth_token\" : \"" . $auth['read']['auth_token'] . "\", \"nonce\" : \"" . $auth['read']['nonce'] . "\"},\n  \"" . lang::get('LANG_Duplicate_Taxon') . "\", 25, 4);\n\n";
     }
     data_entry_helper::$javascript .= "indiciaData.indiciaSvc = '" . data_entry_helper::$base_url . "';\n";
     data_entry_helper::$javascript .= "indiciaData.readAuth = {nonce: '" . $auth['read']['nonce'] . "', auth_token: '" . $auth['read']['auth_token'] . "'};\n";
     data_entry_helper::$javascript .= "indiciaData.transect = " . $parentLocId . ";\n";
     data_entry_helper::$javascript .= "indiciaData.parentSample = " . $parentSampleId . ";\n";
     data_entry_helper::$javascript .= "indiciaData.sections = " . json_encode($sections) . ";\n";
     if (function_exists('module_exists') && module_exists('easy_login')) {
         data_entry_helper::$javascript .= "indiciaData.easyLogin = true;\n";
         $userId = hostsite_get_user_field('indicia_user_id');
         if (!empty($userId)) {
             data_entry_helper::$javascript .= "indiciaData.UserID = " . $userId . ";\n";
         } else {
             return '<p>Easy Login active but could not identify user</p>';
         }
         // something is wrong
     } else {
         data_entry_helper::$javascript .= "indiciaData.easyLogin = false;\n";
         data_entry_helper::$javascript .= "indiciaData.CMSUserAttrID = " . $cmsUserAttr['attributeId'] . ";\n";
         data_entry_helper::$javascript .= "indiciaData.CMSUserID = " . $user->uid . ";\n";
     }
     // Do an AJAX population of the grid rows.
     data_entry_helper::$javascript .= "loadSpeciesList();\njQuery('#tabs').bind('tabsshow', function(event, ui) {\n    var target = ui.panel;\n    // first get rid of any previous tables\n    jQuery('table.sticky-header').remove();\n    jQuery('table.sticky-enabled thead.tableHeader-processed').removeClass('tableHeader-processed');\n    jQuery('table.sticky-enabled.tableheader-processed').removeClass('tableheader-processed');\n    jQuery('table.species-grid.sticky-enabled').removeClass('sticky-enabled');\n    var table = jQuery('#'+target.id+' table.species-grid');\n    if(table.length > 0) {\n        table.addClass('sticky-enabled');\n        if(typeof Drupal.behaviors.tableHeader == 'object') // Drupal 7\n          Drupal.behaviors.tableHeader.attach(table.parent());\n        else // Drupal6 : it is a function\n          Drupal.behaviors.tableHeader(target);\n    }\n    // remove any hanging autocomplete select list.\n    jQuery('.ac_results').hide();\n});";
     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)
 {
     global $user;
     data_entry_helper::$helpTextPos = 'before';
     $checks = self::check_prerequisites();
     $args = self::getArgDefaults($args);
     if ($checks !== true) {
         return $checks;
     }
     iform_load_helpers(array('map_helper'));
     data_entry_helper::add_resource('jquery_form');
     self::$ajaxFormUrl = iform_ajaxproxy_url($node, 'loc-smp-occ');
     self::$ajaxFormLocationUrl = iform_ajaxproxy_url($node, 'location');
     self::$ajaxFormSampleUrl = iform_ajaxproxy_url($node, 'sample');
     $auth = data_entry_helper::get_read_write_auth($args['website_id'], $args['password']);
     $settings = array('SiteLocationType' => helper_base::get_termlist_terms($auth, 'indicia:location_types', array(empty($args['location_type_term']) ? 'TreeSite' : $args['location_type_term'])), 'TreeLocationType' => helper_base::get_termlist_terms($auth, 'indicia:location_types', array(empty($args['tree_type_term']) ? 'Tree' : $args['tree_type_term'])), 'locationId' => isset($_GET['id']) ? $_GET['id'] : null, 'canAllocUser' => $args['manager_permission'] == "" || user_access($args['manager_permission']));
     $settings['attributes'] = data_entry_helper::getAttributes(array('id' => $settings['locationId'], 'valuetable' => 'location_attribute_value', 'attrtable' => 'location_attribute', 'key' => 'location_id', 'fieldprefix' => 'locAttr', 'extraParams' => $auth['read'], 'survey_id' => $args['survey_id'], 'location_type_id' => $settings['SiteLocationType'][0]['id'], 'multiValue' => true));
     $settings['tree_attributes'] = data_entry_helper::getAttributes(array('valuetable' => 'location_attribute_value', 'attrtable' => 'location_attribute', 'key' => 'location_id', 'fieldprefix' => 'locAttr', 'extraParams' => $auth['read'], 'survey_id' => $args['survey_id'], 'location_type_id' => $settings['TreeLocationType'][0]['id'], 'multiValue' => true));
     if ($args['allow_user_assignment']) {
         if (false == ($settings['cmsUserAttr'] = extract_cms_user_attr($settings['attributes']))) {
             return 'This form is designed to be used with the "CMS User ID" attribute setup for Site locations in the survey, or the "Allow users to be assigned to locations" option unticked.';
         }
         // keep a copy of the cms user ID attribute so we can use it later.
         self::$cmsUserAttrId = $settings['cmsUserAttr']['attributeId'];
         $found = false;
         foreach ($settings['tree_attributes'] as $idx => $attr) {
             if (strcasecmp($attr['caption'], 'Recorder Name') === 0) {
                 data_entry_helper::$javascript .= "indiciaData.assignedRecorderID = " . $attr['attributeId'] . ";\n";
                 $found = true;
                 break;
             }
         }
         if (!$found) {
             return 'This form is designed to be used with the "Recorder Name" attribute setup for Tree locations in the survey, or the "Allow users to be assigned to locations" option unticked.';
         }
     }
     // TBD data drive
     $definitions = array(array("attr" => "111", "term" => "WD", "target" => "112", "required" => true, "title" => "You must pick the dominant species from this drop down list when the WD (Dominant Species) checkbox is set."), array("attr" => "111", "term" => "WP", "target" => "113", "required" => false, "title" => "If known, you may enter the year that the woodland was planted in when the WP (Planted Date) checkbox is set."));
     $common = "var check_attrs = function(){\n";
     data_entry_helper::$javascript .= "var checkbox_changed_base = function(changedSelector, targetSelector, required){\n  \$(changedSelector).closest('span').find('label.inline-error').remove();\n  \$(changedSelector).closest('span').find('.ui-state-error').removeClass('ui-state-error');\n  \$(changedSelector).closest('span').find('label.error').remove();\n  \$(changedSelector).closest('span').find('.error').removeClass('error');\n  if(\$(changedSelector).attr('checked'))\n    \$(targetSelector).addClass(required ? 'required' : 'notrequired').closest('span').show();\n  else {\n    \$(targetSelector).removeClass('required').val('').closest('span').hide();\n  }\n};\nvar check_attr_def = [];\ncheck_attrs = function(){\n  for(var i=0; i<check_attr_def.length; i++){\n    checkbox_changed_base(check_attr_def[i][0], check_attr_def[i][1], check_attr_def[i][2]);\n  }\n}\n";
     foreach ($definitions as $defn) {
         data_entry_helper::$javascript .= "\$('[id^=locAttr\\\\:" . $defn["attr"] . "\\\\:]:checkbox').each(function(idx,elem){\n  if(\$('label[for='+\$(elem).attr('id').replace(/:/g,'\\\\:')+']').html() == '" . $defn["term"] . "'){\n    var tgt = \$('#locAttr\\\\:" . $defn["target"] . "');\n    tgt.prev('label').remove();\n    tgt.next('br').remove();\n    var span = \$('<span/>');\n    \$(elem).closest('span').append(span);\n    span.append(tgt);" . ($defn["required"] ? "\n    span.append('<span class=\"deh-required\">*</span>');" : "") . "\n    tgt.attr('title','" . $defn["title"] . "');\n    \$(elem).change(function(e){checkbox_changed_base(e.target, '#locAttr\\\\:" . $defn["target"] . "', " . ($defn["required"] ? "true" : "false") . ");});\n    check_attr_def.push([elem, '#locAttr\\\\:" . $defn["target"] . "', " . ($defn["required"] ? "true" : "false") . "]);\n  }\n});\n";
     }
     data_entry_helper::$javascript .= "check_attrs();\nindiciaData.trees = {};\n";
     $settings['trees'] = array();
     if ($settings['locationId']) {
         data_entry_helper::load_existing_record($auth['read'], 'location', $settings['locationId']);
         // Work out permissions for this user
         $canEdit = $args['manager_permission'] == "" || user_access($args['manager_permission']);
         if ($args['allow_user_assignment'] && isset($settings['cmsUserAttr']['default']) && !empty($settings['cmsUserAttr']['default'])) {
             foreach ($settings['cmsUserAttr']['default'] as $value) {
                 // multi value
                 if ($value['default'] == $user->uid) {
                     // comparing string against int so no triple equals
                     $canEdit = true;
                     break;
                 }
             }
         }
         if (!$canEdit) {
             return 'You do not have access to this site.';
         }
         $trees = data_entry_helper::get_population_data(array('table' => 'location', 'extraParams' => $auth['read'] + array('view' => 'detail', 'parent_id' => $settings['locationId'], 'deleted' => 'f', 'orderby' => 'name'), 'nocache' => true));
         foreach ($trees as $tree) {
             $id = $tree['id'];
             data_entry_helper::$javascript .= "indiciaData.trees[{$id}] = {'id':'" . $tree['id'] . "','name':'" . str_replace("'", "\\'", $tree['name']) . "','geom':'" . $tree['centroid_geom'] . "','sref':'" . $tree['centroid_sref'] . "','system':'" . $tree['centroid_sref_system'] . "'};\n";
             $settings['trees'][$id] = $tree;
         }
     }
     $r = '<div id="controls">';
     $headerOptions = array('tabs' => array('#site-details' => lang::get('Site Details')));
     $tabOptions = array('divId' => 'controls', 'style' => 'Tabs');
     if ($settings['locationId']) {
         $headerOptions['tabs']['#site-trees'] = lang::get('Tree Details');
         $tabOptions['active'] = '#site-trees';
     }
     $r .= data_entry_helper::tab_header($headerOptions);
     data_entry_helper::enable_tabs($tabOptions);
     $settings['treeSampleMethod'] = helper_base::get_termlist_terms($auth, 'indicia:sample_methods', array('TreeInitialRegistration'));
     // TODO put in error check, add in $arg driving of text value
     $settings['treeSampleMethod'] = $settings['treeSampleMethod'][0];
     $r .= self::get_site_tab($auth, $args, $settings);
     if ($settings['locationId']) {
         $r .= self::get_site_trees_tab($auth, $args, $settings);
         data_entry_helper::enable_validation('tree-form');
         data_entry_helper::setup_jquery_validation_js();
     }
     $r .= '</div>';
     // controls
     data_entry_helper::enable_validation('input-form');
     if (function_exists('drupal_set_breadcrumb')) {
         $breadcrumb = array();
         $breadcrumb[] = l(lang::get('Home'), '<front>');
         $breadcrumb[] = l(lang::get('Sites'), $args['sites_list_path']);
         if ($settings['locationId']) {
             $breadcrumb[] = data_entry_helper::$entity_to_load['location:name'];
         } else {
             $breadcrumb[] = lang::get('New Site');
         }
         drupal_set_breadcrumb($breadcrumb);
     }
     // Inform JS where to post data to for AJAX form saving
     data_entry_helper::$javascript .= 'indiciaData.ajaxFormPostUrl="' . self::$ajaxFormUrl . "\";\n";
     data_entry_helper::$javascript .= 'indiciaData.ajaxFormPostLocationUrl="' . self::$ajaxFormLocationUrl . "\";\n";
     data_entry_helper::$javascript .= 'indiciaData.ajaxFormPostSampleUrl="' . self::$ajaxFormSampleUrl . "\";\n";
     data_entry_helper::$javascript .= 'indiciaData.website_id="' . $args['website_id'] . "\";\n";
     data_entry_helper::$javascript .= "indiciaData.indiciaSvc = '" . data_entry_helper::$base_url . "';\n";
     data_entry_helper::$javascript .= "indiciaData.readAuth = {nonce: '" . $auth['read']['nonce'] . "', auth_token: '" . $auth['read']['auth_token'] . "'};\n";
     data_entry_helper::$javascript .= "indiciaData.currentTree = '';\n";
     data_entry_helper::$javascript .= "indiciaData.treeTypeId = '" . $settings['TreeLocationType'][0]['id'] . "';\n";
     data_entry_helper::$javascript .= "indiciaData.treeDeleteConfirm = \"" . lang::get('Are you sure you wish to delete tree') . "\";\n";
     data_entry_helper::$javascript .= "indiciaData.treeInsertConfirm = \"" . lang::get('Are you sure you wish to create a new tree (make sure you have saved any data)') . "\";\n";
     data_entry_helper::$javascript .= "indiciaData.treeChangeConfirm = \"" . lang::get('Do you wish to save the currently unsaved changes you have made to the Tree Details?') . "\";\n";
     data_entry_helper::$javascript .= "indiciaData.treeSampleMethodID = \"" . $settings['treeSampleMethod']['id'] . "\";\n";
     data_entry_helper::$javascript .= "indiciaData.newVisitDialog = \"" . lang::get('You have just created a new tree. You can now create the first phenology observation data, or you can leave it until later. Do you wish to create the phenology observation data now? (This will open in a new window.)') . "\";\n";
     data_entry_helper::$javascript .= "indiciaData.existingVisitDialog = \"" . lang::get('You have just modified an existing tree. Do you wish to create phenology observation data now? (This will open in a new window.)') . "\";\n";
     data_entry_helper::$javascript .= "indiciaData.visitURL = \"" . ($args['visit_path'] . (strpos($args['visit_path'], '?') === false ? '?' : '&') . "new=1&location_id=") . "\";\n";
     $r .= '<a id="visit_link" style="display:none;" href="" target="_blank" />';
     if ($settings['locationId']) {
         data_entry_helper::$onload_javascript .= "var first=true;\njQuery.each(indiciaData.trees, function(idx, tree) {\n  if(first) selectTree(tree.id, true);  \nfirst=false\n});\nif(first) insertTree();\n";
     }
     return $r;
 }
 private static function location_control($args, $readAuth, $node)
 {
     global $user;
     $siteUrlParams = self::get_site_url_params();
     $ctrl = '';
     // survey_id either comes from the location_type control, or from presets; in that order.
     // loctools is not appropriate here as it is based on a node, for which this is a very simple one, invoking other nodes for the sample creation
     // need to scan param_presets for survey_id..
     $presets = get_options_array_with_user_data($args['param_presets']);
     if ($siteUrlParams[self::$SurveyKey]['value'] == '') {
         return '<p>' . lang::get('The location selection control requires that survey_id {' . $siteUrlParams[self::$SurveyKey]['value'] . '} is set in either the presets or mapped against the location_type, in the form parameters.') . '</p>';
     }
     $attrArgs = array('valuetable' => 'location_attribute_value', 'attrtable' => 'location_attribute', 'key' => 'location_id', 'fieldprefix' => 'locAttr', 'extraParams' => $readAuth, 'survey_id' => $siteUrlParams[self::$SurveyKey]['value']);
     if ($siteUrlParams[self::$locationTypeKey]['value'] != "") {
         $attrArgs['location_type_id'] = $siteUrlParams[self::$locationTypeKey]['value'];
     }
     $locationAttributes = data_entry_helper::getAttributes($attrArgs, false);
     $cmsAttr = extract_cms_user_attr($locationAttributes, false);
     if (!$cmsAttr) {
         return '<p>' . lang::get('The location selection control requires that CMS User ID location attribute is defined for locations in this survey {' . $siteUrlParams[self::$SurveyKey]['value'] . '}. If restricting to a particular location type, this must be set in the parameters page for this form instance.') . '</p>';
     }
     $attrListArgs = array('nocache' => true, 'extraParams' => array_merge(array('view' => 'list', 'website_id' => $args['website_id'], 'location_attribute_id' => $cmsAttr['attributeId'], 'raw_value' => $user->uid), $readAuth), 'table' => 'location_attribute_value');
     $attrList = data_entry_helper::get_population_data($attrListArgs);
     if (isset($attrList['error'])) {
         return $attrList['error'];
     }
     $locationIDList = array();
     foreach ($attrList as $attr) {
         $locationIDList[] = $attr['location_id'];
     }
     $locationListArgs = array('nocache' => true, 'extraParams' => array_merge(array('view' => 'list', 'website_id' => $args['website_id'], 'id' => $locationIDList, 'orderby' => 'name'), $readAuth), 'table' => 'location');
     if ($siteUrlParams[self::$locationTypeKey]['value'] != "") {
         $locationListArgs['extraParams']['location_type_id'] = $siteUrlParams[self::$locationTypeKey]['value'];
     }
     $locationList = data_entry_helper::get_population_data($locationListArgs);
     if (isset($locationList['error'])) {
         return $locationList['error'];
     }
     $ctrlid = 'calendar-location-select-' . $node->nid;
     $ctrl .= '<label for="' . $ctrlid . '" class="location-select-label">' . lang::get('Filter by site') . ':</label> <select id="' . $ctrlid . '" class="location-select">' . '<option value="" class="location-select-option" ' . (self::$siteUrlParams[self::$locationKey]['value'] == null ? 'selected=\\"selected\\" ' : '') . '>' . lang::get('All sites') . '</option>';
     foreach ($locationList as $location) {
         $ctrl .= '<option value=' . $location['id'] . ' class="location-select-option" ' . (self::$siteUrlParams[self::$locationKey]['value'] == $location['id'] ? 'selected=\\"selected\\" ' : '') . '>' . $location['name'] . (isset($args['includeSrefInLocationFilter']) && $args['includeSrefInLocationFilter'] ? ' (' . $location['centroid_sref'] . ')' : '') . '</option>';
     }
     $ctrl .= '</select>';
     /*
         // get the url parameters. Don't use $_GET, because it contains any parameters that are not in the
         // URL when search friendly URLs are used (e.g. a Drupal path node/123 is mapped to index.php?q=node/123
         // using Apache mod_alias but we don't want to know about that)
         $reloadUrl = data_entry_helper::get_reload_link_parts();
         // find the names of the params we must not include
         foreach ($reloadUrl['params'] as $key => $value) {
           if (!array_key_exists($key, self::$siteUrlParams)){
             $reloadUrl['path'] .= (strpos($reloadUrl['path'],'?')===false ? '?' : '&')."$key=$value";
           }
         }
         $param=(strpos($reloadUrl['path'],'?')===false ? '?' : '&').self::$locationKey.'='; */
     self::set_up_control_change($ctrlid, self::$locationKey, array());
     return $ctrl;
 }
 /**
  * Get the location control as a select dropdown.
  * Default control ordering is by name.
  * reportProvidesOrderBy option should be set to true if the control is populated by a report that
  * provides its own Order By statement, if the reportProvidesOrderBy option is not set in this situation, then the report
  * will have two Order By statements and will fail.
  */
 protected static function get_control_treelocationselect($auth, $args, $tabAlias, $options)
 {
     global $indicia_templates;
     global $user;
     data_entry_helper::$helpTextPos = 'before';
     $indicia_templates['two-col-50'] = '<div class="two_columns"><div id="leftcol" class="column">{col-1}</div><div id="rightcol" class="column">{col-2}</div></div>';
     $r = "";
     if (!array_key_exists('location_type_id', $options)) {
         return "Control [tree location select] must be provided with a location_type_id.<br />";
     }
     if (!array_key_exists('tree_location_type_id', $options)) {
         return "Control [tree location select] must be provided with a tree_location_type_id.<br />";
     }
     $r .= '<span style="display:none;">' . print_r($_SERVER, true) . '</span>';
     if (isset($_SERVER['HTTP_REFERER']) && $_SERVER['HTTP_REFERER'] != '' && ($referer = self::getRefererPath()) !== false) {
         $r .= '<input name="referer" type="hidden" value="' . $referer . '" />';
     }
     $attrArgs = array('valuetable' => 'sample_attribute_value', 'attrtable' => 'sample_attribute', 'key' => 'sample_id', 'extraParams' => $auth['read'], 'survey_id' => $args['survey_id'], 'fieldprefix' => 'smpAttr');
     $attrArgs['extraParams'] += array('query' => json_encode(array('in' => array('caption' => array('No Understorey Observed')))));
     $smpAttrs = data_entry_helper::getAttributes($attrArgs, false);
     if (!count($smpAttrs)) {
         throw new exception(lang::get('This form must be used with an "No Understorey Observed" sample attribute.'));
     }
     data_entry_helper::$javascript .= "\n// assume map projection is same as indicia internal\n// Create vector layers: one to display the Parent Site onto, and another for the tree locations list\n// the default edit layer is used for this sample\nvar labelRule = new OpenLayers.Rule({\n        symbolizer: {\n          label : \"\${name}\",\n          fontSize: \"16px\",\n          fontFamily: \"Verdana, Arial, Helvetica,sans-serif\",\n          fontWeight: \"bold\",\n          fontColor: \"#FF0000\",\n          labelAlign: \"cm\",\n          labelYOffset: \"-15\"\n        }\n      });\nvar defaultStyle = new OpenLayers.Style({pointRadius: 6,fillColor: \"Red\",fillOpacity: 0.3,strokeColor: \"Yellow\",strokeWidth: 1});\ndefaultStyle.addRules([labelRule]);\n\nParentLocStyleMap = new OpenLayers.StyleMap({\"default\": new OpenLayers.Style({strokeColor: \"Yellow\",fillOpacity: 0,strokeWidth: 4})});\nParentLocationLayer = new OpenLayers.Layer.Vector('Parents',{styleMap: ParentLocStyleMap,displayInLayerSwitcher: false});\n\nTreeStyleMap = new OpenLayers.StyleMap({\"default\": defaultStyle});\nTreeListLayer = new OpenLayers.Layer.Vector('Trees',{styleMap: TreeStyleMap, displayInLayerSwitcher: false});\nvar _zoomToExtent = function(bounds, layer){\n  var dy = Math.max(10, (bounds.top-bounds.bottom) * layer.map.div.settings.maxZoomBuffer);\n  var dx = Math.max(10, (bounds.right-bounds.left) * layer.map.div.settings.maxZoomBuffer);\n  bounds.top = bounds.top + dy;\n  bounds.bottom = bounds.bottom - dy;\n  bounds.right = bounds.right + dx;\n  bounds.left = bounds.left - dx;\n  if (layer.map.getZoomForExtent(bounds) > layer.map.div.settings.maxZoom) {\n    // if showing something small, don't zoom in too far\n    layer.map.setCenter(bounds.getCenterLonLat(), layer.map.div.settings.maxZoom);\n  } else {\n    // Set the default view to show something a bit larger than the size of the grid square\n    layer.map.zoomToExtent(bounds);\n  }\n};\n\$('.scPresence:checkbox').change(function(){\n  var cells = \$(this).closest('tr').find('.scOccAttrCell');\n  if(\$(this).attr('checked')){\n    cells.find('select').addClass('required').removeAttr('disabled');\n    cells.append('<span class=\"deh-required\">*</span>');\n  } else {\n    cells.find('select').removeClass('required').val('').attr('disabled',true);\n    cells.find('.deh-required').remove();\n    cells.find('label.error').remove();\n    cells.find('.error').removeClass('error');\n    cells.find('.inline-error').remove();\n    cells.find('.ui-state-error').removeClass('ui-state-error');\n  }\n});\n\$('.scPresence:checkbox').change();\nindiciaData.searchUpdatesSref=false;\n";
     data_entry_helper::$late_javascript .= "\njQuery('[name=" . str_replace(':', '\\\\:', $smpAttrs[0]['id']) . "],[name^=" . str_replace(':', '\\\\:', $smpAttrs[0]['id']) . "\\\\:]').filter(':checkbox').rules('add', {no_observation: true});\n\$.validator.addMethod('no_observation', function(arg1, arg2){\n  // ignore the hidden zeroing field asscoiated with the boolean\n  if(!\$(arg2).filter(':checkbox').length) return true;\n  var numRows = jQuery('.scPresence').filter(':checkbox').filter('[checked]').length;\n  var isChecked = jQuery(arg2).attr('checked') != false;\n  if(isChecked) return(numRows==0)\n  else if(numRows>0) return true;\n  return false;\n},\n  \"The <strong>" . lang::get('No Understorey Observed') . "</strong> checkbox must be selected if there are no species entered in the Flowering plant phenology grid, otherwise it must be unchecked.\");\n\n";
     self::$treeOccurrenceRecord = false;
     if (self::$loadedSampleId) {
         $location_id = data_entry_helper::$entity_to_load['sample:location_id'];
     } else {
         if (isset($_GET['location_id'])) {
             $location_id = $_GET['location_id'];
         } else {
             $location_id = false;
         }
     }
     $attrArgs = array('valuetable' => 'location_attribute_value', 'attrtable' => 'location_attribute', 'key' => 'location_id', 'extraParams' => $auth['read'], 'survey_id' => $args['survey_id'], 'fieldprefix' => 'locAttr', 'location_type_id' => $options['tree_location_type_id']);
     if ($location_id) {
         $attrArgs['id'] = $location_id;
     }
     $attrArgs['extraParams'] += array('query' => json_encode(array('in' => array('caption' => array('Recorder Name')))));
     $locAttrs = data_entry_helper::getAttributes($attrArgs, false);
     $attrArgs = array('valuetable' => 'sample_attribute_value', 'attrtable' => 'sample_attribute', 'key' => 'sample_id', 'extraParams' => $auth['read'], 'survey_id' => $args['survey_id'], 'fieldprefix' => 'smpAttr', 'sample_method_id' => $args['sample_method_id']);
     $attrArgs['extraParams'] += array('query' => json_encode(array('in' => array('caption' => array('Recorder Name')))));
     $smpAttrs = data_entry_helper::getAttributes($attrArgs, false);
     if (!count($locAttrs)) {
         throw new exception(lang::get('This form must be used with a "Recorder Name" tree location attribute.'));
     }
     if (!count($smpAttrs)) {
         throw new exception(lang::get('This form must be used with a "Recorder Name" sample attribute.'));
     }
     data_entry_helper::$javascript .= "indiciaData.assignedRecorderAttrID='" . $locAttrs[0]['attributeId'] . "';\n";
     data_entry_helper::$javascript .= "indiciaData.recorderNameID='" . $smpAttrs[0]['id'] . "';\n";
     if ($location_id) {
         $r .= '<div class="page-notice ui-state-highlight ui-corner-all">This visit is registered against the tree highlighted on the map. All fields followed by a red asterisk (<span class="deh-required">*</span>) must be filled in. You can not modify any field that is greyed out.</div>';
         $locationRecord = data_entry_helper::get_population_data(array('table' => 'location', 'extraParams' => $auth['read'] + array('id' => $location_id, "view" => "detail"), 'nocache' => true));
         if (count($locationRecord) != 1) {
             throw new exception(lang::get('Could not identify tree location : ID ') . $location_id);
         }
         if (count($locAttrs) && count($smpAttrs)) {
             data_entry_helper::$entity_to_load[$smpAttrs[0]['fieldname']] = $locAttrs[0]['default'];
         }
         $parentLocationRecord = data_entry_helper::get_population_data(array('table' => 'location', 'extraParams' => $auth['read'] + array('id' => $locationRecord[0]['parent_id'], "view" => "detail"), 'nocache' => true));
         if (count($parentLocationRecord) != 1) {
             throw new exception(lang::get('Could not identify site location : ID ') . $locationRecord[0]['parent_id']);
         }
         // TODO make sure user is allocated this tree, or if sample already exists, that they created this sample, or they are admin
         $registrationSampleRecord = data_entry_helper::get_population_data(array('table' => 'sample', 'extraParams' => $auth['read'] + array('location_id' => $locationRecord[0]['id'], "view" => "detail", "sample_method_id" => $args['reg_sample_method_id']), 'nocache' => true));
         if (count($registrationSampleRecord) != 1) {
             throw new exception(lang::get('Could not identify registration sample for tree location ID ') . $locationRecord[0]['id']);
         }
         $registrationOccurrenceRecord = data_entry_helper::get_population_data(array('table' => 'occurrence', 'extraParams' => $auth['read'] + array('sample_id' => $registrationSampleRecord[0]['id'], "view" => "detail"), 'nocache' => true));
         if (count($registrationOccurrenceRecord) != 1) {
             throw new exception(lang::get('Could not identify registration occurrence for tree location ID ') . $locationRecord[0]['id']);
         }
         if (self::$loadedSampleId) {
             self::$treeOccurrenceRecord = data_entry_helper::get_population_data(array('table' => 'occurrence', 'extraParams' => $auth['read'] + array('sample_id' => self::$loadedSampleId, "view" => "detail", 'taxa_taxon_list_id' => $registrationOccurrenceRecord[0]['taxa_taxon_list_id']), 'nocache' => true));
         } else {
             // need to set sref & system to match tree.
             data_entry_helper::$javascript .= "\n\$('#imp-sref').val('" . $locationRecord[0]['centroid_sref'] . "');\n";
         }
         $r .= data_entry_helper::text_input(array('label' => lang::get('Site'), 'fieldname' => 'dummy:site_name', 'class' => 'control-width-4 tree-details-readonly', 'default' => $parentLocationRecord[0]["name"], 'disabled' => ' readonly="readonly"'));
         // don't need a hidden control.
         $r .= data_entry_helper::text_input(array('label' => lang::get('Tree'), 'fieldname' => 'dummy:tree_name', 'class' => 'control-width-4 tree-details-readonly', 'default' => $locationRecord[0]["name"], 'disabled' => ' readonly="readonly"'));
         $r .= '<input name="sample:location_id" type="hidden" value="' . $location_id . '" />';
         $r .= data_entry_helper::text_input(array('label' => lang::get('Tree Species'), 'fieldname' => 'dummy:tree_species', 'class' => 'control-width-4 tree-details-readonly', 'default' => $registrationOccurrenceRecord[0]["taxon"], 'disabled' => ' readonly="readonly"'));
         if (self::$treeOccurrenceRecord && count(self::$treeOccurrenceRecord)) {
             $r .= '<input name="sc:tree:' . self::$treeOccurrenceRecord[0]['id'] . ':present" type="hidden" value="' . self::$treeOccurrenceRecord[0]['taxa_taxon_list_id'] . '" />';
         } else {
             $r .= '<input name="sc:tree::present" type="hidden" value="' . $registrationOccurrenceRecord[0]['taxa_taxon_list_id'] . '" />';
         }
         if (self::$loadedSampleId) {
             $systems = array(data_entry_helper::$entity_to_load['sample:entered_sref_system'] => data_entry_helper::$entity_to_load['sample:entered_sref_system']);
         } else {
             $systems = array($locationRecord[0]['centroid_sref_system'] => $locationRecord[0]['centroid_sref_system']);
         }
         $r .= data_entry_helper::sref_and_system(array_merge(array('label' => lang::get('Tree Grid Ref'), 'systems' => $systems, 'disabled' => ' readonly="readonly"', 'validation' => '', 'class' => 'control-width-4 tree-details-readonly'), $options));
         data_entry_helper::$javascript .= "\nmapInitialisationHooks.push(function (div) {\n  'use strict';\n  \$.getJSON(ParentLocationLayer.map.div.settings.indiciaSvc + 'index.php/services/data/location/'+" . $locationRecord[0]['parent_id'] . " +\r\n            '?mode=json&view=detail' + ParentLocationLayer.map.div.settings.readAuth + '&callback=?', function(data) {\n    if (typeof data.error!=='undefined') {\n      alert(data.error);\n      return;\n    }\r\n    if (data.length>0) {\r\n      var geomwkt = data[0].boundary_geom || data[0].centroid_geom;\r\n      var parser = new OpenLayers.Format.WKT();\r\n      var feature = parser.read(geomwkt);\r\n      ParentLocationLayer.addFeatures([feature]);\n      // no zoom, but put in other trees at site - will add our name.\n      \$.getJSON(TreeListLayer.map.div.settings.indiciaSvc + 'index.php/services/data/location?parent_id='+data[0].id +\n            '&mode=json&view=detail' + TreeListLayer.map.div.settings.readAuth + '&callback=?', function(tdata) {\n        if (typeof tdata.error!=='undefined') {\n          alert(tdata.error);\n          return;\n        }\n        if (tdata.length>0) {\n          for(var i=0; i<tdata.length; i++){\n            var geomwkt = tdata[i].centroid_geom, feature;\n            var parser = new OpenLayers.Format.WKT();\n            var feature = parser.read(geomwkt);\n            feature.attributes.name = tdata[i].name;\n            TreeListLayer.addFeatures(feature);\n      }}});\r\n  }});\n  if(div.map.editLayer.features.length>0) {\n    var highlighter = new OpenLayers.Control.SelectFeature(div.map.editLayer, {highlightOnly: true});\n    div.map.addControl(highlighter);\n    highlighter.activate();\n    highlighter.highlight(div.map.editLayer.features[0]);\n  }\n});";
         if (self::$loadedSampleId) {
             data_entry_helper::$javascript .= "\n\$('[name=sample\\\\:date]').change(function(){ // sample exists so just check that no sample already taken on that date.\n  \$.getJSON(ParentLocationLayer.map.div.settings.indiciaSvc + 'index.php/services/data/sample?location_id='+" . $locationRecord[0]['id'] . " +\n      '&sample_method_id=" . $args['sample_method_id'] . "&mode=json&view=detail' + ParentLocationLayer.map.div.settings.readAuth + '&callback=?', function(data) {\n    if (typeof data.error!=='undefined') {\n      alert(data.error);\n      return;\n    }\n    var date = \$('[name=sample\\\\:date]').val();\n    date = date.split('/');\n    for(var i = 0; i < data.length; i++){\n      if(data[i][\"id\"] != " . self::$loadedSampleId . " && data[i][\"date_start\"] == date[2]+'-'+date[1]+'-'+date[0]){\n        alert(\"Warning: there is already a visit recorded for this tree on \"+data[i][\"date_start\"]);\n        return;\n    }}\n  });\n});\n";
         } else {
             data_entry_helper::$javascript .= "\n\$('[name=sample\\\\:date]').change(function(){\n  \$.getJSON(ParentLocationLayer.map.div.settings.indiciaSvc + 'index.php/services/data/sample?location_id='+" . $locationRecord[0]['id'] . " +\n  \t\t'&sample_method_id=" . $args['sample_method_id'] . "&mode=json&view=detail&orderby=date_start' + ParentLocationLayer.map.div.settings.readAuth + '&callback=?', function(data) {\n    if (typeof data.error!=='undefined') {\n      alert(data.error);\n      return;\n    }\n    var date = \$('[name=sample\\\\:date]').val();\n    date = date.split('/');\n    for(var i = 0; i < data.length; i++){\n      if(data[i][\"date_start\"] == date[2]+'-'+date[1]+'-'+date[0]) {\n        alert(\"Warning: there is already a visit recorded for this tree on \"+data[i][\"date_start\"]);\n        return;\n      }\n    }\n    for(var i = 0; i < data.length; i++){\n      sdate = data[i][\"date_start\"].split('-');\n      if(sdate[0] > date[2] || (sdate[0] == date[2] && (sdate[1] > date[1] || (sdate[1] == date[1] && sdate[2] >= date[0])))) {\n        alert(\"Warning: there is already a visit recorded for this tree after this date, on \"+data[i][\"date_start\"]);\n        break;\n      }\n    }\n    for(var i = data.length-1; i >=0; i--){\n      sdate = data[i][\"date_start\"].split('-');\n      if(sdate[0] < date[2] || (sdate[0] == date[2] && (sdate[1] < date[1] || (sdate[1] == date[1] && sdate[2] <= date[0])))) {\n        if(confirm(\"There was a previously recorded visit for this tree prior to this date, on \"+data[i][\"date_start\"]+'. Do you wish to use the data from this earlier visit as a starting point? (This will not affect any previously recorded observations - it will just fill in this form with the data from your previous visit, excluding the field diary. You can then update the data with any changes for this visit.)')){\n          // this is an initial save: all attributes have vanilla names.\n          \$('.scPresence').removeAttr('checked');\n          var cells = \$('.scOccAttrCell');\n          \$('#" . data_entry_helper::$validated_form_id . "').find('label.error').remove();\n          \$('#" . data_entry_helper::$validated_form_id . "').find('.error').removeClass('error');\n          \$('#" . data_entry_helper::$validated_form_id . "').find('.inline-error').remove();\n          \$('#" . data_entry_helper::$validated_form_id . "').find('.ui-state-error').removeClass('ui-state-error');\n          cells.find('select').removeClass('required').val('').attr('disabled',true);\n          cells.find('.deh-required').remove();\n          \$('[name^=sc\\\\:tree\\\\:\\\\:occAttr\\\\:]').val('');\n          \$.getJSON(ParentLocationLayer.map.div.settings.indiciaSvc + 'index.php/services/data/occurrence?sample_id='+data[i]['id'] +\n              '&mode=json&view=detail' + ParentLocationLayer.map.div.settings.readAuth + '&callback=?', function(odata) {\n            if (typeof odata.error!=='undefined') {\n              alert(odata.error);\n              return;\n            }\n            var occIDs = [];\n            if(odata.length>0){\n              for(var j = 0; j < odata.length; j++) {\n                occIDs.push(odata[j].id);\n                \$('.scPresence[value='+odata[j].taxa_taxon_list_id+']').each(function(idx, elem){\n                  var cells = \$(elem).attr('checked',true).closest('tr').find('.scOccAttrCell');\n                  cells.find('select').addClass('required').removeAttr('disabled');\n                  cells.append('<span class=\"deh-required\">*</span>');\n                });\n              }\n              \$.getJSON(ParentLocationLayer.map.div.settings.indiciaSvc + 'index.php/services/data/occurrence_attribute_value' +\n                  '?query={\"in\":{\"occurrence_id\":'+JSON.stringify(occIDs) +'}}' +\n                  '&mode=json&view=list' + ParentLocationLayer.map.div.settings.readAuth + '&callback=?', function(adata) {\n                if (typeof adata.error!=='undefined') {\n                  alert(adata.error);\n                  return;\n                }\n                var x = adata;\n                for(var k = 0; k < adata.length; k++){\n                  if(adata[k].id != null){\n                    for(var j = 0; j < odata.length; j++) {\n                      if(odata[j].id == adata[k].occurrence_id){\n                        \$('.scPresence[value='+odata[j].taxa_taxon_list_id+']').closest('tr').find('[name\$=\\\\:occAttr\\\\:'+adata[k]['occurrence_attribute_id']+']').val(adata[k]['raw_value']);\n                        \$('[name=sc\\\\:tree\\\\:\\\\:occAttr\\\\:'+adata[k]['occurrence_attribute_id']+']').val(adata[k]['raw_value']);\n                        break;\n              }}}}});\n          }});\n        }\n        break;\n  }}});\n});\n\n";
         }
         return $r;
     }
     $r .= '<div class="page-notice ui-state-highlight ui-corner-all">All fields followed by a red asterisk (<span class="deh-required">*</span>) must be filled in. You can not modify any field that is greyed out.</div>';
     self::$treeOccurrenceRecord = false;
     if (isset($options['extraParams'])) {
         foreach ($options['extraParams'] as $key => &$value) {
             $value = apply_user_replacements($value);
         }
         $options['extraParams'] = array_merge($auth['read'], $options['extraParams']);
     } else {
         $options['extraParams'] = array_merge($auth['read']);
     }
     if (empty($options['reportProvidesOrderBy']) || $options['reportProvidesOrderBy'] == 0) {
         $options['extraParams']['orderby'] = 'name';
     }
     // Get list of sites alocated to me, using CMS User ID.
     $site_attributes = data_entry_helper::getAttributes(array('valuetable' => 'location_attribute_value', 'attrtable' => 'location_attribute', 'key' => 'location_id', 'extraParams' => $auth['read'], 'survey_id' => $args['survey_id'], 'location_type_id' => $options['location_type_id'], 'fieldprefix' => 'locAttr'));
     if (false == ($cmsUserAttr = extract_cms_user_attr($site_attributes))) {
         return 'This form is designed to be used with the "CMS User ID" attribute setup for Site locations in the survey.';
     }
     $response = data_entry_helper::get_population_data(array('table' => 'location_attribute_value', 'extraParams' => $auth['read'] + array('view' => 'list', 'location_attribute_id' => $cmsUserAttr['attributeId'], 'raw_value' => $user->uid), 'nocache' => true));
     if (count($response) == 0) {
         throw new exception(lang::get('You have no sites, so you can not enter any phenology observations. Please create a site and some trees first.'));
     }
     $siteIDs = array();
     foreach ($response as $loc) {
         $siteIDs[] = $loc['location_id'];
     }
     $location_list_args = array_merge(array('label' => lang::get('Site'), 'view' => 'detail', 'fieldname' => 'location:parent_id', 'id' => 'imp-site-location', 'blankText' => lang::get('Please select a site.'), 'validation' => 'required', 'nocache' => true), $options);
     // $options already has the location_type_id set
     $location_list_args['extraParams']['id'] = $siteIDs;
     $r .= data_entry_helper::location_select($location_list_args);
     $location_list_args = array_merge(array('label' => lang::get('Tree'), 'view' => 'detail', 'blankText' => lang::get('Please select a tree.'), 'validation' => 'required', 'nocache' => true), $options);
     $location_list_args['extraParams']['id'] = $siteIDs;
     $location_list_args['location_type_id'] = $options['tree_location_type_id'];
     $r .= data_entry_helper::location_select($location_list_args);
     $r .= data_entry_helper::text_input(array('label' => lang::get('Tree Species'), 'fieldname' => 'dummy:tree_species', 'class' => 'control-width-4 tree-details-readonly', 'disabled' => ' readonly="readonly"', 'validation' => 'required', 'helpText' => lang::get('The following field is filled in automatically when you select a tree.')));
     $r .= '<input name="sc:tree::present" type="hidden" value="" />';
     $systems = array('4326' => lang::get("sref:4326"));
     // this will be overwriten when the tree is loaded.
     $r .= data_entry_helper::sref_and_system(array_merge(array('label' => lang::get('Tree Grid Ref'), 'systems' => $systems, 'disabled' => ' readonly="readonly"', 'validation' => '', 'class' => 'tree-details-readonly', 'helpText' => lang::get('The following field is filled in automatically when you select a tree.')), $options));
     data_entry_helper::$javascript .= "\r\n\$('#imp-site-location').change(function() {\n  \$('#" . data_entry_helper::$validated_form_id . "').find('label.error').remove();\n  \$('#" . data_entry_helper::$validated_form_id . "').find('.error').removeClass('error');\n  \$('#" . data_entry_helper::$validated_form_id . "').find('.inline-error').remove();\n  \$('#" . data_entry_helper::$validated_form_id . "').find('.ui-state-error').removeClass('ui-state-error');\n  ParentLocationLayer.destroyFeatures();\r\n  TreeListLayer.destroyFeatures();\n  var intValue = parseInt(\$(this).val());\r\n  if (!isNaN(intValue)) {\n    \$(this).find('option[value=]').attr('disabled',true);\n    // site list has been populated with correct location_type_ids.\r\n    \$.getJSON(ParentLocationLayer.map.div.settings.indiciaSvc + 'index.php/services/data/location/'+\$(this).val() +\r\n              '?mode=json&view=detail' + ParentLocationLayer.map.div.settings.readAuth + '&callback=?', function(data) {\r\n      if (typeof data.error!=='undefined') {\n        alert(data.error);\n        return;\n      }\n      if (data.length>0) {\r\n        var geomwkt = data[0].boundary_geom || data[0].centroid_geom;\n        // assume single geometry - not a collection, and default style\n        var parser = new OpenLayers.Format.WKT();\n        var feature = parser.read(geomwkt);\n        ParentLocationLayer.addFeatures([feature]);\n        _zoomToExtent(feature.geometry.getBounds(), ParentLocationLayer);\n        \$('#imp-location option[value!=]').not(':selected').remove();\n        \$.getJSON(TreeListLayer.map.div.settings.indiciaSvc + 'index.php/services/data/location?parent_id='+data[0].id +\n              '&mode=json&view=detail' + TreeListLayer.map.div.settings.readAuth + '&callback=?', function(tdata) {\n          if (typeof tdata.error!=='undefined') {\n            alert(tdata.error);\n            return;\n          }\n          if (tdata.length>0) {\n            var features = [], found=false;\n            var bounds = ParentLocationLayer.features[0].geometry.getBounds();\n            for(var i=0; i<tdata.length; i++){\n              var geomwkt = tdata[i].centroid_geom, feature;\n              var parser = new OpenLayers.Format.WKT();\n              var feature = parser.read(geomwkt);\n              feature.attributes.name = tdata[i].name;\n              features.push(feature);\n              bounds.extend(feature.geometry.getBounds());\n              if(\$('#imp-location option[value='+tdata[i].id+']').length == 0)\n                \$('#imp-location').append('<option value=\"'+tdata[i].id+'\">'+tdata[i].name+'</option>');\n              else found=true;\n            }\n            if(!found){ // currently selected tree no longer on this site. Deselect it.\n              \$(this).find('option[value=]').removeAttr('disabled');\n              \$('#imp-location option[value!=]:selected').remove();\n              \$('#imp-location,#imp-sref').val('');\n              TreeListLayer.map.editLayer.destroyFeatures();\n              \$('[name=dummy\\\\:tree_species]').val('');\n            }\n            TreeListLayer.addFeatures(features);\n            _zoomToExtent(bounds, ParentLocationLayer);\n        }});\r\n    }});\n}});\nmapLocationSelectedHooks.push(function(div, data){\n  \$('#" . data_entry_helper::$validated_form_id . "').find('label.error').remove();\n  \$('#" . data_entry_helper::$validated_form_id . "').find('.error').removeClass('error');\n  \$('#" . data_entry_helper::$validated_form_id . "').find('.inline-error').remove();\n  \$('#" . data_entry_helper::$validated_form_id . "').find('.ui-state-error').removeClass('ui-state-error');\n  if(\$('#imp-site-location').val() != data[0].parent_id) {\n    \$('#imp-site-location').val(data[0].parent_id).change();\n    \$('#imp-site-location option[value=]').attr('disabled',true);\n  }\n  if(data[0].parent_id != ''){\n    \$('#imp-location option[value=]').attr('disabled',true);\n  }\n  \$('#'+indiciaData.recorderNameID.replace(/:/g,'\\\\:')).val('');\n  \$.getJSON(ParentLocationLayer.map.div.settings.indiciaSvc + 'index.php/services/data/location_attribute_value?location_id='+data[0]['id'] +\n      '&mode=json&view=list' + ParentLocationLayer.map.div.settings.readAuth + '&callback=?', function(data) {\n    if(data instanceof Array && data.length>0){\n      for (var i=0;i<data.length;i++){\n        if (data[i]['location_attribute_id'] == indiciaData.assignedRecorderAttrID)\n          \$('#'+indiciaData.recorderNameID.replace(/:/g,'\\\\:')).val(data[i].raw_value);\n      }\n  }});\n  // get registration sample and occurrence and fill in species.\n  \$.getJSON(ParentLocationLayer.map.div.settings.indiciaSvc + 'index.php/services/data/sample?location_id='+data[0]['id'] +\n      '&sample_method_id=" . $args['reg_sample_method_id'] . "&mode=json&view=detail' + ParentLocationLayer.map.div.settings.readAuth + '&callback=?', function(data) {\n    if (typeof data.error!=='undefined') {\n      alert(data.error);\n      return;\n    }\n    if(data.length){\n      \$.getJSON(ParentLocationLayer.map.div.settings.indiciaSvc + 'index.php/services/data/occurrence?sample_id='+data[0]['id'] +\n          '&mode=json&view=detail' + ParentLocationLayer.map.div.settings.readAuth + '&callback=?', function(data) {\n        if (typeof data.error!=='undefined') {\n          alert(data.error);\n          return;\n        }\n        if(data.length){\n          \$('[name=dummy\\\\:tree_species]').val(data[0].taxon);\n          \$('[name=sc\\\\:tree\\\\:\\\\:present]').val(data[0].taxa_taxon_list_id);\n      }});\n  }});\n});\n\$('[name=sample\\\\:date]').change(function(){\n  if(\$('#imp-location').val()=='') return;\n  \$.getJSON(ParentLocationLayer.map.div.settings.indiciaSvc + 'index.php/services/data/sample?location_id='+\$('#imp-location').val() +\n  \t\t'&sample_method_id=" . $args['sample_method_id'] . "&mode=json&view=detail&orderby=date_start' + ParentLocationLayer.map.div.settings.readAuth + '&callback=?', function(data) {\n    if (typeof data.error!=='undefined') {\n      alert(data.error);\n      return;\n    }\n    var date = \$('[name=sample\\\\:date]').val();\n    date = date.split('/');\n    for(var i = 0; i < data.length; i++){\n      if(data[i][\"date_start\"] == date[2]+'-'+date[1]+'-'+date[0]) {\n        alert(\"Warning: there is already a visit recorded for this tree on \"+data[i][\"date_start\"]);\n        return;\n      }\n    }\n    for(var i = 0; i < data.length; i++){\n      sdate = data[i][\"date_start\"].split('-');\n      if(sdate[0] > date[2] || (sdate[0] == date[2] && (sdate[1] > date[1] || (sdate[1] == date[1] && sdate[2] >= date[0])))) {\n        alert(\"Warning: there is already a visit recorded for this tree after this date, on \"+data[i][\"date_start\"]);\n        break;\n      }\n    }\n    for(var i = data.length-1; i >=0; i--){\n      sdate = data[i][\"date_start\"].split('-');\n      if(sdate[0] < date[2] || (sdate[0] == date[2] && (sdate[1] < date[1] || (sdate[1] == date[1] && sdate[2] <= date[0])))) {\n        if(confirm(\"There was a previously recorded visit for this tree prior to this date, on \"+data[i][\"date_start\"]+'. Do you wish to use the data from this earlier visit as a starting point? (This will not affect any previously recorded observations - it will just fill in this form with the data from your previous visit, excluding the field diary. You can then update the data with any changes for this visit.)')){\n          // this is an initial save: all attributes have vanilla names.\n          // TODO sample attributes\n          \$('.scPresence').removeAttr('checked');\n          var cells = \$('.scOccAttrCell');\n          cells.find('select').removeClass('required').val('').attr('disabled',true);\n          cells.find('.deh-required').remove();\n          \$('#" . data_entry_helper::$validated_form_id . "').find('label.error').remove();\n          \$('#" . data_entry_helper::$validated_form_id . "').find('.error').removeClass('error');\n          \$('#" . data_entry_helper::$validated_form_id . "').find('.inline-error').remove();\n          \$('#" . data_entry_helper::$validated_form_id . "').find('.ui-state-error').removeClass('ui-state-error');\n          \$('[name^=sc\\\\:tree\\\\:\\\\:occAttr\\\\:]').val('');\n          \$.getJSON(ParentLocationLayer.map.div.settings.indiciaSvc + 'index.php/services/data/occurrence?sample_id='+data[i]['id'] +\n              '&mode=json&view=detail' + ParentLocationLayer.map.div.settings.readAuth + '&callback=?', function(odata) {\n            if (typeof odata.error!=='undefined') {\n              alert(odata.error);\n              return;\n            }\n            var occIDs = [];\n            if(odata.length>0){\n              for(var j = 0; j < odata.length; j++) {\n                occIDs.push(odata[j].id);\n                \$('.scPresence[value='+odata[j].taxa_taxon_list_id+']').each(function(idx, elem){\n                  var cells = \$(elem).attr('checked',true).closest('tr').find('.scOccAttrCell');\n                  cells.find('select').addClass('required').removeAttr('disabled');\n                  cells.append('<span class=\"deh-required\">*</span>');\n                });\n              }\n              \$.getJSON(ParentLocationLayer.map.div.settings.indiciaSvc + 'index.php/services/data/occurrence_attribute_value' +\n                  '?query={\"in\":{\"occurrence_id\":'+JSON.stringify(occIDs) +'}}' +\n                  '&mode=json&view=list' + ParentLocationLayer.map.div.settings.readAuth + '&callback=?', function(adata) {\n                if (typeof adata.error!=='undefined') {\n                  alert(adata.error);\n                  return;\n                }\n                var x = adata;\n                for(var k = 0; k < adata.length; k++){\n                  if(adata[k].id != null){\n                    for(var j = 0; j < odata.length; j++) {\n                      if(odata[j].id == adata[k].occurrence_id){\n                        \$('.scPresence[value='+odata[j].taxa_taxon_list_id+']').closest('tr').find('[name\$=\\\\:occAttr\\\\:'+adata[k]['occurrence_attribute_id']+']').val(adata[k]['raw_value']);\n                        \$('[name=sc\\\\:tree\\\\:\\\\:occAttr\\\\:'+adata[k]['occurrence_attribute_id']+']').val(adata[k]['raw_value']);\n                        break;\n              }}}}});\n          }});\n        }\n        break;\n  }}});\n});\n\n";
     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.
  * @todo: Implement this method 
  */
 public static function get_form($args, $node, $response = null)
 {
     require_once drupal_get_path('module', 'iform') . '/client_helpers/map_helper.php';
     if (function_exists('url')) {
         $args['section_edit_path'] = url($args['section_edit_path']);
     }
     $auth = data_entry_helper::get_read_write_auth($args['website_id'], $args['password']);
     $settings = array('locationTypes' => helper_base::get_termlist_terms($auth, 'indicia:location_types', array('Transect', 'Transect Section')), 'locationId' => isset($_GET['id']) ? $_GET['id'] : null);
     data_entry_helper::$javascript .= "indiciaData.sections = {};\n";
     if ($settings['locationId']) {
         data_entry_helper::load_existing_record($auth['read'], 'location', $settings['locationId']);
         $settings['sections'] = data_entry_helper::get_population_data(array('table' => 'location', 'extraParams' => $auth['read'] + array('view' => 'detail', 'parent_id' => $settings['locationId'], 'deleted' => 'f'), 'nocache' => true));
         foreach ($settings['sections'] as $section) {
             $code = strtolower($section['code']);
             data_entry_helper::$javascript .= "indiciaData.sections.{$code} = {'geom':'" . $section['boundary_geom'] . "','id':'" . $section['id'] . "'};\n";
         }
     } else {
         $settings['sections'] = array();
     }
     $settings['attributes'] = data_entry_helper::getAttributes(array('id' => $settings['locationId'], 'valuetable' => 'location_attribute_value', 'attrtable' => 'location_attribute', 'key' => 'location_id', 'fieldprefix' => 'locAttr', 'extraParams' => $auth['read'], 'survey_id' => $args['survey_id'], 'location_type_id' => $settings['locationTypes'][0]['id'], 'multiValue' => true));
     if (false == ($settings['cmsUserAttr'] = extract_cms_user_attr($settings['attributes']))) {
         return 'This form is designed to be used with the CMS User ID attribute setup for locations in the survey.';
     }
     // keep a copy of the location_attribute_id so we can use it later.
     self::$cmsUserAttrId = $settings['cmsUserAttr']['attributeId'];
     $r = '<form method="post" id="input-form">';
     $r .= $auth['write'];
     $r .= '<div id="controls">';
     $customAttributeTabs = array_merge(array('Site Details' => array('[*]')), get_attribute_tabs($settings['attributes']));
     if (count($customAttributeTabs) > 1) {
         $headerOptions = array('tabs' => array());
         foreach ($customAttributeTabs as $tab => $content) {
             $alias = preg_replace('/[^a-zA-Z0-9]/', '', strtolower($tab));
             $headerOptions['tabs']['#' . $alias] = lang::get($tab);
         }
         $r .= data_entry_helper::tab_header($headerOptions);
         data_entry_helper::enable_tabs(array('divId' => 'controls', 'style' => $args['interface'], 'progressBar' => isset($args['tabProgress']) && $args['tabProgress'] == true));
     }
     foreach ($customAttributeTabs as $tab => $content) {
         if ($tab == 'Site Details') {
             $r .= self::get_site_tab($auth, $args, $settings);
         } else {
             $alias = preg_replace('/[^a-zA-Z0-9]/', '', strtolower($tab));
             $r .= "\n<div id=\"{$alias}\">\n";
             $r .= get_attribute_html($settings['attributes'], $args, array('extraParams' => $auth['read']), $tab);
             $r .= "</div>\n";
         }
     }
     $r .= '</div>';
     // controls
     $r .= '<input type="submit" value="' . lang::get('Save') . '" class="ui-state-default ui-corner-all" />';
     $r .= '</form>';
     data_entry_helper::enable_validation('input-form');
     if (function_exists('drupal_set_breadcrumb')) {
         $breadcrumb = array();
         $breadcrumb[] = l(lang::get('Home'), '<front>');
         $breadcrumb[] = l(lang::get('Sites'), $args['sites_list_path']);
         if ($settings['locationId']) {
             $breadcrumb[] = data_entry_helper::$entity_to_load['location:name'];
         } else {
             $breadcrumb[] = lang::get('New Site');
         }
         drupal_set_breadcrumb($breadcrumb);
     }
     return $r;
 }