// JavaScript Document
var Class = {
  create: function() {
    return function() {
      this.initialize.apply(this, arguments);
    }
  }
}

Object.extend = function(destination, source) {
  for (var property in source) {
    destination[property] = source[property];
  }
  return destination;
}

Function.prototype.bind = function() {
  var __method = this, args = $A(arguments), object = args.shift();
  return function() {
    return __method.apply(object, args.concat($A(arguments)));
  }
}

Function.prototype.bindAsEventListener = function(object) {
  var __method = this, args = $A(arguments), object = args.shift();
  return function(event) {
    return __method.apply(object, [( event || window.event)].concat(args).concat($A(arguments)));
  }
}

Function.prototype.bind = function() {
  var __method = this, args = $A(arguments), object = args.shift();
  return function() {
    return __method.apply(object, args.concat($A(arguments)));
  }
}


function findParents(el, tag, cls) {
    var result = [];
    while (el.parentNode && el.tagName) {
        el = el.parentNode;
        if (el.tagName && (!tag || el.tagName.toLowerCase() == tag.toLowerCase()) && (!cls || hasClass(el, cls))) {
            result.push(el); 
        }
    }
    return result;
}

function findChildren(el, tag, cls, id) {
    var result = [];
    //alert(tag+'#'+id+'.'+cls);    
    if (el.childNodes) {
        for(var i=0; i<el.childNodes.length; i++) {
            var child = el.childNodes[i];
            if (
                    child.tagName && 
                    (!tag || tag == '' || child.tagName.toLowerCase() == tag.toLowerCase()) && 
                    (!cls || cls == '' || hasClass(child, cls)) && 
                    (!id || id == '' || child.id == id)) {
                result.push(el.childNodes[i]);
            }
            result = result.concat(findChildren(child, tag, cls, id));
        }
    }
  
    return result;
}


function findNextSiblings(el, tag, cls, id) {
    var result = [];
    while (el.nextSibling) {
        el = el.nextSibling;
        if (
                el.tagName && 
                (!tag || tag == '' || el.tagName.toLowerCase() == tag.toLowerCase()) && 
                (!cls || cls == '' || hasClass(el, cls)) && 
                (!id || id == '' || child.id == id)) {
            result.push(el);
        }
    }
    return result;
}
function findPrevSiblings(el, tag, cls, id) {
    var result = [];
    while (el.previousSibling) {
        el = el.previousSibling;
        if (
                el.tagName && 
                (!tag || tag == '' || el.tagName.toLowerCase() == tag.toLowerCase()) && 
                (!cls || cls == '' || hasClass(el, cls)) && 
                (!id || id == '' || child.id == id)) {
            result.push(el);
        }
    }
    return result;
}



