/*
 * a - ip : IP of event source.
 * b - pagetimer : Time to finish loading the dom.
 * c - time spent : # of seconds on page.
 * d - domain : 
 * e - new page : First time visitor for the page.
 * f - utc: timestamp of event.
 * g - uid : The chartbeat account.
 * h - host : Hostname of site from location.host.
 * i - title : Page title.
 * j - decay : Time for this event to expire.
 * k - keypress : # of key presses.
 * l - 
 * m - mousemoves : # of mousemove events.
 * n - new : First time visitor for the site.
 * o - 
 * p - path : Path of page from location.pathname.
 * q - conn speed :
 * r - referrer : Referrer from document.referrer.
 * s - scrolls : # of scroll events.
 * t - token : Temporary uuid generated for location.pathname.
 * u - user : Persistent uuid generated for the path /.
 * v - 
 * w - window height : window.innerHeight || document.body.offsetHeight.
 * x - scroll top: window.pageYOffset || document.body.scrollTop ||
 *                 document.documentElement.scrollTop
 * y - scroll height : document.body.scrollHeight.
 * z -
 * R - read :
 * W - write :
 * I - idle :
 *
 */


var SUPERFLY = {
    version: 1,
    ready: false,
    readyList: [],
    query: {},
    interval: 10*1000,
    newToSite: 0,
    newToPage: 0,
    count: 0,
    scrolls: 0,
    keydowns: 0,
    mousemoves: 0,
    pagehash: "",
    domain: "",
    uid: "",
    connSpeed: 0,
    started: 0,
    agg: {
        scrolls: 0,
        keydowns: 0,
        mousemoves: 0
    },
    init: function() {
        this.started = (new Date()).getTime()
        var _slist = document.getElementsByTagName('script')
        var _thisScript = _slist[_slist.length - 1]
        if (_thisScript){
            SUPERFLY.query  = SUPERFLY.parseQueryString(_thisScript.src.split('?')[1])
        }
        if (SUPERFLY.query) {
            SUPERFLY.uid = SUPERFLY.query.uid
            SUPERFLY.domain = SUPERFLY.query.domain || location.host
        } else {
            SUPERFLY.domain = location.host
        }
        this.token = this.uuid()
        SUPERFLY.host = location.host
        SUPERFLY.domain = SUPERFLY.domain.replace(/^www./,'')
        SUPERFLY.host = SUPERFLY.host.replace(/^www./,'')
        SUPERFLY.pathname = location.pathname + location.search
        SUPERFLY.pathname = SUPERFLY.pathname.replace(/PHPSESSID=[^&]+/,'')
        
        SUPERFLY.pagehash = hex_sha1(location.pathname)
        var _sfu = SUPERFLY.readCookie('_sfu')
        if (!_sfu) {
            SUPERFLY.newToSite = 1
            SUPERFLY.createCookie('_sfu', SUPERFLY.uuid(), 365*3)
        }

        var old = (window.onscroll) ? window.onscroll : function () {}
        window.onscroll = function () {old(); SUPERFLY.scrolls++;SUPERFLY.agg.scrolls++}
        var old = (document.body.onkeydown) ? document.body.onkeydown : function () {}
        document.body.onkeydown = function () {old(); SUPERFLY.keydowns++;SUPERFLY.agg.keydowns++}
        var old = (document.body.onmousemove) ? document.body.onmousemove : function () {}
        document.body.onmousemove = function () {old(); SUPERFLY.mousemoves++;SUPERFLY.agg.mousemoves++}
        
        if (typeof(window.addEventListener) != 'undefined') {
            window.addEventListener("load", this.onPageLoad, false);
        } else if (typeof(document.addEventListener) != 'undefined') {
            document.addEventListener("load", this.onPageLoad, false);
        } else if (typeof window.attachEvent != 'undefined') {
            window.attachEvent("onload", this.onPageLoad);
        }
        this.defer(function(){
            SUPERFLY.checkSpeed()
            SUPERFLY.intervalTimer = setInterval(SUPERFLY.checkLog, 10*1000)
            setTimeout(SUPERFLY.createFrame, 200)
            SUPERFLY.timer = setTimeout(SUPERFLY.logAndReschedule, 500)
        })
    },
    parseQueryString: function(queryString) {
        var result = {}
        if (queryString == undefined) {
            queryString = location.search ? location.search : ''
        }
        if (queryString.charAt(0) == '?') queryString = queryString.substring(1)
        queryString = queryString.replace('+', ' ')
        var queryComponents = queryString.split(/[&;]/g)

        for (var i = 0; i < queryComponents.length; i++) {
            var keyValuePair = queryComponents[i].split('=')
            var key = decodeURIComponent(keyValuePair[0])
            var value = decodeURIComponent(keyValuePair[1])
            result[key] = value
        }
        return result
    },
    uuid: function() {
        var result, i, j
        result = ''
        for(j=0; j<16; j++) {
            i = Math.floor(Math.random()*36).toString(36)
            result = result + i
        }
        return result
    },
    createCookie: function(name,value,days,path) {
        if (!path) {
            path = "/"
        }
        if (days) {
            var date = new Date()
            date.setTime(date.getTime()+(days*24*60*60*1000))
            var expires = "; expires="+date.toGMTString()
        }
        else var expires = ""
        document.cookie = name+"="+value+expires+"; path="+path
    },
    readCookie: function(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 null
    },
    checkLog: function() {
        var d = new Date()
        if (SUPERFLY.nextRun - d.getTime() > 10*1000
            && (SUPERFLY.mousemoves || SUPERFLY.keydowns || SUPERFLY.scrolls)) {
            SUPERFLY.interval = 10000
            SUPERFLY.logAndReschedule()
        }
    },
    logAndReschedule: function() {
        clearTimeout(SUPERFLY.timer)
        if (((new Date()).getTime() - SUPERFLY.started) > 60*60*1000) {
            return
        }
        SUPERFLY.interval = SUPERFLY.interval * 2
        if (SUPERFLY.interval > 80000) {
            SUPERFLY.interval = 10000
        }
        SUPERFLY.log()
        SUPERFLY.nextRun = (new Date()).getTime() + SUPERFLY.interval
        SUPERFLY.timer = setTimeout(SUPERFLY.logAndReschedule, SUPERFLY.interval)
    },
    log: function() {
        SUPERFLY.lastRun = (new Date()).getTime()
        var pScroll = [0,0];
        if (typeof(window.pageYOffset) == 'number') {
            //Netscape compliant
            pScroll = [window.pageXOffset, window.pageYOffset];
        } else if (document.body && (document.body.scrollLeft || document.body.scrollTop)) {
            //DOM compliant
            pScroll = [document.body.scrollLeft, document.body.scrollTop];
        } else if (document.documentElement
          && (document.documentElement.scrollLeft || document.documentElement.scrollTop)) {
            //IE6 standards compliant mode
            pScroll = [document.documentElement.scrollLeft,
                       document.documentElement.scrollTop];
        }
        if (pScroll[1] == "undefined") {
            pScroll[1] = 0
        }
        var path = location.pathname
        if (location.search) {
            path += location.search
        }
        var read = write = idle = 0
        if (SUPERFLY.agg.keydowns > 0) {
            write = 1
        } else if (SUPERFLY.agg.mousemoves > 0 || SUPERFLY.agg.scrolls > 0) {
            read = 1
        } else {
            idle = 1
        }
        #var url = (location.protocol || "http:") +
            #"//ec2-75-101-243-167.compute-1.amazonaws.com/ping?h="+encodeURIComponent(SUPERFLY.domain)
        var url = (location.protocol || "http:") +
            "//ping.chartbeat.com/ping?h="+encodeURIComponent(SUPERFLY.domain)
        url += "&p="+encodeURIComponent(path)
        url += "&r="+encodeURIComponent(document.referrer)
        url += "&d="+encodeURIComponent(location.host.replace(/^www./,''))
        url += "&s="+SUPERFLY.agg.scrolls
        url += "&k="+SUPERFLY.agg.keydowns
        url += "&m="+SUPERFLY.agg.mousemoves
        url += "&u="+SUPERFLY.readCookie("_sfu")
        url += "&t="+SUPERFLY.token
        url += "&c="+SUPERFLY.count++
        url += "&x="+pScroll[1]
        url += "&y="+document.body.scrollHeight || 0
        url += "&w="+window.innerHeight || document.body.offsetHeight || 0
        url += "&n="+SUPERFLY.newToSite
        url += "&e="+SUPERFLY.newToPage
        url += "&i="+encodeURIComponent(document.title)
        url += "&g="+SUPERFLY.uid
        url += "&q="+SUPERFLY.connSpeed
        url += "&j="+SUPERFLY.interval/1000
        url += "&R="+read
        url += "&W="+write
        url += "&I="+idle
        url += "&ts="+(new Date()).getTime()
        if (SUPERFLY.pagetimer) {
            url += "&b="+SUPERFLY.pagetimer
        }
        
    	var decr = [-SUPERFLY.scrolls,-SUPERFLY.keydowns,-SUPERFLY.mousemoves]
    	setTimeout(function(){
    	    SUPERFLY.agg.scrolls += decr[0]
    	    SUPERFLY.agg.keydowns += decr[1]
    	    SUPERFLY.agg.mousemoves += decr[2]
    	}, 60*1000);
    	SUPERFLY.scrolls = SUPERFLY.keydowns = SUPERFLY.mousemoves = 0

        var i = new Image(1,1)
        i.src = url
        i.onload = function(){return}

        SUPERFLY.killStatusBar()
    	if (SUPERFLY.count >= 360) {
    	    clearInterval(SUPERFLY.intervalTimer)
    	}
    },
    defer: function(f) {
        if (this.ready) {
            f.apply(document, [SUPERFLY])
        } else {
            this.readyList.push(function(){return f.apply(this, [SUPERFLY])})
        }
    },
    onPageLoad: function() {
        SUPERFLY.ready = true;
        if (typeof(_sf_startpt) == "number") {
            SUPERFLY.pagetimer = (new Date()).getTime() - _sf_startpt
        }
        for (var i = 0; i < SUPERFLY.readyList.length; ++i) {
            SUPERFLY.readyList[i].apply(document, [SUPERFLY])
        }
    },
    checkSpeed: function() {
        SUPERFLY.speedStart = (new Date()).getTime();
        var i = new Image(1,1)
        i.src = "http://static.chartbeat.com/images/speedtest.jpg?"+(new Date()).getTime()
        i.onload = function(){
            var d = new Date()
            var time = Math.round((d.getTime()-SUPERFLY.speedStart)/10)/100
            SUPERFLY.connSpeed = Math.round(20866/time/1000)
        }
    },
    createFrame: function() {
        try {
            var f = document.createElement('<iframe name="superfly"></iframe>')
        } catch(err) {
            var f = document.createElement('iframe')
        }
        try {
            f.id = 'superfly'
            f.name = 'superfly'
            f.src = 'http://static.chartbeat.com/empty.html'
            f.style.visibility = "hidden"
            document.getElementsByTagName('head')[0].appendChild(f)
        } catch(err) {}
    },
    killStatusBar: function() {
        if(navigator.userAgent.indexOf("Firefox")==-1)return
        var imgpath = "static.chartbeat.com/empty.html#"
        src = (("https:" == document.location.protocol) ? "https://s3.amazonaws.com/" : "http://") + imgpath

        var w = document.getElementById("superfly")
        try{
            w.contentWindow.location.href=src
        } catch(c) {}
    }
}
/*
 * A JavaScript implementation of the Secure Hash Algorithm, SHA-1, as defined
 * in FIPS PUB 180-1
 * Version 2.1a Copyright Paul Johnston 2000 - 2002.
 * Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet
 * Distributed under the BSD License
 * See http://pajhome.org.uk/crypt/md5 for details.
 */

