var blibs;
if(!blibs) blibs = {};
if(!blibs.HtmlToolbox) blibs.HtmlToolbox = {};

///////////////////////////////////////////////////////////////////////////////////////////

/**
 * Liefert den momentan vom Browser benutzen Style-Definition zurück.
 * Kann (z.B. bei width) von den Angaben im Stylesheet abweichen
 *
 * @param  DOMElement domElt
 * @param  String     property
 * @return String
 */
blibs.HtmlToolbox.getComputedStyle = function(domElt, property)
{
   if(domElt.currentStyle) // IE API
      return domElt.currentStyle[property];
   else if (document.defaultView && document.defaultView.getComputedStyle) // Standard
      return document.defaultView.getComputedStyle(domElt, null).getPropertyValue(property);
}
// End getComputedStyle

///////////////////////////////////////////////////////////////////////////////////////////

/**
 * Returns the computed width in pixel
 * The functions work on any(?) block element, regardless of whether or not it has a predefined width/height.
 * It has been tested in Internet Explorer 6 & 7, Firefox, Safari and Opera.
 *
 * @param DOMElement domElt
 * @param Boolean includePadding
 * @param Boolean includeBorder
 * @return Integer
 */
blibs.HtmlToolbox.getComputedWidth = function(domElt, includePadding, includeBorder)
{
   var width;
   domElt = (typeof(domElt) === "string") ? document.getElementById(domElt) : domElt;

   if(document.defaultView && document.defaultView.getComputedStyle)
   { // FF, Safari, Opera
      var style = document.defaultView.getComputedStyle(domElt, null);

      if (style.getPropertyValue("display") === "none")
         return 0;

      width = parseInt(style.getPropertyValue("width"));

      if (/opera/i.test(navigator.userAgent))
      {
         // opera includes the padding and border when reporting the width/height - subtract that out
         width -= parseInt(style.getPropertyValue("padding-left"));
         width -= parseInt(style.getPropertyValue("padding-right"));
         width -= parseInt(style.getPropertyValue("border-left-width"));
         width -= parseInt(style.getPropertyValue("border-right-width"));
      }

      if (includePadding)
      {
         width += parseInt(style.getPropertyValue("padding-left"));
         width += parseInt(style.getPropertyValue("padding-right"));
      }

      if (includeBorder)
      {
         width += parseInt(style.getPropertyValue("border-left-width"));
         width += parseInt(style.getPropertyValue("border-right-width"));
      }
   }
   else
   { // IE
      if (domElt.currentStyle["display"] === "none")
         return 0;

      var bRegex = /thin|medium|thick/; // regex for css border width keywords
      width = domElt.offsetWidth; // currently the width including padding + border

      if (!includeBorder)
      {
         var borderLeftCSS = domElt.currentStyle["borderLeftWidth"];
         var borderRightCSS = domElt.currentStyle["borderRightWidth"];
         var temp = document.createElement("DIV");

         if (domElt.offsetWidth > domElt.clientWidth && domElt.currentStyle["borderLeftStyle"] !== "none")
         {
            if (!bRegex.test(borderLeftCSS))
            {
               temp.style.width = borderLeftCSS;
               domElt.parentNode.appendChild(temp);
               width -= Math.round(temp.offsetWidth);
               domElt.parentNode.removeChild(temp);
            }
            else if (bRegex.test(borderLeftCSS))
            {
               temp.style.width = "10px";
               temp.style.border = borderLeftCSS + " " + domElt.currentStyle["borderLeftStyle"] + " #000000";
               domElt.parentNode.appendChild(temp);
               width -= Math.round((temp.offsetWidth-10)/2);
               domElt.parentNode.removeChild(temp);
            }
         }

         if (domElt.offsetWidth > domElt.clientWidth && domElt.currentStyle["borderRightStyle"] !== "none")
         {
            if (!bRegex.test(borderRightCSS))
            {
               temp.style.width = borderRightCSS;
               domElt.parentNode.appendChild(temp);
               width -= Math.round(temp.offsetWidth);
               domElt.parentNode.removeChild(temp);
            }
            else if (bRegex.test(borderRightCSS))
            {
               temp.style.width = "10px";
               temp.style.border = borderRightCSS + " " + domElt.currentStyle["borderRightStyle"] + " #000000";
               domElt.parentNode.appendChild(temp);
               width -= Math.round((temp.offsetWidth-10)/2);
               domElt.parentNode.removeChild(temp);
            }
         }
      }

      if (!includePadding)
      {
         var paddingLeftCSS = domElt.currentStyle["paddingLeft"];
         var paddingRightCSS = domElt.currentStyle["paddingRight"];
         var temp = document.createElement("DIV");
         temp.style.width = paddingLeftCSS;
         domElt.parentNode.appendChild(temp);
         width -= Math.round(temp.offsetWidth);
         temp.style.width = paddingRightCSS;
         width -= Math.round(temp.offsetWidth);
         domElt.parentNode.removeChild(temp);
      }
   }

   return width;
}
// End getComputedWidth

