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

/**
* Plugin for generating reports using data previously recorded by
* MetricsRecorder plugin.
*/
class MetricsReporter extends Plugin {

    /**
    * Set the plugin attributes.  At minimum this method MUST set $this->Name
    * and $this->Version.  This is called when the plugin is initially loaded.
    */
    function Register()
    {
        $this->Name = "Metrics Reporter";
        $this->Version = "1.1.0";
        $this->Description = "Generates usage and web metrics reports"
                ." from data recorded by the <i>Metrics Recorder</i> plugin.";
        $this->Author = "Internet Scout";
        $this->Url = "http://scout.wisc.edu/cwis/";
        $this->Email = "scout@scout.wisc.edu";
        $this->Requires = array(
                "CWISCore" => "2.2.3",
                "MetricsRecorder" => "1.1.3");
        $this->EnabledByDefault = FALSE;

        $this->CfgSetup["PrivsToExcludeFromCounts"] = array(
                "Type" => "Privileges",
                "Label" => "Exclude Users with",
                "AllowMultiple" => TRUE,
                "Help" => "Users with any of the selected privilege flags "
                        ." will be excluded from full record view count"
                        ." and URL click count figures.",
                "Default" => array(
                        PRIV_SYSADMIN,
                        PRIV_RESOURCEADMIN,
                        PRIV_CLASSADMIN,
                        PRIV_NAMEADMIN,
                        PRIV_RELEASEADMIN,
                        PRIV_COLLECTIONADMIN),
                );
    }

    /**
    * Perform any work needed when the plugin is first installed (for example,
    * creating database tables).
    * @return NULL if installation succeeded, otherwise a string containing
    *       an error message indicating why installation failed.
    */
    function Install()
    {
        $DB = new Database();

        $DB->Query("CREATE TABLE IF NOT EXISTS MetricsReporter_Cache (
              Id VARCHAR(32),
              Page VARCHAR(32),
              Data LONGBLOB,
              LastUpdate TIMESTAMP DEFAULT NOW(),
              INDEX (Id, Page),
              INDEX (LastUpdate),
              UNIQUE (Id, Page) )");
    }

    /**
    * 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.
    */
    function Upgrade($PreviousVersion)
    {
        $DB = new Database();

        if (version_compare($PreviousVersion, "1.1.0", "<"))
        {
            $DB->Query("CREATE TABLE IF NOT EXISTS MetricsReporter_Cache (
              Id VARCHAR(32),
              Page VARCHAR(32),
              Data LONGBLOB,
              LastUpdate TIMESTAMP DEFAULT NOW(),
              INDEX (Id, Page),
              INDEX (LastUpdate),
              UNIQUE (Id, Page) )");
        }
    }

    /**
    * Initialize the plugin.  This is called after all plugins have been loaded
    * but before any methods for this plugin (other than Register() or Initialize())
    * have been called.
    * @return NULL if initialization was successful, otherwise a string containing
    *       an error message indicating why initialization failed.
    */
    function Initialize()
    {
        $Schema = new MetadataSchema();
        if (!$Schema->FieldExists("Full Record View Count"))
        {
            $ViewCountFieldDescription = <<<EOT
                <Owner>MetricsReporter</Owner>
                <Name>Full Record View Count</Name>
                <Type>MDFTYPE_NUMBER</Type>
                <Label>Full Record Views</Label>
                <Description>This field is used by the Metrics Reporter plugin
                    to store a count of the number of times the full record page
                    for a resource has been viewed by non-privileged users.</Description>
                <Editable>FALSE</Editable>
                <Enabled>TRUE</Enabled>
                <ViewingPrivileges>
                    <AddPrivilege>PRIV_COLLECTIONADMIN</AddPrivilege>
                </ViewingPrivileges>
                <DefaultValue>-1</DefaultValue>
EOT;
            $Field = $Schema->AddFieldFromXml($ViewCountFieldDescription);
        }
        if (!$Schema->FieldExists("URL Field Click Count"))
        {
            $ViewCountFieldDescription = <<<EOT
                <Owner>MetricsReporter</Owner>
                <Name>URL Field Click Count</Name>
                <Type>MDFTYPE_NUMBER</Type>
                <Label>Resource URL Clicks</Label>
                <Description>This field is used by the Metrics Reporter plugin
                    to store a count of the number of times the primary URL for
                    a resource has been clicked by non-privileged users.</Description>
                <Editable>FALSE</Editable>
                <Enabled>TRUE</Enabled>
                <ViewingPrivileges>
                    <AddPrivilege>PRIV_COLLECTIONADMIN</AddPrivilege>
                </ViewingPrivileges>
                <DefaultValue>-1</DefaultValue>
EOT;
            $Field = $Schema->AddFieldFromXml($ViewCountFieldDescription);
        }
    }

