// JavaScript for micropledge.com

function applyClassCode(obj) {
  /* Loop through elements on the page and turn them into useful members of our UI */
  if (!obj) {
    obj = document;
  }
  var elems = obj.getElementsByTagName('*');
  var i;
  for (i=0; i<elems.length; i++) {
    classCode(elems[i]);
  }
}

function classCode(obj) {
  /* Apply behaviour to an object based on its class, ID, and other attributes. */
  var inputs;
  var j;
  var btn;
  switch (obj.tagName.toLowerCase()) {
    case 'form':
      addEvent(obj, 'submit', clearEmptyInputs);
      if (hasClass(obj, 'disabled')) {
        inputs = obj.getElementsByTagName('input');
        for (j=0; j<inputs.length; j++) {
          inputs[j].disabled = true;
        }
        inputs = obj.getElementsByTagName('select');
        for (j=0; j<inputs.length; j++) {
          inputs[j].disabled = true;
        }
        inputs = obj.getElementsByTagName('textarea');
        for (j=0; j<inputs.length; j++) {
          inputs[j].disabled = true;
        }
      }
      break;
    case 'textarea':
      if (obj.getAttribute('maxlength')) {
        addEvent(obj, 'keypress', charsLeft);
        addEvent(obj, 'keyup', charsLeft);
        addEvent(obj, 'change', charsLeft);
        addEvent(obj, 'mousedown', charsLeft);
      }
      break;
    case 'input':
      if (obj.getAttribute('automoney')) {
        autoMoney(obj);
        addEvent(obj, 'keyup', autoMoney);
        addEvent(obj, 'change', autoMoney);
      }
      break;
    case 'a':
      if (hasClass(obj, 'new-window')) {
        obj.target = '_blank';
        if (! obj.getAttribute('title')) {
          obj.title = 'New window will open';
        }
      }
      if (hasClass(obj, 'munged-email')) {
        addEvent(obj, 'mouseover', unmungeEmail);
      }
      if (hasClass(obj, 'addtag')) {
        addEvent(obj, 'click', addTag);
      }
      if (hasClass(obj, 'submit')) {
        obj.href = '#submit-link';
        addEvent(obj, 'click', submitLink);
      }
      break;
  }
  if (obj.getAttribute('changeappear')) {
    addEvent(obj, 'change', changeAppear);
    changeAppear(obj);
  }
  if (obj.getAttribute('autoupdate')) {
    autoUpdate(obj);
    if (obj.tagName.toLowerCase() == 'input') {
      addEvent(obj, 'keyup', autoUpdate);
      addEvent(obj, 'change', autoUpdate);
    }
    else if (obj.tagName.toLowerCase() == 'select') {
      addEvent(obj, 'change', autoUpdate);
    }
  }
  if (obj.getAttribute('tooltip')) {
    addEvent(obj, 'mouseover', popupTooltip);
  }
  if (obj.getAttribute('eg')) {
    addEvent(obj, 'focus', removeEg);
    addEvent(obj, 'blur', addEg);
    addEg(obj);
  }
  if (obj.getAttribute('rollover')) {
    addEvent(obj, 'mouseover', rollover);
    addEvent(obj, 'mouseout', rollout);
  }
  if (hasClass(obj, 'focus')) {
    obj.focus();
    if (obj.getAttribute('eg')) {
      addEg(obj); // Because obj.focus would've removed the Eg.
      obj.select();
    }
  }
  if (hasClass(obj, 'flash')) {
    flashDiv(obj.id, 0);
  }
  if (hasClass(obj, 'toggle')) {
    obj.href = '#toggle-link';
    addEvent(obj, 'click', toggle);
  }
  if (hasClass(obj, 'slider-bar')) {
    btn = getElementsByClassName('slider-button', obj)[0];
    btn.slider = obj;
    addEvent(btn, 'mousedown', startSlider);
  }
}

/*
 * Nasty complicated Event-handling indirections to
 * make sure IE works the same as Fx
 */

function addGlobalEvent(obj, eventName, func) {
  // This has to be first, because Opera has both but only attachEvent works how we want.
  if (obj.attachEvent) {
    obj.attachEvent("on" + eventName, func);
  } else if (obj.addEventListener) {
    obj.addEventListener(eventName, func, true);
  }
}

