/* ****************************************************************************************** *
 * Das Script kann frei verwendet werden, dieser Kommentar sowie die Nennung des Nicks
 * muss jedoch erhalten bleiben.
 *
 *                                                                           (c) Quaese, 2009
 * ****************************************************************************************** */
function qpReflexion(objAttr){
	this.IDName    = "reflexion";  // Name, der Bilder identifiziert, die reflektiert werden sollen
  this.AttrName  = "rel";        // Attribut, in dem Bilder identifiziert werden
  this.ReflWidth = 0.8;          // Wie weit soll Reflexion gehen 0.0 .. 1.0
  this.StartOpac = 0.7;          // Start-Transparenz (0.0 .. 1.0), 0=volle Transp., 1=keine Transp.
  this.EndOpac   = 0.0;          // End-Transparenz (0.0 .. 1.0), 0=volle Transp., 1=keine Transp.

  this.isFilterIE = false;       // true, wenn IE Version >= 5.5 (kennt filter-Eigenschaft)
  this.isIE7      = false;       // true, falls IE7 in Standard-Mode, false sonst

  // Falls bei der Instanziierung Reflexions-Attribute übergeben wurden
  if(typeof objAttr == "object")
  	this.setAttributes(objAttr);

  this.init();
};


/*
 * Attribut testen (class wird in className getauscht)
 */
qpReflexion.prototype.checkAttr = function(){
	if(this.AttrName == "class")
  	this.AttrName = "className";
};


/*
 * Klasse initialisieren: - Bilderarray erstellen
 *                        - IE-Checkvariablen initialisieren
 */
qpReflexion.prototype.init = function(){
  // IE >= 5.5
  this.isFilterIE = (/MSIE/.test(navigator.userAgent) && !window.opera && (Number(navigator.userAgent.split(";")[1].substr(navigator.userAgent.split(";")[1].search(/\d/))) >=5.5))? true : false;
  // IE7?
  this.isIE7 = (/MSIE/.test(navigator.userAgent) && !window.opera && (Number(navigator.userAgent.split(";")[1].substr(navigator.userAgent.split(";")[1].search(/\d/))) >=7))? true : false;

  // Attribute setzen (wg. IE)
  this.setAttributes({len: this.ReflWidth, start: this.StartOpac, end: this.EndOpac});

	// Kollektion mit allen Bildern im Dokument
  var arrHelp = document.getElementsByTagName("img");

  // Attribut-Eigenschaft checken
  this.checkAttr();

  // Kollektion rückwärts durchlaufen
  for(var i=arrHelp.length-1; i>=0; i--){
		// String ermitteln, der den Reflexions-Identifikations-String enthalten kann
  	var strHelp = (this.AttrName != "className" && (typeof arrHelp[i].getAttribute(this.AttrName) == "string"))? arrHelp[i].getAttribute(this.AttrName) : ((this.AttrName=="className")? arrHelp[i].className : "");

    // Suchmaske für Reflexions-Identifikations-String
    var strPattern = eval("/\\b"+this.IDName+"\\b/");

    // Falls das Attribut mit der Suchmaske übereinstimmt
    if(strHelp.search(strPattern) != -1){
      this.setReflection(arrHelp[i]);
    }
  }
};


/*
 * Methode zum Verarbeiten übergebener Bildobjekte/Bildobjektarrays
 * Übergabe: objArg - Einzelbildobjekt oder Array mit Bildobjekten
 */
qpReflexion.prototype.Reflect = function(objArg){
	try{
	  // Falls es sich um ein Array handelt
	  if(objArg.length > 0){
	    for(var i=objArg.length-1; i>=0; i--){
	      this.setReflection(objArg[i]);
	    }
	  // Falls es ein einzelnes Objekt ist
	  }else{
	    this.setReflection(objArg);
	  }
  }catch(objException){
  	this.setReflection(objArg);
  }
};


/*
 * Methode zum Setzen der Transparenz- und Reflexionswerte
 * Übergabe: objAttr - Objekt mit den Attributwerten
 *                     Form: {len: wert-len, start: wert-start, end: wert-end}
 */
