(function() {

  // initialize _ora path
  var _ora_path = window._ora_path; // we can overwrite the _ora_path before this script is run
  if (undefined === _ora_path) {
     _ora_path = ('http:' == window.document.location.protocol) ? 'http://metrics.outright.com:8080/p.gif' : 'https://metrics.outright.com:8443/p.gif';
  }

  // collect the basic information
  var url = document.location.href;
  var referrer = document.referrer;
  var requestId = _makeRequestId();
  var beaconId = 0;
  var debug = (_readCookie('_oraDebug') == 1);

  function _getUserId() {
    return (window._ora  && window._ora.user_id) ? window._ora.user_id : 0;
  }

  function _getCompanyId() {
    return (window._ora  && window._ora.company_id) ? window._ora.company_id : 0;
  }

  function _getBrowserId() {
    if (window._ora  && window._ora.browser_id) {
        return window._ora.browser_id;
    }

    var __utma = _readCookie('__utma');
    if (__utma) {
        var parts = __utma.split('.');
        if (parts && parts[1]) {
          return parts[1];
        }
    }

    return 0;
  }

  function _getTest() {
    return (window._ora  && window._ora.test) ? window._ora.test : 0;
  }

  function _now() { // this is the number of seconds plus the number of milliseconds
    return (new Date()).getTime() / 1000;
  }

  function _makeRequestId() {
    var text = "";
    var possible = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";

    for (var i=0; i<6; i++) {
      text += possible.charAt(Math.floor(Math.random() * possible.length));
    }

    return text;
  }


  function _readCookie(name) {
    var nameEQ = name + "=";
    var ca = document.cookie.split(';');
    for (var i = 0; i < ca.length; i++) {
      var c = ca[i];
      while (c.charAt(0)==' ') c = c.substring(1,c.length);
      if (c.indexOf(nameEQ) == 0) return c.substring(nameEQ.length,c.length);
    }
    return '';
  }

  // a Beacon is a pixel that can be fired
  // constructor for beacon
  function Beacon() {
    // initialize the beacon created time
    this.data = {time: _now(), beaconId: requestId + '.' + beaconId};
    this.timer = {};
    this.fired = false;
    beaconId++;
    this._debug('new beacon');
  }


  // implementation
  Beacon.prototype.start = function(key) {
    this._debug('start: ' + key);
    this.timer[key] = {start: _now()};
    return this;
  }

  Beacon.prototype.end = function(key) {
    this._debug('end: ' + key);
    if (this.timer[key]) { // we only want to store the end time if it has been started
      this.timer[key].end = _now();
    }
    return this;
  }

  Beacon.prototype.collect = function(key, value, overwrite) {
    this._debug('collect: ' + key + ' = ' + value);
    if (overwrite || !this.data[key]) {
      this.data[key] = value;
    } else {
      this.data[key] += ',' + value;
    }
    return this;
  }

  Beacon.prototype.collectHash = function(hash, overwrite) {
    this._debug('collectHash');
    for (var k in hash) {
      this.collect(k, hash[k], overwrite);
    }
    return this;
  }

  Beacon.prototype.increment = function(key, overwrite) {
    this._debug('increment: ' + key);
    if (overwrite !== undefined) { // we can always overwrite the current count
      var overwrite = parseInt(overwrite);
      if (isNaN(overwrite)) {
        return this; // do nothing if the input is NaN
      }
      this.data[key] = overwrite;
      return this;
    }

    var count = parseInt(this.data[key]);
    this.data[key] = isNaN(count) ? 1 : ++count;
    return this;
  }

  Beacon.prototype.fire = function() {
    if (this.fired) {
      return this;
    }

    this._debug('fire: ' + this.data.beaconId);

    this._misc(); // all of the misc trackings

    var data = this.data;
    var timer = this.timer;

    var params = '';
    for (var k in data) {
      params += encodeURIComponent(k) + '=' + encodeURIComponent(data[k]) + '&';
    }

    for (var k in timer) {
      var t = timer[k];

      if (!t.start) t.start = _now();
      if (!t.end) t.end = _now();
      var time = t.end - t.start;
      params += encodeURIComponent(k) + '=' + encodeURIComponent(time) + '&';
    }

    // ensure that this is async
    (function() {
      var image = new Image(20, 1);
      image.src = _ora_path + '?' + params;
      if (document && document.body) { document.body.appendChild(image); }
    })();

    this.fired = true;
    return this;
  }

  Beacon.prototype._misc = function() {
    this._cookies(['__utma', '__utmb', '__utmc', '__utmz', '__utmv', '__utmx', '__utmxx', '_ora']);
    this.data['url'] = url;
    this.data['referer'] = referrer;
    this.data['_u'] = _getUserId();
    this.data['_c'] = _getCompanyId();
    this.data['_b'] = _getBrowserId();
    this.data['_t'] = _getTest()
  }

  Beacon.prototype._cookies = function(cookies_to_append) { // track the cookies that we are interested in

    var len = cookies_to_append.length;
    var cookieName = '';

    for (var i=0; i<len; i++) {
      cookieName = cookies_to_append[i];
      this.data[cookieName] = _readCookie(cookieName);
    }

  }

  Beacon.prototype._debug = function(data) {
    if (!debug) {
      return;
    }

    if (typeof(data) !== 'object' || data == null) {
      console.log(this.data.beaconId + '|' + data);
    } else {
      var output = '{';
      for (var k in data) {
        output += k + ': ' + data[k] + '; ';
      }
      output += '}';
      console.log(this.data.beaconId + '|' + output);
    }
  }

  // short hand
  Beacon.prototype.s = Beacon.prototype.start;
  Beacon.prototype.e = Beacon.prototype.end;
  Beacon.prototype.c = Beacon.prototype.collect;
  Beacon.prototype.i = Beacon.prototype.increment;
  Beacon.prototype.f = Beacon.prototype.fire;

  // creates a new beacon object
  window._b = function() {return new Beacon();};

  // creates and fires a beacon for a mouse click
  window._c = function(link_text, additional_data_hash, overwrite) { 
    hash = (additional_data_hash) ? additional_data_hash : {};
    overwrite = (overwrite) ? overwrite : false;
    _b().collectHash(hash, overwrite).c('click', link_text).fire();
  };

})();