/*
 * Configurable variables. You may need to tweak these to be compatible with
 * the server-side, but the defaults work in most cases.
 */
var hexcase = 0;  /* hex output format. 0 - lowercase; 1 - uppercase        */
var b64pad  = ""; /* base-64 pad character. "=" for strict RFC compliance   */
var chrsz   = 8;  /* bits per input character. 8 - ASCII; 16 - Unicode      */

/*
 * These are the functions you'll usually want to call
 * They take string arguments and return either hex or base-64 encoded strings
 */
function hex_sha1(s){return binb2hex(core_sha1(str2binb(s),s.length * chrsz));}
function b64_sha1(s){return binb2b64(core_sha1(str2binb(s),s.length * chrsz));}
function str_sha1(s){return binb2str(core_sha1(str2binb(s),s.length * chrsz));}
function hex_hmac_sha1(key, data){ return binb2hex(core_hmac_sha1(key, data));}
function b64_hmac_sha1(key, data){ return binb2b64(core_hmac_sha1(key, data));}
function str_hmac_sha1(key, data){ return binb2str(core_hmac_sha1(key, data));}

/*
 * Perform a simple self-test to see if the VM is working
 */
function sha1_vm_test()
{
  return hex_sha1("abc") == "a9993e364706816aba3e25717850c26c9cd0d89d";
}

