// Versie nummer
var version = "1.0 beta";

function InGenious()
{
};

InGenious.DIR           = "units/InGenious";
InGenious.GFX_DIR       = InGenious.DIR + "/gfx";
InGenious.PAGE_DIR      = "page";
InGenious.TEMPLATE_DIR  = "template";
InGenious.COMPONENT_DIR = "component";

InGenious.loadscreen = new Loadscreen();
InGenious.libraryParts = [InGenious.DIR + "/Object.class.js",
                          InGenious.DIR + "/Component.class.js",
                          InGenious.DIR + "/ComponentPool.class.js",
                          InGenious.DIR + "/Container.class.js",
                          InGenious.DIR + "/Menu.class.js",
                          InGenious.DIR + "/SourceComponent.class.js",
                          InGenious.DIR + "/Value.class.js",
                          InGenious.DIR + "/Debugger.class.js",
                          InGenious.DIR + "/Page.class.js",
                          InGenious.DIR + "/PagePool.class.js",
                          InGenious.DIR + "/Template.class.js",
                          InGenious.DIR + "/TemplatePool.class.js",
                          InGenious.DIR + "/array.lib.js",
                          InGenious.DIR + "/crossbrowser.lib.js",
                          InGenious.DIR + "/datetime.lib.js",
                          InGenious.DIR + "/x.lib.js"];    
InGenious.debug = null;
InGenious.sourceView = null;
InGenious.options = new Array();
InGenious.interface = null; // IFrame waarmee gecommuniceerd kan worden met de server

//<script>
//////////////////
// Helper Stuff //
//////////////////

// used to find the Automation server name
function getDomDocumentPrefix() {
	if (getDomDocumentPrefix.prefix)
		return getDomDocumentPrefix.prefix;
	
	var prefixes = ["MSXML2", "Microsoft", "MSXML", "MSXML3"];
	var o;
	for (var i = 0; i < prefixes.length; i++) {
		try {
			// try to create the objects
			o = new ActiveXObject(prefixes[i] + ".DomDocument");
			return getDomDocumentPrefix.prefix = prefixes[i];
		}
		catch (ex) {};
	}
	
	throw new Error("Could not find an installed XML parser");
}

function getXmlHttpPrefix() {
	if (getXmlHttpPrefix.prefix)
		return getXmlHttpPrefix.prefix;
	
	var prefixes = ["MSXML2", "Microsoft", "MSXML", "MSXML3"];
	var o;
	for (var i = 0; i < prefixes.length; i++) {
		try {
			// try to create the objects
			o = new ActiveXObject(prefixes[i] + ".XmlHttp");
			return getXmlHttpPrefix.prefix = prefixes[i];
		}
		catch (ex) {};
	}
	
	throw new Error("Could not find an installed XML parser");
}

//////////////////////////
// Start the Real stuff //
//////////////////////////


// XmlHttp factory
function XmlHttp() {}

XmlHttp.create = function () {
	try {
		if (window.XMLHttpRequest) {
			var req = new XMLHttpRequest();
			
			// some versions of Moz do not support the readyState property
			// and the onreadystate event so we patch it!
			if (req.readyState == null) {
				req.readyState = 1;
				req.addEventListener("load", function () {
					req.readyState = 4;
					if (typeof req.onreadystatechange == "function")
						req.onreadystatechange();
				}, false);
			}
			
			return req;
		}
		if (window.ActiveXObject) {
			return new ActiveXObject(getXmlHttpPrefix() + ".XmlHttp");
		}
	}
	catch (ex) {}
	// fell through
	throw new Error("Your browser does not support XmlHttp objects");
};

// XmlDocument factory
function XmlDocument() {}


XmlDocument.create = function () {
	try {
		// DOM2
		if (document.implementation && document.implementation.createDocument) {
			var doc = document.implementation.createDocument("", "", null);
			
			// some versions of Moz do not support the readyState property
			// and the onreadystate event so we patch it!
			if (doc.readyState == null) {
				doc.readyState = 1;
				doc.addEventListener("load", function () {
					doc.readyState = 4;
					if (typeof doc.onreadystatechange == "function")
						doc.onreadystatechange();
				}, false);
			}
			
			return doc;
		}
		if (window.ActiveXObject)
			return new ActiveXObject(getDomDocumentPrefix() + ".DomDocument");
	}
	catch (ex) {}
	throw new Error("Your browser does not support XmlDocument objects");
};

