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

/**
* Class for items served via the OAI-PMH Server plugin.
*/
class POAIItem implements OAIItem
{

    # ---- PUBLIC INTERFACE --------------------------------------------------

    /**
    * Object constructor.
    * @param int $ItemId ID of item.
    * @param array $RepDescr Repository description info.
    * @param array $SearchInfo Additional search data to be included with
    *       item metadata.  (OPTIONAL)
    */
    public function __construct($ItemId, array $RepDescr, $SearchInfo = NULL)
    {
        # save ID for later use
        $this->Id = $ItemId;

        # save any search info supplied
        $this->SearchInfo = $SearchInfo;

        # save the repository description
        $this->RepDescr = $RepDescr;

        # if resource ID was invalid
        if (!Resource::ItemExists($ItemId))
        {
            # set status to -1 to indicate constructor failure
            $this->LastStatus = -1;
        }
        else
        {
            # create resource object
            $this->Resource = new Resource($ItemId);

            # set status to 1 to indicate constructor success
            $this->LastStatus = 1;

            # if cumulative rating data is available for this resource
            global $SysConfig;
            if ($SysConfig->ResourceRatingsEnabled()
                    && $this->Resource->CumulativeRating())
            {
                # add cumulative rating data to search info
                $this->SearchInfo["cumulativeRating"] =
                        $this->Resource->CumulativeRating();
                $this->SearchInfo["cumulativeRatingScale"] = 100;
            }
        }
    }

    /**
    * Retrieve item ID.
    * @return int Item ID.
    */
    public function GetId()
    {
        return $this->Id;
    }

    /**
    * Retrieve date stamp associated with item.
    * @return string Date stamp in ISO-8601 format.
    */
    public function GetDatestamp()
    {
        $DateString = $this->Resource->Get("Date Of Record Creation");
        if (!isset($DateString) ||
            $DateString == "0000-00-00 00:00:00") {  $DateString = date("Y-m-d");  }
        $Date = new Date($DateString);
        return $Date->FormattedISO8601();
    }

    /**
    * Retrieve value for specified element.
    * @param string $ElementName Name of element.
    * @return mixed Value for element (string or may be an array if
    *       element is for a Reference field).
    */
    public function GetValue($ElementName)
    {
        # if requested value is a preferred link value
        if ($ElementName == -3)
        {
            $ReturnValue = $this->GetPreferredLinkValueForResource($this->Resource);
        }
        # if requested value is full record page URL
        elseif ($ElementName == -2)
        {
            # set value to full record page URL
            $ReturnValue = $this->GetFullRecordUrlForResource($this->Resource->Id());
        }
        # if requested value is fixed default
        elseif ($ElementName == -3)
        {
            $ReturnValue = NULL;
        }
        else
        {
            # retrieve value
            $ReturnValue = $this->Resource->GetByFieldId($ElementName);

            # this isn't technically necessary for the checks below, but it
            # reduces some overhead when the field obviously isn't a reference
            if (is_array($ReturnValue))
            {
                $Schema = new MetadataSchema();
                $Field = $Schema->GetField($ElementName);

                # if the field is a reference field
                if ($Field->Type() == MetadataSchema::MDFTYPE_REFERENCE)
                {
                    # translate each resource ID to an OAI identifier
                    foreach ($ReturnValue as $Key => $Value)
                    {
                        $ReturnValue[$Key] = $this->GetOaiIdentifierForResource(
                            $Value);
                    }
                }
            }

            # strip out any HTML tags if text value
            if (is_string($ReturnValue))
            {
                $ReturnValue = strip_tags($ReturnValue);
            }

            # format correctly if standardized date
            if ($this->GetQualifier($ElementName) == "W3C-DTF")
            {
                $Timestamp = strtotime($ReturnValue);
                $ReturnValue = date('Y-m-d\TH:i:s', $Timestamp)
                        .substr_replace(date('O', $Timestamp), ':', 3, 0);
            }
        }

        # return value to caller
        return $ReturnValue;
    }

    /**
    * Retrieve qualifier for specified element.
    * @param string $ElementName Name of element.
    * @return string Qualifier for element.
    */
    public function GetQualifier($ElementName)
    {
        $ReturnValue = NULL;
        $Qualifier = $this->Resource->GetQualifierByFieldId($ElementName, TRUE);
        if (is_array($Qualifier))
        {
            foreach ($Qualifier as $ItemId => $QualObj)
            {
                if (is_object($QualObj))
                {
                    $ReturnValue[$ItemId] = $QualObj->Name();
                }
            }
        }
        else
        {
            if (isset($Qualifier) && is_object($Qualifier))
            {
                $ReturnValue = $Qualifier->Name();
            }
        }
        return $ReturnValue;
    }

