<?php
/**
 * Copyright 2016 David Vivier on behalf of Smartic.ca
 * 
 * This file is part of the Smarticops Package
 * 
 * License : MIT
 * 
 * @author David Vivier
 */

namespace Dvivier\Smarticops;

use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;

use DB;
use Auth;

use Dvivier\Smarticops\Permission;

use Dvivier\Smarticops\Facades\Smarticops;


/**
 * The Role model for the Smarticops features.
 * 
 * @author David Vivier
 */
class Role extends Model
{
    use SoftDeletes;
    
    protected $dates = [ 'deleted_at' ];
    
    /**
     * 
     * Allows to temporarly store the permissions that a role has.
     *  Avoids too many useless queries to the database
     * 
     * @var array
     * @see loadPermissions()  loadpermisions
     * @deprecated
     */
    protected $_permissions = array();
    
    public function users() {
        return $this->belongsToMany(User::class, 'users_roles')->withTimeStamps();
    }
    
    public function permissions() {
        return $this->belongsToMany(Permission::class, 'roles_permissions')->withPivot('value', 'created_by', 'updated_by')->withTimeStamps();
    }
    
    public function getName() {
        return $this->name;
    }
    
    /**
     * Retrieves a role by its name
     * 
     * @param  $name  string  The name of the desired role
     * @return  null if no role of this name
     */
    public static function byName($name) {
        /*
        $role = DB::select('SELECT * 
                        FROM roles
                        WHERE name = ?', [$name] );
        if ($role === null or count($role) === 0) {
            return null;
        }
        
        return $role[0];*/
        $role = Role::where('name', $name)->first();
        return $role;
    }
    
    /**
     * Loads all the permissions associated to the role from the database.
     * To avoid too many requests to the DB
     * @deprecated
     */
    public function loadPermissions() {
        $this->_permissions = $this->fresh()->permissions;
        return $this->_permissions; 
    }
    
        
    public function getPermissions() {
        self::loadPermissions();
        return $this->_permissions;
    }
    
    /**
     * Gives a specific permission to the role. 
     * The permission must exist before giving it to the role.
     * By default the permission is set to true, you may set it to false
     *  to explicitly mean that the role does NOT have that permission.
     * 
     * @param permissionCode  string
     * @param  boolean  $value  Value of the permission, usually true
     */
    public function givePermission($permissionCode, $value = true) {
        
        $permissions = Permission::where('code', $permissionCode )->get();

        if ($permissions->count() == 0) {
            // the permission doesn't even exist
            Smarticops::logError(' failed giving permission "'.$permissionCode.
                                 '", which doesn\'t exist, to Role "'.$this->name.'"',
                                [
                                    'role_id'   => $this->id,
                                    'role_name'         => $this->name,
                                    'permission_code'   => $permissionCode,
                                    'permission_value'  => $value,
                                    ]);
            return false;
        }
        
        // the permission exists. 
        //  now we check if the role was already given that permission
        $permission = $permissions->first();
        $permissionId = $permission->id;
        
        /*
        $count = $this->permissions()->where('code', $permissionCode)->get()->count();
        
        if ($count != 0) {
            $hasPermission = true;
        }
        else {
            $hasPermission = false;
        }*/
        $hasPermission = $this->hasPermission($permissionCode) ? true : false;
        
        $auth_user_id = Auth::check() ? Auth::user()->id : 0;
        
        $res = true;
        if ($hasPermission) {
        
                // the role already has the permission
                $res = $this->permissions()->updateExistingPivot($permission->id,[
                                                                        'value' => $value,
                                                                        'updated_by' => $auth_user_id,
                                                                        ]);
                                                                        
                //$table = DB::select('Select * from users_permissions');
                
                return true;
        }
        else {
            // role doesn't already has the permission 
        
            $this->permissions()->attach($permission->id, [
                                                            'value' => $value,
                                                            'created_by' => $auth_user_id,
                                                            ]);
        }
        Smarticops::logPermissionGivenToRole($permission, $this, $value, $res);
        // we update the temporary stored permission in the role object
        $this->loadPermissions();
        return true;
        
    }
    
    /**
     * Checks if a role has a permission or not.
     * 
     * @param  $permissionCode  the code of the permission to test
     * 
     * @return  bool  true if the role has the permission
     * 
     */
    public function hasPermission( $permissionCode ) {

        $permissions = $this->fresh()->permissions;

        if (count($permissions) === 0) {
            return false;
        }

        foreach ( $permissions as $p ) {
            if ($p->code == $permissionCode) {
                if ($p->pivot->value == true) {

                    return true;
                }
            }
        }
        return false;
    }
    
    /** 
     * Removes a Permission from a role
     * 
     * @param string $permissionCode
     */
    public function removePermission( $permissionCode ) {
        
        $permissions = Permission::where('code', $permissionCode )->get();

        if ($permissions->count() == 0) {
            // the permission doesn't even exist
            return false;
        }
        
        $permission = $permissions->first();
        
        $count = $this->permissions()->where('code', $permissionCode)->get()->count();

        if ($count != 0) {
            $hasPermission = true;
        }
        else {
            $hasPermission = false;
        }

        if ($hasPermission) {
            $this->permissions()->detach($permission->id);
            Smarticops::logPermissionRemovedFromRole($permission, $this);
            return true;
        }
        else {
            Smarticops::logError('Failed removing permission "'.$permission->code.
                                 '" from Role "'.$this->name.'", : this role didn\'t have this permission.',
                                 [
                                    'role_id'   => $this->id,
                                    'role_name'     => $this->name,
                                    'role_description'  => $this->description,
                                    'permission_id'     => $permission->id,
                                    'permission_code'   => $permission->code,
                                    'permission_description'    => $permission->description,
                                    ]);
            return false;
        }
    }
    
    /**
     * Removes all the permissions from the role
     * 
     * @see removePermission() removePermission()
     */
    public function removeAllPermissions() {
        $permissions = $this->permissions;
        
        if (count($permissions) === 0) {
            return true;
        }
        
        foreach ($permissions as $permission) {
            $res = $this->removePermission($permission->code);
        }
        return true;
    }
}