// Create the loadXML method and xml getter for Mozilla
if (window.DOMParser &&	window.XMLSerializer &&	window.Node && Node.prototype && Node.prototype.__defineGetter__)
{
	// XMLDocument did not extend the Document interface in some versions
	// of Mozilla. Extend both!
	//XMLDocument.prototype.loadXML = 
	Document.prototype.loadXML = function (s) {
		
		// parse the string to a new doc	
		var doc2 = (new DOMParser()).parseFromString(s, "text/xml");
		
		// remove all initial children
		while (this.hasChildNodes())
			this.removeChild(this.lastChild);
			
		// insert and import nodes
		for (var i = 0; i < doc2.childNodes.length; i++) {
			this.appendChild(this.importNode(doc2.childNodes[i], true));
		}
	};
	
	
	/*
	 * xml getter
	 *
	 * This serializes the DOM tree to an XML String
	 *
	 * Usage: var sXml = oNode.xml
	 *
	 */
	// XMLDocument did not extend the Document interface in some versions
	// of Mozilla. Extend both!
	/*
	XMLDocument.prototype.__defineGetter__("xml", function () {
		return (new XMLSerializer()).serializeToString(this);
	});
	*/
  var getter = function () {
		return (new XMLSerializer()).serializeToString(this);
	}
  
	Document.prototype.__defineGetter__("xml", getter);
}

// NodeType constants for XMLDocument
var ELEMENT_NODE = 1;
var ATTRIBUTE_NODE = 2;
var TEXT_NODE = 3;
var CDATA_SECTION_NODE = 4;
var ENTITY_REFERENCE_NODE = 5;
var ENTITY_NODE = 6;
var PROCESSING_INSTRUCTION_NODE = 7;
var COMMENT_NODE = 8; 
var DOCUMENT_NODE = 9;
var DOCUMENT_TYPE_NODE = 10;
var DOCUMENT_FRAGMENT_NODE = 11;
var NOTATION_NODE = 12;

// Voeg de stylesheet van InGenious in voor basisstijlen
var style = document.createElement("link");
style.rel = "stylesheet";
style.href = InGenious.DIR + "/InGenious.css";
document.getElementsByTagName("HEAD")[0].appendChild(style);
  
/**
* Loadscreen klasse
*
* Deze klasse voegt de html in die een progressbar aan de bezoeker laat zien.
* Bij iedere keer dat de functie loaded() wordt aangeroepen berekent de klasse
* hoever de progressbar opgeschoven moet worden aan de hand van de tickSize.
* tickSize is het percentage dat de progressbar op moet schuiven bij een tick
* (een aanroep aan de functie loaded().
**/
function Loadscreen()
{
  // Maak loadscherm
  //this.loadscreen = document.body.appendChild(document.createElement("div"));
  //this.loadscreen.id = "loadscreen";
  document.write("<div id=\"loadscreen\"></div>");
  this.loadscreen = loadscreen;
  
  // Maak message div
  var div = this.loadscreen.appendChild(document.createElement("div"));
  div.id = "loadscreenMessage";
  this.message = div.appendChild(document.createTextNode("Even geduld, a.u.b."));
  var radertjes = div.appendChild(document.createElement("img"));
  radertjes.src = InGenious.GFX_DIR + "/radertjes.gif";
  
  // Maak table met progressbar
  var table = this.loadscreen.appendChild(document.createElement("table"));
  table.id = "loadscreenProgressbar";
  this.progressbar = table.insertRow();
  
  for (var i = 0; i < 20; ++i)
  {
    var blokje = this.progressbar.insertCell();
    blokje.className = "loadscreenBlokje";
    blokje.appendChild(document.createTextNode("\u00A0"));
  }
  
  var div = this.loadscreen.appendChild(document.createElement("div"));
  div.id = "progress";
  this.progress = div.appendChild(document.createTextNode("0%"));
  
  this.iCell = 0; // Nummer van de cell die gekleurd moet worden
  this.percentage = 0; // Percentage dat geladen is
  this.remaining = 100; // Het percentage dat nog resteert
  this.tickSize = 2.5; // Percentage verhoging per aanroep deze functie
  this.tick = 0; // Restjes van vorige verhoging (afrondingsverschil)
  this.threshold = 100 / this.progressbar.cells.length; // Drempel voor tick
}

/**
* Functie increase()
*
* Bij iedere aanroep van deze functie wordt aan de hand van de tickSize
* bepaald of de progressbar moet worden opgeschoven.
* Als het percentage 100% bereikt blijft het loadscreen nog even staan en
* wordt daarna verborgen.
**/
Loadscreen.prototype.increase = function()
{  
  // Verhoog de tick met de tickSize. Dit is nodig als de ticksize geen heel
  // getal is.
  this.tick += this.tickSize;
  
  // Als de tick hoger is dan de drempelwaarde
  if (this.tick >= this.threshold)
  {
    ticks = Math.floor(this.tick / this.threshold);
    
    for (var i = 0; i < ticks; ++i)
    {
      // Bereken en toon het nieuwe percentage
      this.percentage += this.threshold;
      this.remaining -= this.threshold;
      this.progress.data = Math.round(this.percentage) + "%";
      
      // Kleur het blokje
      var blokje = this.progressbar.cells[this.iCell];
      blokje.style.backgroundColor = "#F1E0AA";
      blokje.style.borderColor = "#E0B73A";
      this.iCell++;
    }
    
    // Verberg het laadscherm als het laden gereed is
    if (this.percentage >= 100)
    {
      var oThis = this;
      
      var f = function()
      {
        oThis.hide();
      }
      
      // Verberg het loadscreen na 1 seconde vertraging
      setTimeout(f, 1000);        
    }
    
    // Update de restjes
    this.tick -= ticks * this.threshold;
  }
};
  
