<?php
    namespace App\Traits;

    trait LtiRolesManager {
        public static $SYSTEM_ROLES = 'http://purl.imsglobal.org/vocab/lis/v2/system/person#';
        public static $INSTITUTIONAL_ROLES = 'http://purl.imsglobal.org/vocab/lis/v2/institution/person#';
        public static $CONTEX_ROLES = 'http://purl.imsglobal.org/vocab/lis/v2/membership#';

        public static $LTI_ADMIN_ROLES_SPEC = ['Administrator', 'Developer', 'ExternalDeveloper',
        'ExternalSupport', 'ExternalSystemAdministrator', 'Support', 'SystemAdministrator'];

        public static $LTI_CONTENT_DEVELOPER_ROLES_SPEC = ['ContentDeveloper', 'ContentExpert',
        'ExternalContentExpert', 'Librarian'];

        public static $LTI_INSTRUCTOR_ROLES_SPEC = ['ExternalInstructor','Grader','GuestInstructor',
        'Lecturer','PrimaryInstructor','SecondaryInstructor','TeachingAssistant',
        'TeachingAssistantGroup','TeachingAssistantOffering', 'TeachingAssistantSection',
        'TeachingAssistantSectionAssociation', 'TeachingAssistantTemplate', 'Instructor'];

        public static $LTI_LEARNER_ROLES_SPEC = ['GuestLearner', 'ExternalLearner', 'Instructor',
        'Learner', 'NonCreditLearner','Student'];

        public static $LTI_MANAGER_ROLES_SPEC = ['AreaManager', 'CourseCoordinator', 'ExternalObserver',
        'Manager', 'Observer'];

        public static $LTI_MENTOR_ROLES_SPEC = ['Advisor','Auditor','ExternalAdvisor','ExternalAuditor',
        'ExternalLearningFacilitator','ExternalMentor','ExternalReviewer','ExternalTutor',
        'LearningFacilitator', 'Mentor', 'Reviewer', 'Tutor'];

        public static $LTI_OFFICER_ROLES_SPEC = ['Chair', 'Communications', 'Secretary', 'Treasurer',
        'Vice-Chair'];

        public function isAdmin(?string $role_context = null) : bool {
            return $this->hasSomeRolesOf(static::$LTI_ADMIN_ROLES_SPEC, $role_context);
        }

        public function isContentDeveloper(?string $role_context = null) : bool {
            return $this->hasSomeRolesOf(static::$LTI_CONTENT_DEVELOPER_ROLES_SPEC, $role_context);
        }

        public function isInstructor(?string $role_context = null) : bool {
            return $this->hasSomeRolesOf(static::$LTI_INSTRUCTOR_ROLES_SPEC, $role_context);
        }

        public function isLearner(?string $role_context = null) : bool {
            return $this->hasSomeRolesOf(static::$LTI_LEARNER_ROLES_SPEC, $role_context);
        }

        public function isManager(?string $role_context = null) : bool {
            return $this->hasSomeRolesOf(static::$LTI_MANAGER_ROLES_SPEC, $role_context);
        }

        public function isMentor(?string $role_context = null) : bool {
            return $this->hasSomeRolesOf(static::$LTI_MENTOR_ROLES_SPEC, $role_context);
        }

        public function isOfficer(?string $role_context = null) : bool {
            return $this->hasSomeRolesOf(static::$LTI_OFFICER_ROLES_SPEC, $role_context);
        }

        public function isMember(?string $role_context = null) : bool {
            $LTI_MEMBER_ROLE_SPEC = ['Member'];
            return $this->hasSomeRolesOf($LTI_MEMBER_ROLE_SPEC, $role_context);
        }

        public function isTestUser(?string $role_context = null) : bool {
            $LTI_TEST_USER_ROLE_SPEC = 'http://purl.imsglobal.org/vocab/lti/system/person#TestUser';
            $roles = explode(" ", $this->roles);
            $isTestUser = in_array($LTI_TEST_USER_ROLE_SPEC, $roles);
            return $isTestUser;
        }

        public function hasSomeRolesOf(array $role_list, ?string $role_context=null) : bool {
            $hasRole = false;
            foreach ($role_list as $role_name){
                if($this->hasRole($role_name, $role_context)){
                    return true;
                }
            }
            return $hasRole;
        }

        public function hasRole(string $role_name , ?string $role_context = null) : bool {
            $roles = [];
            if($role_context == static::$SYSTEM_ROLES){
                $roles = $this->getSystemRoles();
            }else if ($role_context == static::$INSTITUTIONAL_ROLES) {
                $roles = $this->getInstitutionRoles();
            }else if ($role_context == static::$CONTEX_ROLES) {
                $roles = $this->getContextRoles();
            }else{
                $roles = $this->getAllRoles();
            }
            $has_role = in_array($role_name, $roles);
            return $has_role;
        }

        public function getAllRoles(){
            $system = $this->getSystemRoles();
            $institution = $this->getInstitutionRoles();
            $context = $this->getContextRoles();
            $roles = array_merge($system, $institution, $context);
            $roles = array_unique($roles, SORT_REGULAR);
            return $roles;
        }

        public function getSystemRoles() : array {
            $roles = explode(' ', $this->roles);
            $roles = $this->toFriendlyRoles($roles, static::$SYSTEM_ROLES);
            return $roles;
        }

        public function getInstitutionRoles() : array {
            $roles = explode(' ', $this->roles);
            $roles = $this->toFriendlyRoles($roles, static::$INSTITUTIONAL_ROLES);
            return $roles;
        }

        public function getContextRoles() : array {
            $roles = explode(' ', $this->roles);
            $roles = $this->toFriendlyRoles($roles, static::$CONTEX_ROLES);
            return $roles;
        }

        private function toFriendlyRoles(array $roles, string $scope) : array {
            $friendlyRoles = [];
            $start = strlen($scope);
            foreach($roles as $role){
                $isConsultedScope = (strpos($role, $scope) !== false);
                if($isConsultedScope){
                    $end = strlen($role);
                    $role = substr($role, $start, $end);
                    array_push($friendlyRoles, $role);
                }
            }
            return $friendlyRoles;
        }
    }
