
globalTextSpeed = 10;				// Das Interval in Millisekunden, in dem neue Elemente beim BBCode-Aufbau gezeigt werden
globalTextSpeedDefault = 10;			// Das Standardinterval (wird nach Rechtsklick wiederhergestellt)

isBBCodeRunning = false;			// Notiert, ob ein BBCode angezeigt wird
forceBreak = false;				// Notiert, ob der aktuelle Schleifendurchlauf abgebrochen werden soll

/**
  * Add BBCode converted to HTML Nodes to an element (incremental with a timeout)
  */
function addBBCode(elementName, bbCode, direct, callback) {
  isBBCodeRunning = true;			// Notiere, dass zur Zeit eine BB-Code-Funktion aktiv ist
  while(bbCode.length > 0 && !forceBreak) {		// Falls noch Text vorhanden ist und kein Abbruch erzwungen werden soll
    xShow(elementName);
    var symbol = bbCode.charAt(0);			// Hole das erste Symbol
    var sliceLength = 1;				// Die Länge des zu schneidenen Segments ist üblicherweise 1
    if(symbol == "[") {					// Falls nun BBCode folgt
      if(bbCode.search(/\[URL/i) == 0) {			// Falls es ein Hyperlink sein soll
      	var firstClosedBracket = bbCode.search(/\]/i) + 1;		// Suche die erste schließende eckige Klammer und gehe zum Symbol direkt dahinter
      	var secondOpenBracket = firstClosedBracket + bbCode.substring(firstClosedBracket).search(/\[\/URL\]/i); // Suche die zweite öffnende eckige Klammer
      	if(bbCode.charAt(4) == "=" && firstClosedBracket > 4) {	// Die URL hat einen Titel, wenn ein = Zeichen vor der ersten schliessenden eckigen Klammer ist
      	  addHyperlink(elementName, bbCode.substring(5, firstClosedBracket - 1), bbCode.substring(firstClosedBracket, secondOpenBracket));
      	} else {						// Wenn die URL keinen Titel hat, ist Hyperlink auch gleich Titel
      	  addHyperlink(elementName, bbCode.substring(firstClosedBracket, secondOpenBracket), bbCode.substring(firstClosedBracket, secondOpenBracket));
      	}
      	sliceLength = secondOpenBracket + 6;
      } else if(bbCode.search(/\[COLOR/i) == 0) {		// Falls es eine Farbe sein soll
      	var firstClosedBracket = bbCode.search(/\]/i) + 1;		// Suche die erste schließende eckige Klammer und gehe zum Symbol direkt dahinter
      	var secondOpenBracket = firstClosedBracket + bbCode.substring(firstClosedBracket).search(/\[\/COLOR\]/i); // Suche die zweite öffnende eckige Klammer
      	addColorSpan(elementName, bbCode.substring(7, firstClosedBracket - 1), bbCode.substring(firstClosedBracket, secondOpenBracket)); // Schicke Farbe und Text an die entsprechende Funktion
      	sliceLength = secondOpenBracket + 8;
      } else if(bbCode.search(/\[SPAN/i) == 0) {		// Falls es ein Span-Element sein soll
      	var firstClosedBracket = bbCode.search(/\]/i) + 1;		// Suche die erste schließende eckige Klammer und gehe zum Symbol direkt dahinter
      	var secondOpenBracket = firstClosedBracket + bbCode.substring(firstClosedBracket).search(/\[\/SPAN\]/i); // Suche die zweite öffnende eckige Klammer
      	addElemWithClass(elementName, 'span', bbCode.substring(6, firstClosedBracket - 1), bbCode.substring(firstClosedBracket, secondOpenBracket)); // Schicke Farbe und Text an die entsprechende Funktion
      	sliceLength = secondOpenBracket + 7;
      } else if(bbCode.search(/\[DIV/i) == 0) {		// Falls es ein Div-Element sein soll
      	var firstClosedBracket = bbCode.search(/\]/i) + 1;		// Suche die erste schließende eckige Klammer und gehe zum Symbol direkt dahinter
      	var secondOpenBracket = firstClosedBracket + bbCode.substring(firstClosedBracket).search(/\[\/DIV\]/i); // Suche die zweite öffnende eckige Klammer
      	addElemWithClass(elementName, 'div', bbCode.substring(5, firstClosedBracket - 1), bbCode.substring(firstClosedBracket, secondOpenBracket)); // Schicke Farbe und Text an die entsprechende Funktion
      	sliceLength = secondOpenBracket + 6;
      } else if(bbCode.search(/\[B\]/i) == 0) {			// Falls es Fettdruck sein soll
      	var firstClosedBracket = bbCode.search(/\]/i) + 1;		// Suche die erste schließende eckige Klammer und gehe zum Symbol direkt dahinter
      	var secondOpenBracket = firstClosedBracket + bbCode.substring(firstClosedBracket).search(/\[\/B\]/i); // Suche die zweite öffnende eckige Klammer
      	addBoldSpan(elementName, bbCode.substring(firstClosedBracket, secondOpenBracket)); // Schicke den Text an die entsprechende Funktion
      	sliceLength = secondOpenBracket + 4;
      } else if(bbCode.search(/\[U\]/i) == 0) {			// Falls es Unterstrichen sein soll
          var firstClosedBracket = bbCode.search(/\]/i) + 1;		// Suche die erste schließende eckige Klammer und gehe zum Symbol direkt dahinter
          var secondOpenBracket = firstClosedBracket + bbCode.substring(firstClosedBracket).search(/\[\/U\]/i); // Suche die zweite öffnende eckige Klammer
          addUnderlineSpan(elementName, bbCode.substring(firstClosedBracket, secondOpenBracket)); // Schicke den Text an die entsprechende Funktion
          sliceLength = secondOpenBracket + 4;
      } else if(bbCode.search(/\[I\]/i) == 0) {			// Falls es Fettdruck sein soll
      	var firstClosedBracket = bbCode.search(/\]/i) + 1;		// Suche die erste schließende eckige Klammer und gehe zum Symbol direkt dahinter
      	var secondOpenBracket = firstClosedBracket + bbCode.substring(firstClosedBracket).search(/\[\/I\]/i); // Suche die zweite öffnende eckige Klammer
      	addItalicSpan(elementName, bbCode.substring(firstClosedBracket, secondOpenBracket)); // Schicke den Text an die entsprechende Funktion
      	sliceLength = secondOpenBracket + 4;
      } else if(bbCode.search(/\[IMG\]/i) == 0) {		// Falls es ein Bild sein soll
      	var imgUrl = bbCode.substr(5, bbCode.search(/\[\/IMG\]/i) - 5);	// Hole die Bild-URL aus dem BBCode
      	addImage(elementName, imgUrl);					// Füge das Bild in die DOM-Struktur ein
      	sliceLength = imgUrl.length + 11;				// Berechne die Länge des BBCode-Segments, das rausgeschnitten werden kann
      } else {						// In allen anderen Fällen gehen wir von Text aus, auch wenn es nur ein [ ist
        addText(elementName, symbol);				// Füge das Symbol zu
      }
    } else if(symbol == "\n") {				// Falls ein Zeilenumbruch folgt
      addLineBreak(elementName);				// Füge einen Zeilenumbruch hinzu
    } else {						// In allen anderen Fällen gehen wir von Text aus
      addText(elementName, symbol);				// Füge das Symbol zu
    }
    if(globalTextSpeed > 0 && direct != true) {				// Falls der Text nicht auf einmal erscheinen soll
      window.setTimeout(function() { addBBCode(elementName, bbCode.slice(sliceLength), direct, callback); }, globalTextSpeed); // Setze einen Timeout
      return;							// Und verlasse die Funktion
    } else {						// Falls aller Text auf einmal erscheinen soll
      if(sliceLength <= 0) sliceLength = 1;			// Sorge dafür, dass der Text auch kleiner wird (sliceLength sollte eh immer größer 0 sein, aber man weiß ja nie)
      bbCode = bbCode.slice(sliceLength);			// Schneide den Text zurecht - nun beginnt oben die nächste Iteration
    }
  }
  
  forceBreak = false;				// Abbruch erfolgreich, nun kann es weitergehen
  isBBCodeRunning = false;			// Wenn die Schleife verlassen wird wurde aller Text angezeigt
  if(typeof(callback) == 'function') callback(); // Call the callback, if it is a function
  
}

