text: "use strict";
  module.exports = Enum;
  
  // extends ReflectionObject
  var ReflectionObject = require("./object");
  ((Enum.prototype = Object.create(ReflectionObject.prototype)).constructor = Enum).className = "Enum";
  
  var util = require("./util");
  
  /**
   * Constructs a new enum instance.
   * @classdesc Reflected enum.
   * @extends ReflectionObject
   * @constructor
   * @param {string} name Unique name within its namespace
   * @param {Object.<string,number>} [values] Enum values as an object, by name
   * @param {Object.<string,*>} [options] Declared options
   */
  function Enum(name, values, options) {
      ReflectionObject.call(this, name, options);
  
      if (values && typeof values !== "object")
          throw TypeError("values must be an object");
  
      /**
       * Enum values by id.
       * @type {Object.<number,string>}
       */
      this.valuesById = {};
  
      /**
       * Enum values by name.
       * @type {Object.<string,number>}
       */
      this.values = Object.create(this.valuesById); // toJSON, marker
  
      /**
       * Value comment texts, if any.
       * @type {Object.<string,string>}
       */
      this.comments = {};
  
      // Note that values inherit valuesById on their prototype which makes them a TypeScript-
      // compatible enum. This is used by pbts to write actual enum definitions that work for
      // static and reflection code alike instead of emitting generic object definitions.
  
      if (values)
          for (var keys = Object.keys(values), i = 0; i < keys.length; ++i)
              this.valuesById[ this.values[keys[i]] = values[keys[i]] ] = keys[i];
  }
  
  /**
   * Creates an enum from JSON.
   * @param {string} name Enum name
   * @param {Object.<string,*>} json JSON object
   * @returns {Enum} Created enum
   * @throws {TypeError} If arguments are invalid
   */
  Enum.fromJSON = function fromJSON(name, json) {
      return new Enum(name, json.values, json.options);
  };
  
  /**
   * @override
   */
  Enum.prototype.toJSON = function toJSON() {
      return {
          options : this.options,
          values  : this.values
      };
  };
  
  /**
   * Adds a value to this enum.
   * @param {string} name Value name
   * @param {number} id Value id
   * @param {?string} comment Comment, if any
   * @returns {Enum} `this`
   * @throws {TypeError} If arguments are invalid
   * @throws {Error} If there is already a value with this name or id
   */
  Enum.prototype.add = function(name, id, comment) {
      // utilized by the parser but not by .fromJSON
  
      if (!util.isString(name))
          throw TypeError("name must be a string");
  
      if (!util.isInteger(id))
          throw TypeError("id must be an integer");
  
      if (this.values[name] !== undefined)
          throw Error("duplicate name");
  
      if (this.valuesById[id] !== undefined)
          throw Error("duplicate id");
  
      this.valuesById[this.values[name] = id] = name;
      this.comments[name] = comment || null;
  
      return this;
  };
  
  /**
   * Removes a value from this enum
   * @param {string} name Value name
   * @returns {Enum} `this`
   * @throws {TypeError} If arguments are invalid
   * @throws {Error} If `name` is not a name of this enum
   */
  Enum.prototype.remove = function(name) {
  
      if (!util.isString(name))
          throw TypeError("name must be a string");
  
      var val = this.values[name];
      if (val === undefined)
          throw Error("name does not exist");
  
      delete this.valuesById[val];
      delete this.values[name];
      delete this.comments[name];
  
      return this;
  };
  