<?PHP

class MobileUiSwitcher extends Plugin
{

    /**
     * Register information about this plugin to the application framework.
     * @return void
     */
    public function Register()
    {
        $this->Name = "Mobile UI Switcher";
        $this->Version = "1.0.1";
        $this->Description = "Allow automatic switching of CWIS user interfaces"
            ." for users browsing the site from a mobile device.";
        $this->Author = "Internet Scout";
        $this->Url = "http://scout.wisc.edu/";
        $this->Email = "scout@scout.wisc.edu";
        $this->Requires = array(
            "CWISCore" => "2.4.1",
            "BrowserCapabilities" => "1.0.1");
        $this->Instructions = <<<EOT
            <p>
              <b>Note:</b> Use
              <a href="http://www.w3.org/TR/css3-mediaqueries/">CSS media
              queries</a> in the stylesheets of your user interface to customize
              the appearance of your site based on screen size.
            </p>
EOT;

        $UiOptions = array("" => "--" ) + $GLOBALS["AF"]->GetUserInterfaces();

        # add the heading for the default mobile interface setting
        $this->CfgSetup["DefaultsHeader"] = array(
            "Type" => "Heading",
            "Label" => "Defaults");

        # add the setting for the default mobile interface
        $this->CfgSetup["DefaultInterface"] = array(
            "Type" => "Option",
            "Label" => "Default User Interface for Mobile Devices",
            "Help" => "The default user interface to display for all mobile devices.",
            "Options" => $UiOptions);

        # add the heading for the platform overrides
        $this->CfgSetup["DevicesHeader"] = array(
            "Type" => "Heading",
            "Label" => "Override by Device");

        # add settings for device overrides
        foreach (self::$Devices as $Device => $Method)
        {
            $this->CfgSetup[$Device] = array(
                "Type" => "Option",
                "Label" => $Device,
                "Help" => "The default user interface to display for ".$Device." users.",
                "Options" => $UiOptions);
        }

        # add the heading for the platform overrides
        $this->CfgSetup["PlatformsHeader"] = array(
            "Type" => "Heading",
            "Label" => "Override by Platform");

        # add settings for platform overrides
        foreach (self::$Platforms as $Platform => $Method)
        {
            $this->CfgSetup[$Platform] = array(
                "Type" => "Option",
                "Label" => $Platform,
                "Help" => "The default user interface to display for devices running ".$Platform.".",
                "Options" => $UiOptions);
        }
    }

    /**
     * Return event hooks to the application framework.
     * @return array events to be hooked into the application framework
     */
    public function HookEvents()
    {
        return array(
            "EVENT_PAGE_LOAD" => "PageLoad");
    }

    /**
     * Switch the user interface displayed for users browsing the site from a
     * mobile device.
     * @param string $PageName page name
     * @return array parameters to pass to the next callback in the chain
     */
    public function PageLoad($PageName)
    {
        # what the caller is expecting
        $ReturnValue = array($PageName);

        # get the user agent signature for testing
        $Signature = $GLOBALS["AF"]->SignalEvent(
            "BROWSCAP_GET_BROWSER",
            array(NULL, TRUE));

        # no need to do further checking if not a mobile device
        if (!$this->IsMobileDevice($Signature))
        {
            return $ReturnValue;
        }

        # search ordering for matching
        $Search = self::$Devices;
        $Search += self::$Platforms;
        $Search += array("DefaultInterface" => "IsMobileDevice");

        # try to find an interface match
        $Match = $this->FindInterfaceMatch($Search, $Signature);

        # found a match so use it
        if (!is_null($Match))
        {
            $UiName = basename($Match);
            $GLOBALS["AF"]->ActiveUserInterface($UiName);
        }

        return $ReturnValue;
    }

    /**
     * Try to find an alternate user interface to use, if any, given a search
     * space (label => predicate method) and a user agent signature.
     * @param array $Search search space (label => predicate method)
     * @param array $Signature user agent signature
     * @return string|null alternate user interface or NULL if none matched
     */
    protected function FindInterfaceMatch(array $Search, array $Signature)
    {
        $ValidInterfaces = $GLOBALS["AF"]->GetUserInterfaces();

        foreach ($Search as $Label => $Method)
        {
            $Interface = $this->ConfigSetting($Label);

            # skip if the interface is invalid
            if (!isset($ValidInterfaces[$Interface]))
            {
                continue;
            }

            # skip if the user agent doesn't match
            if (!call_user_func(array($this, $Method), $Signature))
            {
                continue;
            }

            # found a match
            return $Interface;
        }

        # couldn't find a match
        return NULL;
    }

