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

/**
* Plugin to wrap PHP's get_browser() function.
*/
class BrowserCapabilities extends Plugin
{
    /**
    * Register information about this plugin.
    */
    public function Register()
    {
        $this->Name = "Browser Capabilities";
        $this->Version = "1.1.0";
        $this->Description = "Provides information about "
             ."the user's browser and its capabilities.";
        $this->Author = "Internet Scout";
        $this->Url = "http://scout.wisc.edu/";
        $this->Email = "scout@scout.wisc.edu";
        $this->Requires = array("CWISCore" => "3.9.1");
        $this->EnabledByDefault = TRUE;

        $this->CfgSetup["EnableDeveloper"] = array(
            "Type" => "Flag",
            "Label" => "Enable Developer Interface",
            "Help" => "Enable an additional developer interface to aid in debugging.",
            "Default" => FALSE,
            "OnLabel" => "Yes",
            "OffLabel" => "No");
    }

    /**
    * Upgrade from a previous version.
    * @param string $PreviousVersion Previous version
    * @return stringnull error message on error or NULL if no errors occurred
    */
    public function Upgrade($PreviousVersion)
    {
        # ugprade from versions < 1.0.1 to 1.0.1
        if (version_compare($PreviousVersion, "1.0.1", "<"))
        {
            $OldCachePath = getcwd() . "/tmp/caches/BrowserCapabilities";

            # see if the old cache directory still exists
            if (file_exists($OldCachePath))
            {
                # remove the old cache directory
                $Result = RemoveFromFilesystem($OldCachePath);

                # could not remove the old cache directory
                if (!$Result)
                {
                    $Message = "Could not remove the old cache directory (";
                    $Message .= $OldCachePath . ").";

                    return $Message;
                }
            }
        }

        if (version_compare($PreviousVersion, "1.0.2", "<"))
        {
            $this->ConfigSetting("EnableDeveloper", FALSE);
        }

        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(
            "BROWSCAP_GET_BROWSER"
              => ApplicationFramework::EVENTTYPE_FIRST,
            "BROWSCAP_BROWSER_CHECK"
              => ApplicationFramework::EVENTTYPE_FIRST,
        );
    }

    /**
    * Return event hooks to the application framework.
    * @return an array of events to be hooked into the application framework
    */
    public function HookEvents()
    {
        $Events= array(
            "BROWSCAP_GET_BROWSER" => "GetBrowser",
            "BROWSCAP_BROWSER_CHECK" => "BrowserCheck");
        if ($this->ConfigSetting("EnableDeveloper"))
        {
            $Events["EVENT_DEVELOPER_SUPPORT_MENU"] = "DeclareDevSupportPages";
        }

        return $Events;
    }

    /**
    * Add page hooks for the system administration section. This should only
    * be called if EnableDeveloper is TRUE.
    * @return map page name to page title for the application framework
    */
    public function DeclareDevSupportPages()
    {
        return array(
            "Developer" => "BrowserCapabilities Developer Page",
            );
    }

    /**
    * Inject a callback into the application framework.
    */
    public function Initialize()
    {
        $GLOBALS["AF"]->SetBrowserDetectionFunc(
            array($this, "BrowserDetectionFunc"));
    }

    /**
    * Inject browser names into the application framework.
    * @param string $UserAgent Custom user agent string to use
    * @return array of browser names
    */
    public function BrowserDetectionFunc($UserAgent=NULL)
    {
        $Browsers = array();
        $Capabilities = $this->GetBrowser($UserAgent, TRUE);

        # add browser name
        if (isset($Capabilities["browser"]))
        {
            $Name = $Capabilities["browser"];
            $Browsers[] = $Name;

            # add version-specific name too
            if (isset($Capabilities["majorver"]))
            {
                $VersionedName = $Name . $Capabilities["majorver"];
                $Browsers[] = $VersionedName;
            }
        }

        return $Browsers;
    }

    /**
    * Get the user agent's name only.
    * @param string|null $UserAgent Custom user agent string to use
    * @return an string giving the browser name on success, NULL on failure
    */
    public function GetBrowserName($UserAgent=NULL)
    {
        $Capabilities = $this->GetBrowser($UserAgent, TRUE);

        return isset($Capabilities["Browser"]) ? $Capabilities["Browser"] : NULL;
    }

    /**
    * Get the user agent's capabilities. Updates the cache after 30 days.
    * @param string|null $UserAgent Custom user agent string to use
    * @return an object of capabilities or an empty object on error
    */
    public function GetBrowser($UserAgent=NULL)
    {
        if (strlen(ini_get('browscap'))==0)
        {
            if (is_null($UserAgent))
            {
                $UserAgent = isset($_SERVER["HTTP_USER_AGENT"]) ?
                           $_SERVER["HTTP_USER_AGENT"] : "";
            }

            if (strpos($UserAgent, 'Opera') || strpos($UserAgent, 'OPR/'))
            {
                $Name= 'Opera';
            }
            elseif (strpos($UserAgent, 'Edge'))
            {
                $Name = 'Edge';
            }
            elseif (strpos($UserAgent, 'Chrome'))
            {
                $Name = "Chrome";
            }
            elseif (strpos($UserAgent, 'Safari'))
            {
                $Name = "Safari";
            }
            elseif (strpos($UserAgent, 'Firefox'))
            {
                $Name = "Firefox";
            }
            elseif (strpos($UserAgent, 'MSIE') || strpos($UserAgent, 'Trident/7'))
            {
                $Name = 'Internet Explorer';
            }
            else
            {
                $Name = 'Other';
            }

            return array("browser" => $Name);
        }
        else
        {
            return get_browser($UserAgent, TRUE);
        }
    }

    /**
    * Check if the given constraints are true for the user agent.
    * @param array $Constraints Constraints to test against.
    *    For example array("Browser" => "Firefox").
    * @param string $UserAgent UserAgent to use.
    * @return TRUE if all constraints are satisfied, FALSE otherwise.
    */
    public function BrowserCheck(array $Constraints, $UserAgent=NULL)
    {
        static $CapabilityMap;

        if (!is_array($CapabilityMap) || !array_key_exists($UserAgent, $CapabilityMap))
        {
            $CapabilityMap[$UserAgent] = $this->GetBrowser($UserAgent);
        }

        $Capabilities = $CapabilityMap[$UserAgent];

        if (count($Capabilities)==0)
        {
            return FALSE;
        }

        foreach ($Constraints as $Key => $Value)
        {
            if (!isset($Capabilities[$Key]) || $Capabilities[$Key] != $Value)
            {
                return FALSE;
            }
        }

        return TRUE;
    }
}