    /**
    * Hook the events into the application framework.
    * @return Returns an array of events to be hooked into the application
    *      framework.
    */
    function HookEvents()
    {
        return array(
                "EVENT_HOURLY" => "ExpireCache",
                "EVENT_COLLECTION_ADMINISTRATION_MENU" => "AddCollectionAdminMenuItems",
                "EVENT_FULL_RECORD_VIEW" => "UpdateFullRecordViewCount",
                "EVENT_URL_FIELD_CLICK" => "UpdateUrlFieldClickCount",
                "EVENT_RESOURCE_ADD" => "HandleResourceAddition",
                );
    }


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

    /**
    * Add entries to the Collection Administration menu.
    * @return array List of entries to add, with the label as the value and
    *       the page to link to as the index.
    */
    function AddCollectionAdminMenuItems()
    {
       $Pages = array(
                "CollectionReports" => "Collection Usage Metrics",
                "UserReports"       => "User Statistics",
                );

       if ($GLOBALS["G_PluginManager"]->PluginEnabled("CalendarEvents") )
           $Pages["EventReports"] = "Event Usage Metrics";

       if ($GLOBALS["G_PluginManager"]->PluginEnabled("Blog") )
           $Pages["BlogReports"] = "Blog Usage Metrics";

       return $Pages;
    }

    /**
    * Update full record view count metadata field from recorded data.
    * @param int $ResourceId ID of resource to update count for.
    */
    function UpdateFullRecordViewCount($ResourceId)
    {
        # calculate and store current view count for resource
        $Resource = new Resource($ResourceId);
        $Recorder = $GLOBALS["G_PluginManager"]->GetPlugin("MetricsRecorder");
        $CurrentCount = $Recorder->GetFullRecordViewCount(
                $Resource->Id(), $this->ConfigSetting("PrivsToExcludeFromCounts"));
        $Resource->Set("Full Record View Count", $CurrentCount);

        # also calculate and store current click count for the resource
        $this->UpdateUrlFieldClickCount($ResourceId, NULL);
    }

    /**
    * Update primary URL field click count metadata field from recorded data.
    * @param int $ResourceId ID of resource to update count for.
    * @param int $FieldId ID of metadata field to retrieve count for.
    */
    function UpdateUrlFieldClickCount($ResourceId, $FieldId)
    {
        # calculate and store current click count for resource
        $Resource = new Resource($ResourceId);
        $Recorder = $GLOBALS["G_PluginManager"]->GetPlugin("MetricsRecorder");
        $Schema = new MetadataSchema();
        $FieldId = $Schema->StdNameToFieldMapping("Url");
        $CurrentCount = $Recorder->GetUrlFieldClickCount(
                $Resource->Id(), $FieldId,
                $this->ConfigSetting("PrivsToExcludeFromCounts"));
        $Resource->Set("URL Field Click Count", $CurrentCount);
    }

    /**
    * Initialize full record view and URL field click count fields in
    * resource record.
    * @param Resource $Resource Resource to update field for.
    */
    function HandleResourceAddition($Resource)
    {
        if ($Resource->SchemaId() == MetadataSchema::SCHEMAID_DEFAULT)
        {
            $Resource->Set("Full Record View Count", -1);
            $Resource->Set("URL Field Click Count", -1);
        }
    }

    /**
    * Get a cached value.
    * @param Name Key to use when looking up value.
    */
    function CacheGet($Name)
    {
        $DB = new Database();

        $DB->Query("SELECT Data FROM MetricsReporter_Cache "
                   ."WHERE Id='".md5($Name)."' AND "
                   ."Page='".md5($GLOBALS["AF"]->GetPageName())."'"
            );

        if ($DB->NumRowsSelected() == 0)
        {
            $Result = NULL;
        }
        else
        {
            $Row = $DB->FetchRow();
            $Result = unserialize(gzinflate(base64_decode($Row["Data"])));
        }

        return $Result;
    }

    /**
    * Store a value in the cache.
    * @param Name Key to use for later retrieval.
    * @param $Data Value to store (must be serializable).
    */
    function CachePut($Name, $Data)
    {
        $DB = new Database();
        $DB->Query("INSERT INTO MetricsReporter_Cache( Id, Page, Data ) "
                   ."VALUES ('".md5($Name)."','".md5($GLOBALS["AF"]->GetPageName())."','"
                   .addslashes(base64_encode(gzdeflate(serialize($Data))))."') ");
    }

    /**
    * Clear all cache entries for the current page.
    */
    function CacheClear()
    {
        $DB = new Database();
        $DB->Query("DELETE FROM MetricsReporter_Cache "
                   ."WHERE Page='".md5($GLOBALS["AF"]->GetPageName())."'" );
    }

    /**
    * Periodic task to expire old cache entries.
    */
    function ExpireCache()
    {
        # Delete entries from the cache if they are older than 4 hours
        $DB = new Database();
        $DB->Query("DELETE FROM MetricsReporter_Cache "
                   ."WHERE NOW() - LastUpdate > 14400");
    }
}
