(function() {
    var Ext = window.Ext4 || window.Ext;

    /**
     * Utility class for determining the various permissions capabilities of the current user.
     * Generally this class will not be instantiated directly but will instead be obtained from
     * the current app context via the Rally.app.Context#getPermissions method.
     *
     *     var permissions = this.getContext().getPermissions();
     *     if(permissions.isWorkspaceAdmin()) {
     *         //do an admin thing
     *     } else if(permissions.isProjectEditor(this.getContext().getProject()) {
     *         //do a project editor thing
     *     }
     */
    Ext.define('Rally.auth.UserPermissions', {
        constructor: function(userPermissions) {
            this.userPermissions = userPermissions;
        },

        getProjectToWorkspaceMap: function() {
            var shouldCache = Rally.environment.narrowJsScriptingValley;

            if (shouldCache && this.projectToWorkspaceMap) {
                return this.projectToWorkspaceMap;
            }

            var projectToWorkspaceMap = {};
            this.userPermissions.forEach(function(permission) {
                if(permission.Workspace) {
                    var projectOid = Rally.util.Ref.getOidFromRef(permission._ref);
                    var workspaceOid = Rally.util.Ref.getOidFromRef(permission.Workspace);
                    projectToWorkspaceMap[projectOid] = workspaceOid;
                }
            });

            if (shouldCache) {
                this.projectToWorkspaceMap = projectToWorkspaceMap;
            }

            return projectToWorkspaceMap;
        },

        /**
         * Determine whether the current user is a subscriptin admin
         * @return {Boolean} True if the current user is a subscription admin
         */
        isSubscriptionAdmin: function() {
            var workspaceRef = Rally.environment.getContext().getWorkspace()._ref;
            return this.isInRoleForScope('Subscription Admin', workspaceRef);
        },

        /**
         * Determine whether the current user is a workspace admin
         * @return {Boolean} True if the current user is a workspace admin
         */
        isWorkspaceAdmin: function(workspaceRef) {
            workspaceRef = workspaceRef || Rally.environment.getContext().getWorkspace()._ref;
            return this.isInRoleForScope('Workspace Admin', workspaceRef);
        },

        /**
         * Determine whether the current user is a workspace admin in any workspace
         * @return {Boolean}
         */
        isWorkspaceAdminInAnyWorkspace: function() {
            return this._hasRoleInAnyWorkspace('Workspace Admin');
        },

        /**
         * Determine whether the current user is a project admin
         * @return {Boolean} True if the current user is a project admin
         */
        isProjectAdmin: function(projectRef) {
            projectRef = projectRef || Rally.environment.getContext().getProject()._ref;
            return this.isInRoleForScope('ProjectAdmin', projectRef);
        },

        /**
         * Determine whether the current user is a project admin for any project in the workspace
         * @return {Boolean} True if the current user is a project admin for any project in the workspace
         */
        isProjectAdminInAnyProject: function() {
            return this._hasRoleForAnyProjectInCurrentWorkspace('ProjectAdmin');
        },

        /**
         * Determine whether the current user is a project admin for any project in any workspace
         * @return {Boolean}
         */
        isProjectAdminInAnyWorkspace: function() {
            return this._hasRoleInAnyWorkspace('ProjectAdmin');
        },

        /**
         * Determine whether the current user has editor access for any project in the workspace
         * @return {Boolean} True if the current user has editor access for any project in the workspace
         */
        hasEditorAccessToAnyProject: function() {
            return this.isProjectAdminInAnyProject() || this._hasRoleForAnyProjectInCurrentWorkspace('Editor');
        },

        /**
         * Determine whether the current user is a super user, subscription admin or workspace admin
         * @return {Boolean} True if the current user is a super user, subscription admin, or workspace admin.
         */
        isWorkspaceOrSubscriptionAdmin: function(workspaceRef) {
            return this.isSubscriptionAdmin() || this.isWorkspaceAdmin(workspaceRef);
        },

        /**
         * Determine whether the current user is a subscription admin, workspace admin or project admin
         * @return {Boolean} True if the current user is a subscription admin, workspace admin or project admin.
         */
        isProjectWorkspaceOrSubscriptionAdmin: function() {
            return this.isSubscriptionAdmin() || this.isWorkspaceAdmin() || this.isProjectAdmin();
        },

        /**
         * Determine whether the current user has editor access for the given project.
         * @param {String} projectRef The ref of the project
         * @return {Boolean} True if the current user has editor access for the given project.
         * Will be true for Subscription Admins and Workspace Admins.
         */
        isProjectEditor: function(projectRef) {
            return this.isSubscriptionAdmin() || this.isInRoleForScope('ProjectAdmin', projectRef) || this.isInRoleForScope('Editor', projectRef);
        },

        /**
         * Determine whether the current user has the given role for the given scope ref (workspace or project)
         * @param {String} role The role to match on. Possible values include:
         *
         * * For Workspace scope:
         *     * "Subscription Admin"
         *     * "Workspace Admin"
         *     * "Workspace User"
         * * For Project scope:
         *     * "Editor"
         *     * "Viewer"
         *     * "ProjectAdmin"
         * @param {String} scopeRef The workspace or project ref
         * @return {Boolean} True if the current user has the given role for the given scope
         */
        isInRoleForScope: function(role, scopeRef) {
            var permission = this.getPermissionAtScope(scopeRef);
            return permission && permission.Role === role;
        },

        getPermissionAtScope: function(scopeRef) {
            this._scopeRoleMap = this._scopeRoleMap || this._generateScopeRoleMap();

            return this._scopeRoleMap[Rally.util.Ref.getRelativeUri(scopeRef)];
        },

        _generateScopeRoleMap: function() {
            var map = {};

            for (var i = 0, l = this.userPermissions.length; i < l; ++i) {
                var userPerm = this.userPermissions[i];
                var ref = Rally.util.Ref.getRelativeUri(userPerm._ref);
                map[ref] = userPerm;
            }
            return map;
        },

        _hasRoleForAnyProjectInCurrentWorkspace: function(accessLevel) {
            var workspaceRef = Rally.environment.getContext().getWorkspace()._ref + ".js";
            return _.some(this.userPermissions, function(perm) {
                return perm.Workspace && perm.Workspace === workspaceRef && perm.Role === accessLevel;
            });
        },

        _hasRoleInAnyWorkspace: function(accessLevel) {
            return _.some(this.userPermissions, function(perm) {
                return perm.Role === accessLevel;
            });
        }
    });

})();