/**
 * Draggable-Klasse
 * 
 * @param {String} htmlAreaToDragOnId Die ID des HTML-Elements wodrauf geklickt wird.
 * @param {String} allUmschliessendesHTMLElementId 
 * @param {String} artId  Jedes DropTarget kann eine Art haben. Hat es eine Art können nur DragObjekte 
 *                                  dran gehangen werden, welche die entsprechende Art übergeben bekommen haben. 
 *                                  Hat das DraopTarget keine Art so kann jedes DragElement dran gehangen werden.
 */
var Draggable = function(htmlAreaToDragOnId, allUmschliessendesHTMLElementId, artId)
{
	// das zu bewegende Objekt
	//Draggable.actualDragObject = null;                              // statischer Member, welches das Objekt, das sich grade bewegt speichert

	// HTML-Elemente
	var htmlAreaToDragOn = document.getElementById(htmlAreaToDragOnId);
	this.htmlAreaToDragOn = htmlAreaToDragOn;                         // Das Element was auf den onclick reagieren soll wird als Member angelegt
	this.htmlAreaToDragOn.parentObject = this;                        // und bekommt die Referenz auf das eigene Objekt als "nachträglicher" Member
	//this.areaForSettings; 
	//this.areaForContent; 
	if(allUmschliessendesHTMLElementId)
	   this.rootElement = document.getElementById(allUmschliessendesHTMLElementId);
	else
	   this.rootElement = this.htmlAreaToDragOn.parentNode;              // rootElement ist das Element, was in seiner Gesamtheit bewegt werden soll
	this.rootElement.parentObject = this;                             // und bekommt die Referenz auf das eigene Objekt als "nachträglicher" Member
	this.platzhalter = null;                                          // der Platzhalter welcher angezeigt werden kann 

	this.dragAndDropManager = m_DragAndDropManager;
	//this.htmlAreaToDragOn.onmousedown = this.onMouseDown;
	this.htmlAreaToDragOn.onmousedown = m_DragAndDropManager.onMouseDown; // Beim mouseDown auf dem dieses Objekts wird der Manager aufgerufen
	
	
	// Abstände vom Mauszeiger zum Rand
	this.offsetLeft;                                                  // Offset zum Rand des beweglichen Elements
	this.offsetTop;                                                   // Offset zum Rand des beweglichen Elements
	
	// Die Art zulässiger Container 
	this.artId = artId;                           // Die Art an welche Container das Draggable gehangen werden kann 
	
	// Hier werden die unrsprünglichen Werte gespeichert, bevor sie beim Bewegen verändert werden müssen
	this.UrPos           = null;                                      // Ursprüngliche Position
   this.UrStylePosition = null;                                      // Ursprüngliche Positionierungsart
   this.UrParent        = null;                                      // Ursprüngliches Element an dem das bewegliche Element hängt.  
   this.UrNextSibling   = null;                                      // Ursprüngliches Nachbarelement  
   this.UrZIndex        = null;                                      // Ursprünglicher z-Index
   this.UrBreite        = null;                                      // Breite des zum Bewegeneden Elements
   this.UrLeft          = null;                                      // Ursprünglicher linker Abstand
   this.UrTop           = null;                                      // Ursprünglicher oberer Abstand
   this.OriginalWidth   = null;                                      // Ursprüngliche Breite
   this.OriginalHeight  = null;                                      // Ursprüngliche Höhe
};



// // // // // // // // // // // // // // // // // // // // // // // // // // // // // // 
// Event-Methoden
// // // // // // // // // // // // // // // // // // // // // // // // // // // // // //

/**
 * Wird nicht direkt vom Event ausgelöst aber deligiert
 * 
 * @param {Object} event
 */
