<?PHP
#
#   FILE:  RSSExport.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/
#

/**
* Plugin that provides support for blog entries.
*/
class RSSExport extends Plugin
{
    # default feed settings
    const DEFAULT_NUMITEMS = 15;
    const DEFAULT_SHOWRESOURCEIMAGES = TRUE;
    const DEFAULT_NOTIFYBROWSER = TRUE;
    const DEFAULT_COMMENTS = FALSE;

    # ---- STANDARD PLUGIN INTERFACE -----------------------------------------

    /**
    * Register information about this plugin.
    */
    public function Register()
    {
        $this->Name = "RSS Export";
        $this->Version = "1.0.1";
        $this->Description = "Plugin that adds RSS export support to CWIS.";
        $this->Author = "Internet Scout";
        $this->Url = "http://scout.wisc.edu/cwis/";
        $this->Email = "scout@scout.wisc.edu";
        $this->Requires = array(
                "CWISCore" => "3.1.0");
        $this->EnabledByDefault = TRUE;

        $this->CfgSetup["CleanUrlPrefix"] = array(
                "Type" => "Text",
                "Label" => "Clean URL Prefix",
                "Help" => "The prefix for the clean URLs for RSS feeds. "
                        . "The prefix will come before the clean URLs for the"
                        . " individual feeds. Example: "
                        . "YourCWISWebsite.com/CleanURLPrefix/CleanURL");

        $this->CfgSetup["SearchFeed"] = array(
                "Type" => "Flag",
                "Label" => "RSS Feed for User Searches",
                "Help" => "Include a link to a list of available RSS feeds in "
                        . "the navigation bar.",
                "OnLabel" => "Yes",
                "OffLabel" => "No",
                "Default" => TRUE);

        $this->CfgSetup["Notify"] = array(
                "Type" => "Flag",
                "Label" => "Notify Browser of RSS Feeds",
                "Help" => "Give browsers a link to available RSS feeds.",
                "OnLabel" => "Yes",
                "OffLabel" => "No",
                "Default" => TRUE);

    }