function removeGlobalEvent(obj, eventName, func) {
  if (document.attachEvent) { // See above
    obj.detachEvent("on" + eventName, func);
  } else if (document.addEventListener) {
    obj.removeEventListener(eventName, func, true);
  }
}

function eventTarget(e) {
  var obj;
  if (document.attachEvent) { // See above
    obj = e.srcElement;
  } else if (document.addEventListener) {
    obj = e.target;
  }
  return obj;
}

function addEvent(obj, eventName, func) {
  addGlobalEvent(obj, eventName, eventHandler);
  if (!obj.eventFunctions) {
    obj.eventFunctions = {};
  }
  obj.eventFunctions[eventName] = func;
}

function removeEvent(obj, eventName, func) {
  removeGlobalEvent(obj, eventName, eventHandler);
  obj.eventFunctions[eventName] = null;
}

function eventHandler(e) {
  var obj = eventTarget(e);
  var eventName = e.type;
  if (!obj.eventFunctions || !obj.eventFunctions[eventName]) {
    return false;
  }
  return obj.eventFunctions[eventName](obj, e);
}


/*
 * Class-name utility functions
 */

function getClasses(obj) {
  return obj.className.split(' ');
}

function hasClass(obj, cName) {
  /* Thanks to Fred Bird from http://fredbird.org */
  return new RegExp('\\b'+cName+'\\b').test(obj.className);
}

function removeClass(obj, cName) {
  /* Thanks to Fred Bird from http://fredbird.org */
  if (!hasClass(obj, cName)) {
    return false;
  }
  var rep = obj.className.match(' '+cName) ? ' '+cName : cName;
  obj.className = obj.className.replace(rep, '');
  return true;
}

function addClass(obj, cName) {
  /* Thanks to Fred Bird from http://fredbird.org */
  if (!hasClass(obj,cName)) {
    obj.className += obj.className ? ' '+cName : cName;
  }
  return true;
}

function getElementsByClassName(className, container, tag) {
  /* Thanks to Fred Bird from http://fredbird.org */
  // default container to document
  container = container || document;
  // default tag to *
  tag = tag || '*';
  // listing container descendants
  var all = container.all || container.getElementsByTagName(tag);
  var found = [];
  // searching for targets
  var f;
  for (f=0; f<all.length; f++) {
    var el = all[f];
    if (hasClass(all[f], className)) {
      found.push(all[f]);
    }
  }
  return found;
}

function computedStyle(obj) {
  if (window.getComputedStyle) {
    return window.getComputedStyle(obj, null);
  }
  else {
    return obj.currentStyle;
  }
}

function contains(node, descendant) {
  var ret;
  try {
    if (!descendant) {
      ret = false;
    } else if (node.contains) {
      ret = node.contains(descendant);
    } else if (descendant == document.body) {
      ret = false;
    } else if (descendant.parentNode == node) {
      ret = true;
    } else {
      ret = contains(node, descendant.parentNode);
    }
  } catch (err) {
    ret = false;
  }
  return ret;
}

function ancestor(node, target) {           // find ancestor with tagName target
  if (node.parentNode.tagName.toLowerCase() == target) {
    return node.parentNode;
  }
  if (node.parentNode == document.body) {
    return null;
  }
  return ancestor(node.parentNode, target); // recurse
}


/*
 * AJAX
 */

var ajaxTimeout = null;

function ajax(url, data, handler) {
  var req = false;

  if (window.XMLHttpRequest) {  // Firefox, Safari, Opera
    req = new XMLHttpRequest();
  } else if (window.ActiveXObject) {  // Internet Explorer
    try {
      req = new ActiveXObject("Msxml2.XMLHTTP");
    } catch (err1) {
      try {
        req = new ActiveXObject("Microsoft.XMLHTTP");
      } catch (err2) {
      }
    }
  }
  if (!req) {
    alert('Browser does not support Ajax!');
    return false;
  }

  req.onreadystatechange = function() { handler(req); };
  if (data) {
    req.open('POST', url, true);
    var datas = [];
    var i = 0;
    var idx;
    for (idx in data) {
      datas[i] = escape(idx) + '=' + escape(data[idx]);
      i++;
    }
    data = datas.join('&');
    req.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
    req.send(data);
  }
  else {
    req.open('GET', url, true);
    req.send(null);
  }
  ajaxTimeout = setTimeout(function() { timeoutHandler(req); }, 7000);
  return req;
}

