<?PHP
#
#   FILE:  ItemFactory.php
#
#   Part of the Collection Workflow Integration System (CWIS)
#   Copyright 2013 Edward Almasy and Internet Scout Research Group
#   http://scout.wisc.edu/cwis/
#

/**
 * Given a metadata field, this class returns human-readable values for each
 * value of the field.
 */
class HumanMetadataField
{

    /**
     * Save the field that will be used to generate the human-readable values.
     * @param MetadataField $Field metadata field
     */
    public function __construct(MetadataField $Field)
    {
        $this->Field = $Field;
    }

    /**
     * Get the human-readable error status of the field.
     * @return string human-readable error status
     */
    public function Status()
    {
        switch ($this->Field->Status())
        {
            case MetadataSchema::MDFSTAT_OK:
                return "OK";
            case MetadataSchema::MDFSTAT_ERROR:
                return "Error";
            case MetadataSchema::MDFSTAT_DUPLICATENAME:
                return "Duplicate field name";
            case MetadataSchema::MDFSTAT_DUPLICATEDBCOLUMN:
                return "Duplicate database column";
            case MetadataSchema::MDFSTAT_FIELDDOESNOTEXIST:
                return "Field does not exist";
            case MetadataSchema::MDFSTAT_ILLEGALNAME:
                return "Illegal field name";
            case MetadataSchema::MDFSTAT_DUPLICATELABEL:
                return "Duplicate label name";
            case MetadataSchema::MDFSTAT_ILLEGALLABEL:
                return "Illegal label name";
        }

        return $this->NotSetText;
    }

    /**
     * Get the human-readable field type of the field.
     * @return string human-readable field type
     */
    public function Type()
    {
        return MetadataField::$FieldTypeDBEnums[$this->Field->Type()];
    }

    /**
     * Get the human-readable field type of the field.
     * @return string human-readable field type
     */
    public function TypeAsName()
    {
        return $this->Field->TypeAsName();
    }

    /**
     * Get the human-readable display name of the field.
     * @return string human-readable display name of the field
     */
    public function GetDisplayName()
    {
        return $this->Field->GetDisplayName();
    }

    /**
     * Get the human-readable name of the field.
     * @return string human-readable field name
     */
    public function Name()
    {
        return $this->Field->Name();
    }

    /**
     * Get the human-readable label of the field.
     * @return string human-readable field label
     */
    public function Label()
    {
        return $this->GetValueCheckingLength($this->Field->Label());
    }

    /**
     * Get the human-readable allowed conversion types of the field.
     * @return string human-readable allowed conversion types of the field
     */
    public function GetAllowedConversionTypes()
    {
        $Value = $this->Field->GetAllowedConversionTypes();

        return count($Value) ? implode(", ", $Value) : $this->NotSetText;
    }

    /**
     * Get the human-readable string that indicates if the field is a temporary
     * field.
     * @return string human-readable string indicating if the field is temporary
     */
    public function IsTempItem()
    {
        return $this->GetYesNo($this->Field->IsTempItem());
    }

    /**
     * Get the human-readable field ID.
     * @return string human-readable field ID
     */
    public function Id()
    {
        return $this->Field->Id();
    }

    /**
     * Get the human-readable database field name of the field.
     * @return string human-readable database field name
     */
    public function DBFieldName()
    {
        return $this->Field->DBFieldName();
    }

    /**
     * Get the human-readable description of the field.
     * @return string human-readable field description
     */
    public function Description()
    {
        # for our purposes, HTML code and some whitespace are not human-readable
        $Value = strip_tags($this->Field->Description());
        $Value = trim(str_replace(array("\r", "\n", "\t"), " ", $Value));
        $Value = preg_replace('/ +/', " ", $Value);

        return $this->GetValueCheckingLength($Value);
    }

