<?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,
        $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;
    }

    # if we are using the default schema, we can use search parameters
    if ($SchemaId == MetadataSchema::SCHEMAID_DEFAULT)
    {
        # retrieve search parameters as search groups
        $SearchGroups = SavedSearch::TranslateUrlParametersToSearchGroups($Parameters);

        # set up search engine
        $Engine = new SPTSearchEngine();
        $Engine->SearchTermsRequiredByDefault($G_SysConfig->SearchTermsRequired());

        # add condition to filter out any temporary resource records
        function FilterOutTempResources($Id) {  return ($Id < 0);  }
        $Engine->AddResultFilterFunction("FilterOutTempResources");

        # add condition to show only released resources
        $ReleaseField = $Schema->GetFieldByName("Release Flag");
        if ($ReleaseField)
        {
            $SearchGroups[$ReleaseField->Id()]["SearchStrings"]
                    ["Release Flag"] = "=1";
            $SearchGroups[$ReleaseField->Id()]["Logic"] = SearchEngine::LOGIC_AND;
        }

        # perform search
        $SearchResults = $Engine->GroupedSearch(
                $SearchGroups, 0, $NumberOfEntriesToPublish,
                $DateFieldId, 1);

        # load resources
        foreach ($SearchResults as $Id => $Score)
        {
            $Resources[$Id] = new Resource($Id);
        }
    }
    # otherwise we use the resource factory
    else
    {
        # get the corresponding item factory
        $Factory = new ResourceFactory($SchemaId);

        # get the IDs of the resources
        $DateFieldName = $DateField->Name();
        $ResourceIds = $Factory->GetResourceIdsSortedBy(
                $DateFieldName, FALSE, $NumberOfEntriesToPublish);

        # add them to the array to be returned
        foreach ($ResourceIds 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);
        }
    }
}

# ----- 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();

# if it is a search feed, fill in the metadata array with predetermined values
if ($SearchFeed === TRUE)
{
    $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&" .  SavedSearch::TranslateSearchGroupsToUrlParameters(
            SavedSearch::TranslateUrlParametersToSearchGroups($_GET)));
    $Metadata["Description"] = "";
    $Metadata["Language"] = "en-US";
    $Metadata["Copyright"] = defaulthtmlspecialchars($G_SysConfig->LegalNotice());
    $Metadata["ManagingEditor"] = "";
    $Metadata["Webmaster"] = "";
    $Metadata["Category"] = "";
    $Metadata["SearchParameters"] =
            SavedSearch::TranslateSearchGroupsToUrlParameters(
            SavedSearch::TranslateUrlParametersToSearchGroups($_GET));
    $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
{
    $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"] =
            SavedSearch::TranslateSearchGroupsToUrlParameters(
            SavedSearch::TranslateUrlParametersToSearchGroups($Feed->SearchParameters()));
    $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(
            $Resource->GetByFieldId(GetArrayValue($Fields, "TitleField")),
            ENT_QUOTES, $AF->HtmlCharset()));
    $ItemLink = defaulthtmlspecialchars(
            $Resource->GetByFieldId(GetArrayValue($Fields, "LinkField")));
    $ItemDescription = defaulthtmlspecialchars(html_entity_decode(
            $Resource->GetByFieldId(GetArrayValue($Fields, "DescriptionField")),
            ENT_QUOTES, $AF->HtmlCharset()));
    $ItemPubDate = $Resource->GetByFieldId(GetArrayValue($Fields, "PubDateField"));

    # 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();