Draggable.prototype.mouseDown = function(event)
{
		var elementToMove = this.rootElement; 
		
//    // definiert man den Move-Event auf der areaToDragOn, kann es passieren, dass der Mauszeiger 
//    // den Bereich verlässt und das Objekt sich nicht mehr bewegt 	 
//		this.onmousemove = function(event)
//		{
//		   event = event || window.event;                                  // event überprüfen und IE-kompatibel machen
//		   this.parentObject.onMouseMove(event);
//		};
		
	   var mousePosition = getMouseCoords(event);

      // alte Erscheinung speichern
		this.UrPos           = getPosition(elementToMove);               // ursprüngliche Koordinaten 
		this.UrStylePosition = elementToMove.style.position;
		this.UrParent        = elementToMove.parentNode;                 // ursprünglicher parent vom übergebenen DragObjekt
		this.UrNextSibling   = elementToMove.nextSibling;                // ursprünglicher nächster Nachbar vom übergebenen DragObjekt
		this.UrZIndex        = elementToMove.style.zIndex;
		this.UrBreite        = elementToMove.style.width;
		this.UrTop           = elementToMove.style.top;
		this.UrLeft          = elementToMove.style.left;
		this.OriginalWidth   = elementToMove.style.width;               // ursprüngliche Breite merken
		this.OriginalHeight  = elementToMove.style.height;              // ursprüngliche Höhe merken
		
      // Bewegung initialisieren

		this.offsetLeft = 0;           
      this.offsetTop = 0;
		
		var left = getPosition(elementToMove).x;
      var top  = getPosition(elementToMove).y;

      this.offsetLeft = mousePosition.x - left;           
      this.offsetTop = mousePosition.y - top;

		//
		// Höhe und Breite fixieren
		//
		elementToMove.style.width = getStyleValue (elementToMove, "width");
		elementToMove.style.height = getStyleValue (elementToMove, "height");
      elementToMove.style.height = this.rootElement.offsetHeight;                // IE
      elementToMove.style.width  = this.rootElement.offsetWidth;                 // IE
		
      // Positionierung wird jetzt absolut
		elementToMove.style.position = 'absolute';                       // die Positionierung vom DragObjekt auf absolut stellen
		
		// 
		elementToMove.style.left = (mousePosition.x - this.offsetLeft) + "px";     // DragObjekt in x-Richtung verschieben?
      elementToMove.style.top = (mousePosition.y - this.offsetTop) + "px";      // DragObjekt in y-Richtung verschieben?
    
      elementToMove.style.zIndex = "11000";
      document.getElementsByTagName("BODY")[0].appendChild(elementToMove);
};


/**
 * Funktionalität zum Bewegen des Draggables
 * Wird nicht direkt vom Event ausgelöst aber deligiert
 * 
 * @param {Object} event
 */
Draggable.prototype.mouseMove = function(event)
{
		var mousePosition = getMouseCoords(event);
		
	   this.rootElement.style.left = (mousePosition.x - this.offsetLeft) + "px";     // DragObjekt in x-Richtung verschieben
	   this.rootElement.style.top = (mousePosition.y - this.offsetTop) + "px";      // DragObjekt in y-Richtung verschieben
	   
		// Wenn kein Container zugeordnet ist
		//Draggable.actualDragObject.platzhalterAnzeigenUndPlatzSchaffen(event);
		//this.platzhalterAnzeigenUndPlatzSchaffen(event);

      return;
};


/**
 * Wird nicht direkt vom Event ausgelöst aber deligiert
 * 
 * @param {Object} event
 */
Draggable.prototype.mouseUp = function(event)
{
//	console.log("Draggable.prototype.mouseUp");
/*
		//writeToDocumentBody("onMouseUp - Eventhandler werden wieder auf null gesetzt");
		if(Draggable.actualDragObject == null)
         return;
			
		// Werte des HTML-Elements zurücksetzen
		Draggable.actualDragObject.bringZurueckZurUrspruenglichenPosition();
		
		Draggable.actualDragObject = null;     // kein DragObjekt reagiert jetzt mehr
*/ 
	//
	// Orginalgröße merken und Größe auf die aktuelle festsetzen.
	//
	this.rootElement.style.width = this.OriginalWidth;
	this.rootElement.style.height = this.OriginalHeight;

};


	

   