    /**
     * Get the human-readable instructions of the field.
     * @return string human-readable field instructions
     */
    public function Instructions()
    {
        # for our purposes, HTML code and some whitespace are not human-readable
        $Value = strip_tags($this->Field->Instructions());
        $Value = trim(str_replace(array("\r", "\n", "\t"), " ", $Value));
        $Value = preg_replace('/ +/', " ", $Value);

        return $this->GetValueCheckingLength($Value);
    }

    /**
     * Get the human-readable field owner.
     * @return string human-readable field owner
     */
    public function Owner()
    {
        return $this->GetValueCheckingLength($this->Field->Owner());
    }

    /**
     * Get the human-readable string that indicates if the field is required by
     * SPT.
     * @return string human-readable string indicating if SPT requires the field
     */
    public function RequiredBySPT()
    {
        return $this->GetYesNo($this->Field->RequiredBySPT());
    }

    /**
     * Get the human-readable string that indicates if the field is enabled.
     * @return string human-readable string indicating if the field is enabled
     */
    public function Enabled()
    {
        return $this->GetYesNo($this->Field->Enabled());
    }

    /**
     * Get the human-readable string that indicates if the field is optional.
     * @return string human-readable string indicating if the field is optional
     */
    public function Optional()
    {
        return $this->GetYesNo($this->Field->Optional());
    }

    /**
     * Get the human-readable string that indicates if the field is editable.
     * @return string human-readable string indicating if the field is editable
     */
    public function Editable()
    {
        return $this->GetYesNo($this->Field->Editable());
    }

    /**
     * Get the human-readable string that indicates if the field is viewable.
     * @return string human-readable string indicating if the field is viewable
     */
    public function Viewable()
    {
        return $this->GetYesNo($this->Field->Viewable());
    }

    /**
     * Get the human-readable string that indicates if multiple field values are
     * permitted.
     * @return string human-readable string indicating if multiple field values
     *   are permitted
     */
    public function AllowMultiple()
    {
        return $this->GetYesNo($this->Field->AllowMultiple());
    }

    /**
     * Get the human-readable string that indicates if the field is included in
     * keyword searches.
     * @return string human-readable string indicating if the field is included
     *   in keyword searches
     */
    public function IncludeInKeywordSearch()
    {
        return $this->GetYesNo($this->Field->IncludeInKeywordSearch());
    }

    /**
     * Get the human-readable string that indicates if the field is included in
     * advanced search options
     * @return string human-readable string indicating if the field is included
     *   in advanced search options
     */
    public function IncludeInAdvancedSearch()
    {
        return $this->GetYesNo($this->Field->IncludeInAdvancedSearch());
    }

    /**
    * Get the human-readable string that indicates if the field is included in
    * faceted search options.
    * @return Returns the human-readable string indicating if the field is
    *      included in faceted search options.
    */
    public function IncludeInFacetedSearch()
    {
        return $this->GetYesNo($this->Field->IncludeInFacetedSearch());
    }

    /**
     * Get the human-readable string that indicates if the field is included in
     * sort options.
     * @return string human-readable string indicating if the field is included
     *   in sort options
     */
    public function IncludeInSortOptions()
    {
        return $this->GetYesNo($this->Field->IncludeInSortOptions());
    }

    /**
     * Get the human-readable string that indicates if the field is included in
     * the recommender system.
     * @return string human-readable string indicating if the field is included
     *   in the recommender system
     */
    public function IncludeInRecommender()
    {
        return $this->GetYesNo($this->Field->IncludeInRecommender());
    }

    /**
     * Get the human-readable size of text field inputs.
     * @return string human-readable size of text field inputs
     */
    public function TextFieldSize()
    {
        return $this->GetValueCheckingLength($this->Field->TextFieldSize());
    }

    /**
     * Get the human-readable maximum size of text field values.
     * @return string human-readable maximum size of text field values
     */
    public function MaxLength()
    {
        return $this->GetValueCheckingLength($this->Field->MaxLength());
    }

