////// DISPATCHER ////////////////////////////////////////////////////////////////
Dispatcher = function() {this.init();}
Dispatcher.prototype.add = function(event) {
  events.push(event);
}
Dispatcher.prototype.dispatch = function(e) {
  // Cross browser fixes
  if (!document.getElementById || !document.createElement) return;
  if (e && e.target) {var obj = e.target;} else { var obj = window.event.srcElement; var e = window.event; }
  if (!obj) obj = document;
        
  var type = "on" + e.type;
  
  for(i=0;i<events.length;i++) {
    if (events[i].event == type) {
    //alert("O: " + events[i].node + "  T: " + events[i].type + "  N: " + events[i].name + "  E: " + events[i].event);
    //alert("O: " + obj.nodeName   + "  I: " + obj.id + "  C: " + obj.className);


      if ((events[i].type == "element" && (events[i].node == obj.nodeName  || (events[i].node == "#document" ))) ||
          (events[i].type == "id"      && (events[i].name == obj.id        && (events[i].node == "" || events[i].node == obj.nodeName ))) ||
          (events[i].type == "class"   && (events[i].name == obj.className && (events[i].node == "" || events[i].node == obj.nodeName )))) {

        if(actions[events[i].parent.action[0]]) {

          var action = actions[events[i].parent.action[0]];
          var arguments = "";
          if (events[i].parent.action[1]) { arguments = events[i].parent.action[1].split(","); }
        
          if (events[i].parent.condition.test()) { action.start(events[i].parent,arguments); }
          else { action.flip(events[i].parent,arguments); }
        }
      }
    }
  }
}
Dispatcher.prototype.init = function() {}


////// RULE //////////////////////////////////////////////////////////////////////
Rule = function(id, event, condition, action) {this.init(id, event, condition, action);}
Rule.prototype.id = Object();
Rule.prototype.event = Object();
Rule.prototype.condition = Object();
Rule.prototype.action = Object();
Rule.prototype.init = function(id, event, condition, action) {
  
  if (event && action) {
    // Save rule span's ID
    this.id = id;
  
    this.event = new Event(this, event);
    this.condition = new Condition(this, condition);
    this.action = action.split(/\((.*?)\)/);
  }
}


////// EVENT /////////////////////////////////////////////////////////////////////
Event = function(parent, event) {this.init(parent, event);}
Event.prototype.parent = Object();
Event.prototype.node = Object();
Event.prototype.type = "";
Event.prototype.name = Object();
Event.prototype.event = Object();
Event.prototype.init = function(parent, event) {
  // Create and save new event - 2: node  3: type  4: name  5: event
  var eparts = event.split(/^((.*)([\.#]))?(.*?)\.(.*)$/);

  this.parent = parent;

  if (eparts[3]) {
    if (eparts[3] == ".") this.type = "class";
    if (eparts[3] == "#") this.type = "id";
    this.node = eparts[2].toUpperCase();
    this.name = eparts[4];
  } else {  
    this.type = "element";
    if (eparts[4].toUpperCase() == "DOCUMENT") {
      this.node = "#document";
    } else {
      this.node = eparts[4].toUpperCase();
    }
    this.name = ""
  }
  
  this.event = eparts[5].toLowerCase();
 
  //alert("O: " + this.node + "  T: " + this.type + "  N: " + this.name + "  E: " + this.event);
 
  dispatcher.add(this); 
}


////// CONDITION /////////////////////////////////////////////////////////////////
Condition = function(parent, condition) {this.init(parent, condition);}
Condition.prototype.parent = Object();
Condition.prototype.condition = "";
Condition.prototype.test = function() {
  // Blank condition is always true
  if (this.condition == "" || eval(this.condition)) return true;
  return false;
}
Condition.prototype.init = function(parent, condition) {

  while(condition.match("#")){
    condition = condition.replace(/#(.*?)([\. =<>!].*)/,"document.getElementById('$1')$2");
  }
  
  this.parent = parent;
  this.condition = condition;
}


////// ACTION ////////////////////////////////////////////////////////////////////
Action = function(name) {this.init(name);}
Action.prototype.name = Object();
Action.prototype.start = function() {}
Action.prototype.flip = function() {}
Action.prototype.init = function(name) {
  this.name = name;
  actions[name] = this;
}


////// INITIALIZE DISPATCHER
var dispatcher = new Dispatcher();
var events = new Array();
var actions = new Object();

document.onclick = dispatcher.dispatch;
document.onmouseover = dispatcher.dispatch;
window.onload = dispatcher.dispatch;