    /**
     * Determine if a user agent is a mobile device based on its signature.
     * @param array $Signature user agent signature
     * @return bool TRUE if the user agent is a mobile device or FALSE otherwise
     */
    protected function IsMobileDevice(array $Signature)
    {
        return GetArrayValue($Signature, "isMobileDevice", FALSE);
    }

    /**
     * Determine if a user agent runs iOS based on its signature.
     * @param array $Signature user agent signature
     * @return bool TRUE if the user agent runs iOS or FALSE otherwise
     */
    protected function IsIos(array $Signature)
    {
        return GetArrayValue($Signature, "Platform") == "iOS";
    }

    /**
     * Determine if a user agent is an iPhone based on its signature.
     * @param array $Signature user agent signature
     * @return bool TRUE if the user agent is an iPhone or FALSE otherwise
     */
    protected function IsIphone(array $Signature)
    {
        return strpos(GetArrayValue($Signature, "browser_name"), " iPhone ") !== FALSE;
    }

    /**
     * Determine if a user agent is an iPad based on its signature.
     * @param array $Signature user agent signature
     * @return bool TRUE if the user agent is an iPad or FALSE otherwise
     */
    protected function IsIpad(array $Signature)
    {
        return strpos(GetArrayValue($Signature, "browser_name"), " iPad ") !== FALSE;
    }

    /**
     * Determine if a user agent runs Android based on its signature.
     * @param array $Signature user agent signature
     * @return bool TRUE if the user agent runs Android or FALSE otherwise
     */
    protected function IsAndroid(array $Signature)
    {
        return GetArrayValue($Signature, "Platform") == "Android";
    }

    /**
     * Determine if a user agent runs Windows Phone 7 based on its signature.
     * @param array $Signature user agent signature
     * @return bool TRUE if the user agent runs Windows Phone 7 or FALSE otherwise
     */
    protected function IsWindowsPhone7(array $Signature)
    {
        return GetArrayValue($Signature, "Platform") == "WinPhone7";
    }

    /**
     * Determine if a user agent runs Windows Mobile based on its signature.
     * @param array $Signature user agent signature
     * @return bool TRUE if the user agent runs Windows Mobile or FALSE otherwise
     */
    protected function IsWindowsMobile(array $Signature)
    {
        return GetArrayValue($Signature, "Platform") == "WinMobile";
    }

    /**
     * Determine if a user agent runs Blackberry OS based on its signature.
     * @param array $Signature user agent signature
     * @return bool TRUE if the user agent runs Blackberry OS or FALSE otherwise
     */
    protected function IsBlackberryOs(array $Signature)
    {
        return GetArrayValue($Signature, "Platform") == "BlackBerry OS";
    }

    /**
     * Determine if a user agent runs webOS based on its signature.
     * @param array $Signature user agent signature
     * @return bool TRUE if the user agent runs webOS or FALSE otherwise
     */
    protected function isWebOs(array $Signature)
    {
        return GetArrayValue($Signature, "Platform") == "webOS";
    }

    /**
     * Determine if a user agent runs Symbian based on its signature.
     * @param array $Signature user agent signature
     * @return bool TRUE if the user agent runs Symbian or FALSE otherwise
     */
    protected function IsSymbian(array $Signature)
    {
        return GetArrayValue($Signature, "Platform") == "SymbianOS";
    }

    /**
     * Determine if a user agent runs Bada based on its signature.
     * @param array $Signature user agent signature
     * @return bool TRUE if the user agent runs Bada or FALSE otherwise
     */
    protected function IsBada(array $Signature)
    {
        return GetArrayValue($Signature, "Platform") == "Bada";
    }

    /**
     * @var array $Devices a list of devices and methods to check for them
     */
    protected static $Devices = array(
        "iPhone" => "IsIphone",
        "iPad" => "IsIpad");

    /**
     * @var array $Platforms a list of platforms and methods to check for them
     */
    protected static $Platforms = array(
        "iOS" => "IsIos",
        "Android" => "IsAndroid",
        "Windows Phone 7" => "IsWindowsPhone7",
        "Windows Mobile" => "IsWindowsMobile",
        "BlackBerry OS" => "IsBlackberryOs",
        "webOS" => "IsWebos",
        "Symbian" => "IsSymbian",
        "Bada" => "IsBada");

}
