<?php
/**
 * Rights helper class file.
 *
 * Provides static functions for interaction with Rights from outside of the module.
 *
 * @author Christoffer Niska <cniska@live.com>
 * @copyright Copyright &copy; 2010 Christoffer Niska
 * @since 0.9.1
 */
class Rights
{
    const PERM_NONE = 0;
    const PERM_DIRECT = 1;
    const PERM_INHERITED = 2;
    private static $_m;
    private static $_a;
    /**
     * Assigns an authorization item to a specific user.
     * @param string $itemName the name of the item to assign.
     * @param integer $userId the user id of the user for which to assign the item.
     * @param string $bizRule business rule associated with the item. This is a piece of
     * PHP code that will be executed when {@link checkAccess} is called for the item.
     * @param mixed $data additional data associated with the item.
     * @return CAuthItem the authorization item
     */
    public static function assign($itemName, $userId, $bizRule = null, $data = null)
    {
	$authorizer = self::getAuthorizer();
	return $authorizer->authManager->assign($itemName, $userId, $bizRule, $data);
    }
    /**
     * Revokes an authorization item from a specific user.
     * @param string $itemName the name of the item to revoke.
     * @param integer $userId the user id of the user for which to revoke the item.
     * @return boolean whether the item was removed.
     */
    public static function revoke($itemName, $userId)
    {
	$authorizer = self::getAuthorizer();
	return $authorizer->authManager->revoke($itemName, $userId);
    }
    /**
     * Returns the roles assigned to a specific user.
     * If no user id is provided the logged in user will be used.
     * @param integer $userId the user id of the user for which roles to get.
     * @param boolean $sort whether to sort the items by their weights.
     * @return array the roles.
     */
    public static function getAssignedRoles($userId = null, $sort = true)
    {
	$user = Yii::app()->getUser();
	if ($userId === null && $user->isGuest === false)
	    $userId = $user->id;
	$authorizer = self::getAuthorizer();
	return $authorizer->getAuthItems(CAuthItem::TYPE_ROLE, $userId, null, $sort);
    }
    /**
     * Returns the base url to Rights.
     * @return the url to Rights.
     */
    public static function getBaseUrl()
    {
	$module = self::module();
	return Yii::app()->createUrl($module->baseUrl);
    }
    /**
     * Returns the list of authorization item types.
     * @return array the list of types.
     */
    public static function getAuthItemOptions()
    {
	return array(
	    CAuthItem::TYPE_OPERATION => Rights::t('core', 'Operation'),
	    CAuthItem::TYPE_TASK => Rights::t('core', 'Task'),
	    CAuthItem::TYPE_ROLE => Rights::t('core', 'Role'),
	);
    }
    /**
     * Returns the name of a specific authorization item.
     * @param integer $type the item type (0: operation, 1: task, 2: role).
     * @return string the authorization item type name.
     */
    public static function getAuthItemTypeName($type)
    {
	$options = self::getAuthItemOptions();
	if (isset($options[$type]) === true)
	    return $options[$type];
	else
	    throw new CException(Rights::t('core', 'Invalid authorization item type.'));
    }
    /**
     * Returns the name of a specific authorization item in plural.
     * @param integer $type the item type (0: operation, 1: task, 2: role).
     * @return string the authorization item type name.
     */
    public static function getAuthItemTypeNamePlural($type)
    {
	switch ((int) $type)
	{
	    case CAuthItem::TYPE_OPERATION: return Rights::t('core', 'Operations');
	    case CAuthItem::TYPE_TASK: return Rights::t('core', 'Tasks');
	    case CAuthItem::TYPE_ROLE: return Rights::t('core', 'Roles');
	    default: throw new CException(Rights::t('core', 'Invalid authorization item type.'));
	}
    }
    /**
     * Returns the route to a specific authorization item list view.
     * @param integer $type the item type (0: operation, 1: task, 2: role).
     * @return array the route.
     */
    public static function getAuthItemRoute($type)
    {
	switch ((int) $type)
	{
	    case CAuthItem::TYPE_OPERATION: return array('authItem/operations');
	    case CAuthItem::TYPE_TASK: return array('authItem/tasks');
	    case CAuthItem::TYPE_ROLE: return array('authItem/roles');
	    default: throw new CException(Rights::t('core', 'Invalid authorization item type.'));
	}
    }
    /**
     * Returns the valid child item types for a specific type.
     * @param string $type the item type (0: operation, 1: task, 2: role).
     * @return array the valid types.
     */
    public static function getValidChildTypes($type)
    {
	switch ((int) $type)
	{
	    // Roles can consist of any type of authorization items
	    case CAuthItem::TYPE_ROLE: return null;
	    // Tasks can consist of other tasks and operations
	    case CAuthItem::TYPE_TASK: return array(CAuthItem::TYPE_TASK, CAuthItem::TYPE_OPERATION);
	    // Operations can consist of other operations
	    case CAuthItem::TYPE_OPERATION: return array(CAuthItem::TYPE_OPERATION);
	    // Invalid type
	    default: throw new CException(Rights::t('core', 'Invalid authorization item type.'));
	}
    }
    /**
     * Returns the authorization item select options.
     * @param mixed $type the item type (0: operation, 1: task, 2: role). Defaults to null,
     * meaning returning all items regardless of their type.
     * @param array $exclude the items to be excluded.
     * @return array the select options.
     */
    public static function getAuthItemSelectOptions($type = null, $exclude = array())
    {
	$authorizer = self::getAuthorizer();
	$items = $authorizer->getAuthItems($type, null, null, true, $exclude);
	return self::generateAuthItemSelectOptions($items, $type);
    }
    /**
     * Returns the valid authorization item select options for a model.
     * @param mixed $parent the item type (0: operation, 1: task, 2: role). Defaults to null,
     * meaning returning all items regardless of their type.
     * @param CAuthItem $type the item for which to get the select options.
     * @param array $exclude the items to be excluded.
     * @return array the select options.
     */
    public static function getParentAuthItemSelectOptions(CAuthItem $parent, $type = null, $exclude = array())
    {
	$authorizer = self::getAuthorizer();
	$items = $authorizer->getAuthItems($type, null, $parent, true, $exclude);
	return self::generateAuthItemSelectOptions($items, $type);
    }
    /**
     * Generates the authorization item select options.
     * @param array $items the authorization items.
     * @param mixed $type the item type (0: operation, 1: task, 2: role).
     * @return array the select options.
     */
    protected static function generateAuthItemSelectOptions($items, $type)
    {
	$selectOptions = array();
	// We have multiple types, nest the items under their types
	if ($type !== (int) $type)
	{
	    foreach ($items as $itemName => $item)
		$selectOptions[self::getAuthItemTypeNamePlural($item->type)][$itemName] = $item->getNameText();
	}
	// We have only one type
	else
	{
	    foreach ($items as $itemName => $item)
		$selectOptions[$itemName] = $item->getNameText();
	}
	return $selectOptions;
    }
    /**
     * Returns the cross-site request forgery parameter 
     * to be placed in the data of Ajax-requests.
     * An empty string is returned if csrf-validation is disabled.
     * @return string the csrf parameter.
     */
    public static function getDataCsrf()
    {
	return ($csrf = self::getCsrfParam()) !== null ? ', ' . $csrf : '';
    }
    /**
     * Returns the cross-site request forgery parameter for Ajax-requests.
     * Null is returned if csrf-validation is disabled.
     * @return string the csrf parameter.
     */
    public static function getCsrfParam()
    {
	if (Yii::app()->request->enableCsrfValidation === true)
	{
	    $csrfTokenName = Yii::app()->request->csrfTokenName;
	    $csrfToken = Yii::app()->request->csrfToken;
	    return "'$csrfTokenName':'$csrfToken'";
	}
	else
	{
	    return null;
	}
    }
    /**
     * @return string a string that can be displayed on your Web page
     * showing Powered-by-Rights information.
     */
    public static function powered()
    {
	$module = self::module();
	return 'Secured with <a href="http://www.yiiframework.com/extension/rights" rel="external">Rights</a> version ' . $module->getVersion() . '.';
    }
    /**
     * @return RightsModule the Rights module.
     */
    public static function module()
    {
	if (isset(self::$_m) === false)
	    self::$_m = self::findModule();
	return self::$_m;
    }
    /**
     * Searches for the Rights module among all installed modules.
     * The module will be found even if it's nested within another module.
     * @param CModule $module the module to find the module in. Defaults to null,
     * meaning that the application will be used.
     * @return the Rights module.
     */
    private static function findModule(CModule $module = null)
    {
	if ($module === null)
	    $module = Yii::app();
	if (($m = $module->getModule('rights')) !== null)
	    return $m;
	foreach ($module->getModules() as $id => $c)
	    if (($m = self::findModule($module->getModule($id))) !== null)
		return $m;
	return null;
    }
    /**
     * @return RAuthorizer the authorizer component.
     */
    public static function getAuthorizer()
    {
	if (isset(self::$_a) === false)
	    self::$_a = self::module()->getAuthorizer();
	return self::$_a;
    }
    /**
     * Translates a message to the specified language.
     * Wrapper class for setting the category correctly.
     * @param string $category message category.
     * @param string $message the original message.
     * @param array $params parameters to be applied to the message using <code>strtr</code>.
     * @param string $source which message source application component to use.
     * @param string $language the target language.
     * @return string the translated message.
     */
    public static function t($category, $message, $params = array(), $source = null, $language = null)
    {
	return Yii::t('RightsModule.' . $category, $message, $params, $source, $language);
    }
}
