// ==UserScript== (by Edward Lee)
// @name          Firefox Download Counter
// @namespace     http://ed.agadak.net/
// @description	  Put an animated counter on every page (click to fade, click/drag to move, double click firefox to close)
// ==/UserScript== (edilee gmail)

(function() {
if (top.location != document.location) return;
if (document.contentType != 'text/html') return;
window.addEventListener('load', function() {
if (document.getElementById('ffCounter') != null) return;

var newScript = document.createElement('style');
// no literal strings of html yet.. http://www.mozdev.org/pipermail/greasemonkey/2005-April/001309.html
newScript.innerHTML = '\
div.ffContainer { position: fixed; top: 1px; right: 1px; } \
div#ffCounter { width: 0px; height: 31px; position: relative; top: 0px; left: 0px; -moz-opacity: .1; } \
div#ffCounter div.left { position: absolute; top: 0px; left: 0px; width: 10px; height: 31px; background: url(data:image/gif;base64,R0lGODlhCgAfAMQAAGaZmX+pqZ6/v7PMzMDa2sXd3b7V1dHk5LzNzdfn587d3d7s7NXe3ubu7u/29t7g4P////f39+/v7+bm5v///wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAABQALAAAAAAKAB8AAAWCICUOZDmMg5KsKzUYDiTPZDTfw3Hj0k7HPojCFmwQg0iIMcJsMhUNh3QqRSyoVMGhwe1yA4WFeCwGGFjohPnAbrMBKYV8roAX7vg7nMDv8/d+fXZ5eHB0dAAIDIuMi4mNjYkPk5STAAITmZqZAAATXl0UAAEMEqanop0CcXIiqZ2wIQA7); } \
div#ffCounter div.mid { position: absolute; top: 0px; left: 10px; right: 31px; height: 31px; background: url(data:image/gif;base64,R0lGODlhAQAfAMQAAGaZmbPMzMDa2sXd3dHk5Nfn587d3d7s7NXe3ubu7u/29t7g4P////f39+/v7+bm5v///wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAABAALAAAAAABAB8AAAUWYFAwZEk2ipIcBWEMgjAYCLI8iWMAIQA7); } \
div#ffCounter div.right { position: absolute; top: 0px; right: 0px; width: 31px; height: 31px; background: url(data:image/gif;base64,R0lGODlhHwAfAOYAALOz0lZWY8jI1pOVwERJiwAKSScwXQAWYCk7ZlhojwAlbD9KYAAwdwA9kTFtrwBIjwBDhwA8egAzZgBTmQAhPgBepQ91tDN5pQBwsCJYdwBmmQJFaACBuhGRyqTH1wCSxxin26fP3QCZzAul1xhzjxy66T3J8WPM7DZpd6yztanY5K2/wlyIi2aZmX+pqZ6/v7PMzMDa2sXd3b7V1dHk5LzNzdfn587d3d7s7MzX19Xe3ubu7u/29t7g4ISnpZ+pnkZKQsTGu/3srtzFm8Gznda9nLWqnf/MmZ6QgsVrGd1/JMacdOp6GNCERf+3euRvFt5sFtJxJvmeVeBiDvKAMeWdbK13UvBmE+NkFO90JYpKIfKFQLdrOumKT96UZeRSAedaCOFaCvZpGfBpH+dsJ/+IQd9TCLlZJZpQK7d8Xt5KBtNHB8FNGdqPbJU4EcwzAKpzYb8xB9U7DLKhnG5MRakXAMUgB74WB5IbEEw2Nf////f39+/v78zMzP///wAAACH5BAEAAH4ALAAAAAAfAB8AAAf/gDCCg4SFhod+iTaLjI2OMwAAHpOUISoqgol6m5ybe50ABAoRDxMTFRUWFh0gJSczMH6dm3xLfZwDCqMQEKWnqRYlwiawnZ9eSTl6OwkHCgwMEby+qBatwpizRFBMRQIEzrrQEaQJcz8X1sKuMJx7e15MTFwLBQf34hEJQ0JOKBMd1oEAEcNdkCbymGixZwCBQwRIjjiREgBChREDQXToYMPdnCRMnkyZgiZNFScou5ShIsaKBgwdRozYuJGHJz5IkmBZY4ZMmZ9lpEjJMmaMGBYiZCql+W4PHz5p2MiRU/SK1atFxYAJICKpUqU4ePDY0QNOHJ5mRoJZu/bqFzwa/0Z0/Toixo4dOMquCZN2ZBi2bK+YqYOHxIcPXROvuIsjSBQsI588AUx5cB03dOgAIZH4BQ4cOpZAgTJFiZIwXygDjhPnzZs1boAc/uBi0cHTpaekVs12zWsyToaw4MDhQwsaNIgomaJm9JcwU3ivNRPFiZAgKDQQN35jhugvX6CECUNa+pUpXo4g2TABA3EOLWQcHAk+PBTzY7JksbLhwcv3LcTg2GiofbGcalbpRwUVXGzwEgYQYhDgCnAwodsXU0CxW2D5ZbHgShlUECGELdyQAhdMFEjahldg4SIZMG6xhRQZnDJiCzkYcYaGGD6BxYZq3CHkHXhQQEEeTdSIyriSOBoh1XMZ8ghGkEPekYcEEpBTypKoNMnGGxheCB4Yb9xhx5l25BHNNKZwieMcbIwHXX3gvYGmHXKwIUEDD/hiiikOvFnHGyKJWadrU8lxxRkI8Nnnowv40IIOc+BhxxNpFQheoolaxQYQETTQQAR0cNGFCy30kIKlUKiBBY/gqcGpGmFYhcUZaKARRRZlSOpHDjXMkUYbXhRrrBdtJKtsslU02ywRP7QgrR/SVmvttdhm20IifgQCADs=); } \
div.ffScreen { position: absolute; top: 0px; left: 0px; z-index: 2; width: 100%; height: 100%; } \
div.ffScreen span { position: absolute; top: 0px; left: 0px; width: 100%; height: 100%; -moz-opacity: 0; } \
div#ffNumbers { position: relative; top: 5px; left: 4px; padding-top: 3px; height: 20px; overflow: hidden; z-index: -1; } \
div#ffNumbers img { vertical-align: top; background-repeat: no-repeat; }';
document.getElementsByTagName('head')[0].appendChild(newScript);
var newDiv = document.createElement('div');
newDiv.className = 'ffContainer';
newDiv.innerHTML = '<div id="ffCounter"><div class="ffScreen"><span></span><div id="ffNumbers"></div></div><div class="left"></div><div class="mid"></div><div class="right"></div></div>';
document.body.appendChild(newDiv);

var removed = false;

// click fader, click n drag movement, double click closer
with (document.getElementById('ffCounter')) {
  var unfade = false, fading = false;
  var fadeRate = .1, fadeTime = 20;
  var maxOpacity = 1, minOpacity = .1;

  style.MozOpacity = minOpacity;

  function fade() {
    fading = true;

    function doFade(inc) {
      style.MozOpacity = Math.min(.999, Math.max(0, style.MozOpacity - 0 + inc)); // image flickers when it hits 1, so go to .999
      setTimeout(function() { fade(); }, fadeTime);
    }

    if (unfade == true && style.MozOpacity < Math.min(1, maxOpacity)) {
      doFade(fadeRate);
    } else if (unfade == false && style.MozOpacity > Math.max(0, minOpacity)) {
      doFade(-fadeRate);
    } else {
      fading = false;
    }
  }

  var lastClick = false, movable = false;
  addEventListener('mousedown', function(e) {
    movable = {"x": e.screenX, "y": e.screenY, "startX": style.left, "startY": style.top }; // style is of ffCounter
    if (e.layerX > intVal(style.width) - 31) { // clicked on the firefox part of the image
      var time = new Date().getTime();
      if (lastClick && time - lastClick < 500) {
        style.display = parentNode.style.display = 'none'; // remove container.. and counter? too (not sure why the counter stays)
        removed = true;
//        parentNode.parentNode.removeChild(parentNode); // remove ffCounter's parent ffContainer
      } else {
        lastClick = time;
      }
    }
  }, false);
  window.addEventListener('mouseup', function(e) {
    if (movable.x == e.screenX && movable.y == e.screenY) { // fade toggle if not moved
      unfade = !unfade;
      if (fading == false) { // only fade if not already fading
        fade();
      }
    }
    movable = false;
  }, false);
  window.addEventListener('mousemove', function(e) {
    if (movable != false) {
      with (style) { // this is ffCounter's style
        top = (e.screenY - intVal(movable.y) + intVal(movable.startY)) + 'px';
        left = (e.screenX - intVal(movable.x) + intVal(movable.startX)) + 'px';
      }
    }
  }, false);
//  addEventListener('mouseover', function() { unfade = true; fading || fade(); }, true);
//  addEventListener('mouseout', function() { unfade = false; fading || fade(); }, true);
}

// various images in base64 data uri encoding
var images = {
  'blank': 'data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACH5BAEAAAAALAAAAAABAAEAAAICRAEAOw==',
  'comma': 'data:image/gif;base64,R0lGODlhAwASAKIAAAAIPgAIPQAKRwAKRgAIOx0mXjxEdP///yH5BAEAAAcALAAAAAADABIAAAMOeLrc/pCZcoo4g5xwgEoAOw==',
  '0': 'data:image/gif;base64,R0lGODlhCgAPANUAAAAJRQAJRAAHNQAGLw0WUhMcV0JJeEZNe0dOfFthigAKSQAKRgAJQwAJQAAIPAAIOgAIOAAINwAHMgAHMAAGLAAGKQAGKAAFJQoUUBYfWRskXCIrYSQtYyUuYy83azE5bDQ8bjpCcklQfUtSf1hfiGVrkf///wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAACYALAAAAAAKAA8AAAZLQJNwSCSWEqOiiSQygTTFwxATGCI+Q0Vj6CkMF44hhxh4CA0bIgAiDEGHDIHw8xY2JMJOBs4WEhRDEANfDEMTRQ4RJhMVShQWF0RBADs=',
  '1': 'data:image/gif;base64,R0lGODlhCgAPAMQAAAAJRQAJRAAIPQAHNQ0WUhEaVUZNe1thil9ljQAKSQAKSAAIPAAIOwAIOgAIOAAHNAAHMgAHMAAGKwAFJQAFIwELSgQOTBYfWSQtYyYvZDI6bTtDcz5GdUpRfmNpkP///yH5BAEAAB8ALAAAAAAKAA8AAAUz4CeOZClupnhgpodwSmmI15JmAZQSTfolA18lmCo4Uh2CTwPwXQSpS+BRsgQYkQlFIgoBADs=',
  '2': 'data:image/gif;base64,R0lGODlhCgAPAMQAAAAJRAAIPgAHNgAFJykxZkRLegAKSQAKSAAKRwAJQgAJQQAJPwAIOwAIOQAIOAAINwAHMwAHMAAGKhcgWRkiWxwlXSUuYyw0aC83azhAcUxTf1JZhFNahFVchv///wAAACH5BAEAAB4ALAAAAAAKAA8AAAUzoCeOZMl1Rell4mWQ1jglqng0tRdEuZMDghoFkCPkNLlObkNikDCVw+IBGSEUjohkMAoBADs=',
  '3': 'data:image/gif;base64,R0lGODlhCgAPAMQAAAAJRQAJRAAHNwAHNQ0WUhAZVCcvZSgwZgAKRwAKRgAJQQAJPwAJPgAIOwAHMgAGLAIMSgUPTQgSTxghWhskXB8oXy42ai83azY+cDhAcT5GdUxTf09Wgf///wAAAAAAACH5BAEAAB0ALAAAAAAKAA8AAAUwYCeOZLlxWtlh4gGpIoXAHRHQEW3Ql1XRnUmCVljQEAJa4wFTOEgZESBJkgAYA1IIADs=',
  '4': 'data:image/gif;base64,R0lGODlhCgAPANUAAAAJRAAHNgAGLgAFJwAFJgAEIBAZVEBHd0JJeFxiiwAKSAAKRwAKRgAJQwAJQAAJPwAJPgAHNAAHMgAHMAAGKQAFJQAFIwELSgQOTBkiWy42ajE5bDQ8bk1UgFJZhFhfiFlgiWdtk2pwlW1zl////wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAACQALAAAAAAKAA8AAAY+QJJwSCwOOUahJ5MMbQDGUQdjFIE0D2OCZAgUP0LGhIg4CB0ComYISQsXl4uiERlUjAFKkiQh7AUWexQFQ0EAOw==',
  '5': 'data:image/gif;base64,R0lGODlhCgAPAMQAAAAJRQAJRAAHNREaVRIbVikxZl9ljQAKRgAJQwAJQgAJQQAJQAAJPwAJPgAIOwAIOgAIOAAINwAHNAAHMgELSgIMSgcRTggSTwoUUAsVURwlXS42ajc/cElQff///wAAACH5BAEAAB4ALAAAAAAKAA8AAAUxoCeOI0Z6RldQzMkRSOSe5EaPWnaL1rF7GMVusNhVHrvEZOfYBSQkjggAOV0ADcEpBAA7',
  '6': 'data:image/gif;base64,R0lGODlhCgAPANUAAAAJRQAJRAAIPQAHNgAHNQAGLgAFKAAFJxIbVhMcVykxZkBHd1xii11jiwAKSQAJQQAJQAAJPgAIPAAIOwAIOAAGLAAFJAELSgUPTRQdVxUeWBskXB4nXh8oXzlBcjpCcj9HdklQfU5VgVVchmpwlXB2mf///wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAACYALAAAAAAKAA8AAAZDQJNwSCwKMw7jgmM0jZomUqhZakAZoA0mQBR9EkKIZOjpDCOUoQIxFBCGmqRwUBheuMLCYQh4DCtFEwMmekYVBhZEQQA7',
  '7': 'data:image/gif;base64,R0lGODlhCgAPAMQAAAAJRAAIPgAHNQAFKA4XUxAZVENKeQAKSQAKRwAKRgAJQwAJQgAIOwAIOAAHMwAGLAAGKgQOTAYQTQwWUhwlXR0mXiMsYjA4a1hfiGFnjv///wAAAAAAAAAAAAAAAAAAACH5BAEAABoALAAAAAAKAA8AAAUtoCaO5JhlmFEhwHhZRcI443SMT0kOugj1GgFQEwAShhIgZRgBFhZARQPI6IUAADs=',
  '8': 'data:image/gif;base64,R0lGODlhCgAPANUAAAAJRQAJRAAIPgAIPQAHNgAFJwAFJigwZkBHd0FId0VMegAKSQAKRwAJPgAIPAAIOgAIOQAINwAHMQAHMAAGLQAGLAAGKgAGKQAFJAAFIwMNSxYfWR8oXyEqYTQ8bjU9bzc/cDhAcUlQfUpRflBXglFYg1deh1ZdhlhfiGFnjmJoj////wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAACsALAAAAAAKAA8AAAZIwJVwSCyiEIfiSqUQBoip07BBNImGEOIoJIwoDxqqkrMYKEErhqNI8ggfkmEpMSRQhp/OcHIZbhZDFgZDAAJCFRhFEhYFGURBADs=',
  '9': 'data:image/gif;base64,R0lGODlhCgAPANUAAAAJRQAJRAAIPgAIPQAHNgAHNQAGLwAFKAAEIA0WUigwZlxii2BmjgAKRwAJQwAJQgAJQQAJPwAIPAAHNAAHMwAHMAAGKwAGKQAFIwcRTgsVURkiWxwlXSIrYTc/cDhAcT9HdkxTf05VgVJZhFVchmdtk////wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAACYALAAAAAAKAA8AAAZEQJNwSCSWFqGiiTEyeThF0jABGJJEwwxkCPoMG5KhojN8EIabzXBQGWoSQsfkQmwEIoWDUnhB7A0YeyYWewIUSg1bSkEAOw=='
};

// set up the initial value of the counter
var lastValueRev; // reversed last value
function prepCounter(num) {
  if (lastValueRev != undefined) { // only prep once
    return;
  }

  lastValueRev = reverseNum(num);
  var len = getCommaSize(num);
  updateWidth(len);
  with (document.getElementById('ffNumbers')) {
    for (var i = 0, j = 0; i < len; i++) {
      var img = document.createElement('img');
      if (isCommaSpot(len - i)) { // it's a comma
        img.src = images['comma'];
        img.className = 'comma'
        img.style.position = 'relative';
        img.style.left = '-1px';
      } else {
        img.id = 'ffNumber' + (num.length - j - 1);
        img.src = images[num[j]];
        j++;
      }
      appendChild(img);
    }
  }
}

// update the counter
var updateTime = 100;
function updateCounter(num) {
  var len = num.length, lenC = getCommaSize(num);
  var len2 = lastValueRev.length, lenC2 = getCommaSize(lastValueRev);
  var reverse = reverseNum(num);

  if (len < len2) { // need to shrink
    for (var i = lenC2, ii = len2; i > lenC; i--) {
      var img, j, k;
      if (isCommaSpot(i)) {
        img = null;
      } else {
        img = document.getElementById('ffNumber' + (ii - 1));
        ii--;
      }

      for (var j = 0; j > -1; j -= 1/20) {
        var k = i + j;
        setTimeout((function(j, k, img) { return function() {
          updateWidth(k);

          if (img != null) {
            var scaling = Math.max(0, 1 + j - 1/20);
            img.style.MozOpacity = scaling;
            img.style.width = Math.round(scaling * 10) + 'px';
            with (img.nextSibling) {
              if (className == 'comma') { // it's a comma
                style.MozOpacity = scaling;
              img.style.width = Math.round(scaling * 3) + 'px';
              }
            }
          }
        }; }) (j, k, img), (lenC2 - k) * updateTime);
      }
      setTimeout((function(img) { return function() {
        if (img != null) {
          img.src = images['blank'];
          img.style.backgroundImage = 'url(' + images['blank'] + ')';
          img.style.display = 'none';
          with (img.nextSibling) {
            if (className == 'comma') { // it's a comma
              style.display = 'none';
            }
          }
        }
      }; }) (img), (lenC2 - i - j) * updateTime);
    }
  } else if (len > len2) { // need to grow
    for (var i = lenC2, ii = len2; i < lenC; i++) {
      var img, j, k;
      if (isCommaSpot(i)) {
        img = null;
      } else {
        img = document.getElementById('ffNumber' + (ii - 0));
        if (img == null) { // need to make a new image
          if (isCommaSpot(i+1)) { // new comma too
            img = document.createElement('img');
            img.className = 'comma';
            img.src = images['comma'];
            img.style.width = '0px';
            img.style.position = 'relative';
            img.style.left = '-1px';
            img.style.display = 'none';
            img.style.MozOpacity = 0;
            with (document.getElementById('ffNumbers')) {
              insertBefore(img, firstChild);
            }
          }
          img = document.createElement('img');
          img.id = 'ffNumber' + (ii - 0);
          img.src = images['blank'];
          img.style.width = '0px';
          img.style.display = 'none';
          img.style.MozOpacity = 0;
          with (document.getElementById('ffNumbers')) {
            insertBefore(img, firstChild);
          }
        }
        ii++;
      }

      setTimeout((function(img) { return function() {
        if (img != null) {
          img.style.display = '';
          with (img.nextSibling) {
            if (className == 'comma') { // it's a comma
              style.display = '';
            }
          }
        }
      }; }) (img), (i - lenC2) * updateTime);

      for (var j = 0; j < 1; j += 1/20) {
        var k = i + j;
        setTimeout((function(j, k, img) { return function() {
          updateWidth(k);

          if (img != null) {
            var scaling = Math.min(1, j + 1/20);
            img.style.MozOpacity = scaling;
            img.style.width = Math.round(scaling * 10) + 'px';
            with (img.nextSibling) {
              if (className == 'comma') { // it's a comma
                style.MozOpacity = scaling;
                style.width = Math.round(scaling * 3) + 'px';
              }
            }
          }
        }; }) (j, k, img), (k - lenC2) * updateTime);
      }
    }
  }

  // update the digits after the space has been prepared
  for (var i = 0; i < len; i++) {
    if (reverse[i] != lastValueRev[i]) {
      setTimeout((function(i) { return function() {
        shiftDigit('ffNumber' + i, reverse[i]);
      }; }) (i), i * updateTime);
    }
  }

  lastValueRev = reverse;
}

function updateWidth(lengthWithComma) {
  document.getElementById('ffCounter').style.width = Math.round(10 + lengthWithComma * 8.234 + 31) + 'px'; // scale the size of the "background" image plus partial comma
}

function getCommaSize(num) {
  return num.length + Math.floor((num.length - 1) / 3);
}

function isCommaSpot(num) {
 return num % 4 == 0;
}

// digit shifting
var shiftRate = 1, shiftTime = 15, shiftAmount = 20; // 15 * 20 = 300 ms to update
function shiftDigit(id, num) {
  with (document.getElementById(id)) {
    style.backgroundImage = 'url(' + images[num] + ')'; // insert the new number
    style.backgroundPosition = '0px ' + shiftAmount + 'px';
    var i;
    for (i = 0; i <= shiftAmount; i += shiftRate) {
      setTimeout((function(i) { return function() {
        style.backgroundPosition = '0px ' + Math.min(0, -shiftAmount + 1 + i) + 'px';
        style.paddingTop = Math.min(shiftAmount, i) + 'px';
      }; }) (i), i * shiftTime);
    }
    setTimeout(function() {
      src = images[num]; // make the new number the actual image
      style.paddingTop = '0px'; // shift it back to the original position
    }, i * shiftTime);
  }
}


// test cases

//prepCounter('50000000');

/*// shift it! with different sizes.. choppyish...
prepCounter('0');
setTimeout(function() { updateCounter('50123456'); }, 1000);
setTimeout(function() { updateCounter('546'); }, 2500);
setTimeout(function() { updateCounter('56105987'); }, 5000);
*/

/*// really really realllyy long number :o
prepCounter('12345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890');
*/

/*// watch all 100 digits shift down! wheeee ;)
prepCounter('1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890');
for (var i = 0; i < 100; i++) {
  setTimeout((function(i) { return function() { shiftDigit('ffNumber' + i, i % 10); }; }) (i), 100*i);
}
*/

// utility stuff

function intVal(str) {
  str = '' + str;
  if (str == '') return 0;
  return str.match(/-?\d+/) - 0;
}

function reverseNum(num) {
  return num.split('').reverse().join('');
}

function debug(out) {
  with(document) {
    body.appendChild(createTextNode(out));
    body.appendChild(createElement('br'));
  }
}

/*  Slightly modified by Ed ;)
 *  ffcounter.js - A simple "odometer-style" counter for Firefox downloads.
 *
 *  History:
 *      v0.1 - Initial version. Untested in IE. Inefficient handling of updates.
 *
 *  Copyright 2005 Infocraft
 *  http://www.infocraft.com/
 *
 *  The latest version of this script can be found at:
 *  http://www.infocraft.com/projects/ffcounter/ffcounter.js
 *
 *  You may use this script in its entirety, modify it to suit your needs,
 *  adapt its functions, or just use it for inspiration.  However, some form
 *  of acknowledgement, especially a link back to http://www.infocraft.com/, is
 *  always appreciated.
 */

/***************************  Adjustable Parameters ***************************/

var counter_url = "http://feeds.spreadfirefox.com/downloads/firefox.xml";  // The URL to your counter mirror.
var counter_id = "ffcounter";  // The id of the counter in your HTML.
var update_interval = 315;  // The interval, in ms, to update the counter.
var resync_interval = 60000;  // The interval, in ms, to resync with the feed.

/***************************     Static Globals     ***************************/

var current_count = null;
var initial_count = null;
var initial_time = null;
var download_rate = null;
var request = null;
var counter_on = false;

/***************************    Public Functions    ***************************/

// This should be called from your HTML, probably as an onload="get_count();"
// event in your <body> tag.
function get_count()
{
  var delay = (!initial_time || !initial_count) ? 10000 : resync_interval;

  load_xml(counter_url);
// EDited to be a recursive call
  if (!removed) {
    setTimeout(function() { get_count(); }, delay);
  }
}

/***************************    Private Functions   ***************************/


// Adapted from the good people at ADC:
// http://developer.apple.com/internet/webcontent/xmlhttpreq.html
// this starts loading the XML data and sets up the process_request handler.
function load_xml(url) 
{

/*// EDited: use greasemonkey instead
  // branch for native XMLHttpRequest object
  if (window.XMLHttpRequest) {
    request = new XMLHttpRequest();
    request.onreadystatechange = process_request;
    request.open("GET", url, true);
    request.send(null);

  // branch for IE/Windows ActiveX version
  } else if (window.ActiveXObject) {
    request = new ActiveXObject("Microsoft.XMLHTTP");
    if (request) {
      request.onreadystatechange = process_request;
      request.open("GET", url, true);
      request.send();
    }
  }
*/

  GM_xmlhttpRequest({
    method: "GET",
    url: url,
    onload: function(details) { // just grab it when it finishes instead of readystate
      request = details;
      request.responseXML = (new DOMParser()).parseFromString(details.responseText, 'text/xml'); // greasemonkey doesn't provide responseXML
      process_request();
    }
  });
}

// This function is called once the request state changes.  It pulls the
// relevant data from the response and sends to update_count().
function process_request()
{
  var response;
  var time;
  var count_item;
  var count;

  if (request.readyState == 4 && request.status == 200) {
    response = request.responseXML;
    time = response.getElementsByTagName('pubDate')[0].firstChild.data;
    count_item = response.getElementsByTagName('item')[0];
    count = count_item.getElementsByTagName('description')[0].firstChild.data;
    update_count(time, count);
  }
}

// Now that the data from the XML request has been extracted, this updates the
// global variables with that data.
function update_count(time, count)
{

  if (!initial_count) {
    initial_time = new Date(time);
    initial_count = count.replace(/\D/g,'');
  } else {
    var last_time = new Date(time);
    var last_count = count.replace(/\D/g,'');
    download_rate = calculate_rate(last_time, last_count);
  }

  current_count = parseFloat(count.replace(/\D/g,''));
  if (!counter_on) {
    counter_on = true;
    update_counter();
  }
}

// Sticks the current download value into the DOM, and calls itself every
// update interval to increment the counter.
function update_counter()
{
// EDited: make counter calls instead of updating a html element
//  var counter = document.getElementById(counter_id);

  if (download_rate) {
    current_count = current_count + download_rate;
    updateCounter(format_count(current_count));
  } else {
    prepCounter(format_count(current_count));
    download_rate = (3 + Math.random()) / 4; // just to get the counter moving, but this is pretty conservative
  }

//  counter.firstChild.data = format_count(current_count);

  if (!removed) {
    setTimeout(function() { update_counter(); }, update_interval);
  }
}

/***************************    Utility Functions   ***************************/

// Calculates the number of downloads per update interval.
function calculate_rate(last_time, last_count)
{
  var time_delta = (last_time - initial_time) / update_interval;
  var count_delta = (last_count - initial_count);

  return count_delta / time_delta;
}

// Round off the current count and stick in commas where appropriate.
function format_count(count)
{
  count = Math.round(count).toString();

// EDited: don't need commas.. just a string of numbers
//  for (var i = count.length - 3; i > 0 ; i -= 3) {
//    count = count.slice(0, i) + ',' + count.slice(i, count.length);
//  }

  return count;
}

get_count();

}, false);
}) ();
