text: 'use strict';
  
  var _ = require('underscore');
  var AVError = require('./error');
  
  module.exports = function (AV) {
    AV.Role = AV.Object.extend("_Role", /** @lends AV.Role.prototype */{
      // Instance Methods
  
      /**
      * Represents a Role on the AV server. Roles represent groupings of
      * Users for the purposes of granting permissions (e.g. specifying an ACL
      * for an Object). Roles are specified by their sets of child users and
      * child roles, all of which are granted any permissions that the parent
      * role has.
      *
      * <p>Roles must have a name (which cannot be changed after creation of the
      * role), and must specify an ACL.</p>
      * An AV.Role is a local representation of a role persisted to the AV
      * cloud.
       * @class AV.Role
       * @param {String} name The name of the Role to create.
       * @param {AV.ACL} [acl] The ACL for this role. if absent, the default ACL
       *    `{'*': { read: true }}` will be used.
       */
      constructor: function constructor(name, acl) {
        if (_.isString(name)) {
          AV.Object.prototype.constructor.call(this, null, null);
          this.setName(name);
        } else {
          AV.Object.prototype.constructor.call(this, name, acl);
        }
        if (acl === undefined) {
          var defaultAcl = new AV.ACL();
          defaultAcl.setPublicReadAccess(true);
          if (!this.getACL()) {
            this.setACL(defaultAcl);
          }
        } else if (!(acl instanceof AV.ACL)) {
          throw new TypeError('acl must be an instance of AV.ACL');
        } else {
          this.setACL(acl);
        }
      },
  
      /**
       * Gets the name of the role.  You can alternatively call role.get("name")
       *
       * @return {String} the name of the role.
       */
      getName: function getName() {
        return this.get("name");
      },
  
      /**
       * Sets the name for a role. This value must be set before the role has
       * been saved to the server, and cannot be set once the role has been
       * saved.
       *
       * <p>
       *   A role's name can only contain alphanumeric characters, _, -, and
       *   spaces.
       * </p>
       *
       * <p>This is equivalent to calling role.set("name", name)</p>
       *
       * @param {String} name The name of the role.
       */
      setName: function setName(name, options) {
        return this.set("name", name, options);
      },
  
      /**
       * Gets the AV.Relation for the AV.Users that are direct
       * children of this role. These users are granted any privileges that this
       * role has been granted (e.g. read or write access through ACLs). You can
       * add or remove users from the role through this relation.
       *
       * <p>This is equivalent to calling role.relation("users")</p>
       *
       * @return {AV.Relation} the relation for the users belonging to this
       *     role.
       */
      getUsers: function getUsers() {
        return this.relation("users");
      },
  
      /**
       * Gets the AV.Relation for the AV.Roles that are direct
       * children of this role. These roles' users are granted any privileges that
       * this role has been granted (e.g. read or write access through ACLs). You
       * can add or remove child roles from this role through this relation.
       *
       * <p>This is equivalent to calling role.relation("roles")</p>
       *
       * @return {AV.Relation} the relation for the roles belonging to this
       *     role.
       */
      getRoles: function getRoles() {
        return this.relation("roles");
      },
  
      /**
       * @ignore
       */
      validate: function validate(attrs, options) {
        if ("name" in attrs && attrs.name !== this.getName()) {
          var newName = attrs.name;
          if (this.id && this.id !== attrs.objectId) {
            // Check to see if the objectId being set matches this.id.
            // This happens during a fetch -- the id is set before calling fetch.
            // Let the name be set in this case.
            return new AVError(AVError.OTHER_CAUSE, "A role's name can only be set before it has been saved.");
          }
          if (!_.isString(newName)) {
            return new AVError(AVError.OTHER_CAUSE, "A role's name must be a String.");
          }
          if (!/^[0-9a-zA-Z\-_ ]+$/.test(newName)) {
            return new AVError(AVError.OTHER_CAUSE, "A role's name can only contain alphanumeric characters, _," + " -, and spaces.");
          }
        }
        if (AV.Object.prototype.validate) {
          return AV.Object.prototype.validate.call(this, attrs, options);
        }
        return false;
      }
    });
  };