qpReflexion.prototype.setAttributes = function(objAttr){
	if(typeof objAttr == "object"){
  	for(var strEntry in objAttr){
    	switch(strEntry.toLowerCase()){
      	case "len"		:	this.ReflWidth = ((Number(objAttr[strEntry])>=0) && (Number(objAttr[strEntry])<=1))? Number(objAttr[strEntry]) : 1.0;
        								break;
      	case "start"	:	this.StartOpac = ((Number(objAttr[strEntry])>=0) && (Number(objAttr[strEntry])<=1))? Number(objAttr[strEntry]) : 0.8;
        								this.StartOpacIE = parseInt(100 * this.StartOpac);
        								break;
      	case "end"		:	this.EndOpac = ((Number(objAttr[strEntry])>=0) && (Number(objAttr[strEntry])<=1))? Number(objAttr[strEntry]) : 0.0;
        								this.EndOpacIE = parseInt(100 * this.EndOpac);
        								break;
      }
    }
  }
};


/*
 * Bildobjekt mit Reflexion versehen
 * Das Bildobjekt wird aus dem Dokument genommen und durch ein Reflexionskonstrukt
 * ersetzt. Das umschliessende Element wird dabei mit dem CSS-Klassenattribut
 * "refl-class" versehen (<elem class="refl-class">Reflexionskonstrukt</elem>).
 *
 * Übergabe: objImg - Bildobjekt, das mit Reflexionseffekt versehen werden soll
 */
