
var URI = function(uri)
{
  this.uri       = uri;  // private
  this.scheme    = null;
  this.host      = null;
  this.username  = null;
  this.password  = null;
  this.port      = 0;
  this.path      = null;
  this.query     = null; // private
  this.fragment  = null;
  this.variables = {};

  // Standard ports
  this.ports = {
    'ftp'    : 21,
    'ssh'    : 22,
    'telnet' : 23,
    'smtp'   : 25,
    'http'   : 80,
    'https'  : 443
  };

  var re = new RegExp("([-+a-zA-Z0-9]+)://" + // Scheme
                      "((.[^:]*):?(.*)?@)?" + // Userinfo
                      "(.[^:/]*)"           + // Host
                      ":?([0-9]{1,6})?"     + // Port
                      "(/.[^?#]*)"          + // Path
                      "[?]?(.[^#]*)?"       + // Query
                      "#?(.*)?");             // Fragment
  var m;
  if (this.uri && (m = re.exec(this.uri))) {
    this.scheme   = m[1] && m[1].toLowerCase();
    this.username = m[3];
    this.password = m[4];
    this.host     = m[5] && m[5].toLowerCase();
    this.port     = m[6] && parseInt(m[6]) || 0;
    this.path     = m[7] || "/";
    this.query    = m[8];
    this.fragment = m[9];

    if (this.port == 0 && this.scheme)
      this.port = this.ports[this.scheme];

    if (this.query && this.query.length) {
      var q = this.query.split('&');
      for (var i = 0; i < q.length; i++) {
	var p = q[i].split('=');
	this.variables[unescape(p[0])] = p.length > 1 ? unescape(p[1]) : null;
      }
    }
  }
};

URI.prototype =
{
  queryString: function()
  {
    var tmp = [];
    for (var name in this.variables)
      tmp.push(escape(name) + "=" + escape(this.variables[name]));

    return tmp.length && tmp.join("&") || null;
  },

  toString: function()
  {
    var s = "", q = null;
    if (this.scheme)                    s  = this.scheme + "://";
    if (this.username)                  s += this.username;
    if (this.username && this.password) s += ":";
    if (this.password)                  s += this.password;
    if (this.username)                  s += "@";
    if (this.host)                      s += this.host;
    if (!this.isDefaultPort())          s += ":" + this.port;
    if (this.path)                      s += this.path;
    if (q = this.queryString())         s += "?" + q;
    if (this.fragment)                  s += "#" + this.fragment;

    return s;
  },

  // Private
  isDefaultPort: function()
  {
    if (!this.port) return true;
    for (var scheme in this.ports) {
      if (scheme == this.scheme && this.port != this.ports[scheme])
	return false;
    }

    return true;
  }
};