function select(elements, expr, debug) {
    var result = [];
    if (elements.constructor != Array) {
        elements = [elements];
    }
    
    //first split using separator, and remove any leading and trailing whitespace
    var expr = expr.split(/\s*,\s*/);
    for (var i=0; i < expr.length;i++) {
        var expr1 = expr[i];
        // split using whitepace
        var expr1 = expr1.split(/\s+/);
        var parents = elements;
        for (var j=0; j< expr1.length;j++) {
            var children = [];
            var expr2 = expr1[j];
            if (expr2.match(/^(\w+|\*|)((#)(\w+))?((\.)(\w+))?$/)) {
                var tag = RegExp.$1;
                if (tag == '*') {
                    tag = null;
                }
                var id = RegExp.$4;
                var cls = RegExp.$7;
                for(var k=0; k<parents.length;k++) {
                    children = children.concat(findChildren(parents[k], tag, cls, id));
                }
            }
            parents = children;
        }
        result = result.concat(children);
    }
    return result;
}

function hasClass(el, cls) {
    clss = el.className.split(' ');
    for(var i = 0; i<clss.length;i++) {
        if (clss[i] ==  cls) {
            return true;
        }
    }
    return false;
}

function addClass(el, cls) {
    clss = el.className.split(' ');
    for(var i = 0; i<clss.length;i++) {
        if (clss[i] ==  cls) {
            return;
        }
    }
    clss.push(cls);
    el.className = clss.join(' ');
}

function removeClass(el, cls) {
    clss = el.className.split(' ');
    for(var i = 0; i<clss.length;i++) {
        if (clss[i] ==  cls) {
            clss[i] = null;
            delete clss[i];
        }
    }
    el.className = clss.join(' ');
}

Array.prototype.first = function () {
    return (this.length > 0) ? this[0] : null;
}

Array.prototype.last = function () {
    return (this.length > 0) ? this[this.length-1]:null;
}

Array.prototype.each = function (f) {
    for(var i = 0; i < this.length; i++) {
        f(this[i]);
    }
}

Array.prototype.reduce = function () {
    return this.length > 1 ? this : this[0];
}

Array.prototype.filter = function (f) {
    var result = [];
    for(var i = 0; i < this.length; i++) {
        if (f(this[i])) {
            result.push(this[i]);
        }
    }
    return result;
}

Array.from = function (x) {
    if (x == null) {
        return [];
    } else if (x.constructor == Array) {
        return x;
    } else {
        return [x];
    }
}

var $A = function(iterable) {
    if (iterable == null) {
        return [];
    } else if (iterable.toArray) {
        return iterable.toArray();
    } else if (iterable.constructor == Array) {
        return iterable;
    } else if (typeof iterable == 'object' && iterable.length) {
        var results = [];
        for (var i = 0; i < iterable.length; i++) {
            results.push(iterable[i]);
        }
        return results;
    } else {
        return [iterable];
    }
}

function $() {
    elements=[];  
    for (var i = 0; i < arguments.length; i++) {
        element = arguments[i];
        if (element.constructor == Array) {
            elements = elements.concat($.apply(this, element));
        } else {
            if (typeof element == 'string') {
                element = document.getElementById(element);
            }
            elements.push(element);
        }
    }
    //reduce
    return elements.reduce();
}

function addLoadEvent (f) {
    var o = window.onload;
		
    if (typeof window.onload != 'function') {
        window.onload = f;
    } else {
        window.onload = function() {
            o();
            f();
        }
    }
}

function doLoadEvent () {
    //return;
    var o = window.onload;
    if (typeof o == 'function') {
        o();
        window.onload = null;
    }
}

dumpObject = function (object, level) {
	if (!level) {
		level=0;
	}
    var string = '';

    string += '{';
    if (typeof(object) == 'object') {
        for (var property in object) {
            if (typeof(object[property]) != 'function') {
                string += property + ': '+ object[property] + ', ';
            }
        }
        string += '}';
    } else {
        string += object;
    }
    return string;
}

if (!Array.prototype.indexOf) {
  Array.prototype.indexOf = function(elt /*, from*/) {
    var len = this.length;

    var from = Number(arguments[1]) || 0;
    from = (from < 0) ? Math.ceil(from) : Math.floor(from);
    if (from < 0) from += len;

    for (; from < len; from++) {
      if (from in this && this[from]  == elt)
        return from;
    }
    return -1;
  };
}
var Element = Class.create();
/*
Element.addHandler = function (element, event, f) {
    var o = element[event];
    if (typeof o != 'function') {
        element[event] = f;
    } else {
        element[event] = function () {
            o()
            f();
        }
    }
}
*/
Element.addHandler = function (element, event, id, f) {
    if (!element._events) {
        element._events = {};
    }
    if (!element._events[event]) {
        element._events[event] = {};
        var o = element[event];
        if (typeof o == 'function') {
            element._events[event]['org'] = o;
        }
        element[event] = function () {
            //alert('upgraded:'+event);
            for(prop in this._events[event]) {
                this._events[event][prop].apply(this);
            }
        }
    }
    element._events[event][id] = f; 
}
Element.removeHandler = function (element, event, id) {
    if (!element._events) {
        element._events = {};
    }
    if (!element._events[event]) {
        element._events[event] = {};
        var o = element[event];
        if (typeof o == 'function') {
            element._events[event]['org'] = o;
        }
        element[event] = function () {
            for(prop in this._events[event]) {
                this._events[event][prop].apply(this);
            }
        }
    }
    delete element._events[event][id];
}

var Form = Class.create();
Form.element = function (form) {
    elements=[];
    for (var i = 1; i < arguments.length; i++) {
        element = arguments[i];
        if (!element) {
            // nothing...
        } else if (element.constructor == Array) {
            elements = elements.concat(Form.element.apply(this, [form].concat(element)));
        } else if (typeof element == 'string') {
            element = form[element];
            if (element) {
                elements = elements.concat(Form.element.apply(this, [form].concat(element)));
            }
        } else if (element.length && !element.form) {
            
            // can also be a nodelist
            result = []
            for (var j = 0; j < element.length; j++) {
                result.push(element[j]);
            }
            elements = elements.concat(Form.element.apply(this, [form].concat(result)));
        } else if (element.form && element.form == form) {
            elements.push(element);
        } else {
            //nothing
        }
    }
    return elements.reduce();    
}

Form.value = function (elements) {
    var value = [];
    elements = Array.from(elements);
    
    elements.each(
        function (element) {
            switch (element.type) {
                case 'checkbox' :
                case 'radio' :
                    if (element.checked) {
                        value.push(element.value);
                    }
                    break;
                case 'select-one' :
                    var index = element.selectedIndex;

                    if (index >= 0) {
                        var opt = element.options[index];
                        value.push(opt.value);
                    }
                    break;
                case 'select-multiple' :
                    for (var i=0;i < element.options.length;i++) {
                        var option = element.options[i];
                        if (option.selected) {
                            value.push(option.value);
                        }
                    }
                    break;
                case 'textarea' :
                case 'text' :
                case 'file' :
                case 'hidden' :
                case 'password' :
                    value.push(element.value);
            }            
        }
    );
    return value.length > 1 ? value : value[0] || '';
}

Form.serialize = function (form) {
    var result = [];
    for(var i=0;i<form.elements.length;i++) {
        result.push(form.elements[i].name+'='+escape(Form.value(form.elements[i])));
    }
    return result.join('&');
}

var Ajax = Class.create();
Ajax.getHttp = function () {
    var ro;	//This will hold the request object -- either Microsoft.XMLHTTP or XMLHttpRequest
    try {	//Let's use a try/catch system just in case something goes wrong -- we can at least default back to the XMLHttpRequest object
    	ro = new XMLHttpRequest();
    } catch (e) {
    	ro = new ActiveXObject("Microsoft.XMLHTTP"); //We'll at least try the IE6 and lower version	
    }
    return ro;	//Now that we've taken care of cross-browser compatibility, this.http will represent the request object for this instance of AjaxObject
}
Ajax.Request = Class.create();
Ajax.Request.prototype = {
    initialize: function(action, url, data, callback) {
        this.http = Ajax.getHttp();
        this.callback = callback;
        var self = this;
        var hr = function () {self.handleResponse.apply(self, arguments);}
		if (action.toUpperCase() == "POST") { //Post method
			this.http.open(action, url, true); //The URL includes any GET or POST variables you want
			this.http.setRequestHeader('Content-Type','application/x-www-form-urlencoded'); //Encode the data
			this.http.onreadystatechange = handleResponse; //This is the callback function when the state of the http object changes
			this.http.send(data);	//Actually start the request process -- this will contact the URL via the action specified, and wait to call this.handleResponse
		}
		else {	//'get' method is default
			this.http.open(action,url + '?' + data,true); //The URL includes any GET or POST variables you want
			this.http.onreadystatechange = hr; //This is the callback function when the state of the http object changes
			this.http.send(null);	//Actually start the request process -- this will contact the URL via the action specified, and wait to call this.handleResponse
		}
    },
	handleResponse: function() { //This function is called when this.http's state changes
		if (this.http.readyState == 4) { //State of 4 means the connection is done (data was transferred)
			if (typeof this.callback == 'function') {
			    var result = new Function("return "+this.http.responseText) ();
                this.callback(result);
			}
		}
	}
}
