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

# ----- LOCAL FUNCTIONS ------------------------------------------------------

/**
* Add images to the description of the RSS item.
* @param string $Description The unmodified description of the item.  (OPTIONAL)
* @param int $ResourceId The ID of the corresponding resource.
* @param int $ImageFieldId The ID of the MetadataSchema::MDFTYPE_IMAGE metadata
*       field.  (OPTIONAL)
* @return string The description with images added to it.
*/
function AddImagesToDescription($Description = NULL, $ResourceId = NULL,
        $ImageFieldId = NULL)
{
    # make sure we have the parameters we need
    if ($Description == NULL) { $Description = ""; }
    if ($ResourceId == NULL) { return $Description; }
    if ($ImageFieldId == NULL) { return $Description; }

    # create the metadatafield object
    $ImageField = new MetadataField($ImageFieldId);

    # start by assuming no images will be found
    $ImageIds = array();

    # find all images associated with the resource
    $DB = new Database();
    $DB->Query("SELECT ImageId FROM ResourceImageInts "
            . "WHERE ResourceId = " . $ResourceId
            . " AND FieldId = " . $ImageFieldId);

    # if images were found put the image objects into the array
    if ($DB->NumRowsSelected())
    {
        $ImageIds = $DB->FetchColumn("ImageId");
    }

    # for each image id that was found
    foreach($ImageIds as $ImageId)
    {
        # create an image object
        $Image = new SPTImage($ImageId);

        # add each image to the description
        $Description = $Description . "<![CDATA[ <br /><img src='" . OurBaseUrl()
                . $Image->Url() . "' alt='" . $ImageField->GetDisplayName()
                . "' \>]]>";
    }

    # give back the item description
    return $Description;
}

/**
* Get the resources that will be items in the RSS feed.
* @param int $SchemaId The ID of the MetadataSchema to use in the search.
* @param int $DateFieldId The ID of the MetadataSchema::MDFTYPE_DATE metadata
*       field to use to filter the search results.
* @param string $Parameters The search parameters to use,
*       in the form of a query string.  (OPTIONAL)
* @param int $NumberOfEntriesToPublish The number of resources to return.
*       (OPTIONAL)
* @return array An array of $NumberOfEntriesToPublish resources in the schema
*       $SchemaId, sorted using the $DateFieldId date descending.
*/
function GetResources($SchemaId, $DateFieldId, $Parameters = "",
        $NumberOfEntriesToPublish = NULL)
{
    global $G_SysConfig;

    # start out with no resources to return
    $Resources = array();

    # give up if we don't have a schema ID and a date field ID
    if ($SchemaId === NULL || $DateFieldId === NULL)
    {
        return $Resources;
    }

    # get the schema and date field
    $Schema = new MetadataSchema($SchemaId);
    $DateField = $Schema->GetField($DateFieldId);

    # give up if the date field isn't in the schema
    if ($DateField === NULL)
    {
        return $Resources;
    }

    # grab a resource factory, set up search parameters
    $RFactory = new ResourceFactory($SchemaId);

    $SearchParams = new SearchParameterSet();
    $SearchParams->UrlParameters($Parameters);

    # if we are using the default schema, and we have search params,
    #  use them
    if ($SchemaId == MetadataSchema::SCHEMAID_DEFAULT &&
        $SearchParams->ParameterCount() != 0)
    {
        $Engine = new SPTSearchEngine();
        $SearchResults = $Engine->Search(
            $SearchParams, 0, PHP_INT_MAX, $DateField->Name() );
        # extract the ItemIds
        $ItemIds = array_keys($SearchResults);
    }
    else
    {
        # otherwise we have to fall back to just extracting the resources
        $ItemIds = $RFactory->GetItemIds(
            NULL, FALSE, $DateField->DBFieldName(), FALSE);
    }

    # filter out non-viewable IDs
    $ItemIds = $RFactory->FilterNonViewableResources(
        $ItemIds, $GLOBALS["G_User"] );

    # cut down to the correct number of entries
    $ItemIds = array_slice($ItemIds, 0, $NumberOfEntriesToPublish);

    # load resources
    foreach ($ItemIds as $Id)
    {
        $Resources[$Id] = new Resource($Id);
    }

    # return the resources to the caller
    return $Resources;
}