///////////////////////////////////////////////////////////////////////////////////////////

/**
 * Returns the computed height in pixel
 * The functions work on any(?) block element, regardless of whether or not it has a predefined width/height.
 * It has been tested in Internet Explorer 6 & 7, Firefox, Safari and Opera.
 *
 * @param DOMElement domElt
 * @param Boolean includePadding
 * @param Boolean includeBorder
 * @return Integer
 */
blibs.HtmlToolbox.getComputedHeight = function(domElt, includePadding, includeBorder)
{
   var height;

   domElt = (typeof(domElt) === "string") ? document.getElementById(domElt) : domElt;

   if(document.defaultView && document.defaultView.getComputedStyle)
   { // FF, Safari, Opera
      var style = document.defaultView.getComputedStyle(domElt, null);

      if (style.getPropertyValue("display") === "none")
         return 0;

      height = parseInt(style.getPropertyValue("height"));

      if (/opera/i.test(navigator.userAgent))
      {
         // opera includes the padding and border when reporting the width/height - subtract that out
         height -= parseInt(style.getPropertyValue("padding-top"));
         height -= parseInt(style.getPropertyValue("padding-bottom"));
         height -= parseInt(style.getPropertyValue("border-top-width"));
         height -= parseInt(style.getPropertyValue("border-bottom-width"));
      }

      if (includePadding)
      {
         height += parseInt(style.getPropertyValue("padding-top"));
         height += parseInt(style.getPropertyValue("padding-bottom"));
      }

      if (includeBorder)
      {
         height += parseInt(style.getPropertyValue("border-top-width"));
         height += parseInt(style.getPropertyValue("border-bottom-width"));
      }
    }
   else
   { // IE
      if (domElt.currentStyle["display"] === "none")
         return 0;

      var bRegex = /thin|medium|thick/; // regex for css border width keywords
      height = domElt.offsetHeight; // currently the height including padding + border

      if (!includeBorder)
      {
         var borderTopCSS = domElt.currentStyle["borderTopWidth"];
         var borderBottomCSS = domElt.currentStyle["borderBottomWidth"];
         var temp = document.createElement("DIV");

         if (domElt.offsetHeight > domElt.clientHeight && domElt.currentStyle["borderTopStyle"] !== "none")
         {
            if (!bRegex.test(borderTopCSS))
            {
               temp.style.width = borderTopCSS;
               domElt.parentNode.appendChild(temp);
               height -= Math.round(temp.offsetWidth);
               domElt.parentNode.removeChild(temp);
            }
            else if (bRegex.test(borderTopCSS))
            {
               temp.style.width = "10px";
               temp.style.border = borderTopCSS + " " + domElt.currentStyle["borderTopStyle"] + " #000000";
               domElt.parentNode.appendChild(temp);
               height -= Math.round((temp.offsetWidth-10)/2);
               domElt.parentNode.removeChild(temp);
            }
         }

         if (domElt.offsetHeight > domElt.clientHeight && domElt.currentStyle["borderBottomStyle"] !== "none")
         {
            if (!bRegex.test(borderBottomCSS))
            {
               temp.style.width = borderBottomCSS;
               domElt.parentNode.appendChild(temp);
               height -= Math.round(temp.offsetWidth);
               domElt.parentNode.removeChild(temp);
            }
            else if (bRegex.test(borderBottomCSS))
            {
               temp.style.width = "10px";
               temp.style.border = borderBottomCSS + " " + domElt.currentStyle["borderBottomStyle"] + " #000000";
               domElt.parentNode.appendChild(temp);
               height -= Math.round((temp.offsetWidth-10)/2);
               domElt.parentNode.removeChild(temp);
            }
         }
      }

      if (!includePadding)
      {
         var paddingTopCSS = domElt.currentStyle["paddingTop"];
         var paddingBottomCSS = domElt.currentStyle["paddingBottom"];
         var temp = document.createElement("DIV");
         temp.style.width = paddingTopCSS;
         domElt.parentNode.appendChild(temp);
         height -= Math.round(temp.offsetWidth);
         temp.style.width = paddingBottomCSS;
         height -= Math.round(temp.offsetWidth);
         domElt.parentNode.removeChild(temp);
      }
   }

   return height;
}
// End getComputedHeight

