function format_missing_field_errors(&$entry)
{
    // $entry is a HeuristNativeEntry with validation problems;
    // return an array of errors describing the missing fields in the entry and its containers
    global $heurist_rectypes, $bib_requirement_names;
    if (!$heurist_rectypes) {
        load_heurist_rectypes();
    }
    if (!$bib_requirement_names) {
        load_bib_requirement_names();
    }
    $errors = array();
    $missing_fields = $entry->getMissingFields();
    if ($missing_fields) {
        $err_msg = '';
        $have_multiple = count($missing_fields) > 1;
        while ($field = array_shift($missing_fields)) {
            if ($err_msg && $missing_fields) {
                $err_msg .= ', ';
            } else {
                if ($err_msg) {
                    $err_msg .= ' and ';
                }
            }
            // except for the final one
            $err_msg .= strtoupper($bib_requirement_names[$entry->getReferenceType()][$field]);
        }
        $err_msg = strtoupper($heurist_rectypes[$entry->getReferenceType()]['rty_Name']) . ' is missing ' . $err_msg . ($have_multiple ? ' fields' : ' field');
        array_push($errors, $err_msg);
    }
    if ($entry->getContainerEntry()) {
        $container =& $entry->getContainerEntry();
        $container_errors = format_missing_field_errors($container);
        if ($container_errors && !$entry->containerIsOptional()) {
            // publisher is "optional" for non-book types (i.e. it's disregarded if none of its fields are specified at all)
            foreach ($container_errors as $error) {
                array_push($errors, $error);
            }
        }
    }
    return $errors;
}
 function get_field_value($field_name)
 {
     /* Return the value for the given field in this record */
     global $bib_type_name_to_id, $bib_requirement_names, $rectype_name_to_id;
     if (!$bib_type_name_to_id) {
         load_bib_type_name_to_id();
     }
     if (!$bib_requirement_names) {
         load_bib_requirement_names();
     }
     if (!$rectype_name_to_id) {
         load_rectype_name_to_id();
     }
     if (count($this->_fields_by_bdt_id) == 0) {
         // dupe code ... FIXME ... safe to remove now that this is handled in addField ..?
         for ($i = 0; $i < count($this->_fields); ++$i) {
             $field =& $this->_fields[$i];
             if (!$this->_fields_by_bdt_id[$field->_type]) {
                 $this->_fields_by_bdt_id[$field->_type] = array();
             }
             $this->_fields_by_bdt_id[$field->_type][] = $field->_value;
         }
     }
     if (strpos($field_name, '.') === FALSE) {
         /* direct field-name lookup */
         if (preg_match('/^(\\d+)/', $field_name, $matches)) {
             $rdt_id = $matches[1];
         } else {
             $rdt_id = $bib_type_name_to_id[strtolower($field_name)];
         }
         return join(', ', $this->_fields_by_bdt_id[$rdt_id]);
     }
     // have to decode a RESOURCE REFERENCE, and pull out a field from within that
     if (preg_match('/^(\\d+)\\s*(?:-[^.]*?)?\\.\\s*(.+)$/', $field_name, $matches)) {
         $rt_id = $matches[1];
         $inner_field_name = $matches[2];
     } else {
         if (preg_match('/^([^.]+?)\\s*\\.\\s*(.+)$/', $field_name, $matches)) {
             /*
             			$bdr = _title_mask__get_bib_detail_requirements();
             
             			$rt_id = $rectype_name_to_id$bib_requirement_names[$rt][strtolower($matches[1])];
             */
             // FIXME : currently assuming that the resource type linked to is the (former) container type
             $rt_id = $this->_container->getReferenceType();
             $inner_field_name = $matches[2];
         } else {
             return '';
         }
     }
     if ($rt_id && $inner_field_name) {
         // FIXME: we only understand two types of resource reference at the moment --
         // a person reference (author), and whatever used to correspond to the container type for this rectype
         if ($rt_id == 75) {
             // author reference//MAGIC NUMBER
             if (preg_match('/^(\\d+)/', $inner_field_name, $matches)) {
                 $inner_bdt_id = $matches[1];
             } else {
                 $inner_bdt_id = $bib_requirement_names[55][strtolower($inner_field_name)];
             }
             //MAGIC NUMBER
             /*****DEBUG****/
             //error_log($inner_bdt_id);
             /*****DEBUG****/
             //error_log($inner_field_name);
             /*****DEBUG****/
             //error_log(print_r($bib_requirement_names[55], 1));
             if ($this->_authors[0] == 'anonymous') {
                 if ($inner_bdt_id == 160) {
                     return 'Anonymous';
                 } else {
                     if ($inner_bdt_id == 291 && count($this->_authors) > 1) {
                         return 'et al.';
                     } else {
                         return '';
                     }
                 }
             }
             if (count($this->_authors) == 1) {
                 // a single author -- return the relevant field
                 return $this->_authors[0][$inner_bdt_id];
             } else {
                 if ($inner_bdt_id == 291) {
                     //MAGIC NUMBER// authors' first names are included after all else, so whack an "et al." on the end
                     return $this->_authors[0][$inner_bdt_id] . ' et al.';
                 } else {
                     return $this->_authors[0][$inner_bdt_id];
                     // multiple authors, but we're not being asked for the "first names" field
                     // -- just return the value for the first author
                 }
             }
         } else {
             if ($rt_id == $this->_container->getReferenceType()) {
                 return $this->_container->get_field_value($inner_field_name);
             }
         }
     }
     return '';
 }