/**
* Functie show()
*
* Toon het laadscherm
**/
Loadscreen.prototype.show = function()
{
  xShow(this.loadscreen);
};

/**
* Functie hide()
*
* Verberg het laadscherm
**/
Loadscreen.prototype.hide = function()
{
  xHide(this.loadscreen);
  this.reset();
};

/**
* Functie reset()
*
* Zet alle waardes terug op de beginstand
**/
Loadscreen.prototype.reset = function()
{
  // Maak de progressbar leeg
  for (var i = 0; i < this.progressbar.cells.length; ++i)
  {
    var blokje = this.progressbar.cells[i];
    blokje.style.backgroundColor = "";
    blokje.style.borderColor = "#666666";
  }
  
  // Zet de variabelen op hun beginstand
  this.percentage = 0;
  this.remaining = 100;
  this.iCell = 0;
  this.message.data = "Een ogenblik geduld a.u.b.";
  this.progress.data = "0%";
};

/**
* Functie message(string : message)
*
* Stelt het bericht in van het loadscreen
**/
Loadscreen.prototype.setMessage = function(message)
{
  this.message.data = message;
};

//var loadscreen = new Loadscreen();

/**
* Klasse Script
*
* 
**/
function Script(src)
{
  this.src = src;
  this.htmlHttp = XmlHttp.create();
  this.async = true;
  this.text = "";
  this.readyState = "uninitialized";
  this.executed = false;
}

/**
* Functie load()
*
* Start het laden van het script
**/
Script.prototype.load = function()
{
  this.readyState = "loading";
  
  var oThis = this;
  
  this.htmlHttp.onreadystatechange = function()
  {
    if(oThis.htmlHttp.readyState == 4)
    {
      oThis.text = oThis.htmlHttp.responseText;
      oThis.readyState = "complete";
      oThis.onload();
    }
  }
  
  this.htmlHttp.open("GET", this.src, this.async);
  this.htmlHttp.send(null);
}

/**
* Functie onload()
*
* Wordt aangeroepen als het script is geladen.
**/
Script.prototype.onload = function()
{
}

/**
* Klasse ScriptQueue(scripts : array, onScriptLoaded : functie)
*
* Werkt het laden van alle scripts af
**/
function ScriptQueue(scripts, onScriptLoaded)
{
  this.scripts = new Array();
  this.numScripts = scripts.length;
  this.onScriptLoaded = onScriptLoaded;
  
  // Maak van elk script een Script object
  for (var i = 0; i < scripts.length; ++i)
  {
    this.scripts[i] = new Script(scripts[i]);
  }
}

/**
* Functie load()
*
* Laad alle scripts in de queue
**/
ScriptQueue.prototype.load = function()
{  
  var oThis = this;
  
  // Loop langs alle scripts in deze queue
  for (var i = 0; i < this.scripts.length; ++i)
  {
    var script = this.scripts[i];
    script.onload = function()
    {
      oThis.scriptLoaded(this);
    }
    script.load();
  }
}

/**
* Functie scriptLoaded(script : Script)
*
* Wordt aangeroepen als een script klaar is met laden
**/
ScriptQueue.prototype.scriptLoaded = function(script)
{
  this.numScripts--;
  this.execScript(script);  
  this.onscriptloaded();
  
  if (this.numScripts == 0)
  {
    this.onload();
  }
}

/**
* Functie onscriptloaded()
*
* Wordt aangeroepen door scriptLoaded als een script klaar is met laden
**/
ScriptQueue.prototype.onScriptloaded = function()
{
}

/**
* Functie execScript(script : Script)
*
* Voer het script uit
**/
ScriptQueue.prototype.execScript = function(script)
{
  if (script.readyState != "complete" || script.executed == true)
  {
    return;
  }
  
  // Zoek de index van dit script in de array
  var index = 0;
  for (var i = 0; i < this.scripts.length; ++i)
  {
    if (script == this.scripts[i])
    {
      index = i;
      break;
    }
  }
  
  if (index > 0)
  {
    if (this.scripts[index - 1].readyState != "complete")
    {
      return;
    }
  }

  window.execScript(script.text, "javascript");
  script.executed = true;
  
  if (index + 1 < this.scripts.length)
  {
    this.execScript(this.scripts[index + 1]);
  }
}

