
var islands = {
  isMSIE : (window.navigator.userAgent.search('MSIE') != -1 ),

  getElementsByAttribute : function (node, att) {
    var rv = [];
    this.getEBArecursive(rv, node, att);
    return rv;
  },

  getEBArecursive : function (list, node, att) {
    for (var i=node.childNodes.length-1; i>=0; i--)
    {
      var child = node.childNodes.item(i);
      if ( child.nodeType == 1 ) {
        if ( child.getAttribute(att) ) {
          list.push(child);
        }
        this.getEBArecursive(list, child, att);
      }
    }
  },

  getFieldDataFromRecord : function (rec,field) {
    var found;
    for (var i=0; i < rec.childNodes.length; i++) {
      if (rec.childNodes.item(i).nodeName.toLowerCase() == field) {
        found = rec.childNodes.item(i).firstChild;
	if (found == null )
	  return "";
        else
	  return found.nodeValue;
      }
    }
  },

  makeIEtree : function (island) {
    var subtree = document.createElement(island.nodeName);
    var current = subtree;
    var next;

    for (var j = 0; j < island.childNodes.length; j++)
    {
      var record = island.childNodes.item(j);
      if ( record.nodeName == '#text' )
      {
        current.appendChild(document.createTextNode(record.nodeValue));
      }
      else if ( record.nodeName.charAt(0) == '/' )
      {
        current = current.parentNode;
      }
      else
      {
        next = document.createElement(record.nodeName);
        current.appendChild(next);
        current = next;
      }
    }
    return subtree;
  },

  merge : function (target, template, record) {
    // dig out from the template the fields requiring update
    var fields   = this.getElementsByAttribute(template,'datafield');
    if (!fields || fields.length == 0) next;

    // update the text for each target field in the template
    for (var k=fields.length-1; k>=0; k--) {
      var thetag   = fields[k];
      var thefield = thetag.getAttribute('datafield');
      var newtext  = this.getFieldDataFromRecord(record,thefield);

      if (thetag.firstChild)            // replace existing text
      {
        thetag.firstChild.nodeValue = newtext;
      }
      else if ( thetag.value == null )  // not a form element
      {
        thetag.appendChild(document.createTextNode(newtext));
      }
      else                              // a form element
      {
        thetag.value = newtext;
      }
    }

    // put the updated template content back into the page.
    for (k=0; k < template.childNodes.length; k++) {
      target.appendChild(template.childNodes.item(k).cloneNode(true));
    }
  },

  bind : function () {
    // 1. Find all the datasources in the page.
    var targets = this.getElementsByAttribute(document,'datasource');
    if (!targets || targets.length == 0) return;

    // Do it for each data binding 'target' in the page 
    for (var i=0; i < targets.length; i++) {
      var iid      = targets[i].getAttribute('datasource');
      var island   = document.getElementById(iid);
      if (!island) return;

      // 2. Extract a copy of the current content for this target
      var template = targets[i].cloneNode(true);

      // ... and delete the real copy
      for (var j = targets[i].childNodes.length-1; j>=0; j--) {
        targets[i].removeChild(targets[i].childNodes.item(j));
      }

      if ( this.isMSIE ) { island = this.makeIEtree(island); }

      // 4. Apply the template once for each XML record
      for (j = 0; j < island.childNodes.length; j++)
      {
        // children that are text nodes aren't real records
        var record = island.childNodes.item(j);
        if ( record.nodeName == '#text' )
          continue;

	// 5, 6. Combine page, template and data
        this.merge(targets[i], template, record);
      }
        
      if ( this.isMSIE ) { delete island; }
    }
  }
};

window.onload = function () { islands.bind(); };