/**
  * Füge einen Hyperlink einem Knoten hinzu
  */
function addHyperlink(elementName, linkUrl, linkText) {
  var textObject = xGetElementById(elementName);
  if(textObject) {
    var newHyperlinkNode = document.createElement("a");			// Erstelle Hyperlink
    newHyperlinkNode.href = linkUrl;					// Setze URL für Hyperlink
    //var newTextNode = document.createTextNode(linkText);		// Erstelle Textnode für Hyperlink
    //newHyperlinkNode.appendChild(newTextNode);				// Hänge Textnode unter Hyperlink
    addBBCode(newHyperlinkNode, linkText, true);
    textObject.appendChild(newHyperlinkNode);				// Füge Hyperlink ins Dokument ein
    return(newHyperlinkNode);						// Gebe neu erstelltes Element zurück
  }
  return(null);							// Gebe null zurück, da nichts erstellt werden konnte
}

/**
  * Füge einen farbigen Textbereich hinzu
  */
function addColorSpan(elementName, spanColor, spanText) {
  var textObject = xGetElementById(elementName);
  if(textObject) {
    var newColorNode = document.createElement("span");			// Erstelle Span Element
    newColorNode.style.color = spanColor;				// Setze Farbe für den Span
    addBBCode(newColorNode, spanText, true);					// Füge weiteren Text hinzu
    textObject.appendChild(newColorNode);				// Füge Span ins Dokument ein
    return(newColorNode);						// Gebe neu erstelltes Element zurück
  }
  return(null);							// Gebe null zurück, da nichts erstellt werden konnte
}

/**
  * Füge einen span mit einer bestimmten Klasse hinzu
  */
