var validator = new RegExp("^[a-z0-9]{8}-[a-z0-9]{4}-[a-z0-9]{4}-[a-z0-9]{4}-[a-z0-9]{12}$", "i");

function gen(count) {
  var out = "";
  for (var i=0; i<count; i++) {
    out += (((1+Math.random())*0x10000)|0).toString(16).substring(1);
  }
  return out;
}

function Guid(guid) {
  if (!guid) throw new TypeError("Invalid argument; `value` has no value.");
    
  this.value = Guid.EMPTY;
  
  if (guid && guid instanceof Guid) {
    this.value = guid.toString();

  } else if (guid && Object.prototype.toString.call(guid) === "[object String]" && Guid.isGuid(guid)) {
    this.value = guid;
  }
  
  this.equals = function(other) {
    // Comparing string `value` against provided `guid` will auto-call
    // toString on `guid` for comparison
    return Guid.isGuid(other) && this.value == other;
  };

  this.isEmpty = function() {
    return this.value === Guid.EMPTY;
  };
  
  this.toString = function() {
    return this.value;
  };
  
  this.toJSON = function() {
    return this.value;
  };
};

Guid.EMPTY = "00000000-0000-0000-0000-000000000000";

Guid.isGuid = function(value) {
  return value && (value instanceof Guid || validator.test(value.toString()));
};

Guid.create = function() {
  return new Guid([gen(2), gen(1), gen(1), gen(1), gen(3)].join("-"));
};

Guid.raw = function() {
  return [gen(2), gen(1), gen(1), gen(1), gen(3)].join("-");
};

if(typeof module != 'undefined' && module.exports) {
  module.exports = Guid;
}