/**
* Add the category of an item to the RSS feed based on a given category field.
* @param object $RSS The RSS object to modify.
* @param int $ResourceId The ID of the resource in question.
* @param int $CategoryFieldId The ID of the field to use.
*/
function HandleCategories($RSS, $ResourceId, $CategoryFieldId)
{
    # make sure we have the needed parameters
    if ($RSS == NULL) { return NULL; }
    if ($ResourceId == NULL) { return $RSS; }
    if ($CategoryFieldId == NULL) { return $RSS; }

    # gather up the needed variables
    $CategoryField = new MetadataField($CategoryFieldId);
    $Resource = new Resource($ResourceId);
    $Type = $CategoryField->Type();
    if ($Type == MetadataSchema::MDFTYPE_TREE)
    {
        # make the array of all categories
        $Categories = array();

        # get the classifications
        $Classifications = $Resource->GetByFieldId($CategoryFieldId);
        foreach ($Classifications as $Id => $Classification)
        {
            # divide up by depth
            $Parts = explode(" -- ", $Classification);

            # set the categories
            foreach ($Parts as $Part)
            {
                if (!in_array($Part, $Categories))
                {
                    $RSS->AddItemCategory($Part);
                }
                $Categories[] = $Part;
            }
        }
    }
    else if ($Type == MetadataSchema::MDFTYPE_OPTION
            || $Type == MetadataSchema::MDFTYPE_CONTROLLEDNAME)
    {
        # set the categories
        $Categories = $Resource->GetByFieldId($CategoryFieldId);
        foreach ($Categories as $Category)
        {
            $RSS->AddItemCategory($Category);
        }
    }
}

/**
* Helper function extract a field value, when one exists, from a resource.
* @param array $Fields List of configured fields.
* @param string $FieldName Field to extract.
* @param Resource $Resource Resource to get the value from.
* @return field value or NULL
*/
function GetFieldValue($Fields, $FieldName, $Resource)
{
    # assume we won't find anything
    $Result = NULL;

    try
    {
        $Result = $Resource->GetByFieldId(GetArrayValue($Fields, $FieldName));
    }
    catch (Exception $e)
    {
        ; // continue on if field did not exist
    }

    return $Result;
}

# ----- MAIN -----------------------------------------------------------------

# initialize some necessary variables
$RSS = new RSS();
global $AF, $G_SysConfig, $G_PluginManager;
$Exporter = $G_PluginManager->GetPlugin("RSSExport");
$FeedId = intval(GetArrayValue($_GET, "ID"));

# if the plugin can't be found, give up
if ($Exporter == NULL) { return; }

# get the available feeds
$Feeds = $Exporter->GetFeeds();

# if the feed is not valid, go to the list of RSS feeds
if (!array_key_exists($FeedId, $Feeds) && $FeedId != 0)
{
    $AF->SetJumpToPage("P_RSSExport_ListFeeds");
    return;
}

# make the feed object or decide we have a search feed
if ($FeedId !== 0)
{
    $Feed = new RSSExport_Feed($FeedId);
    $SearchFeed = FALSE;
}
else
{
    # if the search feed is not enabled, send the user to the list of feeds
    if ($Exporter->ConfigSetting("SearchFeed") == FALSE)
    {
        $AF->SetJumpToPage("P_RSSExport_ListFeeds");
        return;
    }

    # otherwise decide we are using a search feed
    $SearchFeed = TRUE;
}


# grab the date and use it to set the new last update
$Date = date("Y-m-d H:i:s");
if ($SearchFeed === FALSE) { $Feed->LastBuildDate($Date); }

# create the array of feed metadata to pass when the event is signaled
$Metadata = array();

$SearchParams = new SearchParameterSet();