/*
 * Calculate the SHA-1 of an array of big-endian words, and a bit length
 */
function core_sha1(x, len)
{
  /* append padding */
  x[len >> 5] |= 0x80 << (24 - len % 32);
  x[((len + 64 >> 9) << 4) + 15] = len;

  var w = Array(80);
  var a =  1732584193;
  var b = -271733879;
  var c = -1732584194;
  var d =  271733878;
  var e = -1009589776;

  for(var i = 0; i < x.length; i += 16)
  {
    var olda = a;
    var oldb = b;
    var oldc = c;
    var oldd = d;
    var olde = e;

    for(var j = 0; j < 80; j++)
    {
      if(j < 16) w[j] = x[i + j];
      else w[j] = rol(w[j-3] ^ w[j-8] ^ w[j-14] ^ w[j-16], 1);
      var t = safe_add(safe_add(rol(a, 5), sha1_ft(j, b, c, d)),
                       safe_add(safe_add(e, w[j]), sha1_kt(j)));
      e = d;
      d = c;
      c = rol(b, 30);
      b = a;
      a = t;
    }

    a = safe_add(a, olda);
    b = safe_add(b, oldb);
    c = safe_add(c, oldc);
    d = safe_add(d, oldd);
    e = safe_add(e, olde);
  }
  return Array(a, b, c, d, e);

}