// // // // // // // // // // // // // // // // // // // // // // // // // // // // // // 
// Commands
// // // // // // // // // // // // // // // // // // // // // // // // // // // // // //
	
/**
 * Platzhalter mit den gleichen Maßen erstellen und zurück geben
 */
Draggable.prototype.getPlatzhalter = function()
{
	//
	// Platzhalter anzeigen
	//
	if(this.platzhalter && this.platzhalter.parentNode)
		this.platzhalter.parentNode.removeChild(this.platzhalter);
		
	this.platzhalter = document.createElement(this.rootElement.tagName);       // Platzhalter erstellen
	
	//this.platzhalter.style.borderColor = "#BBBBBB";
	this.platzhalter.style.borderColor = "orange";
	this.platzhalter.style.borderWidth = "2px";
	this.platzhalter.style.borderStyle = "dashed";

   // Platzhalter in die Form des dragObjekts bringen
	this.platzhalter.style.height      = getStyleValue (this.rootElement, "height");
	this.platzhalter.style.height      = this.rootElement.offsetHeight;                // IE
	this.platzhalter.style.width       = getStyleValue (this.rootElement, "width");
	
	//this.platzhalter.style.cssFloat    = getStyleValue (this.rootElement, "cssFloat");
	//this.platzhalter.style.styleFloat  = getStyleValue (this.rootElement, "styleFloat");
	this.platzhalter.style.cssFloat    = this.rootElement.style.cssFloat;
	this.platzhalter.style.styleFloat  = this.rootElement.style.styleFloat;
	
	return this.platzhalter;
}

/**
 * Entfernt den Platzhalter dieses Draggables
 */
Draggable.prototype.destroyPlatzhalter = function()
{
	if(this.platzhalter)
	{
	   this.platzhalter = null;
		this.platzhalter.parentNode.remove(this.platzhalter);
	}
}

/**
 * Versteckt das Draggable
 */
Draggable.prototype.hide = function()
{
   this.rootElement.style.display = "none";	
}

/**
 * Zeigt das Draggable
 */
Draggable.prototype.makeVisibile = function()
{
	this.rootElement.style.display = "";
}


/**
 * TODO: Kommt das besser ins DropTarget????
 * Das aktuell bewegte Objekt springt wieder zurück.
 */
Draggable.prototype.bringZurueckZurUrspruenglichenPosition = function()
{
		var elementToMove = this.rootElement;
      
		// Das umschließende Element des Draggables verstecken		
      elementToMove.style.visibility="hidden";
				 
      // war der Parent ein zugeordneter und zulässiger ZielContainer und hatte das dragObjekt ein ihm folgendes GeschwisterElement?
      // wird mit insertBefore das dragObjekt wieder zurück gebracht
		
      //if (this.UrNextSibling && this.UrNextSibling.id)
		
      if (this.UrNextSibling) // TODO So ists eigentlich korrekter (vor allem für die Vorgangsliste)
		{
          this.UrParent.insertBefore(elementToMove, this.UrNextSibling);
		} 
      // war der Parent ein zugeordneter und zulässiger ZielContainer und hatte das dragObjekt kein folgendes GeschwisterElement?
      // wird mit einfachen appendChild das dragObjekt wieder zurück gebracht
      else
		{
          this.UrParent.appendChild(elementToMove);
		}
		
		// alte Werte wieder herstellen		 
		this.recallOldStyleValues();
		
		// Das umschließende Element des Draggables anzeigen		
		elementToMove.style.visibility = "visible";
}

/**
 * Stellt die CSS-Werte wieder her, die beim MouseDown gespeichert wurden
 */
Draggable.prototype.recallOldStyleValues = function()
{
	var elementToMove = this.rootElement;
   elementToMove.style.position   = this.UrStylePosition;
   elementToMove.style.left       = this.UrLeft;
   elementToMove.style.top        = this.UrTop;
//   elementToMove.style.zIndex     = this.UrZIndex; 
   elementToMove.style.width      = this.UrBreite; 
   elementToMove.style.top        = this.UrTop;
   elementToMove.style.left       = this.UrLeft;	
}