# if it is a search feed, fill in the metadata array with predetermined values
if ($SearchFeed === TRUE)
{
    $SearchParams->UrlParameters($_GET);

    $Metadata["NumItems"] = 15;
    $Metadata["ShowResourceImages"] = FALSE;
    $Metadata["Comments"] = FALSE;
    $Metadata["Title"] = "Search Results RSS Feed";
    $Metadata["Link"] = defaulthtmlspecialchars(OurBaseUrl());
    $Metadata["RssLink"] = defaulthtmlspecialchars(OurUrl()
            . "&ID=0&" .  $SearchParams->UrlParameterString());
    $Metadata["Description"] = "";
    $Metadata["Language"] = "en-US";
    $Metadata["Copyright"] = defaulthtmlspecialchars($G_SysConfig->LegalNotice());
    $Metadata["ManagingEditor"] = "";
    $Metadata["Webmaster"] = "";
    $Metadata["Category"] = "";
    $Metadata["SearchParameters"] = $SearchParams;
    $Metadata["ImageUrl"] = "";
    $Metadata["ImageWidth"] = 10;
    $Metadata["ImageHeight"] = 10;
    $Metadata["ImageDescription"] = "";
    $Metadata["Encoding"] = $AF->HtmlCharset() ?
            $AF->HtmlCharset() : $G_SysConfig->DefaultCharacterSet();
}
# otherwise get the values from the database
else
{
    $SearchParams->UrlParameters($Feed->SearchParameters());

    $Metadata["NumItems"] = intval($Feed->NumItems());
    $Metadata["ShowResourceImages"] = (bool)$Feed->ShowResourceImages();
    $Metadata["Comments"] = (bool)$Feed->Comments();
    $Metadata["Title"] = defaulthtmlspecialchars($Feed->Title());
    $Metadata["Link"] = defaulthtmlspecialchars($Feed->Link());
    $Metadata["RssLink"] = defaulthtmlspecialchars(OurBaseUrl() . $AF->GetCleanUrl());
    $Metadata["Description"] = defaulthtmlspecialchars($Feed->Description());
    $Metadata["Language"] = defaulthtmlspecialchars($Feed->Language());
    $Metadata["Copyright"] = defaulthtmlspecialchars($Feed->Copyright());
    $Metadata["ManagingEditor"] = defaulthtmlspecialchars($Feed->ManagingEditor());
    $Metadata["Webmaster"] = defaulthtmlspecialchars($Feed->WebMaster());
    $Metadata["Category"] = defaulthtmlspecialchars($Feed->Category());
    $Metadata["SearchParameters"] = $SearchParams->UrlParameterString();
    $Metadata["ImageUrl"] = defaulthtmlspecialchars($Feed->ImageUrl());
    $Metadata["ImageWidth"] = $Feed->ImageWidth();
    $Metadata["ImageHeight"] = $Feed->ImageHeight();
    $Metadata["ImageDescription"] = defaulthtmlspecialchars($Feed->ImageDescription());
    $Metadata["Encoding"] = $AF->HtmlCharset() ?
            $AF->HtmlCharset() : $G_SysConfig->DefaultCharacterSet();
}

# set off the event so that others can modify the feed metadata
$Metadata = $AF->SignalEvent("RSSExport_EVENT_GET_RSS_FEED_METADATA", $Metadata);

# set up the channel
$RSS->AddChannel($Metadata["Title"], $Metadata["Link"],
        $Metadata["Description"], $Metadata["RssLink"]);
if ($Metadata["ImageUrl"])
    { $RSS->SetImage($Metadata["ImageUrl"],
            $Metadata["ImageHeight"], $Metadata["ImageWidth"],
                     $Metadata["ImageDescription"]); }
$RSS->SetEncoding($Metadata["Encoding"]);
$RSS->SetLanguage($Metadata["Language"]);
if ($Metadata["Copyright"])
    { $RSS->SetCopyright($Metadata["Copyright"]); }
if ($Metadata["ManagingEditor"])
    { $RSS->SetManagingEditor($Metadata["ManagingEditor"]); }
if ($Metadata["Webmaster"])
    { $RSS->SetWebmaster($Metadata["Webmaster"]); }
$RSS->SetLastChangeDate($Date);

# add the channel categories
if (strlen($Metadata["Category"]))
{
    $Categories = explode(", ", $Metadata["Category"]);
    foreach ($Categories as $Category)
    {
        $RSS->AddCategory($Category);
    }
}

# build the field array
$Fields = array();