/*
 * Ajax voting n stuff
 */

function ajaxData(doc) {
  var dict;
  eval("dict = " + doc);
  return dict;
}

function progressRequest(url, amount) {
  var formKey = document.getElementById('progress').getAttribute('formkey');
  var data = {'ajax' : 'true', 'formKey' : formKey, 'amount' : amount};
  if (ajax(url, data, progressHandler)) {
    // Ajax worked, don't post form
    return false;
  }
  else {
    // Ajax doesn't work, post normally
    return true;
  }
}

function progressHandler(req) {
  if (req.readyState == 4) {
    clearTimeout(ajaxTimeout);
    ajaxTimeout = null;
    var data;
    var stat;

    try {
      // Fx throws an exception when you access req.status for certain errors
      stat = req.status;
    } catch (err1) {
      stat = 500;
    }

    if (stat == 200 || stat == 403) {
      try {
        data = ajaxData(req.responseText);
      } catch (err2) {
        // crazy data, or possibly a formKey error
        stat = 777;
      }
    }

    var progress = document.getElementById('progress-bar');
    var slider = getElementsByClassName('slider-bar', progress)[0];
    var inf = document.getElementById(slider.getAttribute('info'));
    removeClass(slider, 'slider-bar-waiting');

    if (stat == 200) {
      inf.innerHTML = slider.getAttribute('altinfo');
      var t1 = document.getElementById('active-right-tooltip');
      var t2 = document.getElementById('active-right-tooltip2');
      if (t2) {
        t1.innerHTML = t2.innerHTML;
      }
      var span = document.getElementById('slider-percent-update');
      if (span) {
        span.firstChild.nodeValue = (data.amount*100).toFixed(0) + '%';
      }
    }
    else if (stat == 403) {
      data = ajaxData(req.responseText);
      inf.innerHTML = '<span class="alert">' + data.error + '</span>';
    }
    else if (stat == 777) {
      var formKey = document.getElementById('progress').getAttribute('formkey');
      data = {'formKey' : formKey, 'response' : escape(req.responseText)};
      ajax(root + 'ajaxerror', data, function(req) {return;});
      inf.innerHTML = '<span class="alert">error interpreting response!</span>';
    }
    else {
      inf.innerHTML = '<span class="alert">error talking to server!</span>';
    }
  }
}

function timeoutHandler(req) {
  req.abort();
  var progress = document.getElementById('progress-bar');
  var slider = getElementsByClassName('slider-bar', progress)[0];
  var inf = document.getElementById(slider.getAttribute('info'));
  removeClass(slider, 'slider-bar-waiting');
  inf.innerHTML = '<span class="alert">timeout talking to server!</span>';
}


/*
 * Slider UI code
 */

var currentSliderPercentage = null;
var currentSliderButton = null;
var currentClickX = null;
var currentSliderPos = null;

function startSlider(btn, e) {
  var slider = btn.slider;
  if (hasClass(slider, 'slider-bar-waiting') || hasClass(slider, 'slider-bar-disabled')) {
    return false;
  }
  currentSliderButton = btn;
  currentClickX = e.clientX;
  currentSliderPercentage = sliderPercentage(slider);
  currentSliderPos = btn.offsetLeft - parseInt(computedStyle(btn).marginLeft, 10);
  addGlobalEvent(document, 'mousemove', moveSlider);
  addGlobalEvent(document, 'mouseup', stopSlider);
  return true;
}

function stopSlider(e) {
  var btn = currentSliderButton;
  var slider = btn.slider;
  if (sliderPercentage(slider) != currentSliderPercentage || slider.getAttribute('allowEqual')) {
    // If they haven't simply moved the slider
    // back to its original position
    var inf = document.getElementById(slider.getAttribute('info'));
    inf.innerHTML = slider.getAttribute('tempinfo');
    eval(slider.getAttribute('function') + "('" + slider.getAttribute('url') + "', " + sliderPercentage(slider)/100 + ");");
    addClass(slider, 'slider-bar-waiting');
  }
  removeGlobalEvent(document, 'mousemove', moveSlider);
  removeGlobalEvent(document, 'mouseup', stopSlider);
}