    /**
     * Get the human-readable number of rows of paragraph field inputs.
     * @return string human-readable number of rows of paragraph field inputs
     */
    public function ParagraphRows()
    {
        return $this->GetValueCheckingLength($this->Field->ParagraphRows());
    }

    /**
     * Get the human-readable number of columns of paragraph field inputs.
     * @return string human-readable number of columns of paragraph field inputs
     */
    public function ParagraphCols()
    {
        return $this->GetValueCheckingLength($this->Field->ParagraphCols());
    }

    /**
     * Get the human-readable minimum value for number fields.
     * @return string human-readable minimum value for number fields
     */
    public function MinValue()
    {
        return $this->GetValueCheckingLength($this->Field->MinValue());
    }

    /**
     * Get the human-readable maximum value for number fields.
     * @return string human-readable maximum value for number fields
     */
    public function MaxValue()
    {
        return $this->GetValueCheckingLength($this->Field->MaxValue());
    }

    /**
     * Get the human-readable flag-on label for flag fields.
     * @return string human-readable flag-on label for flag fields
     */
    public function FlagOnLabel()
    {
        return $this->GetValueCheckingLength($this->Field->FlagOnLabel());
    }

    /**
     * Get the human-readable flag-off label for flag fields.
     * @return string human-readable flag-off label for flag fields
     */
    public function FlagOffLabel()
    {
        return $this->GetValueCheckingLength($this->Field->FlagOffLabel());
    }

    /**
     * Get the human-readable field date format.
     * @return string human-readable field date format
     */
    public function DateFormat()
    {
        return $this->GetValueCheckingLength($this->Field->DateFormat());
    }

    /**
     * Get the human-readable search weight of the field.
     * @return string human-readable field search weight
     */
    public function SearchWeight()
    {
        return $this->GetValueCheckingLength($this->Field->SearchWeight());
    }

    /**
     * Get the human-readable recommender weight of the field.
     * @return string human-readable field recommender weight
     */
    public function RecommenderWeight()
    {
        return $this->GetValueCheckingLength($this->Field->RecommenderWeight());
    }

    /**
     * Get the human-readable maximum height of images of image fields.
     * @return string human-readable maximum height of images of image fields
     */
    public function MaxHeight()
    {
        return $this->GetValueCheckingLength($this->Field->MaxHeight());
    }

    /**
     * Get the human-readable maximum width of images of image fields.
     * @return string human-readable maximum width of images of image fields
     */
    public function MaxWidth()
    {
        return $this->GetValueCheckingLength($this->Field->MaxWidth());
    }

    /**
     * Get the human-readable maximum height of preview images of image fields.
     * @return string human-readable maximum height of preview images of image
     *   fields
     */
    public function MaxPreviewHeight()
    {
        return $this->GetValueCheckingLength($this->Field->MaxPreviewHeight());
    }

    /**
     * Get the human-readable maximum width of preview images of image fields.
     * @return string human-readable maximim width of preview images of image
     *   fields
     */
    public function MaxPreviewWidth()
    {
        return $this->GetValueCheckingLength($this->Field->MaxPreviewWidth());
    }

    /**
     * Get the human-readable maximum height of thumbnail images of image
     * fields.
     * @return string human-readable maximum height of thumbnail images of image
     *   fields
     */
    public function MaxThumbnailHeight()
    {
        return $this->GetValueCheckingLength($this->Field->MaxThumbnailHeight());
    }

    /**
     * Get the human-readable maximum width of thumbnail images of image fields.
     * @return string human-readable maximum width of thumbnail images of image
     *   fields
     */
    public function MaxThumbnailWidth()
    {
        return $this->GetValueCheckingLength($this->Field->MaxThumbnailWidth());
    }

    /**
     * Get the human-readable default alternate text of images of image fields.
     * @return string human-readable default alternate text of images of image
     *   fields
     */
    public function DefaultAltText()
    {
        return $this->GetValueCheckingLength($this->Field->DefaultAltText());
    }