Draggable.prototype.addPostionOffset = function(x,y)
{
	this.rootElement.style.left = parseInt(this.rootElement.style.left) + x + "px";     // DragObjekt in x-Richtung verschieben
	this.rootElement.style.top  = parseInt(this.rootElement.style.top)  + y + "px";     // DragObjekt in y-Richtung verschieben
}



// // // // // // // // // // // // // // // // // // // // // // // // // // // // // // 
// Queries
// // // // // // // // // // // // // // // // // // // // // // // // // // // // // //
	
/**
 * Gibt das HTML-Element zurück, was als RootElement für DragObjekt dient.
 */	
Draggable.prototype.getRootHtmlElement = function()
{
	return this.rootElement;
}

/**
 * Gibt true zurück, wenn sich der Mauspfeil auf der linken Seite des Draggables befindet.
 * Ansonsten wird false zurück gegeben.
 * @param {Object} event
 */
Draggable.prototype.istMausLinks = function(event)
{
	if(!isMouseOverElement(this.rootElement,event))              // befindet sich die Maus nicht über dem Draggable
		return null;                                              // wird null zurück gegeben
	var mousePos  = getMouseCoords(event);                       // wo befindet sich die Maus 
   var targPos   = getPosition(this.rootElement);               // wo befindet sich das draggable?
   var targWidth = parseInt(this.rootElement.offsetWidth);      // die breite des draggables
   var mitte     = targPos.x + (targWidth/2);                   // die Mitte des Draggables, aber als Abstand zum linken Rand
	
   if(mousePos.x < mitte)
   {
      return true;
   }
   else
   {
      return false;
   }
}
	
/**
 * Gibt true zurück, wenn der Mauspfeil sich in der oberen Hälfte des Draggables befindet.
 * Befindet sich die Maus in der unteren Hälfte, wird false zurück gegeben.
 * @param {Object} event
 */
Draggable.prototype.istMausOben = function(event)
{
   if(!isMouseOverElement(this.rootElement,event))              // befindet sich die Maus nicht über dem Draggable
      return null;                                              // wird null zurück gegeben
   var mousePos  = getMouseCoords(event);                       // wo befindet sich die Maus 
   var targPos   = getPosition(this.rootElement);               // wo befindet sich das draggable?
   
   var targHeight= parseInt(this.rootElement.offsetHeight);     // die Höhe des draggables
   var mitte     = targPos.y + (targHeight/2);                  // die Mitte des Draggables, aber als Abstand zum oberen Rand
   
   if(mousePos.y < mitte)
   {
      return true;
   }
   else
   {
      return false;
   }
}

/**
 * Löscht das Draggable
 * @param {Object} event
 */
Draggable.prototype.removeHTML = function()
{
   // Das HTML-Element aus dem DOM-Baum löschen   
	this.rootElement.parentNode.removeChild(this.rootElement);
}




/**
 * 
 * @param {Object} event
 */
Draggable.prototype.printKeyValueToDebuggingInfoDiv = function(key,value)
{
	  var ausgabeDiv = document.getElementById("idDivDebuggingInfosDraggable_" + this.rootElement.id);
	  if(!ausgabeDiv)
	     return;
     var keyValueDiv = document.getElementById("IdKeyValueDraggableDebuggingInfoDiv_" + this.rootElement.id + "_" + key);
     if (keyValueDiv == null )
     {
         keyValueDiv = document.createElement( "DIV" );
         keyValueDiv.id = "IdKeyValueDraggableDebuggingInfoDiv_" + this.rootElement.id + "_" + key;
         ausgabeDiv.appendChild(keyValueDiv);
     }
     keyValueDiv.innerHTML = "<p>" + key + ": " + value + "</p>";
     return ausgabeDiv;    
}