function value2pos(value) {
  var hundredPos = 0.85;
  var maxval = 2;
  if (value > 1) {
    return hundredPos + (value - 1) * ((maxval - 1) * (1 - hundredPos));
  } else {
    return value * hundredPos;
  }
}

function pos2value(pos) {
  var hundredPos = 0.85;
  var maxval = 2;
  if (pos > hundredPos) {
    return 1 + ((pos - hundredPos) / (1 - hundredPos)) * (maxval - 1);
  } else {
    return pos / hundredPos;
  }
}

function sliderPercentage(slider) {
  var btn = getElementsByClassName('slider-button', slider)[0];
  var max = slider.offsetWidth;
  var btnLeft = btn.offsetLeft - parseInt(computedStyle(btn).marginLeft, 10);
  var end = value2pos(parseFloat(slider.getAttribute('end')));
  var begin = value2pos(parseFloat(slider.getAttribute('begin')));
  var range = end - begin;
  var pos = (begin + (btnLeft / max) * range);
  return Math.round(pos2value(pos) * 100);
}

function moveSlider(e) {
  var btn = currentSliderButton;
  var slider = btn.slider;
  var slidervalue = getElementsByClassName('slider-value', slider)[0];

  var min = 0;
  var max = slider.offsetWidth;
  var pos = currentSliderPos + (e.clientX - currentClickX);
  pos = Math.max(Math.min(pos, max), min);

  btn.style.left = pos + 'px';
  slidervalue.style.left = pos + 'px';

  slidervalue.firstChild.nodeValue = sliderPercentage(slider) + '%';
}

function positionSliderInfo(slider) {
  var inf = document.getElementById(slider.getAttribute('info'));
  var btn = getElementsByClassName('slider-button', slider)[0];
  var btnPos = btn.offsetLeft - parseInt(computedStyle(btn).marginLeft, 10);

  var infwidth = inf.offsetWidth;
  var left = parseInt(slider.offsetLeft, 10) + btnPos - (infwidth * btnPos / slider.offsetWidth);
  inf.style.left = left + 'px';
}



/*
 * Miscellaneous functions
 */

var currentTooltip = null;
var currentKeepVisible = null;

function popupTooltip(obj) {
  var tooltip = document.getElementById(obj.getAttribute('tooltip'));
  currentTooltip = tooltip;
  var keepvisible;
  var vId = tooltip.getAttribute('keepvisible');
  if (!vId) {
    keepvisible = obj;
  } else {
    keepvisible = document.getElementById(vId);
  }
  currentKeepVisible = keepvisible;
  addGlobalEvent(keepvisible, 'mouseout', hideTooltip);
  tooltip.style.display = 'block';
}

function hideTooltip(e) {
  var relatedTarget;
  if (e.relatedTarget) {
    relatedTarget = e.relatedTarget;
  } else if (e.toElement) {
    relatedTarget = e.toElement;
  }
  if (contains(currentKeepVisible, relatedTarget)) {
    return false;
  }
  if (relatedTarget == currentKeepVisible) {
    return false;
  }
  if (currentTooltip) {
    currentTooltip.style.display = 'none';
    removeGlobalEvent(currentKeepVisible, 'mouseout', hideTooltip);
  }
  currentTooltip = null;
  currentKeepVisible = null;
  return true;
}

var preloadedImages = {};

function preload(filename) {
  preloadedImages[filename] = new Image();
  preloadedImages[filename].src = filename;
}

function clearEmptyInputs(form) {
  /* Empty out all elements that have example text in them */
  var elems = form.getElementsByTagName('*');
  var i;
  for (i=0; i<elems.length; i++) {
    if (hasClass(elems[i], 'empty') && elems[i].getAttribute('eg')) {
      elems[i].value = '';
      removeClass(elems[i], 'empty');
    }
  }
}