    /**
     * Startup initialization for this plugin.
     * @return NULL if initialization was successful, otherwise a string
     *     containing an error message indicating why inizialization failed.
     */
    public function Install()
    {
        # set up the database table
        $DB = new Database();
        $DB->Query(
                "CREATE TABLE IF NOT EXISTS RSSExport_Feeds (
	                `FeedId`                INT NOT NULL PRIMARY KEY,
	                `CleanUrl`              TEXT,
	                `NumItems`              INT,
	                `ShowResourceImages`    INT,
	                `NotifyBrowser`         INT,
	                `Title`                 TEXT,
	                `Description`           TEXT,
	                `Copyright`             TEXT,
	                `ManagingEditor`        TEXT,
	                `WebMaster`             TEXT,
	                `LastBuildDate`         DATETIME,
                    `Category`              TEXT,
                    `SearchParameters`      TEXT,
                    `ImageUrl`              TEXT,
                    `ImageWidth`            INT,
                    `ImageHeight`           INT,
                    `ImageDescription`      TEXT,
                    `SchemaId`              INT,
                    `TitleFieldId`          INT,
                    `LinkFieldId`           INT,
                    `DescriptionFieldId`    INT,
                    `AuthorFieldId`         INT,
                    `CategoryFieldId`       INT,
                    `Comments`              INT,
                    `EnclosureFieldId`      INT,
                    `PubDateFieldId`        INT,
                    `ImageFieldId`          INT
                );");

        # set default config values
        $this->ConfigSetting("CleanUrlPrefix", "rss");
        $this->ConfigSetting("SearchFeed", TRUE);
        $this->ConfigSetting("Notify", TRUE);

        # get a copy of the sytem configuration
        $SysConfig = new SystemConfiguration();

        # get the default schema and pub date field
        $DefaultSchema = new MetadataSchema(MetadataSchema::SCHEMAID_DEFAULT);
        $DefaultPubDateField = $DefaultSchema->GetFieldByName("Date Of Record Release");

        # make the default first feed
        $DefaultFeed = new RSSExport_Feed();

        # check for the old version of RSS
        $DB->Query("SHOW TABLES LIKE 'RSSConfiguration'");
        $OldVersion = $DB->FetchRow();

        # if the old version of RSS is still around, upgrade
        if ($OldVersion)
        {
            # we are going to need the plugin manager
            global $G_PluginManager;

            # get the old RSS data
            $DB->Query("SELECT * FROM RSSConfiguration");
            $Config = $DB->FetchRow();

            # set up the default CWIS feed
            $DefaultFeed->CleanUrl("new");
            $DefaultFeed->NumItems($Config["EntriesToPublish"]);
            $DefaultFeed->ShowResourceImages(FALSE);
            $DefaultFeed->NotifyBrowser((bool)$Config["NotifyBrowser"]);
            $DefaultFeed->Title($Config["ChannelTitle"]);
            $DefaultFeed->Description($Config["ChannelDescription"]);
            $DefaultFeed->Copyright($Config["Copyright"]);
            $DefaultFeed->ManagingEditor($Config["ManagingEditor"]);
            $DefaultFeed->WebMaster($Config["Webmaster"]);
            $DefaultFeed->ImageUrl($Config["ImageUrl"]);
            $DefaultFeed->ImageHeight($Config["ImageHeight"]);
            $DefaultFeed->ImageWidth($Config["ImageWidth"]);
            $DefaultFeed->ImageDescription($Config["ImageDescription"]);
            $DefaultFeed->SchemaId(MetadataSchema::SCHEMAID_DEFAULT);
            $DefaultFeed->TitleFieldId($SysConfig->TitleField());
            $DefaultFeed->LinkFieldId($SysConfig->UrlField());
            $DefaultFeed->DescriptionFieldId($SysConfig->DescriptionField());
            $DefaultFeed->PubDateFieldId($DefaultPubDateField->Id());
            $DefaultFeed->Comments(FALSE);

            # set up the blog feed if it is in use
            if ($G_PluginManager->PluginEnabled("Blog"))
            {
                # get the blog plugin and schema
                $BlogPlugin = $G_PluginManager->GetPlugin("Blog");
                $BlogSchemaId = $BlogPlugin->GetSchemaId();
                $BlogSchema = new MetadataSchema($BlogSchemaId);

                # configure the blog rss feed
                $BlogFeed = new RSSExport_Feed();
                $BlogFeed->SchemaId($BlogSchemaId);
                $BlogFeed->CleanUrl($BlogPlugin->ConfigSetting("CleanUrlPrefix"));
                $BlogFeed->NumItems(25);
                $BlogFeed->ShowResourceImages(TRUE);
                $BlogFeed->NotifyBrowser($Config["NotifyBrowser"]);
                $BlogFeed->Comments($BlogPlugin->ConfigSetting("EnableComments"));
                $BlogFeed->Title($BlogPlugin->ConfigSetting("BlogName"));
                $BlogFeed->Description($BlogPlugin->ConfigSetting("BlogDescription"));
                $BlogFeed->TitleFieldId($BlogSchema->GetFieldIdByName("Title"));
                $BlogFeed->DescriptionFieldId($BlogSchema->GetFieldIdByName("Body"));
                $BlogFeed->CategoryFieldId($BlogSchema->GetFieldIdByName("Categories"));
                $BlogFeed->PubDateFieldId(
                    $BlogSchema->GetFieldIdByName("Date of Publication"));
                $BlogFeed->ImageFieldId($BlogSchema->GetFieldIdByName("Image"));
            }

            # set up the calendar events feed if it is in use
            if ($G_PluginManager->PluginEnabled("CalendarEvents"))
            {
                # get the calendar events plugin and schema
                $EventsPlugin = $G_PluginManager->GetPlugin("CalendarEvents");
                $EventsSchemaId = $EventsPlugin->GetSchemaId();
                $EventsSchema = new MetadataSchema($EventsSchemaId);

                # configure the calendar events RSS feed
                $EventsFeed = new RSSExport_Feed();
                $EventsFeed->SchemaId($EventsSchemaId);
                $EventsFeed->CleanUrl($EventsPlugin->ConfigSetting("CleanUrlPrefix"));
                $EventsFeed->NumItems(30);
                $EventsFeed->ShowResourceImages(FALSE);
                $EventsFeed->NotifyBrowser($Config["NotifyBrowser"]);
                $EventsFeed->Comments(FALSE);
                $EventsFeed->Title("Calendar Events");
                $EventsFeed->Description("Recent updates to the events for "
                        . $SysConfig->PortalName());
                $EventsFeed->TitleFieldId($EventsSchema->GetFieldIdByName("Title"));
                $EventsFeed->DescriptionFieldId(
                    $EventsSchema->GetFieldIdByName("Description"));
                $EventsFeed->Copyright($Config["Copyright"]);
                $EventsFeed->ManagingEditor($Config["ManagingEditor"]);
                $EventsFeed->WebMaster($Config["Webmaster"]);
                $EventsFeed->LinkFieldId($EventsSchema->GetFieldIdByName("Url"));
                $EventsFeed->PubDateFieldId(
                    $EventsSchema->GetFieldIdByName("Date of Modification"));
                $EventsFeed->EnclosureFieldId(
                    $EventsSchema->GetFieldIdByName("Attachments"));
            }

            # get rid of the old RSSConfiguration database table
            if (!$DB->Query("DROP TABLE RSSConfiguration"))
            {
                return "Could not drop the old RSSConfiguration database "
                        . "table.";
            }
        }
        # otherwise set up the default RSS feed
        else
        {
            $DefaultFeed->CleanUrl("new");
            $DefaultFeed->NumItems(self::DEFAULT_NUMITEMS);
            $DefaultFeed->ShowResourceImages(self::DEFAULT_SHOWRESOURCEIMAGES);
            $DefaultFeed->NotifyBrowser(self::DEFAULT_NOTIFYBROWSER);
            $DefaultFeed->Title($SysConfig->PortalName());
            $DefaultFeed->Description("The newest " . $SysConfig->PortalName()
                    . " resources.");
            $DefaultFeed->Copyright($SysConfig->LegalNotice());
            $DefaultFeed->SchemaId(MetadataSchema::SCHEMAID_DEFAULT);
            $DefaultFeed->TitleFieldId($SysConfig->TitleField());
            $DefaultFeed->LinkFieldId($SysConfig->UrlField());
            $DefaultFeed->DescriptionFieldId($SysConfig->DescriptionField());
            $DefaultFeed->Comments(self::DEFAULT_COMMENTS);
            $DefaultFeed->PubDateFieldId($DefaultPubDateField->Id());
            $DefaultFeed->ImageFieldId($SysConfig->ScreenshotField());
        }

        # report success
        return NULL;
    }