# get the schema
if ($SearchFeed === TRUE)
{
    $Schema = new MetadataSchema(MetadataSchema::SCHEMAID_DEFAULT);
    $Fields["Schema"] = $Schema->Id();
    $Fields["TitleField"] = $G_SysConfig->TitleField();
    $Fields["DescriptionField"] = $G_SysConfig->DescriptionField();
    $Fields["LinkField"] = $G_SysConfig->UrlField();
    $Fields["PubDateField"] = $Schema->GetFieldIdByName("Date Of Record Release");
}
else
{
    $Schema = new MetadataSchema($Feed->SchemaId());
    $Fields["Schema"] = $Schema->Id();
    if ($Feed->TitleFieldId())
        { $Fields["TitleField"] = $Feed->TitleFieldId(); }
    if ($Feed->DescriptionFieldId())
        { $Fields["DescriptionField"] = $Feed->DescriptionFieldId(); }
    if ($Feed->LinkFieldId())
        { $Fields["LinkField"] = $Feed->LinkFieldId(); }
    if ($Feed->AuthorFieldId())
        { $Fields["AuthorField"] = $Feed->AuthorFieldId(); }
    if ($Feed->EnclosureFieldId())
        { $Fields["EnclosureField"] = $Feed->EnclosureFieldId(); }
    if ($Feed->CategoryFieldId())
        { $Fields["CategoryField"] = $Feed->CategoryFieldId(); }
    if ($Feed->PubDateFieldId())
        { $Fields["PubDateField"] = $Feed->PubDateFieldId(); }
    if ($Feed->ImageFieldId())
        { $Fields["ImageField"] = $Feed->ImageFieldId(); }
}

# set off the event to get the Metadata field values that will be used
$Fields = $AF->SignalEvent("RSSExport_EVENT_GET_RSS_FIELDS", $Fields);

# get the relevant resources
$Resources = GetResources(GetArrayValue($Fields, "Schema"),
        GetArrayValue($Fields, "PubDateField"),
        GetArrayValue($Metadata, "SearchParameters", ""),
        GetArrayValue($Metadata, "NumItems", 10));

# make the RSS items
foreach ($Resources as $ResourceId => $Resource)
{
    # get function parameters
    $ItemTitle = defaulthtmlspecialchars(html_entity_decode(
            GetFieldValue($Fields, "TitleField", $Resource),
            ENT_QUOTES, $AF->HtmlCharset()));
    $ItemLink = defaulthtmlspecialchars(
            GetFieldValue($Fields, "LinkField", $Resource));
    $ItemDescription = defaulthtmlspecialchars(html_entity_decode(
            GetFieldValue($Fields, "DescriptionField", $Resource),
            ENT_QUOTES, $AF->HtmlCharset()));
    $ItemPubDate = GetFieldValue($Fields, "PubDateField", $Resource);

    # add images to the description if desired
    if ($Metadata["ShowResourceImages"] == TRUE && $ItemDescription !== NULL)
    {
        $ItemDescription = AddImagesToDescription($ItemDescription, $ResourceId,
                GetArrayValue($Fields, "ImageField"));
    }

    # add the resource to the feed
    $RSS->AddItem($ItemTitle, $ItemLink, $ItemDescription, $ItemPubDate);

    # handle author field
    if (isset($Fields["AuthorField"]))
    {
        $Author = defaulthtmlspecialchars(
                $Resource->GetByFieldId($Fields["AuthorField"]));
        $RSS->AddItemAuthor($Author);
    }

    # handle categories
    if (isset($Fields["CategoryField"]))
    {
        HandleCategories($RSS, $ResourceId, $Fields["CategoryField"]);
    }

    # if resource comments are enabled, include comment page
    if ($Metadata["Comments"] === TRUE && $G_SysConfig->ResourceCommentsEnabled())
    {
        $RSS->AddItemComments(defaulthtmlspecialchars(
                OurBaseUrl() . "index.php?P=FullRecord&ID=" . $Resource->Id()));
    }

    # handle enclosures
    if (isset($Fields["EnclosureField"]))
    {
        # get the first file
        $Files = $Resource->GetByFieldId($Fields["EnclosureField"]);
        if (isset($Files) && !empty($Files))
        {
            foreach($Files as $FileId => $FileName)
            {
                $File = new File($FileId);
                if ($File->Status() === File::FILESTAT_OK
                        && intval($File->ResourceId()) === $ResourceId)
                {
                    break;
                }
            }
        }

        # add the enclosure
        if (isset($File) && get_class($File) === "File"
                && $File->Status() === File::FILESTAT_OK)
        {
            $RSS->AddItemEnclosure(defaulthtmlspecialchars(
                    OurBaseUrl() . $File->GetLink()), $File->GetLength(),
                    $File->GetMimeType());
            $File = NULL;
        }
    }
}

# suppress HTML output and print the feed
$AF->SuppressHtmlOutput();
$RSS->PrintRss();