    /**
     * Get the human-readable string indicating if the field uses qualifiers.
     * @return string human-readable string indicating if the field uses
     *   qualifiers
     */
    public function UsesQualifiers()
    {
        return $this->GetYesNo($this->Field->UsesQualifiers());
    }

    /**
     * Get the human-readable string indicating if qualifiers are shown for the
     * field.
     * @return string human-readable string indicating if qualifiers are shown
     *   for the field
     */
    public function ShowQualifiers()
    {
        return $this->GetYesNo($this->Field->ShowQualifiers());
    }

    /**
     * Get the human-readable default qualifier of the field.
     * @return string human-readable default qualifier of the field
     */
    public function DefaultQualifier()
    {
        $DefaultQualifier = $this->Field->DefaultQualifier();

        if ($DefaultQualifier > 0)
        {
            $Qualifier = new Qualifier($DefaultQualifier);

            return $Qualifier->Name();
        }

        return $this->NotSetText;
    }

    /**
     * Get the human-readable string indicating if HTML is allowed as the value.
     * @return string human-readable string indicating if HTML is allowed as the
     *   value
     */
    public function AllowHTML()
    {
        return $this->GetYesNo($this->Field->AllowHTML());
    }

    /**
     * Get the human-readable string indicating if a WYSIWYG editor should be
     * used when editing the field value.
     * @return string human-readable string indicating if a WYSIWYG editor
     *   should be used when editing the field value
     */
    public function UseWysiwygEditor()
    {
        return $this->GetYesNo($this->Field->UseWysiwygEditor());
    }

    /**
     * Get the human-readable string indicating if the field should be used for
     * OAI sets.
     * @return string human-readable string indicating if the field should be
     *   used for OAI sets
     */
    public function UseForOaiSets()
    {
        return $this->GetYesNo($this->Field->UseForOaiSets());
    }

    /**
     * Get the human-readable number of AJAX search results to display for the
     * field.
     * @return string human-readable number of AJAX search results to display
     */
    public function NumAjaxResults()
    {
        return $this->Field->NumAjaxResults();
    }

    /**
     * Get the human-readable viewing privilege of the field.
     * @return string human-readable field viewing privilege
     */
    public function ViewingPrivilege()
    {
        $Value = $this->MapPrivilege($this->Field->ViewingPrivilege());

        return $this->GetValueCheckingLength($Value);
    }

    /**
     * Get the human-readable authoring privilege of the field.
     * @return string human-readable field authoring privilege
     */
    public function AuthoringPrivilege()
    {
        $Value = $this->MapPrivilege($this->Field->AuthoringPrivilege());

        return $this->GetValueCheckingLength($Value);
    }

    /**
     * Get the human-readable editing privilege of the field.
     * @return string human-readable field editing privilege
     */
    public function EditingPrivilege()
    {
        $Value = $this->MapPrivilege($this->Field->EditingPrivilege());

        return $this->GetValueCheckingLength($Value);
    }

    /**
     * Get the human-readable image preview privilege of image fields.
     * @return string human-readable image preview privilege of image fields
     */
    public function ImagePreviewPrivilege()
    {
        $Value = $this->MapPrivilege($this->Field->ImagePreviewPrivilege());

        return $this->GetValueCheckingLength($Value);
    }

    /**
     * Get the human-readable string indicating if the field should be enabled
     * when the owner/plugin is available.
     * @return string human-readable string indicating if the field should be
     *   enabled when the owner returns
     */
    public function EnableOnOwnerReturn()
    {
        return $this->GetYesNo($this->Field->EnableOnOwnerReturn());
    }

    /**
     * Get the human-readable viewing user is value of the field
     * @return string human-readable viewing user is value of the field.
     */
    public function ViewingUserIsValue()
    {
        $Value = $this->MapUserIsValue($this->Field->ViewingUserIsValue());

        return $this->GetValueCheckingLength($Value);
    }