    /**
    * Retrieve list of sets to which this item belongs.
    * @return array List of sets (strings).
    */
    public function GetSets()
    {
        # start out with empty list
        $Sets = array();

        # for each possible metadata field
        $Schema = new MetadataSchema();
        $Fields = $Schema->GetFields(MetadataSchema::MDFTYPE_TREE
                |MetadataSchema::MDFTYPE_CONTROLLEDNAME
                |MetadataSchema::MDFTYPE_OPTION);
        foreach ($Fields as $Field)
        {
            # if field is flagged for use for OAI sets
            if ($Field->UseForOaiSets())
            {
                # retrieve values for resource for this field and add to set list
                $FieldName = $Field->Name();
                $Values = $this->Resource->Get($FieldName);
                if (isset($Values) && ($Values != NULL))
                {
                    $NormalizedFieldName = $this->NormalizeForSetSpec($FieldName);
                    if (is_array($Values) && count($Values))
                    {
                        foreach ($Values as $Value)
                        {
                            $Sets[] = $NormalizedFieldName.":"
                                    .$this->NormalizeForSetSpec($Value);
                        }
                    }
                    else
                    {
                        $Sets[] = $NormalizedFieldName.":"
                                .$this->NormalizeForSetSpec($Values);
                    }
                }
            }
        }

        # return list of sets to caller
        return $Sets;
    }

    /**
    * Retrieve additional search info, if any.  (Passed in via constructor.)
    * @return array Search info.
    */
    public function GetSearchInfo()
    {
        return $this->SearchInfo;
    }

    /**
    * Check whether object constructor succeeded.
    * @return int 1 if constructor succeeded, or -1 if it failed.
    */
    public function Status()
    {
        return $this->LastStatus;
    }


    # ---- PRIVATE INTERFACE -------------------------------------------------

    private $Id;
    private $Resource;
    private $LastStatus;
    private $RepDescr;
    private $SearchInfo;

    /**
    * Normalize value for use as an OAI set spec.
    * @param string $Name Value to normalize.
    * @return string Normalized value.
    */
    protected function NormalizeForSetSpec($Name)
    {
        return preg_replace("/[^a-zA-Z0-9\-_.!~*'()]/", "", $Name);
    }

    /**
    * Get the URL to the full record of a resource.
    * @param int $ResourceId Resource ID.
    * @return string The URL to the full record of the resource.
    * @see GetOaiIdentifierForResource()
    */
    protected function GetFullRecordUrlForResource($ResourceId)
    {
        $SafeResourceId = urlencode($ResourceId);
        return OurBaseUrl() .
            $GLOBALS["AF"]->GetCleanUrlForPath(
            "index.php?P=FullRecord&ID=" . $SafeResourceId );
    }

    /**
    * Get the Preferred Link Value for a resource.
    * @param Resource $Resource Resource to use.
    * @return string URL corresponding to the pref. link value.
    */
    protected function GetPreferredLinkValueForResource($Resource)
    {
        global $G_SysConfig;

        $GLOBALS["AF"]->LoadFunction("GetResourceFieldValue");

        # start off assuming no result
        $Result = "";

        # pull the mapped URL and File fields from the schema
        $Schema = new MetadataSchema();
        $UrlField = $Schema->GetFieldByMappedName("Url");
        $FileField = $Schema->GetFieldByMappedName("File");

        $Url = ( !is_null($UrlField) &&
                 $UrlField->Status() === MetadataSchema::MDFSTAT_OK )
            ? GetResourceFieldValue($Resource, $UrlField) : "";
        $Files = ( !is_null($FileField) &&
                   $FileField->Status() === MetadataSchema::MDFSTAT_OK )
            ? GetResourceFieldValue($Resource, $FileField) : array();

        # figure out what the preferred link should be
        if (is_array($Files) && count($Files) > 0
            && ($G_SysConfig->Value("PreferredLinkValue") == "FILE"
                || !$G_SysConfig->Value("PreferredLinkValue")))
        {
            # if we prefer files, use the first one
            $LinkFlie = array_shift($Files);
            $Result =  OurBaseUrl() .
                $GLOBALS["AF"]->GetCleanUrlForPath(
                $LinkFile->GetLink() );
        }
        elseif (strlen($Url) > 0)
        {
            # otherwise, if there's a sane-looking URL, use that
            if ( preg_match('/^\s*[a-zA-Z]+:\/\//', $Url) )
            {
                $Result = $Url;
            }
        }

        return $Result;
    }

    /**
    * Get the OAI identifier of a resource.
    * @param int $ResourceId Resource ID.
    * @return string The OAI identifier of a resource.
    * @see GetFullRecordUrlForResource()
    */
    protected function GetOaiIdentifierForResource($ResourceId)
    {
        # return encoded value to caller
        return "oai:".$this->RepDescr["IDDomain"]
                .":".$this->RepDescr["IDPrefix"]."-".$ResourceId;
    }
}