///////////////////////////////////////////////////////////////////////////////////////////

/**
 * Ermittelt wie breit das Element als Blockelement wäre
 *
 * @param DOMElement domElt
 * @return int
 */
blibs.HtmlToolbox.getBlockWidth = function(domElt, includePadding, includeBorder)
{
   // Ermitteln des aktuellen display-Styles
   var displayStyle = blibs.HtmlToolbox.getComputedStyle(domElt, 'display');

   // Display-Style auf Block setzen
   if(displayStyle != 'block')
      domElt.style.display = 'block';

   // opera needs focus to recalculate the size
   if(window.opera)
      domElt.focus();

   // holt die computedWidth ohne padding und border
   var width = blibs.HtmlToolbox.getComputedWidth(domElt, includePadding, includeBorder);

   // Display-Style wieder auf den alten Wert setzen
   if(displayStyle != 'block')
      domElt.style.display = displayStyle;

   return width;
}
// End getBlockWidth

///////////////////////////////////////////////////////////////////////////////////////////

/**
 * Ermittelt wie hoch das Element als Blockelement wäre
 *
 * @param DOMElement domElt
 * @return int
 */
blibs.HtmlToolbox.getBlockHeight = function(domElt, includePadding, includeBorder)
{
   // Ermitteln des aktuellen display-Styles
   var displayStyle = blibs.HtmlToolbox.getComputedStyle(domElt, 'display');

   // Display-Style auf Block setzen
   if(displayStyle != 'block')
      domElt.style.display = 'block';

   // opera needs focus to recalculate the size
   if(window.opera)
      domElt.focus();

   // holt die computedWidth ohne padding und border
   var height = blibs.HtmlToolbox.getComputedHeight(domElt, includePadding, includeBorder);

   // Display-Style wieder auf den alten Wert setzen
   if(displayStyle != 'block')
      domElt.style.display = displayStyle;

   return height;
}
// End getBlockHeight

///////////////////////////////////////////////////////////////////////////////////////////

/**
 * Der übergebene String wird per DomText an das DomElt angehängt.
 * Nach n Reihen wird der String mit einem Finisher-String abgeschnitten.
 * Überlange Worte werden einfach in der nächsten Zeile weitergeführt.
 */
