shq.Events={};

shq.Events.register = {};

shq.Events._addToRegister = function(node, type, fn, capt) {
    // DOM node gets converted into a string; we keep an array for
    // shq.Events of similar DOM nodes, and also a separate reference
    // to the node itself
    if (!shq.Events.register[node]) shq.Events.register[node] = [];
    shq.Events.register[node].push({'node': node, 'type': type, 'fn': fn,
'capt': capt});
};

shq.Events._removeFromRegister = function(node, type, fn) {
    // Remove from cached register
    if (node in shq.Events.register) {
        var r = shq.Events.register[node];
        for (var i=0; i<r.length; i++) {
            if (r[i].type == type && r[i].fn == fn) {
                var e = shq.Events.register[node].splice(i, 1)[0];
                if (r.length == 0) delete shq.Events.register[node];
                return e;
            }
        }
    }
};

// De-registers all shq.Events
shq.Events.clear = function(node) {
    if (node) {
        var n = shq.Events.register[node];
        for (var i=0; i<n.length; i++) {
            if (n[i].type == 'unload') continue;
            shq.Events.remove(n[i].node, n[i].type, n[i].fn);
        }
    } else {
        for (var node in shq.Events.register) {
            shq.Events.clear(node);
        }
    }
};

// Browser-specific implementations
if (document.addEventListener) {
    shq.Events.add = function(node, type, fn, capt) {
        capt = capt || false;
        node.addEventListener(type, fn, capt);
        this._addToRegister(node, type, fn, capt);
    };
} else if (document.attachEvent) {
    shq.Events.add = function(node, type, fn) {
        node.attachEvent('on'+type, fn);
        this._addToRegister(node, type, fn);
    };
} else {
    shq.Events.add = function(node, type, fn) {
        node['on'+type] = fn;
    };
}


if (document.createEvent) {
    shq.Events.create = function(type, data, eventClass) {
        eventClass = eventClass || 'Event';
        var e = document.createEvent(eventClass);
        e.initEvent(type, true, false);
        e.datatype = type;
        e.data = data;
        return e;
    };
} else if (document.createEventObject) {
    shq.Events.create = function(type, data) {
        var e = document.createEventObject();
        e.datatype = type;
        e.data = data;
        return e;
    };
} else shq.Events.create = function() {return null; };


if (document.dispatchEvent) {
    shq.Events.fire = function(node, e) {
        node.dispatchEvent(e);
    };
} else if (document.fireEvent) {
    shq.Events.fire = function(node, e, type) {
        node.fireEvent(type, e);
    };
}


if (document.removeEventListener) {
    shq.Events.remove = function(node, type, fn, capt) {
        if (!node.removeEventListener) {
            shq.Events._removeFromRegister(node, type, fn);
            return;
        }
        var e = shq.Events._removeFromRegister(node, type, fn);
        if (e) node.removeEventListener(type, fn, e.capt);
    };
} else if (document.detachEvent) {
    shq.Events.remove = function(node, type, fn) {
        try {
            node.detachEvent('on' + type, fn);
        } catch (ex) {}
        shq.Events._removeFromRegister(node, type, fn);
    };
} else {
    shq.Events.remove = function(node, type, fn) {
        node['on'+type] = null;
        delete node['on'+type];
    };
}

shq.Events.click = function(node) {
    if (node.click) node.click();
    else {
        var e = shq.Events.create('click', null, 'MouseEvents');
        e.initMouseEvent('click', true, true, window,0, 0, 0, 0, 0, false, false, false, false, 0, null);
        shq.Events.fire(node, e, 'click');
    }

}; 
