﻿((function () {
  var enc = encodeURIComponent;
  var IE = document.all ? true : false;
  var Ajax = {
    newXMLHttpRequest: function () { return window.XMLHttpRequest ? new XMLHttpRequest() : new ActiveXObject("Microsoft.XMLHTTP"); },
    getClientDateTimeString: function () { return new Date().getTime().toString(); },
    sget: function (url, params, callback, fnCacheBuster) { this.get(url, params, false, callback, fnCacheBuster); },
    aget: function (url, params, callback, fnCacheBuster) { this.get(url, params, true, callback, fnCacheBuster); },
    get: function (url, params, async, callback, fnCacheBuster) { this.request("get", url, params, async, callback, fnCacheBuster); },
    spost: function (url, params, callback, fnCacheBuster) { this.post(url, params, false, callback, fnCacheBuster); },
    apost: function (url, params, callback, fnCacheBuster) { this.post(url, params, true, callback, fnCacheBuster); },
    post: function (url, params, async, callback, fnCacheBuster) { this.request("post", url, params, async, callback, fnCacheBuster); },
    request: function (method, url, params, async, callback, fnCacheBuster) {
      var r = this.newXMLHttpRequest(), postData = null;
      if (fnCacheBuster === undefined) fnCacheBuster = this.getClientDateTimeString;
      if (fnCacheBuster !== null) url += '&cdt=' + fnCacheBuster();
      r.open(method, url, async);
      if (method == "post") this.setHeader(r, "Content-Type", "application/x-www-form-urlencoded");
      if (params) {
        switch (method) {
          case "get": for (var paramName in params) this.setHeader(r, paramName, params[paramName]); break;
          case "post": postData = this.getPostData(params); break;
        }
      }
      if (async && callback) r.onreadystatechange = function () { if (r.readyState == 4) callback(r.responseText, r); }
      r.send(postData);
      if (!async && callback) callback(r.responseText, r);
    },
    getPostData: function (params) {
      var a = [];
      for (var paramName in params) a.push([enc(paramName), '=', enc(params[paramName])].join(''));
      return a.join('&');
    },
    setHeader: function (r, name, value) {
      r.setRequestHeader(name, value);
    }
  }

  var addEvent = function (o, e, h) {
    if (o.addEventListener) o.addEventListener(e, h, false);
    else if (o.attachEvent) o.attachEvent("on" + e, h);
  }

  var pageViewId = -1;

  var getPoint = function (p) {
    return [Math.max(p[0], 0), Math.max(p[1], 0)];
  }

  var Page = {
    getInnerDim: function () {
      var p, w = window, d = document, b = d.body, e = d.documentElement;
      if (window.innerWidth) p = [window.innerWidth, window.innerHeight];
      else if (!(e.clientWidth == 0)) p = [e.clientWidth, e.clientHeight];
      else p = [b.clientWidth, b.clientHeight];
      return p;
    },
    getScrollDim: function () {
      var d = document, b = d.body, e = d.documentElement;
      return [Math.max(e.scrollWidth, b.scrollWidth, b.offsetWidth, e.offsetWidth, e.clientWidth, b.clientWidth),
              Math.max(e.scrollHeight, b.scrollHeight, b.offsetHeight, e.offsetHeight, e.clientHeight, b.clientHeight)];
    },
    getScrollPos: function () {
      var p;
      if (window.pageXOffset) {
        p = [pageXOffset, pageYOffset];
      }
      else {
        var d = document;
        var e = d.documentElement;
        if (!e.clientWidth) e = d.body;
        p = [e.scrollLeft, e.scrollTop];
      }
      return getPoint(p);
    }
  }

  var Mouse = {
    point: [0, 0],
    eventHandler: function (evt, isClick, handler, scope) {
      var p;
      if (IE) {
        p = Page.getScrollPos();
        p[0] += event.clientX;
        p[1] += event.clientY;
      }
      else {
        p = getPoint([evt.pageX, evt.pageY]);
      }
      this.point = p;
      handler.apply(scope, [p, isClick]);
    }
  }

  var Tracks = {
    MAX_BUFFER_SIZE: 50,
    bufferSize: 0,
    buffer: {
      mouseX: [], mouseY: [],
      scrollX: [], scrollY: [],
      innerWidth: [], innerHeight: [],
      scrollWidth: [], scrollHeight: [],
      isClick: []
    },

    recordTrack: function (mousePos, isClick) {
      var scrollPos = Page.getScrollPos(),
          innerDim = Page.getInnerDim(),
          scrollDim = Page.getScrollDim(),
          b = this.buffer;

      b.mouseX.push(mousePos[0]);
      b.mouseY.push(mousePos[1]);
      b.scrollX.push(scrollPos[0]);
      b.scrollY.push(scrollPos[1]);
      b.innerWidth.push(innerDim[0]);
      b.innerHeight.push(innerDim[1]);
      b.scrollWidth.push(scrollDim[0]);
      b.scrollHeight.push(scrollDim[1]);
      b.isClick.push(isClick);
      this.bufferSize++;

      if (this.bufferSize >= this.MAX_BUFFER_SIZE) {
        this.flushToServer();
      }
    },
    flushToServer: function () {
      var b = this.buffer,
          params = { pageViewId: pageViewId };
      for (var a in b) {
        params[a] = b[a].join(',');
        b[a] = [];
      }
      this.bufferSize = 0;
      Ajax.apost("Callbacks.php?c=newTracks", params);
    },
    startRecording: function () {
      addEvent(document, "mousemove", function (evt) {
        Mouse.eventHandler(evt, 0, Tracks.recordTrack, Tracks);
      });
      addEvent(document.body, "click", function (evt) {
        Mouse.eventHandler(evt, 1, Tracks.recordTrack, Tracks);
      });
    }
  }

  Ajax.apost("Callbacks.php?c=newPageView", { title: enc(document.title), url: enc(document.location.href) }, function (rt) {
    if (rt) { // record only Nth page view
      pageViewId = rt;
      Tracks.startRecording.call(Tracks);
    }
  });
})());
