
/**
 * Namespace
 */
var indivisual = {
  utils: {}
};


/**
 * Shortcut
 */
var indy = indivisual;


/**
 * Utilities
 */
(function() {

  /**
   * Array.forEach
   * Execute a function in place on every member of an array.
   */
  if (!Array.prototype.forEach) {
    Array.prototype.forEach = function(func) {
      var i;
      var len = this.length;
      var thisp = arguments[1];
      for (i = 0; i < len; ++i) {
        if (i in this) {
          func.call(thisp, this[i], i, this);
        }
      }
    };
  }

  /**
   * indivisual.utils.getText
   * Get the text content of the given node (browser independent)
   */
  indivisual.utils.getText = function(node) {
    if (node.textContent) {
      return node.textContent;
    } else if (node.text) {
      return node.text;
    } else if (node.innerText) {
      return node.innerText;
    }
    return '';
  } // getText
  
  /**
   * indivisual.utils.addEvent
   * Add an event listener to an object (browser independent)
   */
  indivisual.utils.addListener = function(obj, type, func) {
    if (obj.attachEvent) {
      var pseudoHandler = type + func.toString().substr(0, 48);
      var handler = "e" + pseudoHandler;
      obj[handler] = func;
      obj[pseudoHandler] = function() {
        if (obj[handler]) {
          obj[handler](window.event); 
        }
      };
      obj.attachEvent("on" + type, obj[pseudoHandler]);
    } else if (obj.addEventListener) {
      obj.addEventListener(type, func, true);
    } else {
      obj['on' + type] = func;                        
    }
  } // addListener
   
  /**
   * indivisual.utils.getElementsByClass
   * Get the children, with the given class name, of a given node. An optional tag
   * name may be supplied as a third argument to limit the search to that specific
   * kind of element.
   */ 
  indivisual.utils.getElementsByClass = function(node, className, optTag) {
    return indy.utils.getElementsBy(node, 'className', className, optTag);
  } // getElementsByClass

  /**
   * indivisual.utils.getElementsBy
   * Get the children of a given node that match on a given attribute. An optional tag
   * name may be supplied as a third argument to limit the search to that specific
   * kind of element.
   */ 
  indivisual.utils.getElementsBy = function(node, attr, comparison, optTag) {
    var element;
    var nodes;
    var matches;
    var i;
    
    if (!node) {
      return;
    }

    if (!optTag) {
      nodes = node.getElementsByTagName('*');
    } else {
      nodes = node.getElementsByTagName(optTag);
    }
    
    matches = [];
    for (i = 0, element; element = nodes[i]; ++i) {
      if (!comparison || (attr && element[attr].match(comparison))) {
        matches.push(element);
      }
    }
    
    return matches;
  } // getElementsBy

})();


/**
 * Main definitions
 */ 
(function() {

  /**
   * getAge
   * Return a current age based on date of birth.
   */
  function getAge(dob) {
    var now = new Date();
    var day = now.getDate();
    var month = now.getMonth() + 1;
    var year = now.getFullYear();

    if ((month > dob.month) || (month === dob.month && day >= dob.day)) {
      return year - dob.year;
    } else {
      return year - dob.year - 1;
    }
  } // getAge

  /**
   * stringReverse
   * Reverse a string
   */
   function stringReverse(str) {
    return str.split('').reverse().join('');
   } // stringReverse
  
  /**
   * deobfuscateDoB
   * Deobfuscate a DoB - really we should do the age calculation on the server...
   */
  function deobfuscateDoB(obDoB) {
    return {
      day: parseInt(stringReverse(obDoB.substring(2, 4)), 10),
      month: parseInt(stringReverse(obDoB.substring(4, 6)), 10),
      year: parseInt(stringReverse(obDoB.substring(6, 8)) + stringReverse(obDoB.substring(10)), 10),
    }
  } // deobfuscateDoB
  
  /**
   * indivisual.dobToAge
   * Transform a node containing a DoB to an age.
   */
  indivisual.dobToAge = function(node) {
    var dob = deobfuscateDoB(indy.utils.getText(node));
    var age = getAge(dob);
    var ageNode = document.createTextNode('' + age);
    node.parentNode.replaceChild(ageNode, node);
  } // dobToAge

})();


/**
 * On load
 */ 
(function() {

  /**
   * transformDoBs
   * Transform all relevant DoB nodes to ages.
   */
  function transformDoBs() {
    var ageNodes = indy.utils.getElementsByClass(document, 'dob2age');
    if (ageNodes) {
      ageNodes.forEach(indy.dobToAge);
    }
  } // transformDoBs

  indy.utils.addListener(window, 'load', function() {
    transformDoBs();
  });

})();