    /**
    * Perform any work needed when the plugin is upgraded to a new version
    * (for example, adding fields to database tables).
    * @param string $PreviousVersion The version number of this plugin that was
    *       previously installed.
    * @return NULL if upgrade succeeded, otherwise a string containing
    *       an error message indicating why upgrade failed.
    */
    public function Upgrade($PreviousVersion)
    {
        if (version_compare($PreviousVersion, "1.0.1", "<"))
        {
            # replace old Type/User index with Type/User/Date index for event data
            $DB = new Database();
            $DB->Query("SELECT FeedId, SearchParameters FROM RSSExport_Feeds");

            $Feeds = $DB->FetchColumn("SearchParameters", "FeedId");

            foreach ($Feeds as $FeedId => $SearchParams)
            {
                $NewParams = SearchParameterSet::ConvertLegacyUrl($SearchParams);

                $DB->Query("UPDATE RSSExport_Feeds "
                           ."SET SearchParameters='".addslashes($NewParams)."' "
                           ."WHERE FeedId=".intval($FeedId));
            }
        }
        return NULL;
    }

    /**
    * Perform any work needed when the plugin is uninstalled.
    * @return NULL if uninstall succeeded, otherwise a string containing
    *       an error message indicating why uninstall failed.
    */
    public function Uninstall()
    {
        # delete our database table
        $DB = new Database();
        $DB->Query("DROP TABLE IF EXISTS RSSExport_Feeds");

        # report success to caller
        return NULL;
    }

    /** Declare the events this plugin provides to the application framework.
     * @return An array of the events this plugin provides.
     */
    public function DeclareEvents()
    {
        return array(
                "RSSExport_EVENT_GET_RSS_FEED_METADATA"
                => ApplicationFramework::EVENTTYPE_CHAIN,
                "RSSExport_EVENT_GET_RSS_FIELDS"
                => ApplicationFramework::EVENTTYPE_CHAIN);
    }

    /**
    * Hook event callbacks into the application framework.
    * @returns Returns an array of events to be hooked into the application
    *     framework.
    */
    public function HookEvents()
    {
        return array(
                "EVENT_IN_HTML_HEADER" => "RSSNotify",
                "EVENT_SYSTEM_ADMINISTRATION_MENU" => "AdminMenu",
        );
    }