function makeSlug(text) {
  var filter = 'abcdefghijklmnopqrstuvwxyz0123456789';
  var hyphens = ' .-';

  var slug = '';
  var c;
  var i;
  for (i=0; i<text.length; i++) {
    c = text.charAt(i).toLowerCase();
    if (filter.indexOf(c) >= 0) {
      slug += c;
    }
    if (hyphens.indexOf(c) >= 0) {
      slug += '-';
    }
  }
  return slug.substr(0, 50);
}

var months = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"];

function finishDate(span) {
  var time = parseFloat(document.getElementById(span.getAttribute('time')).value);
  var unit = document.getElementById(span.getAttribute('unit')).value;
  var begin = parseFloat(span.getAttribute('begin'));

  if (isNaN(time)) {
    return '';
  }

  var d = new Date();
  if (unit == 'days') {
    d.setDate(d.getDate() + time);
  }
  else if (unit == 'weeks') {
    d.setDate(d.getDate() + time*7);
  }
  else if (unit == 'months') {
    d.setMonth(d.getMonth() + time);
  }
  d.setDate(d.getDate() + begin);

  return "(meaning you will be finished " + d.getDate() + ' ' + months[d.getMonth()] + ', ' + d.getFullYear() + ")";
}

function autoUpdate(input) {
  var updateElem = document.getElementById(input.getAttribute('autoupdate'));
  var defaultVal = updateElem.getAttribute('autodefault');

  if (input.value === '') {
    updateElem.firstChild.nodeValue = defaultVal;
  }
  else {
    var newstring = eval(updateElem.getAttribute('updatefunc') + '(updateElem);');
    updateElem.firstChild.nodeValue = newstring;
  }
}

function autoUrl(span) {
  var val = document.getElementById(span.getAttribute('autoinput')).value;
  var prefix = span.getAttribute('urlprefix');
  return prefix + makeSlug(val);
}

function roundToCents(amount) {
  return Math.round(amount * 100) / 100;
}

function paypalFee(amount, rate, flatFee) {
  /* Return fee PayPal will charge on total amount + fee */
  amount = roundToCents(amount);
  var inclusive = (amount + flatFee) / (1.0 - rate);
  var fee = inclusive - amount;
  return fee;
}

function masspayFee(amount, rate, cap) {
  /* Return fee PayPal will charge for MassPay of amount (including fee) */
  amount = roundToCents(amount);
  var total = amount / (1.0 - rate);
  total = roundToCents(total);
  var fee = total - amount;
  if (fee > cap) {
    fee = cap;
  }
  return fee;
}

function autoMoney(input) {
  var fee;
  var buttonId = input.getAttribute('automoney');
  var prefix = input.getAttribute('moneyprefix');
  var defaultVal = input.getAttribute('autodefault');
  var fees = input.getAttribute('fees');
  var rate = parseFloat(input.getAttribute('rate'));
  var flat = parseFloat(input.getAttribute('flat'));
  var minimum = parseFloat(input.getAttribute('minimum'));
  var maximum = parseFloat(input.getAttribute('maximum'));

  var button = document.getElementById(buttonId);
  var eg = input.getAttribute('eg');
  if (input.value === '' || (eg && eg == input.value)) {
    button.value = defaultVal;
  }
  else {
    var amount = parseFloat(input.value);
    if (isNaN(amount) || amount < minimum) {
      amount = minimum;
    }
    if (amount > maximum) {
      amount = maximum;
    }
    if (fees == 'paypal') {
      fee = paypalFee(amount, rate, flat);
      button.value = prefix + amount.toFixed(2) + ' + $' + fee.toFixed(2) + ' PayPal fee';
    }
    else if (fees == 'masspay') {
      fee = masspayFee(amount, rate, flat);
      button.value = prefix + amount.toFixed(2) + ' (PayPal fee: $' + fee.toFixed(2) + ')';
    }
    else {
      button.value = prefix + amount.toFixed(2);
    }
  }
}

function removeEg(input) {
  if (hasClass(input, 'empty')) {
    if (hasClass(input, 'focus')) {         // Fix for IE to make sure the eg text doesn't go away the first time.
      removeClass(input, 'focus');          // Remove the 'focus' class, so we don't ever try to focus it again.
      addEvent(input, 'keydown', removeEg); // Make sure the text is not marked as 'empty' when they start typing
    } else {
      input.value = '';
    }
    removeClass(input, 'empty');
  }
}

