/**
* lib.js
* Minimal version of dom_evt.js for simple script actions
*
* @author       Tom Wright <developer@tomwright.me.uk>
* @last update  01/04/05 00:27
*
* EventManager object based on EventManager.js by Keith Gaughan
* Visit http://talideon.com/weblog/2005/03/js-memory-leaks.cfm
* for licensing and latest updates.
*/



// --------------------------
// ------- DIY Legacy -------
// --------------------------

/* Strictly illegal reserved word - but temp soln for IE */
var undefined; // for IE5.0x

if (typeof Function.prototype.call === String(undefined)) {
  Function.prototype.call = function(obj, param) {
    obj.base = this;
    obj.base(param);
  };
}

if (typeof Array.prototype.push === String(undefined)) {
  Array.prototype.push = function(elem) {
    this[this.length] = elem;
  };
}

// ----------------------------
// -- Prototype enhancements --
// ----------------------------

Function.prototype.Iterate = function(collection) {
  var elem;
//  if (typeof TreeWalker !== String(undefined) && collection instanceof TreeWalker) {
// :NOTE: IE Mac throws compile errors on instanceof
  if (typeof TreeWalker !== String(undefined) && /TreeWalker/i.test(collection.constructor)) {
    while((elem = collection.nextNode()) !== null) {
      this(elem);
    }
  }
  else {
    // note use the collection index rather than item() method
    // since IE will pass a standard array if getSet has been
    // used to build the collection
    for (var i = 0; (elem = collection[i]) ; i+=1 ) {
      this(elem, i);
    }
  }
};

Array.prototype.search = function(str) {
  var re;
  for (var i = 0, m = this.length; i < m; i+=1) {
    re = new RegExp('^' + str + '$', 'i');
    if (re.test(this[i])) {
      return true;
    }
  }
  return false;
};

// ---------------------------
// -- Standard DOM Routines --
// ---------------------------

if (typeof Node === String(undefined)) {
// set some node constants for IE.
  var Node = {};
  Node.ELEMENT_NODE                =1;
  Node.ATTRIBUTE_NODE              =2;
  Node.TEXT_NODE                   =3;
  Node.CDATA_SECTION_NODE          =4;
  Node.ENTITY_REFERENCE_NODE       =5;
  Node.ENTITY_NODE                 =6;
  Node.PROCESSING_INSTRUCTION_NODE =7;
  Node.COMMENT_NODE                =8;
  Node.DOCUMENT_NODE               =9;
  Node.DOCUMENT_TYPE_NODE          =10;
  Node.DOCUMENT_FRAGMENT_NODE      =11;
  Node.NOTATION_NODE               =12;
}

// compressed method for navigating through the dom tree, similar to get but based
// on properties (ie prototyping).
// get('form')(0).get('input')(0) would get the first input in first form
//
// this method depends on assignToDOM to work in IE and is setup by calling __initDOMCrawler
var get = function(tag) {
  var self = (this.nodeName !== undefined) ?
    this :    //  this instanceof Node
    document; //  this instanceof Window

  return function(idx) {
    //if (tag instanceof Array) {
    if (typeof tag === "array") {
      return getSet(tag, self);
    }
    else {
      return (idx === undefined) ?
        self.getElementsByTagName(tag) :
        self.getElementsByTagName(tag).item(idx);
    }
  };
};

function getSet(tags, root) {
  var set = null;
  if (document.createTreeWalker) {
    // Keep out IE unless we build an IE TreeWalker object!!
    root = (root === undefined) ? document : root;
    set = document.createTreeWalker(root,
                                        NodeFilter.SHOW_ELEMENT,
                                        {
                                          acceptNode : function(n) {
                                            return (tags.search(n.tagName)) ?
                                              NodeFilter.FILTER_ACCEPT :
                                              NodeFilter.FILTER_SKIP;
                                            }
                                          },
                                        false);
  }
  else {
    set = [];
    try {
      for(var i = 0, m = tags.length; i < m; i+=1) {
        // cannot call get on document so check for root parameter
        // and if it does not exist call get globally
        if (root == document || root === undefined) {
          (function(elem){set[set.length]=elem;}).Iterate(get(tags[i])());
        }
        else {
          (function(elem){set[set.length]=elem;}).Iterate(root.get(tags[i])());
        }

      }
    } catch(e) {alert("Error thrown in getSet()");report_errors(e);}
  }
  return set;
}