    /**
     * Get the human-readable authoring user is value of the field.
     * @return string human-readable authoring user is value of the field
     */
    public function AuthoringUserIsValue()
    {
        $Value = $this->MapUserIsValue($this->Field->AuthoringUserIsValue());

        return $this->GetValueCheckingLength($Value);
    }

    /**
     * Get the human-readable editing user is value of the field.
     * @return string human-readable editing user is value of the field
     */
    public function EditingUserIsValue()
    {
        $Value = $this->MapUserIsValue($this->Field->EditingUserIsValue());

        return $this->GetValueCheckingLength($Value);
    }

    /**
     * Get the human-readable viewing user value of the field.
     * @return string human-readable viewing user value of the field
     */
    public function ViewingUserValue()
    {
        $Value = $this->MapUserValue($this->Field->ViewingUserValue());

        return $this->GetValueCheckingLength($Value);
    }

    /**
     * Get the human-readable authoring user value of the field.
     * @return string human-readable authoring user value of the field
     */
    public function AuthoringUserValue()
    {
        $Value = $this->MapUserValue($this->Field->AuthoringUserValue());

        return $this->GetValueCheckingLength($Value);
    }

    /**
     * Get the human-readable editing user value of the field.
     * @return string human-readable editing user value of the field
     */
    public function EditingUserValue()
    {
        $Value = $this->MapUserValue($this->Field->EditingUserValue());

        return $this->GetValueCheckingLength($Value);
    }

    /**
     * Get the human-readable user privilege restrictions of user fields.
     * @return string human-readable user privilege restrictions of user fields
     */
    public function UserPrivilegeRestrictions()
    {
        $Value = $this->Field->UserPrivilegeRestrictions();
        $Values = array();

        # need to map each privilege ID to its text
        foreach ($Value as $Id)
        {
            $Values[] = $this->MapPrivilege($Id);
        }

        return count($Values) ? implode(", ", $Values) : $this->NotSetText;
    }

    /**
     * Get the human-readable point precision of point fields.
     * @return string human-readable point precision of point fields
     */
    public function PointPrecision()
    {
        return $this->GetValueCheckingLength($this->Field->PointPrecision());
    }

    /**
     * Get the human-readable point decimal digits of point fields.
     * @return string human-readable point decimal digits of point fields
     */
    public function PointDecimalDigits()
    {
        return $this->GetValueCheckingLength($this->Field->PointDecimalDigits());
    }

    /**
     * Get the human-readable default value of the field.
     * @return string human-readable default value of the field
     */
    public function DefaultValue()
    {
        $Type = $this->Field->Type();
        $Value = $this->Field->DefaultValue();

        if ($Type == MetadataSchema::MDFTYPE_POINT)
        {
            $XText = NULL;
            $X = $Value["X"];
            $Y = $Value["Y"];

            if (strlen($X))
            {
                $XText = "X: " . $X;
            }

            if (strlen($Y))
            {
                return (strlen($XText) ? $XText . ", " : "") . "Y: " . $Y;
            }

            return $this->NotSetText;
        }

        if ($Type == MetadataSchema::MDFTYPE_OPTION)
        {
            # multiple default values are set
            if (is_array($Value))
            {
                foreach ($Value as $Id)
                {
                    $ControlledName = new ControlledName($Id);

                    $Names[] = $ControlledName->Name();
                }

                return implode(", ", $Names);
            }

            # only one default value
            else if ($Value)
            {
                $ControlledName = new ControlledName($Value);

                return $ControlledName->Name();
            }

            return $this->NotSetText;
        }

        if ($Type == MetadataSchema::MDFTYPE_FLAG)
        {
            return $Value ? $this->FlagOnLabel() : $this->FlagOffLabel();
        }

        return $this->GetValueCheckingLength($Value);
    }