/**
* Functie onload()
*
* Wordt aangeroepen als alle scripts uit de queue geladen zijn.
**/
ScriptQueue.prototype.onload = function()
{
}

/**
* Functie window.onload
*
* Wordt automatisch aangeroepen als de pagina is geladen. Zorgt er voor dat alle
* benodigde classes zijn geladen die nodig zijn voor de engine
**/
window.onload = function()
{
  // Kijk of er opties met de url meegegeven zijn
  var uri = document.location.href;
  var i = uri.indexOf("#");
  
  // Er zijn opties meegegeven
  if (i >= 0)
  {
    // Haal de opties uit de string
    var options = uri.substring(i + 1, uri.length);
    var re = /[a-z]+=[a-z0-9]+/gi;
    var options = options.match(re);
    
    if (options != null)
    {
      re = /([a-z]+)=([a-z0-9]+)/i;

      // Loop alle opties langs en stop ze in een array
      for (var i = 0; i < options.length; ++i)
      {
        var match = options[i].match(re);
        if (match.length == 3)
        {
          InGenious.options[match[1]] = match[2];
        }
      }
    }
  }
  
  // Standaardwaarden voor opties instellen als die niet gespecificeerd zijn
  InGenious.options["debug"] = (typeof InGenious.options["debug"] == "undefined") ? false : Boolean(InGenious.options["debug"]);
  
  InGenious.options["page"] = (typeof InGenious.options["page"] == "undefined") ? "1" : InGenious.options["page"];
  
  // Laad alle benodigde scripts
  InGenious.scriptQueue = new ScriptQueue(InGenious.libraryParts);
  InGenious.loadscreen.tickSize = 40 / InGenious.libraryParts.length;
  InGenious.scriptQueue.onscriptloaded = function()
  {
    InGenious.loadscreen.increase();
  }
  InGenious.scriptQueue.onload = function()
  {
    // Initialiseer en start InGenious
    InGenious.init();
  }
  InGenious.scriptQueue.load();
};

/**
* Functie init(bool : enableDebug)
*
* Initialiseer en start InGenious
**/
InGenious.init = function()
{
  // Maak de debugtools aan, als de debug class bestaat
  if (typeof Debugger != "undefined")
  {
    InGenious.debug = new Debugger(InGenious.options["debug"]);
  }
  
  // Creeer het iframe voor de interface
  InGenious.interface = document.createElement("<iframe name=\"interface\"></iframe>");
  InGenious.interface.id = "interface";
  //InGenious.interface.name = "interface";
  document.body.appendChild(InGenious.interface);
  
  // Laad het configuratiebestand
  var config = XmlDocument.create();
  config.async = false;
  config.load("config.xml");
  config = config.childNodes[1];
  
  // Doorloop het configuratiebestand
  for (var i = 0; i < config.childNodes.length; ++i)
  {
    xmlNode = config.childNodes[i];
    
    // Als de xmlNode geen tag (nodeType = 1) is, moet de xmlNode
    // overgeslagen worden
    if(xmlNode.nodeType != 1) {
      continue;
    }
    
    switch (xmlNode.tagName)
    {
      case "script":
        InGenious.addScript(xmlNode);
        break;
      
      case "stylesheet":
        InGenious.addStylesheet(xmlNode);
        break;
      
      default:
        break;
    }
  }
    
  // Deactiveer selecteren
  document.onselectstart = function()
  {
    return false;
  }
  
  // Deactiveer de rechtermuisknop
  if(document.all) {
    document.oncontextmenu = function()
    {
      return false;
    }
  } else if(document.captureEvents) {
    document.captureEvents(Event.MOUSEDOWN);
    document.onmousedown = function(evt)
    {
      if (evt.which == 3) {
        return false;
      }
    }
  } else {
    document.onmouseup = function(evt)
    {
      if (evt.button == 3) {
        event.preventDefault();
      }
    }
  }
  
  // Open de default pagina
  InGenious.page = new Page();
  InGenious.page.open(InGenious.options["page"]);
};

/**
* Functie addScript(xmlNode : xmlNode)
*
* Voeg een script toe aan de browser
**/
InGenious.addScript = function(xmlNode)
{
  var script = document.createElement("script");
  script.type = "text/javascript";
  script.defer = false;
  script.src = "js/" + xmlNode.getAttribute("src");
  document.getElementsByTagName("head")[0].appendChild(script);
}

/**
* Functie addStylesheet(xmlNode : xmlNode)
*
* Voeg een stylesheet toe aan de browser
**/
InGenious.addStylesheet = function(xmlNode)
{
  var stylesheet = document.createElement("link");
  stylesheet.rel = "stylesheet";
  stylesheet.href = "css/" + xmlNode.getAttribute("src");
  
  document.getElementsByTagName("head")[0].appendChild(stylesheet);
}