qpReflexion.prototype.setReflection = function(objImg){
	// Test, ob Bildobjekt existiert
	try{
  	objImg.src;
  }catch(objExc){
  	return;
  }

  // Ermitteln, ob Orginalbild versteckt werden soll
  var blnHide = (this.GetStyle(objImg, 'display', 'display') == "none")? true : false;

  // wg. Opera Bild kurz sichtbar machen -> sonst können keine Dimensionen bestimmt werden
  if(blnHide)
	  objImg.style.display = "block";
  // Bilddimensionen ermitteln (falls Bild vergrössert oder verkleinert)
  var intWidth = parseInt(this.GetStyle(objImg, "width", "width"));
  var intHeight = parseInt(this.GetStyle(objImg, "height", "height"));
  // Falls notwendig, wieder verstecken
  if(blnHide)
	  objImg.style.display = "none";

	// Falls der Browser das Canvas-Element kennt
  if (document.createElement("canvas").getContext){

    // Neues Canvas-Element anlegen
    var objCanvas = document.createElement("canvas");
    objCanvas.className = "refl-class";

    // CSS-Formatierungen von Bild an Canvas
    objCanvas.style.cssText = objImg.style.cssText;

    // Canvas-Element in jedem Fall anzeigen
    if(blnHide)
      objCanvas.style.display = "";

    // Canvas-Element formatieren
    objCanvas.width = intWidth;                                                     // Breite
    objCanvas.height = (blnHide)? intHeight : 2*intHeight;                          // Höhe
    objCanvas.style.width = intWidth + "px";                                        // Breite (über CSS)
    objCanvas.style.height = (blnHide)? (intHeight + "px") : (2*intHeight + "px");  // Höhe (über CSS)

    // Kontext
    var objContext = objCanvas.getContext('2d');

    // Kontext-Zustand sichern
    objContext.save();
    var intMove = (blnHide)? (intHeight-1): (2*intHeight-1);
    // Um doppelte Bildhöhe nach unten verschieben
    objContext.translate(0, intMove);
    // Bild nach oben spiegeln = negative Skalierung um negative Ausgangsgrösse
    objContext.scale(1, -1);
    // Vertikal gespiegeltes Bild in Kontext zeichnen
    objContext.drawImage(objImg, 0, 0, intWidth, intHeight);
    // Zustand des Kontextes wiederherstellen
    objContext.restore();

    // Kontext-Zustand speichern
    objContext.save();
    intMove = (blnHide)? 0: intHeight;
    // Um Bildhöhe verschieben
    objContext.translate(0, intMove);
    // Verknüpfungseigenschaft festlegen
    objContext.globalCompositeOperation = "destination-in";
    // Veritkalen linearen Verlauf für Bildhöhe instanziieren
    var objGradient = objContext.createLinearGradient(0, 0, 0, intHeight);
    // Verlaufspunkte setzen
    objGradient.addColorStop(0, "rgba(0,0,0,"+ this.StartOpac +")");            // Anfangswerte: Farbe/Transparenz
    objGradient.addColorStop(this.ReflWidth, "rgba(0,0,0,"+ this.EndOpac +")"); // Endwerte: Farbe/Transparenz
    // Verlaufsobjekt an Füllstyle zuweisen
    objContext.fillStyle = objGradient;
    // Rechteck mit Verlauf zeichnen (wg. Verknüpfung wird nur nicht transparenter Bereich angezeigt)
    objContext.fillRect(0, 0, intWidth, intHeight);
    // Zustandn wiederherstellen
    objContext.restore();

    // Falls das Orginalbild gezeichnet werden soll
    if(!blnHide)
	    // Bild auf Verlauf zeichnen (-> Verknüpfung)
	    objContext.drawImage(objImg, 0, 0, intWidth, intHeight);

return objCanvas;
    // Canvas in DOM einhängen
    //objImg.parentNode.replaceChild(objCanvas, objImg);

  }else{

  	// Falls es sich um einen IE grösser gleich Version 5.5 handelt
    if(this.isFilterIE){
    	// Äusseres SPAN (zum Positionieren)
			var objOuter = document.createElement("span");
      objOuter.className = "refl-class";
      // Falls absolute oder relative Positionierung
      if(objImg.style.position=="absolute" || objImg.style.position=="relative"){
      	objOuter.style.position = objImg.style.position;
      	objOuter.style.top = (objImg.style.top!="")? objImg.style.top : "0px";
      	objOuter.style.left = (objImg.style.left!="")? objImg.style.left : "0px";
      	objOuter.style.zIndex = (objImg.style.zIndex!="")? objImg.style.zIndex : "";
      }
      // Falls Floateigenschaften gesetzt sind
      objOuter.style.styleFloat = (objImg.style.styleFloat!="")? objImg.style.styleFloat : "";
      // Margin-Eigenschaften des Bildes als Padding-Eigenschaften des Positionselements
      objOuter.style.paddingTop = objImg.style.marginTop;
      objOuter.style.paddingRight = objImg.style.marginRight;
      objOuter.style.paddingBottom = objImg.style.marginBottom;
      objOuter.style.paddingLeft = objImg.style.marginLeft;
      objOuter.style.display = "inline-block";
      //objOuter.style.border = "1px solid #000";

      // Inneres Element (relativ, damit Bilder absolut positioniert werden können)
      var objInner = document.createElement("span");
      objInner.style.position = "relative";
      objInner.style.border = objImg.style.border;
      objInner.style.background = objImg.style.background;
      if(this.isIE7)
      	objInner.style.display = "inline-block";

      // Breite und Höhe für Spacerelement ermitteln
			var intHelpW = intHelpH = 0;
			var arrCSS = new Array();
      // Grössen, die in Breite eingehen
      arrCSS[0] = new Array("paddingLeft", "paddingRight"/*, "borderLeftWidth", "borderRightWidth"*/);
      // Grössen, die in Höhe eingehen
      arrCSS[1] = new Array("paddingTop", "paddingBottom", "borderTopWidth", "borderBottomWidth");
      // Grössen addieren
      for(var j=0; j<arrCSS[0].length; j++){
      	intHelpW += (objImg.style[arrCSS[0][j]] != "")? parseInt(objImg.style[arrCSS[0][j]]) : 0;
      	intHelpH += (objImg.style[arrCSS[1][j]] != "")? parseInt(objImg.style[arrCSS[1][j]]) : 0;
      }

			// Versteckter iFrame als Spacer (die Grösse spannt das SPAN auf)
      var objSpacer = document.createElement("iframe");
      objSpacer.style.width = (intHelpW + intWidth) + "px";
      // Falls das Orginalbild nicht angezeigt werden soll -> halbe Höhe
      if(blnHide){
      	objSpacer.style.height = (intHelpH + intHeight) + "px";
      }else{
	      objSpacer.style.height = (intHelpH + 2*intHeight) + "px";
      }
      objSpacer.style.visibility = "hidden";
			// Spacer in inneres Element einhängen
      objInner.appendChild(objSpacer);

      // Padding-Eigenschaften des Bildes ermitteln (werden als absolute Grössen left und top zugewiesen)
      intHelpW = (objImg.style.paddingLeft != "")? parseInt(objImg.style.paddingLeft) : 0;
      intHelpH = (objImg.style.paddingTop != "")? parseInt(objImg.style.paddingTop) : 0;

      // Orginalbild erstellen
      var objBild = document.createElement("img");
      objBild.src = objImg.src;
      objBild.style.width = intWidth + "px";
      objBild.style.height = intHeight + "px";
      objBild.style.position = "absolute";
      // Falls das Orginalbild nicht angezeigt werden soll
      if(blnHide){
	      objBild.style.display = "none";
      }
			// Falls es sich um den IE7 im Standardmode handelt (interpretiert Boxmodell korrekt)
      if(this.isIE7 && (window.document.compatMode == "CSS1Compat")){
        var intBorderTop = intBorderLeft = 0;
      }else{
      	// Rahmenstärken oben und links ermitteln
	      var intBorderTop = (objImg.style.borderTopWidth != "")? parseInt(objImg.style.borderTopWidth) : 0;
	      var intBorderLeft = (objImg.style.borderLeftWidth != "")? parseInt(objImg.style.borderLeftWidth) : 0;
      }
      // Bild positionieren
      objBild.style.top = (intHelpH+intBorderTop) + "px";   // Obere Rahmenstärke + paddingTop-objImg
      objBild.style.left = (intHelpW+intBorderLeft) + "px"; // Linke Rahmenstärke + paddingLeft-objImg
			// Orginalbild in inneres Element einhängen
      objInner.appendChild(objBild);

      // Reflexionsbild
      var objBild = document.createElement("img");
      objBild.src = objImg.src;
      objBild.style.width = intWidth + "px";
      objBild.style.height = intHeight + "px";
      objBild.style.position = "absolute";
      // Falls das Orginalbild nicht angezeigt wird
      if(blnHide){
	      objBild.style.top = (intHelpH+intBorderTop) + "px";
      // Sonst
      }else{
	      objBild.style.top = (intHelpH+intHeight+intBorderTop) + "px";
      }
      objBild.style.left = (intHelpW+intBorderLeft) + "px";
      objBild.style.filter = "flipv progid:DXImageTransform.Microsoft.Alpha(opacity="+this.StartOpacIE+", style=1, finishOpacity="+this.EndOpacIE+", startx=0, starty=0, finishx=0, finishy="+parseInt(this.ReflWidth*intHeight)+")";
      // Reflexionsbild in inneres Element einhängen
      objInner.appendChild(objBild);

      // Inneres Element in äusseres einhängen
      objOuter.appendChild(objInner);

      // Ausgabeelement in zugehörigem Elternelement einhängen
      var objParent = objImg.parentNode;

return objOuter;
      //objParent.replaceChild(objOuter, objImg);
    }

  }  // ENDE - else
};  // ENDE - setReflection


/*
 * Methode ermittelt aktuellen CSS-Wert zu einer Eigenschaft
 *
 * Übergabe: objElem          - Element, dessen Eigenschaft ausgelesen werden soll
 *           strCSS, strCSSjs - Eigenschaft in CSS- (strCSS) und JS-Syntax (strCSSjs)
 * Rückgabe: CSS-Wert
 */
qpReflexion.prototype.GetStyle = function(objElem, strCSS, strCSSjs){
  //  Falls der Brower die Methode "getComputedStyle" kennt (W3C-DOM)
  if(window.getComputedStyle){
    strStyle = window.getComputedStyle(objElem, null).getPropertyValue(strCSS);  // strCSS z.B. font-size
  //  Falls der Browser die Methode "currentStyle" kennt (neuere IEs)
  }else if(objElem.currentStyle){
    strStyle = objElem.currentStyle[strCSSjs];                                   // strCSSjs z.B. fontSize
  }

  return strStyle;
};