    /**
     * Get the human-readable update method of the field.
     * @return string human-readable update method of the field
     */
    public function UpdateMethod()
    {
        $Value = $this->Field->UpdateMethod();
        $String = $this->GetArrayValue(MetadataField::$UpdateTypes, $Value);

        return $this->GetValueCheckingLength($String);
    }

    /**
     * Get the human-readable possible values of the field. This is only
     * meaningful for Tree, ControlledName, Option, Flag, and User fields.
     * @return string human-readable possible values of the field
     */
    public function GetPossibleValues()
    {
        $Value = $this->Field->GetPossibleValues();

        return count($Value) ? implode(", ", $Value) : $this->NotSetText;
    }

    /**
     * Get the human-readable count of possible values of the field. This is
     * only meaningful for Tree, ControlledName, Option, Flag, and User fields.
     * @return string human-readable count of possible values of the field
     */
    public function GetCountOfPossibleValues()
    {
        return $this->GetValueCheckingLength($this->Field->GetCountOfPossibleValues());
    }

    /**
     * Get the human-readable string that indicates if the field has item-level
     * qualifiers.
     * @return string human-readable string indicating if the field has
     *   item-level qualifiers
     */
    public function HasItemLevelQualifiers()
    {
        return $this->GetYesNo($this->Field->HasItemLevelQualifiers());
    }

    /**
     * Get the human-readable list of associated qualifiers of the field.
     * @return string human-readable list of associated field qualifiers
     */
    public function AssociatedQualifierList()
    {
        $Value = $this->Field->AssociatedQualifierList();

        return count($Value) ? implode(", ", $Value) : $this->NotSetText;
    }
    /**
     * Get the human-readable list of unassociated qualifiers of the field.
     * @return string human-readable list of unassociated field qualifiers
     */
    public function UnassociatedQualifierList()
    {
        $Value = $this->Field->UnassociatedQualifierList();

        return count($Value) ? implode(", ", $Value) : $this->NotSetText;
    }

    /**
     * Get the human-readable viewing privilege string that includes the viewing
     * privilege required, along with the the "user is value ..." setting.
     * @return string human-readable viewing privilege string
     */
    public function GetViewingPrivilegeString()
    {
        return $this->GetPrivilegeString("Viewing");
    }

    /**
     * Get the human-readable authoring privilege string that includes the
     * authoring privilege required, along with the the "user is value ..."
     * setting.
     * @return string human-readable authoring privilege string
     */
    public function GetAuthoringPrivilegeString()
    {
        return $this->GetPrivilegeString("Authoring");
    }

    /**
     * Get the human-readable editing privilege string that includes the editing
     * privilege required, along with the the "user is value ..." setting.
     * @return string human-readable editing privilege string
     */
    public function GetEditingPrivilegeString()
    {
        return $this->GetPrivilegeString("Editing");
    }

    /**
     * Get the text that is used when a value is not set.
     * @return string text used when a value is not set
     */
    public function GetNotSetText()
    {
        return $this->NotSetText;
    }

    /**
     * Set the text that is used when a value is not set.
     * @param string $Text text to be used when a value is not set
     */
    public function SetNotSetText($Text)
    {
        $this->NotSetText = $Text;
    }

    /**
     * Get the human-readable string for a boolean-like value.
     * @param mixed $Value boolean-like value
     * @return string the human-readable string for the value
     */
    protected function GetYesNo($Value)
    {
        return $Value ? "Yes" : "No";
    }

    /**
     * Get the value or the not-set text depending on the length of the value.
     * @param string $Value value to check
     * @return string the value if the string length is greater than zero or the
     *   not-set text if it is zero
     */
    protected function GetValueCheckingLength($Value)
    {
        return strlen($Value) ? $Value : $this->NotSetText;
    }

