<?php
namespace library;

use \ILogger;
use models\IUser;

/**
 * Authorization class
 * @author Jérôme Brilland
 * @version 4.0
 * @copyright (c) 2019-2023, Jérôme Brilland
 * @license http://www.gnu.org/licenses/gpl.txt GNU General Public License
 */
class Authorization implements \IAuthorization {

    /**
     * @var IUser
     * @access protected
     */
    protected $user;
    
    /**
     * @var ILogger
     * @access protected
     */
    protected $logger = null;
    
    /**
     * @var string
     * @access private
     */
    private $loginUrl = null;
    
    /**
     * @var array
     * @access private
     */
    private $policies = [];

    /**
     * Class constructor
     * @param IUser $user
     * @access public
     */
    public function __construct( IUser $user, ILogger $logger, string $loginUrl ) {
        $this->user = $user;
        $this->logger = $logger;
        $this->loginUrl = $loginUrl;
    }

    /**
     * @param mixed $activity
     * @param mixed $object
     */
    public function authorize( $activity, $object = null ) {
        $this->logger->info( "Authorization::authorize( $activity )" );
        if ( !$this->isAuthorized( $activity, $object ) ) {
            if ( !$this->user->isAuthenticated() ) {
                $this->logger->debug( 'Not logged in' );
                $_SESSION['return_to'] = $_SERVER['REQUEST_URI'];
                header( 'Location: ' . BASE_URL . $this->loginUrl );
                exit();
            } else {
                $this->logger->info( '403 Forbidden' );
                $_SESSION['return_to'] = parse_url( $_SERVER['REQUEST_URI'], PHP_URL_PATH );
                header( 'Location: ' . BASE_URL . 'error/403' );
                exit();
            }
        }
    }
    
    /**
     * @param mixed $activity
     * @param mixed $object
     * @return boolean True if the user is authorized, false otherwise
     */
    public function isAuthorized( $activity, $object = null ) {
        $this->logger->info( "Authorization::isAuthorized( $activity )" );
        $this->logger->debug( join( ', ', $this->user->getPermissions() ) );
        if ( array_key_exists( $activity, $this->policies ) ) {
            return $this->policies[$activity]( $this->user, $object );
        } else {
            return ( $this->user->hasPermission( $activity ) );
        }
    }
    
    /**
     * @param mixed $activity
     * @param Closure $callback
     * @access public
     */
    public function define( $activity, \Closure $callback ) {
        $this->policies[$activity] = $callback;
    }
}
