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

/**
* Provides support for selecting a different user interface
* automatically for mobile users.
*/
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 = "2.0.0";
        $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" => "3.9.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");
    }

    /**
    * Handle plugin initialization, pulling in required libraries.
    */
    public function Initialize()
    {
        $this->Detector = new Mobile_Detect();
    }

    /**
    * 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 = array();

        # no need to do further checking if not a mobile device
        if (!$this->Detector->isMobile())
        {
            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);

        # 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)
    * @return string|null alternate user interface or NULL if none matched
    */
    protected function FindInterfaceMatch(array $Search)
    {
        $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)))
            {
                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.
    * @return bool TRUE if the user agent is a mobile device or FALSE otherwise
    */
    protected function IsMobileDevice()
    {
        return $this->Detector->isMobile();
    }

    /**
    * Determine if a user agent runs iOS based on its signature.
    * @return bool TRUE if the user agent runs iOS or FALSE otherwise
    */
    protected function IsIos()
    {
        return $this->Detector->isiOS();
    }

    /**
    * Determine if a user agent is an iPhone based on its signature.
    * @return bool TRUE if the user agent is an iPhone or FALSE otherwise
    */
    protected function IsIphone()
    {
        return $this->Detector->isiPhone();
    }

    /**
    * Determine if a user agent is an iPad based on its signature.
    * @return bool TRUE if the user agent is an iPad or FALSE otherwise
    */
    protected function IsIpad()
    {
        return $this->Detector->isiPad();
    }

    /**
    * Determine if a user agent runs Android based on its signature.
    * @return bool TRUE if the user agent runs Android or FALSE otherwise
    */
    protected function IsAndroid()
    {
        return $this->Detector->isAndroidOS();
    }

    /**
    * Determine if a user agent runs Windows Phone 7 based on its signature.
    * @return bool TRUE if the user agent runs Windows Phone 7 or FALSE otherwise
    */
    protected function IsWindowsPhone7()
    {
        return $this->Detector->isWindowsPhoneOS();
    }

    /**
    * Determine if a user agent runs Windows Mobile based on its signature.
    * @return bool TRUE if the user agent runs Windows Mobile or FALSE otherwise
    */
    protected function IsWindowsMobile()
    {
        return $this->Detector->isWindowsMobileOS();
    }

    /**
    * Determine if a user agent runs Blackberry OS based on its signature.
    * @return bool TRUE if the user agent runs Blackberry OS or FALSE otherwise
    */
    protected function IsBlackberryOs()
    {
        return $this->Detector->isBlackberryOS();
    }

    /**
    * Determine if a user agent runs webOS based on its signature.
    * @return bool TRUE if the user agent runs webOS or FALSE otherwise
    */
    protected function isWebOs()
    {
        return $this->Detector->isWebOS();
    }

    /**
    * Determine if a user agent runs Symbian based on its signature.
    * @return bool TRUE if the user agent runs Symbian or FALSE otherwise
    */
    protected function IsSymbian()
    {
        return $this->Detector->isSymbianOS();
    }

    /**
    * Determine if a user agent runs Bada based on its signature.
    * @return bool TRUE if the user agent runs Bada or FALSE otherwise
    */
    protected function IsBada()
    {
        return $this->Detector->isBadaOS();
    }

    /**
    * @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");

    private $Detector;
}