    /**
     * This method makes getting privilege strings for viewing, authoring, and
     * editing a little more convenient.
     * @param string $Mode should be one of "Viewing", "Authoring", or "Editing"
     * @return string human-readable privilege string
     */
    protected function GetPrivilegeString($Mode)
    {
        $Privilege = $this->MapPrivilege($this->Field->{$Mode."Privileges"}());
        $UserIsValue = $this->MapUserIsValue($this->Field->{$Mode."UserIsValue"}());
        $UserValue = $this->MapUserValue($this->Field->{$Mode."UserValue"}());

        $String = NULL;

        # add the user privilege constraint first, if set
        if (!is_null($Privilege))
        {
            $String = $Privilege;
        }

        # then add the "user is value of field" constraint, if set
        if (!is_null($UserIsValue) && !is_null($UserValue))
        {
            if (is_null($String))
            {
                $String = "User is value of " . $UserValue;
            }

            else
            {
                $String .= " " . $UserIsValue . " user is value of ";
                $String .= $UserValue;
            }
        }

        return is_null($String) ? $this->NotSetText : $String;
    }

    /**
     * Map a privilege value to a privilege name.
     * @param string|int $Value privilege value
     * @return string privilege name
     */
    protected function MapPrivilege($Value)
    {
        if (!isset(self::$PrivilegeList))
        {
            $this->LoadPrivilegeList();
        }

        return $this->GetArrayValue(self::$PrivilegeList, $Value);
    }

    /**
     * Load the static privilege list.
     */
    protected function LoadPrivilegeList()
    {
        $PrivilegeFactory = new PrivilegeFactory();

        self::$PrivilegeList = $PrivilegeFactory->GetPrivileges(TRUE, FALSE);
    }

    /**
     * Map a UserIsValue value to a name.
     * @param int $Value UserIsValue value
     * @return string UserIsValue name
     */
    protected function MapUserIsValue($Value)
    {
        return $this->GetArrayValue(self::$UserIsValueList, $Value);
    }

    /**
     * Map a UserValue value to a field display name.
     * @param int $Value UserValue value
     * @return string user field display name
     */
    protected function MapUserValue($Value)
    {
        if (!isset(self::$UserFieldList))
        {
            $this->LoadUserFieldList();
        }

        return $this->GetArrayValue(self::$UserFieldList, $Value);
    }

    /**
     * Load the static user field list.
     */
    protected function LoadUserFieldList()
    {
        $Schema = new MetadataSchema($this->Field->SchemaId());
        $UserFields = $Schema->GetFields(MetadataSchema::MDFTYPE_USER);

        # make sure the list is set to something even if there are no user
        # fields
        self::$UserFieldList = array();

        foreach ($UserFields as $Field)
        {
            self::$UserFieldList[$Field->Id()] = $Field->GetDisplayName();
        }
    }

    /**
     * Get the value from an array with a given index or a default value if it
     * does not exist.
     * @param array $Array array to check
     * @param mixed $Key index of the value to retrieve
     * @param mixed $Default value to return if the value does not exist
     *   (defaults to NULL)
     * @return mixed the value at the given index or the default value if it
     *   doesn't exist
     */
    protected function GetArrayValue(array $Array, $Key, $Default=NULL)
    {
        return array_key_exists($Key, $Array) ? $Array[$Key] : $Default;
    }

    /**
     * The metadata field that is having its values returned in human-readable
     * form.
     * @var MetadataField $Field
     */
    protected $Field;

    /**
     * The text used when a value is not set.
     * @var string $NotSetText
     */
    protected $NotSetText = "--";

    /**
     * A static array of privilege values and names.
     * @var array $PrivilegeList
     */
    protected static $PrivilegeList;

    /**
     * A static array of UserIsValue strings.
     * @var array $UserIsValueList
     */
    protected static $UserIsValueList = array(
        MetadataField::USERISVALUE_OR => "or",
        MetadataField::USERISVALUE_AND => "and");

    /**
     * A static array of user fields.
     * @var array $UserFieldList
     */
    protected static $UserFieldList;

}
