public static function mnhnl_reptiles_species_checklist()
 {
     global $indicia_templates;
     $options = data_entry_helper::check_arguments(func_get_args(), array('listId', 'occAttrs', 'readAuth', 'extraParams', 'lookupListId'));
     $options = data_entry_helper::get_species_checklist_options($options);
     data_entry_helper::add_resource('json');
     data_entry_helper::add_resource('autocomplete');
     $occAttrControls = array();
     $occAttrs = array();
     // Load any existing sample's occurrence data into $entity_to_load
     $subSamples = array();
     if (isset(data_entry_helper::$entity_to_load['sample:id'])) {
         data_entry_helper::preload_species_checklist_occurrences(data_entry_helper::$entity_to_load['sample:id'], $options['readAuth'], false, array(), $subSamples, false);
     }
     // load the full list of species for the grid, including the main checklist plus any additional species in the reloaded occurrences.
     $options['extraParams']['view'] = 'detail';
     $occList = self::get_species_checklist_occ_list($options);
     // If we managed to read the species list data we can proceed
     if (!array_key_exists('error', $occList)) {
         $attributes = data_entry_helper::getAttributes(array('id' => null, 'valuetable' => 'occurrence_attribute_value', 'attrtable' => 'occurrence_attribute', 'key' => 'occurrence_id', 'fieldprefix' => "{fieldname}", 'extraParams' => $options['readAuth'], 'survey_id' => array_key_exists('survey_id', $options) ? $options['survey_id'] : null));
         // Get the attribute and control information required to build the custom occurrence attribute columns
         data_entry_helper::species_checklist_prepare_attributes($options, $attributes, $occAttrControls, $occAttrs);
         $grid = "<p>" . lang::get('LANG_SpeciesInstructions') . "</p>\n";
         if (isset($options['lookupListId'])) {
             $grid .= self::get_species_checklist_clonable_row($options, $occAttrControls, $attributes);
         }
         $grid .= '<table class="ui-widget ui-widget-content mnhnl-species-grid ' . $options['class'] . '" id="' . $options['id'] . '">';
         $grid .= self::get_species_checklist_header($options, $occAttrs);
         $rows = array();
         $rowIdx = 0;
         foreach ($occList as $occ) {
             $ttlid = $occ['taxon']['id'];
             $firstCell = data_entry_helper::mergeParamsIntoTemplate($occ['taxon'], 'taxon_label', false, true);
             if ($options['PHPtaxonLabel']) {
                 $firstCell = eval($firstCell);
             }
             $colspan = ' colspan="' . count($attributes) . '"';
             // assume always removeable and presence is hidden.
             $firstrow = '<td class="ui-state-default remove-row" style="width: 1%" rowspan="' . ($options['occurrenceComment'] ? "3" : "2") . '" >X</td>';
             $firstrow .= str_replace('{content}', $firstCell, str_replace('{colspan}', $colspan, $indicia_templates['taxon_label_cell']));
             $existing_record_id = $occ['id'];
             $hidden = $options['rowInclusionCheck'] == 'checkbox' ? '' : ' style="display:none"';
             if ($options['rowInclusionCheck'] == 'alwaysFixed' || $options['rowInclusionCheck'] == 'alwaysRemovable' || data_entry_helper::$entity_to_load != null && array_key_exists("sc:{$ttlid}:{$existing_record_id}:present", data_entry_helper::$entity_to_load)) {
                 $checked = ' checked="checked"';
             } else {
                 $checked = '';
             }
             $secondrow = "<td class=\"scPresenceCell\"{$hidden}>" . ($options['rowInclusionCheck'] != 'hasData' ? "<input type=\"hidden\" class=\"scPresence\" name=\"sc:{$ttlid}:{$existing_record_id}:present\" value=\"0\"/><input type=\"checkbox\" class=\"scPresence\" name=\"sc:{$ttlid}:{$existing_record_id}:present\" {$checked} />" : '') . "</td>";
             foreach ($occAttrControls as $attrId => $control) {
                 if ($existing_record_id) {
                     $search = preg_grep("/^sc:" . $ttlid . "[_[0-9]*]?:{$existing_record_id}:occAttr:{$attrId}" . '[:[0-9]*]?$/', array_keys(data_entry_helper::$entity_to_load));
                     $ctrlId = count($search) === 1 ? implode('', $search) : "sc:{$ttlid}:{$existing_record_id}:occAttr:{$attrId}";
                 } else {
                     $ctrlId = "sc:{$ttlid}:x{$rowIdx}:occAttr:{$attrId}";
                 }
                 if (isset(data_entry_helper::$entity_to_load[$ctrlId])) {
                     $existing_value = data_entry_helper::$entity_to_load[$ctrlId];
                 } elseif (array_key_exists('default', $attributes[$attrId])) {
                     $existing_value = $attributes[$attrId]['default'];
                 } else {
                     $existing_value = '';
                 }
                 $oc = str_replace('{fieldname}', $ctrlId, $control);
                 if (!empty($existing_value)) {
                     // For select controls, specify which option is selected from the existing value
                     if (substr($oc, 0, 7) == '<select') {
                         $oc = str_replace('value="' . $existing_value . '"', 'value="' . $existing_value . '" selected="selected"', $oc);
                     } else {
                         if (strpos($oc, 'checkbox') !== false) {
                             if ($existing_value == "1") {
                                 $oc = str_replace('type="checkbox"', 'type="checkbox" checked="checked"', $oc);
                             }
                         } else {
                             $oc = str_replace('value=""', 'value="' . $existing_value . '"', $oc);
                         }
                     }
                     // assume all error handling/validation done client side
                 }
                 $secondrow .= str_replace(array('{label}', '{content}'), array(lang::get($attributes[$attrId]['caption']), $oc), $indicia_templates[$options['attrCellTemplate']]);
             }
             $thirdrow = "";
             if ($options['occurrenceComment']) {
                 $thirdrow .= "\n<td class=\"ui-widget-content scCommentCell\" {$colspan}><label for=\"sc:{$ttlid}:{$existing_record_id}:occurrence:comment\" class=\"auto-width\" >" . lang::get("Comment") . " : </label><input class=\"scComment\" type=\"text\" name=\"sc:{$ttlid}:{$existing_record_id}:occurrence:comment\" " . "id=\"sc:{$ttlid}:{$existing_record_id}:occurrence:comment\" value=\"" . htmlspecialchars(data_entry_helper::$entity_to_load["sc:{$ttlid}:{$existing_record_id}:occurrence:comment"]) . "\" /></td>";
             }
             $rows[] = '<tr>' . $firstrow . '</tr>';
             $rows[] = '<tr class="scMeaning-' . $occ['taxon']['taxon_meaning_id'] . ' scDataRow">' . $secondrow . '</tr>';
             // no images.
             if ($thirdrow != "") {
                 $rows[] = '<tr class="scMeaning-' . $occ['taxon']['taxon_meaning_id'] . ' scDataRow">' . $thirdrow . '</tr>';
             }
             // no images.
             $rowIdx++;
         }
         $grid .= "\n<tbody>\n";
         if (count($rows) > 0) {
             $grid .= implode("\n", $rows) . "\n";
         } else {
             $grid .= "<tr style=\"display: none\"><td></td></tr>\n";
         }
         $grid .= "</tbody>\n</table>\n";
         if ($options['rowInclusionCheck'] == 'hasData') {
             $grid .= '<input name="rowInclusionCheck" value="hasData" type="hidden" />';
         }
         // If the lookupListId parameter is specified then the user is able to add extra rows to the grid,
         // selecting the species from this list. Add the required controls for this.
         if (isset($options['lookupListId'])) {
             $grid .= "<label for=\"taxonLookupControl\" class=\"auto-width\">" . lang::get('Add species to list') . " : </label> <input id=\"taxonLookupControl\" name=\"taxonLookupControl\" >";
             // Javascript to add further rows to the grid
             data_entry_helper::$javascript .= "var formatter = function(rowData,taxonCell) {\r\n  taxonCell.html(\"" . lang::get('loading') . "\");\r\n  jQuery.getJSON('" . data_entry_helper::$base_url . "/index.php/services/data/taxa_taxon_list/' + rowData.id +\r\n            '?mode=json&view=detail&auth_token=" . $options['readAuth']['auth_token'] . "&nonce=" . $options['readAuth']["nonce"] . "&callback=?', function(mdata) {\r\n    if(mdata instanceof Array && mdata.length>0){\r\n      jQuery.getJSON('" . data_entry_helper::$base_url . "/index.php/services/data/taxa_taxon_list' +\r\n            '?mode=json&view=detail&auth_token=" . $options['readAuth']['auth_token'] . "&nonce=" . $options['readAuth']["nonce"] . "&taxon_meaning_id='+mdata[0].taxon_meaning_id+'&taxon_list_id=" . $options["extra_list_id"] . "&callback=?', function(data) {\r\n        var taxaList = '';\r\n         if(data instanceof Array && data.length>0){\r\n          for (var i=0;i<data.length;i++){\r\n            if(data[i].preferred == 'f')\r\n              taxaList += (taxaList == '' ? '' : ', ')+data[i].taxon;\r\n            else\r\n              taxaList = '<em>'+data[i].taxon+'</em>'+(taxaList == '' ? '' : ', '+taxaList);\r\n            }\r\n          }\r\n          taxonCell.html(taxaList).removeClass('extraCommonNames');\r\n        });\r\n    }})\r\n}  \r\nbindSpeciesAutocomplete(\"taxonLookupControl\",\"" . data_entry_helper::$base_url . "index.php/services/data\", \"" . $options['id'] . "\", \"" . $options['lookupListId'] . "\", {\"auth_token\" : \"" . $options['readAuth']['auth_token'] . "\", \"nonce\" : \"" . $options['readAuth']['nonce'] . "\"}, formatter);\r\n";
         }
         // No help text
         return $grid;
     } else {
         return $taxalist['error'];
     }
 }
 protected static function cloneEntity($args, $auth, &$attributes)
 {
     // First modify the sample attribute information in the $attributes array.
     // Set the sample attribute fieldnames as for a new record
     foreach ($attributes as $attributeKey => $attributeValue) {
         if ($attributeValue['multi_value'] == 't') {
             // Set the attribute fieldname to the attribute id plus brackets for multi-value attributes
             $attributes[$attributeKey]['fieldname'] = $attributeValue['id'] . '[]';
             foreach ($attributeValue['default'] as $defaultKey => $defaultValue) {
                 //Fixed a problem with a checkbox_group that the client reported as not saving after cloning. The problem is the value field was also including the fieldname which was
                 //preventing save, so I have removed the fieldname from the defaults list here. I don't have time to test all the scenarios for this, so to be safe I have just made it
                 //so the fix is only applied to the checkbox_group, if we find there are problems with other types of multi-value control then this check can be removed, but as we only
                 //have one reported issue and I can't test all the scenarios I have left in this checkbox_group check to avoid breaking existing code that I can't test.
                 if (isset($attributeValue['control_type']) && $attributeValue['control_type'] === 'checkbox_group') {
                     unset($attributes[$attributeKey]['default'][$defaultKey]['fieldname']);
                 } else {
                     $attributes[$attributeKey]['default'][$defaultKey]['fieldname'] = $attributeValue['id'] . '[]';
                 }
             }
         } else {
             // Set the attribute fieldname to the attribute id for single values
             $attributes[$attributeKey]['fieldname'] = $attributeValue['id'];
         }
     }
     // Now load the occurrences and their attributes.
     // @todo: Convert to occurrences media capabilities.
     $loadImages = $args['occurrence_images'];
     $subSamples = array();
     data_entry_helper::preload_species_checklist_occurrences(data_entry_helper::$entity_to_load['sample:id'], $auth['read'], $loadImages, array(), $subSamples, false);
     // If using a species grid $entity_to_load will now contain elements in the form
     //  sc:row_num:occ_id:occurrence:field_name
     //  sc:row_num:occ_id:present
     //  sc:row_num:occ_id:occAttr:occAttr_id:attrValue_id
     // We are going to strip out the occ_id and the attrValue_id
     $keysToDelete = array();
     $elementsToAdd = array();
     foreach (data_entry_helper::$entity_to_load as $key => $value) {
         $parts = explode(':', $key);
         // Is this an occurrence?
         if ($parts[0] === 'sc') {
             // We'll be deleting this
             $keysToDelete[] = $key;
             // And replacing it
             $parts[2] = '';
             if (count($parts) == 6) {
                 unset($parts[5]);
             }
             $keyToCreate = implode(':', $parts);
             $elementsToAdd[$keyToCreate] = $value;
         }
     }
     foreach ($keysToDelete as $key) {
         unset(data_entry_helper::$entity_to_load[$key]);
     }
     data_entry_helper::$entity_to_load = array_merge(data_entry_helper::$entity_to_load, $elementsToAdd);
     // Unset the sample and occurrence id from entitiy_to_load as for a new record.
     unset(data_entry_helper::$entity_to_load['sample:id']);
     unset(data_entry_helper::$entity_to_load['occurrence:id']);
 }
 protected static function cloneEntity($args, $auth, &$attributes)
 {
     // First modify the sample attribute information in the $attributes array.
     // Set the sample attribute fieldnames as for a new record
     foreach ($attributes as $attributeKey => $attributeValue) {
         if ($attributeValue['multi_value'] == 't') {
             // Set the attribute fieldname to the attribute id plus brackets for multi-value attributes
             $attributes[$attributeKey]['fieldname'] = $attributeValue['id'] . '[]';
             foreach ($attributeValue['default'] as $defaultKey => $defaultValue) {
                 // Set the fieldname in the defaults array to the attribute id plus brackets as well
                 $attributes[$attributeKey]['default'][$defaultKey]['fieldname'] = $attributeValue['id'] . '[]';
             }
         } else {
             // Set the attribute fieldname to the attribute id for single values
             $attributes[$attributeKey]['fieldname'] = $attributeValue['id'];
         }
     }
     // Now load the occurrences and their attributes.
     // @todo: Convert to occurrences media capabilities.
     $loadImages = $args['occurrence_images'];
     $subSamples = array();
     data_entry_helper::preload_species_checklist_occurrences(data_entry_helper::$entity_to_load['sample:id'], $auth['read'], $loadImages, array(), $subSamples, false);
     // If using a species grid $entity_to_load will now contain elements in the form
     //  sc:row_num:occ_id:occurrence:field_name
     //  sc:row_num:occ_id:present
     //  sc:row_num:occ_id:occAttr:occAttr_id:attrValue_id
     // We are going to strip out the occ_id and the attrValue_id
     $keysToDelete = array();
     $elementsToAdd = array();
     foreach (data_entry_helper::$entity_to_load as $key => $value) {
         $parts = explode(':', $key);
         // Is this an occurrence?
         if ($parts[0] === 'sc') {
             // We'll be deleting this
             $keysToDelete[] = $key;
             // And replacing it
             $parts[2] = '';
             if (count($parts) == 6) {
                 unset($parts[5]);
             }
             $keyToCreate = implode(':', $parts);
             $elementsToAdd[$keyToCreate] = $value;
         }
     }
     foreach ($keysToDelete as $key) {
         unset(data_entry_helper::$entity_to_load[$key]);
     }
     data_entry_helper::$entity_to_load = array_merge(data_entry_helper::$entity_to_load, $elementsToAdd);
     // Unset the sample and occurrence id from entitiy_to_load as for a new record.
     unset(data_entry_helper::$entity_to_load['sample:id']);
     unset(data_entry_helper::$entity_to_load['occurrence:id']);
 }
 protected static function get_form_sampleoccurrence($args, $node)
 {
     // attributes must be fetched after the entity to load is filled in - this is because the id gets filled in then!
     $cancelUrl = self::$currentUrl;
     $cancelUrl .= strpos($cancelUrl, '?') === false ? '?' : '&';
     $cancelUrl .= "supersample_id=" . data_entry_helper::$entity_to_load['sample:parent_id'];
     $attributes = data_entry_helper::getAttributes(array('id' => data_entry_helper::$entity_to_load['sample:id'], 'valuetable' => 'sample_attribute_value', 'attrtable' => 'sample_attribute', 'key' => 'sample_id', 'fieldprefix' => 'smpAttr', 'extraParams' => self::$auth['read'], 'survey_id' => $args['survey_id']));
     if (self::$mode == MODE_EXISTING_OCCURRENCE && self::$gridmode == false && isset(data_entry_helper::$entity_to_load['sample:id'])) {
         $cloneEntity = data_entry_helper::$entity_to_load;
         $occList = data_entry_helper::preload_species_checklist_occurrences(data_entry_helper::$entity_to_load['sample:id'], self::$auth['read'], $args['occurrence_images']);
         foreach ($occList as $id => $taxon) {
             self::$occurrenceIds[] = $id;
         }
         if (count(self::$occurrenceIds) > 1) {
             self::$gridmode = true;
             data_entry_helper::$entity_to_load = $cloneEntity;
         }
     }
     // Make sure the form action points back to this page
     $r = "<form method=\"post\" id=\"entry_form\" action=\"" . self::$currentUrl . "\">\n";
     // Get authorisation tokens to update the Warehouse, plus any other hidden data.
     $hiddens = self::$auth['write'] . "<input type=\"hidden\" id=\"website_id\" name=\"website_id\" value=\"" . $args['website_id'] . "\" />\n" . "<input type=\"hidden\" id=\"survey_id\" name=\"survey_id\" value=\"" . $args['survey_id'] . "\" />\n" . "<input type=\"hidden\" id=\"parent_id\" name=\"sample:parent_id\" value=\"" . data_entry_helper::$entity_to_load['sample:parent_id'] . "\" />\n" . "<input type=\"hidden\" id=\"date\" name=\"sample:date\" value=\"" . data_entry_helper::$entity_to_load['sample:date'] . "\" />\n";
     if (isset(data_entry_helper::$entity_to_load['sample:id'])) {
         $hiddens .= "<input type=\"hidden\" id=\"sample:id\" name=\"sample:id\" value=\"" . data_entry_helper::$entity_to_load['sample:id'] . "\" />\n";
     }
     // Check if Record Status is included as a control. If not, then add it as a hidden.
     $arr = explode("\r\n", $args['structure']);
     if (!in_array('[record status]', $arr)) {
         $value = isset($args['defaults']['occurrence:record_status']) ? $args['defaults']['occurrence:record_status'] : 'C';
         $hiddens .= "<input type=\"hidden\" id=\"occurrence:record_status\" name=\"occurrence:record_status\" value=\"{$value}\" />\n";
     }
     // request automatic JS validation
     if (!isset($args['clientSideValidation']) || $args['clientSideValidation']) {
         data_entry_helper::enable_validation('entry_form');
     }
     self::set_attribute_default_block($attributes);
     $tabs = self::get_all_tabs($args['occurrence_structure'], array());
     $r .= "<div id=\"controls\">\n";
     // Build a list of the tabs that actually have content
     $tabHtml = self::get_tab_html($tabs, self::$auth, $args, $attributes, $hiddens);
     // Output the dynamic tab headers
     $headerOptions = array('tabs' => array());
     foreach ($tabHtml as $tab => $tabContent) {
         $alias = preg_replace('/[^a-zA-Z0-9]/', '', strtolower($tab));
         $tabtitle = lang::get("LANG_Tab_{$alias}");
         if ($tabtitle == "LANG_Tab_{$alias}") {
             // if no translation provided, we'll just use the standard heading
             $tabtitle = $tab;
         }
         $headerOptions['tabs']['#' . $alias] = $tabtitle;
     }
     if ($args['interface'] != 'one_page') {
         $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));
     }
     // Output the dynamic tab content
     $pageIdx = 0;
     foreach ($tabHtml as $tab => $tabContent) {
         // get a machine readable alias for the heading
         $tabalias = preg_replace('/[^a-zA-Z0-9]/', '', strtolower($tab));
         $r .= '<div id="' . $tabalias . '">' . "\n";
         // For wizard include the tab title as a header.
         if ($args['interface'] != 'tabs') {
             $r .= '<h1>' . $headerOptions['tabs']['#' . $tabalias] . '</h1>';
         }
         $r .= $tabContent;
         // Add any buttons required at the bottom of the tab
         if ($args['interface'] == 'wizard') {
             $r .= data_entry_helper::wizard_buttons(array('classRedisplay' => 'ui-widget-content ui-state-default ui-corner-all indicia-button tab-submit-redisplay', 'captionSaveRedisplay' => 'save and redisplay', 'divId' => 'controls', 'page' => $pageIdx === 0 ? 'first' : ($pageIdx == count($tabs) - 1 ? 'last' : 'middle')));
         } elseif ($pageIdx == count($tabs) - 1 && !($args['interface'] == 'tabs' && $args['save_button_below_all_pages'])) {
             // last part of a non wizard interface must insert a save button, unless it is tabbed interface with save button beneath all pages
             $r .= "<input type=\"submit\" class=\"ui-state-default ui-corner-all\" value=\"" . lang::get('LANG_Save') . "\" />\n";
             $r .= "<input type=\"submit\" name=\"navigate:newoccurrence\" class=\"ui-state-default ui-corner-all\" value=\"" . lang::get('LANG_Save_and_New') . "\" />\n";
             $r .= "<input type=\"button\" class=\"ui-state-default ui-corner-all\"value=\"" . lang::get('LANG_Cancel') . "\" onclick=\"window.location.href='" . $cancelUrl . "'\" >\n";
         }
         $pageIdx++;
         $r .= "</div>\n";
     }
     $r .= "</div>\n";
     if ($args['interface'] == 'tabs' && $args['save_button_below_all_pages']) {
         $r .= "<input type=\"submit\" class=\"ui-state-default ui-corner-all\" value=\"" . lang::get('LANG_Save') . "\" />\n";
         $r .= "<input type=\"submit\" name=\"navigate:newoccurrence\" class=\"ui-state-default ui-corner-all\" value=\"" . lang::get('LANG_Save_and_New') . "\" />\n";
         $r .= "<input type=\"button\" class=\"ui-state-default ui-corner-all\" value=\"" . lang::get('LANG_Cancel') . "\" onclick=\"window.location.href='" . $cancelUrl . "'\" >\n";
     }
     if (!empty(data_entry_helper::$validation_errors)) {
         $r .= data_entry_helper::dump_remaining_errors();
     }
     $r .= "</form>";
     $url = self::$svcUrl . "/data/sample/" . data_entry_helper::$entity_to_load['sample:parent_id'];
     $url .= "?mode=json&view=detail&auth_token=" . self::$auth['read']['auth_token'] . "&nonce=" . self::$auth['read']['nonce'];
     $session = curl_init($url);
     curl_setopt($session, CURLOPT_RETURNTRANSFER, true);
     $entity = json_decode(curl_exec($session), true);
     if (isset($entity['error'])) {
         throw new Exception($entity['error']);
     }
     data_entry_helper::$javascript .= "\n// Create a vector layer to display the supersample location\n// the default edit layer is used for the subsamples\nSSStyleMap = new OpenLayers.StyleMap({\n                \"default\": new OpenLayers.Style({\n                    fillColor: \"Green\",\n                    strokeColor: \"Black\",\n                    fillOpacity: 0.2,\n                    strokeWidth: 1\n                  })\n  });\nSSLayer = new OpenLayers.Layer.Vector(\"" . lang::get("LANG_Supersample_Layer") . "\",\n                                    {styleMap: SSStyleMap});\nSSparser = new OpenLayers.Format.WKT();\nSSfeature = SSparser.read('" . $entity[0]['wkt'] . "');\nSSLayer.addFeatures([SSfeature]);\n";
     // The map can get initialised an awful lot later (eg when the tab it is on is displayed).
     // It is therefore virtually impossible to zoom to this supersample in as the code is not templated
     return $r;
 }