function assignToDOM(fn, fn_name, obj) {
  var elem;
  if (obj.childNodes && obj.childNodes.length > 0) {
    elem = obj.firstChild;
    do {
      if (elem.nodeType == Node.ELEMENT_NODE) {
        elem[fn_name] = fn;
        assignToDOM(fn, fn_name, elem);
      }
    } while (( elem = elem.nextSibling ));
  }
}

function __initDOMCrawler() {
  if (typeof HTMLElement !== String(undefined)) { HTMLElement.prototype.get = get; }
  else { assignToDOM(get, 'get', get('body')(0)); }
}

// ------------------------------
// ------ Event Management ------
// ------------------------------

/**
 * @updated     31/03/05 23:45
 *
 * Temporary resolution to memory leakage issues in IE particular and possibly Firefox
 * Implemented new EventManager class.
 * This is based on Keith Gaughan's class @ http://talideon.com/weblog/2005/03/js-memory-leaks.cfm
 * Extended the code to ensure capture is not ignored with restricted default false value
* ::TODO:: replace the with block - performance ?
 */

var EventManager =
{
  _registry: null,

  Initialise: function() {
    if (this._registry === null) {
      this._registry = [];
EventManager.Add(window, 'unload', this.CleanUp);
    }
  },

  Add: function(obj, type, fn, capture) {

    this.Initialise();

    // Not needed since addEventListener will default the capture
// parameter value to false if it is undefined
    capture = Boolean(capture);

// If a string was passed assume working with an ID value
    if (typeof obj == "string") {
      obj = ref(obj);
    }
    if (obj === undefined || fn === undefined) {
      return false;
    }

    // W3C DOM Event Listeners
    if (obj.addEventListener) {
      obj.addEventListener(type, fn, capture);
      this._registry.push({obj: obj, type: type, fn: fn, capture: capture});
      return true;
    }

    // IE Proprietary DOM Event Listeners
    else if (obj.attachEvent && obj.attachEvent("on" + type, fn)) {
      this._registry.push({obj: obj, type: type, fn: fn});
      return true;
    }

    return false;
  },

  CleanUp: function() {
    for (var i = EventManager._registry.length - 1; i >= 0; i-=1) {
      with (EventManager._registry[i]) {
        if (obj.removeEventListener) {
          obj.removeEventListener(type, fn, Boolean(capture));
        }
        else if (obj.detachEvent) {
          obj.detachEvent("on" + type, fn);
        }
      }
    }

// kill the registry itself to remove last remaining references
    EventManager._registry = null;
  }
};

EventManager.Add(window, 'load', function() {  __initDOMCrawler(); });

/** Default actions for all pages **/

function __initNewWindowAnchors() {
  if (document.getElementById) {
    (function(elem) {
      if (/^new|thumb/.test(elem.className)) {
        elem.target = "blank";
        if (elem.title.length == 0) {
          elem.title = "Open this page in a new window";
        }
        else {
          elem.title += " - New Window";
        }
      }
    }).Iterate(document.getElementsByTagName('a'));
  }
}

function __initAlternateRows() {
  var colors = ['light','dark'], rows;
  try {
    var tables = document.getElementsByTagName('table');
    for (var j = 0; j < tables.length; j++) {
      if (tables[j].className == 'fill') {
        rows = tables[j].getElementsByTagName('tr');
        for (var i = 0; i < rows.length; i++) {
          rows[i].className=(i%2)?colors[1]:colors[0];
        }
      }
    }

  } catch(e) {  }
}

EventManager.Add(window, 'load', __initNewWindowAnchors);
EventManager.Add(window, 'load', __initAlternateRows);