'use strict';
var CLASS_NAME = 'Enumeration';
var Argument = require('./argument-check.js');
var EnumerationError = require('./enumeration-error.js');
/**
 * @classdesc
 *      Serves as the base class for enumerations.
 * @description
 *      Creates a new enumeration.
 *      The enumeration instances should be frozen.
 *
 * @memberof bo.system
 * @constructor
 */
function Enumeration () {
  /**
   * The name of the enumeration. The default value is the name of the constructor.
   * @type {string}
   * @readonly
   */
  this.$name = this.constructor.name;
}
/**
 * Returns the count of the items in enumeration.
 *
 * @function bo.system.Enumeration#count
 * @returns {number} The count of the enumeration items.
 */
Enumeration.prototype.count = function () {
  var count = 0;
  for (var propertyName in this) {
    if (this.hasOwnProperty(propertyName) && typeof this[propertyName] === 'number') {
      count++;
    }
  }
  return count;
};
/**
 * Returns the name of an enumeration item.
 *
 * @function bo.system.Enumeration#getName
 * @param {number} value - The enumeration item that name to be returned of.
 * @returns {string} The name of the enumeration item.
 *
 * @throws {@link bo.system.ArgumentError Argument error}: The value must be a number.
 * @throws {@link bo.system.EnumerationError Enumeration error}: The passed value is not an enumeration item.
 */
Enumeration.prototype.getName = function (value) {
  value = Argument.inMethod(CLASS_NAME, 'getName').check(value).forMandatory('value').asNumber();
  for (var propertyName in this) {
    if (this.hasOwnProperty(propertyName) && typeof this[propertyName] === 'number') {
      if (this[propertyName] === value)
        return propertyName;
    }
  }
  throw new EnumerationError('enumValue', this.$name, value);
};
/**
 * Returns the value of an enumeration item based on its name.
 *
 * @function bo.system.Enumeration#getValue
 * @param {string} name - The enumeration item that value to be returned of.
 * @returns {number} The value of the enumeration item.
 *
 * @throws {@link bo.system.ArgumentError Argument error}: The name must be a non-empty string.
 * @throws {@link bo.system.EnumerationError Enumeration error}: The passed name is not an enumeration item.
 */
Enumeration.prototype.getValue = function (name) {
  name = Argument.inMethod(CLASS_NAME, 'getValue').check(name).forMandatory('name').asString();
  for (var propertyName in this) {
    if (this.hasOwnProperty(propertyName) && typeof this[propertyName] === 'number') {
      if (propertyName === name)
        return this[propertyName];
    }
  }
  throw new EnumerationError('enumName', this.$name, name);
};
/**
 * Determines if the enumeration has an item with the given name.
 *
 * @function bo.system.Enumeration#hasValue
 * @param {string} name - The name of the enumeration item.
 * @returns {boolean} True if the name is an enumeration item, otherwise false.
 */
Enumeration.prototype.isMemberName = function (name) {
  for (var propertyName in this) {
    if (this.hasOwnProperty(propertyName) && typeof this[propertyName] === 'number') {
      if (propertyName === name)
        return true;
    }
  }
  return false;
};
/**
 * Checks whether the enumeration has an item with the given value.
 * If not, throws an error.
 *
 * @function bo.system.Enumeration#check
 * @param {number} value - The value to check.
 * @param {string} [message] - Human-readable description of the error.
 * @param {...*} [messageParams] - Optional interpolation parameters of the message.
 *
 * @throws {@link bo.system.EnumerationError Enumeration error}: The passed value is not an enumeration item.
 */
Enumeration.prototype.check = function (value, message) {
  for (var propertyName in this) {
    if (this.hasOwnProperty(propertyName) && typeof this[propertyName] === 'number') {
      if (this[propertyName] === value)
        return;
    }
  }
  throw new EnumerationError(message || 'enumValue', this.$name, value);
};
/**
 * Determines if the enumeration has an item with the given value.
 *
 * @function bo.system.Enumeration#hasMember
 * @param {number} value - The value to check.
 * @returns {boolean} True if the value is an enumeration item, otherwise false.
 */
Enumeration.prototype.hasMember = function (value) {
  for (var propertyName in this) {
    if (this.hasOwnProperty(propertyName) && typeof this[propertyName] === 'number') {
      if (this[propertyName] === value)
        return true;
    }
  }
  return false;
};
module.exports = Enumeration;