function addEg(input) {
  if ((input.value == input.getAttribute('eg')) || (input.value === '')) {
    addClass(input, 'empty');
    input.value = input.getAttribute('eg');
  }
}

function flashDiv(id, state) {
  var div = document.getElementById(id);
  if (state == 6) {
    return;
  }
  if (state%2 === 0) {
    removeClass(div, 'flash-off');
    removeClass(div, 'flash');
    addClass(div, 'flash');
  } else {
    removeClass(div, 'flash');
    addClass(div, 'flash-off');
  }
  state += 1;
  var code = 'flashDiv("' + id + '", ' + state + ');';
  setTimeout(code, 250);
}

function unmungeEmail(anchor) {
  if (anchor.href.indexOf('mailto:') >= 0) {
    return;
  }
  var text = anchor.firstChild.nodeValue;
  var titleWords = anchor.title.split(' ');
  var email = titleWords[titleWords.length-1];
  if (text.indexOf('@') >= 0) {
    email = text.replace(/\.\.\./, email);
  } else {
    email = email.replace(/\[aht\]/, '@');
  }
  anchor.href = 'mailto:' + email;
  anchor.title = 'Click to email';
  // I cannot fathom why IE changes nodeValue without this, but it seems to!
  anchor.firstChild.nodeValue = email;
}

function changeAppear(input) {
  var div = document.getElementById(input.getAttribute('changeappear'));
  if (div == null) return;
  var appearvalue = input.getAttribute('appearvalue');
  if (input.getAttribute('val') != null) val = input.getAttribute('val');
  else val = input.value;
  
  if ((input.type == 'checkbox') || (input.type == 'radio')) {
    if (appearvalue) display = !!input.checked;
    else display = !input.checked;
  }
  else {
    r = RegExp(appearvalue, "i");
    if (r.test(val)) display = true;
    else display = false;
  }
  
  if (display) div.style.display = 'block'; /* This should ideally be
                                             * div.style.display = 'whatever-it-was-before'; */
  else div.style.display = 'none';
}

function toggle(anchor, e) {
  var show = document.getElementById(anchor.getAttribute('showid'));
  var hide = document.getElementById(anchor.getAttribute('hideid'));

  show.style.display = 'block';
  hide.style.display = 'none';

  var focusid = anchor.getAttribute('focusid');
  if (focusid) {
    var input = document.getElementById(focusid);
    input.focus();
  }
}

function addTag(anchor) {
  var tags = document.getElementById('tags');
  removeEg(tags);
  var tagName = anchor.firstChild.nodeValue;
  if (tags.value.length>0 && tags.value.charAt(tags.value.length-1) != ' ') {
    tags.value += ' ';
  }
  tags.value += tagName + ' ';
  tags.focus();
}

function submitLink(obj) {
  if (obj.tagName.toLowerCase() != 'a') {
    return;
  }
  var form = ancestor(obj, 'form');
  if (form) {
    form.submit();
  }
}

function rollover(obj, postfix) {
  var img;
  if (obj.tagName.toLowerCase() == 'img') {
    img = obj;
  } else {
    img = obj.getElementsByTagName('img')[0];
  }

  var altsrc = img.getAttribute('rollover');
  if (!img.origsrc) {
    img.origsrc = img.src;
  }
  if (!altsrc) {
    var parts = img.origsrc.split('.');
    altsrc = parts[0];
    var j;
    for (j = 1; j < (parts.length - 1); j++) {
      altsrc = altsrc + '.' + parts[j];
    }
    altsrc = altsrc + postfix + '.' + parts[parts.length - 1];
  }
  img.src = altsrc;
}

function rollout(obj) {
  var img;
  if (obj.tagName.toLowerCase() == 'img') {
    img = obj;
  } else {
    img = obj.getElementsByTagName('img')[0];
  }

  var origsrc = img.origsrc;
  img.src = origsrc;
}

function charsLeft(textarea) {
  var maxlength = parseInt(textarea.getAttribute('maxlength'), 10);
  var countdown = document.getElementById(textarea.getAttribute('countdown'));
  textarea.value = textarea.value.substring(0, maxlength);
  countdown.firstChild.nodeValue = maxlength - textarea.value.length;
}