blibs.HtmlToolbox.appendStrCutToDomElt = function(domElt, string, rows, finisher)
{
   if (finisher == false)
      finisher = '';
   else if(finisher == undefined || typeof finisher != 'string')
      finisher = '...';

   // Ermitteln wie breit das Element als Blockelement wäre
   var width = blibs.HtmlToolbox.getBlockWidth(domElt, true, true);

   // Einen ersten (leeren) DomText einhängen.
   // Ein &nbsp für den Safari 1.3, sonst entsteht die TextNode nicht
   var domText = domElt.appendChild(document.createTextNode('\u00a0'));

   // Beginn mit der ersten Zeile
   var rowCount = 1;
   var rowWordCount = 0;

   // Den übergebenen String bei Leerzeichen splitten
   var splitted = string.split(" ");
   if(typeof splitted != 'object')
      splitted = [string];

   // Lokale Funktion die aufgerufen wird um immer ein Wort an den DomText anzuhängen
   var appendNextWord = function(word)
   {
      var heightBefore = domElt.offsetHeight;

      // Wenn es nicht das erste Wort ist, ein Space davorhängen, ansonsten das &nbsp; rausnehmen
      if(domText.nodeValue == '\u00a0')
      {
         domText.nodeValue = '';
      }
      else
         word = " " + word;

      // Das Wort wir angehängt
      domText.nodeValue += word;

      // Ein erzwungenes aufbereiten des Browser-Contents, sonst stimmen die Breiten- und Höhenangaben nicht
      blibs.HtmlToolbox.forceRedraw(domElt);

      // Wenn eine neue Zeile entstanden ist...
      if(domElt.offsetHeight > heightBefore)
      {
         // RowCounter erhöhen
         rowCount++;
         rowWordCount = 0;

         // Das Wort, das die letzte Reihe zum Überlauf bringt, wieder entfernen,
         // und noch weitere Zeichen für den Finisher (Pünktchen) entfernen und diesen dafür anhängen
         if(rowCount > rows)
         {
            domText.nodeValue = domText.nodeValue.slice(0, -(word.length)-(finisher.length)) + finisher;
         }
         // Das Wort, das diese Reihe zum Überlauf bringt, wieder entfernen,
         // und ein <br> anhängen (schützt vor Problemen in verschiedenen Browsern)
         else
         {
            domText.nodeValue = domText.nodeValue.slice(0, -(word.length));
            splitted.unshift(word.slice(1,word.length));
            domElt.appendChild(document.createElement('br'));
            domText = domElt.appendChild(document.createTextNode('\u00a0'));
         }
      }
      else
      {
         rowWordCount++;
      }

      // Wenn eine das Element breiter geworden ist, als es eigentlich Platz hat...
      if(domElt.offsetWidth > width)
      {
         if(rowWordCount == 1)
         {
            // Wenn das erste Wort der Reihe länger ist als die ganze zur verfügung stehende Breite,
            // wird dieses Wort immer um drei Chars abgeschnitten, bis es passt.
            // Der Rest wird dann in die nächste Zeile angehängt
            var charCounter = 0;
            do
            {
               domText.nodeValue = domText.nodeValue.slice(0, -3);
               charCounter -= 3;
            }
            while(domElt.offsetWidth >= width && domText.nodeValue.length > 0);

            // Der Rest wird einfach als erstes Wort ins Array zurückgeschoben,
            // sodass es quasi als nächstes Wort eingehängt wird
            splitted.unshift(word.slice(charCounter));
            domElt.appendChild(document.createElement('br'));
            domText = domElt.appendChild(document.createTextNode('\u00a0'));
            rowWordCount = 0;
         }
         else
         {
            // Die Breite der Box ist breiter geworden als sie darf und
            // keinen automatischen Zeilenumbruch gemacht. (IE/Opera-Fehler)
            // In diesem Fall letztes Wort wieder herausnehmen und <br> einfügen
            //
            // Kann eigentlichnicht mehr vorkommen,
            // da oben schon für jede Zeile <br> eingehängt werden
            domText.nodeValue = domText.nodeValue.slice(0, -(word.length));
            splitted.unshift(word.slice(1,word.length));
            domElt.appendChild(document.createElement('br'));
            domText = domElt.appendChild(document.createTextNode('\u00a0'));
            rowWordCount = 0;
         }
      }
   }

   // Hier läuft die eigentliche Iteration über die Wörter des übergenen Textes
   // Muss hier unten stehen, weil die Funktionen zuerst definiert sein müssen
   do
   {
      appendNextWord(splitted.shift());
   }
   while(splitted.length && rowCount <= rows);
}
// End appendStrCutToDomElt

///////////////////////////////////////////////////////////////////////////////////////////

/**
 * Der Browser wird dazu veranlasst das übergebene Element neu zu rendern
 */
blibs.HtmlToolbox.forceRedraw = function(domElt)
{
   var display = blibs.HtmlToolbox.getComputedStyle(domElt, 'display');

   if(display != 'none')
   {
      domElt.style.display = 'none';
      domElt.style.display = display;
   }
}
// End forceRedraw

///////////////////////////////////////////////////////////////////////////////////////////