/*
 * Perform the appropriate triplet combination function for the current
 * iteration
 */
function sha1_ft(t, b, c, d)
{
  if(t < 20) return (b & c) | ((~b) & d);
  if(t < 40) return b ^ c ^ d;
  if(t < 60) return (b & c) | (b & d) | (c & d);
  return b ^ c ^ d;
}

/*
 * Determine the appropriate additive constant for the current iteration
 */
function sha1_kt(t)
{
  return (t < 20) ?  1518500249 : (t < 40) ?  1859775393 :
         (t < 60) ? -1894007588 : -899497514;
}

/*
 * Calculate the HMAC-SHA1 of a key and some data
 */
function core_hmac_sha1(key, data)
{
  var bkey = str2binb(key);
  if(bkey.length > 16) bkey = core_sha1(bkey, key.length * chrsz);

  var ipad = Array(16), opad = Array(16);
  for(var i = 0; i < 16; i++)
  {
    ipad[i] = bkey[i] ^ 0x36363636;
    opad[i] = bkey[i] ^ 0x5C5C5C5C;
  }

  var hash = core_sha1(ipad.concat(str2binb(data)), 512 + data.length * chrsz);
  return core_sha1(opad.concat(hash), 512 + 160);
}

/*
 * Add integers, wrapping at 2^32. This uses 16-bit operations internally
 * to work around bugs in some JS interpreters.
 */
function safe_add(x, y)
{
  var lsw = (x & 0xFFFF) + (y & 0xFFFF);
  var msw = (x >> 16) + (y >> 16) + (lsw >> 16);
  return (msw << 16) | (lsw & 0xFFFF);
}

/*
 * Bitwise rotate a 32-bit number to the left.
 */
function rol(num, cnt)
{
  return (num << cnt) | (num >>> (32 - cnt));
}

/*
 * Convert an 8-bit or 16-bit string to an array of big-endian words
 * In 8-bit function, characters >255 have their hi-byte silently ignored.
 */
function str2binb(str)
{
  var bin = Array();
  var mask = (1 << chrsz) - 1;
  for(var i = 0; i < str.length * chrsz; i += chrsz)
    bin[i>>5] |= (str.charCodeAt(i / chrsz) & mask) << (32 - chrsz - i%32);
  return bin;
}

/*
 * Convert an array of big-endian words to a string
 */
function binb2str(bin)
{
  var str = "";
  var mask = (1 << chrsz) - 1;
  for(var i = 0; i < bin.length * 32; i += chrsz)
    str += String.fromCharCode((bin[i>>5] >>> (32 - chrsz - i%32)) & mask);
  return str;
}

/*
 * Convert an array of big-endian words to a hex string.
 */
function binb2hex(binarray)
{
  var hex_tab = hexcase ? "0123456789ABCDEF" : "0123456789abcdef";
  var str = "";
  for(var i = 0; i < binarray.length * 4; i++)
  {
    str += hex_tab.charAt((binarray[i>>2] >> ((3 - i%4)*8+4)) & 0xF) +
           hex_tab.charAt((binarray[i>>2] >> ((3 - i%4)*8  )) & 0xF);
  }
  return str;
}

/*
 * Convert an array of big-endian words to a base-64 string
 */
function binb2b64(binarray)
{
  var tab = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
  var str = "";
  for(var i = 0; i < binarray.length * 4; i += 3)
  {
    var triplet = (((binarray[i   >> 2] >> 8 * (3 -  i   %4)) & 0xFF) << 16)
                | (((binarray[i+1 >> 2] >> 8 * (3 - (i+1)%4)) & 0xFF) << 8 )
                |  ((binarray[i+2 >> 2] >> 8 * (3 - (i+2)%4)) & 0xFF);
    for(var j = 0; j < 4; j++)
    {
      if(i * 8 + j * 6 > binarray.length * 32) str += b64pad;
      else str += tab.charAt((triplet >> 6*(3-j)) & 0x3F);
    }
  }
  return str;
}


SUPERFLY.init()