function addElemWithClass(elementName, elemType, spanClass, spanText) {
  var textObject = xGetElementById(elementName);
  if(textObject) {
    var newSpanClassNode = document.createElement(elemType);		// Erstelle gewünschtes Element (meist span oder div)
    newSpanClassNode.className = spanClass;				// Setze Farbe für den Span
    textObject.appendChild(newSpanClassNode);				// Füge Span ins Dokument ein
    addBBCode(newSpanClassNode, spanText, true);
    return(newSpanClassNode);						// Gebe neu erstelltes Element zurück
  }
  return(null);							// Gebe null zurück, da nichts erstellt werden konnte
}


/**
  * Füge einen fettgedruckten Textbereich hinzu
  */
function addBoldSpan(elementName, spanText) {
  var textObject = xGetElementById(elementName);
  if(textObject) {
    var newBoldNode = document.createElement("strong");			// Erstelle Strong Element
    textObject.appendChild(newBoldNode);				// Füge Strong ins Dokument ein
    addBBCode(newBoldNode, spanText, true);					// Füge weiteren Text hinzu
    return(newBoldNode);						// Gebe neu erstelltes Element zurück
  }
  return(null);							// Gebe null zurück, da nichts erstellt werden konnte
}

/**
   * Füge einen unterstrichenen Textbereich hinzu
   */
function addUnderlineSpan(elementName, spanText) {
  var textObject = xGetElementById(elementName);
  if(textObject) {
    var newULNode = document.createElement("span");			// Erstelle Span Element
    newULNode.style.textDecoration = 'underline';		// Unterstreich Element
    textObject.appendChild(newULNode);				// Füge Span ins Dokument ein
    addBBCode(newULNode, spanText, true);					// Füge weiteren Text hinzu
    return(newULNode);						// Gebe neu erstelltes Element zurück
  }
  return(null);							// Gebe null zurück, da nichts erstellt werden konnte
}
  
/**
  * Füge einen kursiv gedruckten Textbereich hinzu
  */
function addItalicSpan(elementName, spanText) {
  var textObject = xGetElementById(elementName);
  if(textObject) {
    var newItalicNode = document.createElement("em");			// Erstelle em Element
    textObject.appendChild(newItalicNode);				// Füge em ins Dokument ein
    addBBCode(newItalicNode, spanText, true);					// Füge weiteren Text hinzu
    return(newItalicNode);						// Gebe neu erstelltes Element zurück
  }
  return(null);							// Gebe null zurück, da nichts erstellt werden konnte
}

/**
  * Füge Text inkrementell einem Textelementknoten hinzu
  */
function addText(elementName, msgText) {
  if(msgText.length > 0) {
    var textObject = xGetElementById(elementName);
    if(textObject) {
      if(textObject.childNodes.length == 0 || textObject.lastChild.nodeType != 3) {
      	var newTextNode = document.createTextNode("");
      	textObject.appendChild(newTextNode);
      }
      textObject.lastChild.appendData(msgText);
    }
  }
}

/**
  * Füge einen Zeilenumbruch ans Ende des angegebenen Knotens
  */
function addLineBreak(elementName) {
  var textObject = xGetElementById(elementName);
  if(textObject) {
    var newBreakNode = document.createElement("br");			// Erstelle Zeilenumbruch
    textObject.appendChild(newBreakNode);				// Füge Zeilenumbruch ins Dokument ein
    return(newBreakNode);						// Gebe Zeilenumbruch zurück
  }
  return(null);							// Gebe null zurück, da nichts erstellt werden konnte
}


/**
  * Fügt als letzten Knoten unterhalb eines anderen Knotens ein Bild ein
  */
function addImage(elementName, imageUrl) {
  var imgObject = xGetElementById(elementName);	// Hole das zukünftige Elternelement
  if(imgObject) {				// Falls das Elternelement gefunden wurde
    var newImage = document.createElement("img");	// Erstelle in neues Image-Tag
    newImage.alt = "";					// Erstelle den alternativen Text (leer), um die XHTML-Anforderungen zu erfüllen
    newImage.src = imageUrl;				// Füge die Bildquelle hinzu
    newImage.style.verticalAlign = "middle";		// Zentriere das Bild vertikal
    imgObject.appendChild(newImage);			// Füge das Bild als letzten Kindknoten hinzu
    return(newImage);					// Gebe Bild-Element zurück
  }
  return(null);							// Gebe null zurück, da nichts erstellt werden konnte
}



/**
  * Beende aktuellen Lauf der BBCode-Anzeige (falls nötig) und rufe danach die genannte Funktion auf
  */
function continueAfterBBCodeEnd(funcCall) {
  globalTextSpeed = globalTextSpeedDefault;			// Stelle den Standard-BBCode-Speed her (da wir jetzt eh abbrechen)
  if(isBBCodeRunning) {						// Falls noch Code läuft
    forceBreak = true;							// Breche ihn ab
    window.setTimeout(funcCall, 100);					// Rufe 100ms später das Skript auf (100ms, damit danach der BBCode auf jeden Fall angezeigt ist)
  } else {							// Falls kein Code läuft
    window.setTimeout(funcCall, 0);					// Rufe Skript sofort auf
  }
}