    /**
     * Install this plugin.
     * @return Returns NULL if everything went OK or an error message otherwise.
     */
    public function Initialize()
    {
        # set up base clean URL
        $CleanUrlPrefix = trim($this->ConfigSetting("CleanUrlPrefix"));

        if (!isset($CleanUrlPrefix) || !strlen($CleanUrlPrefix)
                || !preg_match("/^[A-Za-z0-9_]+$/", $CleanUrlPrefix))
        {
            return "Not a valid Clean URL Prefix: a Clean URL prefix must "
                    . "be chosen, and it can only contain the A-Z, a-z, 0-9, "
                    . "and _ characters.";
        }

        $Pattern = preg_quote($CleanUrlPrefix);
        $AF = $GLOBALS["AF"];
        $AF->AddCleanUrl(
                "%^" . $Pattern . "/?$%",
                "P_RSSExport_ListFeeds",
                array(),
                $CleanUrlPrefix);

        # set up clean URLs for each feed
        $Feeds = $this->GetFeeds();
        foreach ($Feeds as $Feed)
        {
            $FeedId = $Feed->Id();
            $CleanUrlFeed = $Feed->CleanUrl();
            if (isset($CleanUrlFeed) && strlen($CleanUrlFeed))
            {
                $FeedPattern = preg_quote(trim($CleanUrlFeed));
                $AF->AddCleanUrl(
                         "%^" . $Pattern . "/" . $FeedPattern . "/?%",
                         "P_RSSExport_Feed",
                         array("ID" => $FeedId),
                         $CleanUrlPrefix . "/" . $CleanUrlFeed);
            }
        }

        # report success
        return NULL;
    }

    # ---- HOOKED METHODS ----------------------------------------------------

    /**
    * Print links to RSS feeds in the html header if the global notify setting
    * is set to notify and the individual feed setting is set to notify.
    */
    public function RSSNotify()
    {
        if ($this->ConfigSetting("Notify") == TRUE)
        {
            print "<!-- RSS feeds -->\n";

            if ($this->ConfigSetting("SearchFeed") == TRUE
                    && $GLOBALS["AF"]->GetPageName() == "AdvancedSearch")
            {
                # retrieve search parameters from URL
                $SearchParams = new SearchParameterSet();
                $SearchParams->UrlParameters($_GET);

                # translate search groups to URL parameters
                $Parameters = $SearchParams->UrlParameterString();

                # translate search groups to text description
                $SearchDescription = $SearchParams->TextDescription(FALSE, FALSE, 0);

                # print link
                // @codingStandardsIgnoreStart
?>
<link rel="alternate" type="application/rss+xml" title="Search Results for <?PHP print defaulthtmlentities(preg_replace("/\n|\r|\n\r|\r\n/", " ", $SearchDescription)); ?>" href="<?PHP print OurBaseUrl(); ?>index.php?P=P_RSSExport_Feed&amp;ID=0&amp;<?PHP print defaulthtmlspecialchars($Parameters); ?>" />
      <?PHP }
            // @codingStandardsIgnoreEnd

            # print the rest of the links
            $Feeds = $this->GetFeeds();
            foreach ($Feeds as $Feed)
            {
                if ($Feed->NotifyBrowser())
                {
                    print "<link rel=\"alternate\" type=\"application/rss+xml\" "
                        ."title=\"".$Feed->Title()."\" href=\""
                        .$GLOBALS["AF"]->GetCleanUrlForPath(
                            "index.php?P=P_RSSExport_Feed&amp;Id=".$Feed->Id())."\" />\n";
                }
            }
        }
    }

    /**
    * Add a link to the list of RSS feeds in the administration menu.
    * @return array The array of links.
    */
    public function AdminMenu()
    {
        return array("ListFeeds" => "RSS Feeds (Export)");
    }

    # ---- CALLABLE METHODS --------------------------------------------------

    /**
    * Gets all of the available RSS feeds from the database.
    * @return array Array of Feed objects
    */
    public function GetFeeds()
    {
        # initialize return variable
        $Feeds = array();

        # get an instance of the database
        $DB = new Database();

        # tell the database to give us all of the feeds
        $DB->Query("SELECT * FROM `RSSExport_Feeds`");

        # make feed objects
        while ($Feed = $DB->FetchRow())
        {
            $Id = $Feed["FeedId"];
            $Feeds[$Id] = new RSSExport_Feed($Id);
        }

        # return the feeds to the caller
        return $Feeds;
    }
}
