

	/* This class never gets instantiated. It is mostly for internal use by DragDrop and DragDropCopy classes */

	DDStore = function() {

		return {
				
			/* The destination being hovered over */

			hover: null,
				
			/* A valid interaction element which is being hovered over */

			hoverInt: null,
				
			/* Has as its properties all drag-drop elements which have destinations or which interact */

			DDs: {},

			/* A counter used for adding ids to drag-drop elements with no id */
				
			idNo: 0,
	
			/* Stores drag-drop elements as properties of this.DDs and gives each a destination (array) and dropNo property. 
			dropNo is for use by DragDropCopy */

			store: function(element) {

				this.DDs[element] = {};
				this.DDs[element].destinations = [];
				this.DDs[element].dropNo = 0;
			},
	
			/* Calls store method for any elements which haven't already been stored and assigns their destinations 
			to their destination property */
				
			destinate: function(destination, elements) {

				for(var i = 1; i < arguments.length; i++) {					
					if(!this.DDs[arguments[i]])
						this.store(arguments[i]);
					this.DDs[arguments[i]].destinations.push(arguments[0]);
				}
			}

		}

	}();
	   

	/* The main drag-drop class. If you are using destinations or interacting elements you should instantiate this onload to avoid
	beginning a drag-drop before other interacting elements have finished loading. If it's necessary to instantiate this onmousedown you
	you will also need to call the onMouseDown method that one time. */
	
	function DragDrop(element, options) {
		
		/* Calls the method which makes the element drag-dropable */

		this.turnOnDD(element, options);   
	}
    
	DragDrop.prototype = {
		
		/* The drag-drop object */		

		element: null,
		
		/* The id of the drag-srop object */ 		

		id: null,

		/* Stores in its properties those options passed in as optional object parameter */ 		

		options: null,

		/* Set to true when an element is given a destination. Need to set to false if you want a destined element to behave as undestined */
		
		destined: false,

		/* Stores true/false depending on whether the object is drag-dropable or not. Automatically set to false for destinations */

		isOn: false,

		/* Set to 'true' while the element is being dragged */

		isDragging: false,	

		/* Stores true/false depending on whether automatic scrolling is on or not */

		scrollAutoOn: false,

		/* Distance in pixels of mouse from bottom of page at which scrolling begins when dragging an element */

		scrollThresh: 30,

		/* Stores in .l .t properties the original left/top position of the element */

		elementOrigin: null,

		/* Stores in .l .r .t .b properties the distance of the mouse from left/right/top/bottom of the element on mousedown */

		diff: null,  //store only el position?

		/* Stores in .x .y properties the x and y coordinates of the mouse */

		moCoords: null,

		/* Sets upper limit for top side of dragged element */

		topLimit: null,

		/* Sets the bottom limit for the top side of the dragged element */

		bottomLimit: null,

		/* Sets the left limit for the left side of the dragged element */

		leftLimit: null,

		/* Sets the right limit for the left side of the dragged element */

		rightLimit: null,

		/* Set to on when limit() is called */

		limits: 'off',

		/* Set to true when holdX() is called and when true prevents movement on the X axis */

		keepX: false,

		/* Set to true when holdY() is called and when true prevens movement on the Y axis */

		keepY: false,

		/* Set to true when useRelative() is called and prevents dragdrop element from being positioned absolutely on mousedown */

		relative: false,

		_getElPos: function(element) {
	
			/* Returns positions of all four sides of the element being dragged */
			
			var element = $.id(element);
			var width = parseInt(DomUtils.getStyle(element, 'width'));
			var height = parseInt(DomUtils.getStyle(element, 'height'));
		
			var l = parseInt(DomUtils.getStyle(element, 'left'));
			var r = l + width;
			var t = parseInt(DomUtils.getStyle(element, 'top'));
			var b = t + height;

			this.elementOrigin = {l: l +'px',t: t+'px'}

			if(this.keepX == true)
				this.X = l;

			if(this.keepY == true)
				this.Y = t;

			return {l: l, r: r, t: t, b: b}	
		},

		_override: function() {
			   
			/* Sets the configurable properties and methods to the values of the respective properties/methods of this.options
			If no option available uses default value or null */ 
 
			if(this.options) {
				this.onDragStart = this.onDragStart || this.options.onDragStart;
				this.onValidDrop = this.options.onValidDrop || this.onValidDrop;
				this.onInvalidDrop = this.options.onInvalidDrop || this.onInvalidDrop;
				this.defaultValid = this.options.defaultValid || this.defaultValid;
				this.defaultInvalid = this.options.defaultInvalid || this.defaultInvalid;
				this.makePlacer = this.options.makePlacer || this.makePlacer;
				this.makeCopy = this.options.makeCopy || this.makeCopy;
				this.onInteract = this.options.onInteract || this.onInteract;
				this.onUninteract = this.options.onUninteract || this.onUninteract;
				this.defaultInteract = this.options.defaultInteract || this.defaultInteract;
				this.defaultUninteract = this.options.defaultUninteract || this.defaultUninteract;
				this.onMouseMove = this.options.onMouseMove || this.onMouseMove;
			}
		},

		_onMouseMove: function(e) {

			/* Moves the element to match the position of the mouse */

			if(this.isOn == true) {

			if (document.all && !e.button) {
			    EventUtils.stopDefault(e);
		            return this.onMouseUp(e);
			}

				this.moCoords = EventUtils.mouse(e);

				var left = (this.X || this.X == 0)? this.X: this.moCoords.x - this.diff.l;
				var top = (this.Y || this.Y == 0)? this.Y: this.moCoords.y - this.diff.t;

				if(this.limits == 'on') {

					if(top <= this.topLimit)
						top = this.topLimit;					

					if(top >= this.bottomLimit)
						top = this.bottomLimit;
					
					if(left <= this.leftLimit) 
						left = this.leftLimit;

					if(left >= this.rightLimit)
						left = this.rightLimit;
				}
			
				this.onMouseMove(left,top);

				this.element.style.left = (left || 0) + 'px';
				this.element.style.top = (top || 0) + 'px';

				EventUtils.stopDefault(e);
			}

		},

		onMouseMove: function() {

		},

		_makeSecretL: function(element, forInteract) {

			/* Makes hidden layer. Can be either on top of the drag element's destination or elements it will interact with.
			If the latter, the element's margins are added to the length/width of the hidden layer. ****BORDERS**** 
			A z-index of 999 should place the element above any others on the page. */
 
			var offset = DomUtils.getTrueOffset(element); 
			var left = offset.l + "px";
			var top = offset.t + "px";
			var marginT = (forInteract == true)? parseInt(DomUtils.getStyle(element,'margin-top')):0;
			var marginB = (forInteract == true)? parseInt(DomUtils.getStyle(element,'margin-bottom')):0;
			var marginL = (forInteract == true)? parseInt(DomUtils.getStyle(element,'margin-left')):0;
			var marginR = (forInteract == true)? parseInt(DomUtils.getStyle(element,'margin-right')):0;
			var height = parseInt(DomUtils.getStyle(element,'height')) + marginB + marginT;
			var width = parseInt(DomUtils.getStyle(element,'width')) + marginL + marginR;

			ElementHandler.putAtEnd(document.body,{tag: 'div', id: element + 'SL', style: 'width:'+width+'; height:'+height+'px; left:'+left+'; top:'+top+'; position: absolute; cursor: move; z-index: 999;'});

			/* Attaches onMouseOver and onMouseOut methods to mouseover and mouseout events on hidden layer if layer is a destination.
			Attaches defaultInteract and defaultUninteract methods if layer is for interacting */

			this._onMouseOver_wrap = (forInteract == true)? EventUtils.wrapListener(this.defaultInteract,this): EventUtils.wrapListener(this.onMouseOver,this);
			this._onMouseOut_wrap = (forInteract == true)? EventUtils.wrapListener(this.defaultUninteract,this): EventUtils.wrapListener(this.onMouseOut,this);
			EventUtils.addEventListener(element+'SL','mouseover',this._onMouseOver_wrap);
			EventUtils.addEventListener(element+'SL','mouseout',this._onMouseOut_wrap);
		},

		turnOnDD: function(element, options) {
		
			/*
			Stores element in this.element
			Gives element an id if it doesn't have one and increases value of DDStore.idNo by 1
			Stores element's id in this.id for slightly quicker reference
			Stores the optional object parameter in this.options
			Calls configuration method
			
			Attaches this.onMouseDown() and this.onMouseup() to mousedown and mouseup events respectively

			Lables the element as being on for drag-dropping

			Note: call this for destination elements if you want them to be drag-droppable.	
			*/

			this.element = $.id(element);
			if(!element.id) element.id = 'id'+DDStore.idNo;
			this.id = this.element.id;
			this.options = options;
			this._override();
			this.element._destined = this.element._destined || this.destined;

			this._onMouseDown_wrap = EventUtils.wrapListener(this.onMouseDown, this);
			this._onMouseUp_wrap = EventUtils.wrapListener(this.onMouseUp, this);
			EventUtils.addEventListener(this.element,'mousedown',this._onMouseDown_wrap);
			EventUtils.addEventListener(document,'mouseup',this._onMouseUp_wrap);

			this.isOn = true;
		},

		turnOffDD: function() {
			
			/* Removes onMouseDown and onMouseUp listeners from their respective events. Call this to remove drag-drop functionality
			for an element and call turnOnDD to reinstate it. Gets called automatically for destination elements. */
	
			EventUtils.removeEventListener(this.element,'mousedown',this._onMouseDown_wrap);
			EventUtils.removeEventListener(document,'mouseup',this._onMouseUp_wrap);
		
			this.isOn = false;
		},

		onDragStart: function() {

		/* CAN OVERRIDE by passing as method of optional object parameter. */ 

		},

		defaultValid: function() {
		
		/* CAN OVERRIDE. If you want to keep this method but add extra functality, override onValidDrop instead. */		

			/* Calls onValidDrop which can be passed in as a method of the optional object parameter */
	
			this.onValidDrop();
			
			/* If element is interacting with a valid interaction element it is inserted before it in the DOM */

			if(DDStore.hoverInt != null) {
				DomUtils.makeRelative(this.element);
				var parent = DDStore.hoverInt.parentNode;
				parent.insertBefore(this.element,DDStore.hoverInt);			

				DDStore.hoverInt = null;
			}

			/* If there's no interaction then the element is appended as last child of the destination it is over */

			else if(this.relative == false) {
				DomUtils.makeRelative(this.element);
				DDStore.hover.appendChild(this.element);
			}
		},
		
		onValidDrop: function() {

		/* CAN OVERRIDE by passing as method of optional object parameter. Adds extra functionality to defaultValid */

		},

		defaultInvalid: function() {

		/* CAN OVERRIDE. If you want to keep this method but add extra functality, override onInValidDrop instead. */
			
			/* Calls onInvalidDrop which can be passed in as a method of the optional object parameter */

			this.onInvalidDrop();

			/* Returns element to its original position */

			if(this.element._oldSibling != null)
				this.element._oldParent.insertBefore(this.element, this.element._oldSibling);
			else
				this.element._oldParent.appendChild(this.element);

			DomUtils.makeRelative(this.element);

			DDStore.hoverInt = null;
		},
		
		onInvalidDrop: function() {

		/* CAN OVERRIDE by passing as method of optional object parameter. Adds extra functionality to defaultValid */

		},
		
		defaultInteract: function(e) {
			
		/* CAN OVERRIDE. If you want to keep this method but add extra functality, override onInteract instead. */
			
			/* Calls onInvalidDrop which can be passed in as a method of the optional object parameter */
			
			this.onInteract();

			/* Stores the element being interacted with in DDStore.hoverInt and adds placer element before this element in the DOM 
			(or moves placer element if one already exists) */

			var target = EventUtils.targetElement(e).id;
			DDStore.hoverInt = $.id(target.replace(/SL/,""));
			
			ElementHandler.putBefore(DDStore.hoverInt,this.makePlacer());
		},

		onInteract: function(e) {

		/* CAN OVERRIDE by passing as method of optional object parameter. Adds extra functionality to defaultInteract */

		},

		defaultUninteract: function(e) {

		/* CAN OVERRIDE. If you want to keep this method but add extra functality, override onUninteract instead. */
			
			/* Calls onInvalidDrop which can be passed in as a method of the optional object parameter */
			
			this.onUninteract();

			/* Moves placer element to the end of the children of the destination which is being hovered over) and sets the hoverInt
			label to null */

			DDStore.hover.appendChild($.id('placer'));
			DDStore.hoverInt = null;
		},

		onUninteract: function(e) {

		/* CAN OVERRIDE by passing as method of optional object parameter. Adds extra functionality to defaultUninteract */

		},

		onMouseDown: function(e) {
			
			/* Stores the original element, as when a copy has been made the value of this.element changes to refer to the copy */

			var element = this.element;
			
			/* Calls _copy method. It exists only in DragDropCopy class, which inherits onMouseDown method from DragDrop */			

			if(this._copy) 
				this._copy();
			
			/* Positions the dragged element absolutely and as last child of 'body'. Note 'this.element' rather than 'element', 
			as 'element' no longer refers to the dragged element if a copy has been made */		

			if(this.relative == false) {
				DomUtils.makeAbsolute(this.element, true);
				document.body.appendChild(this.element);
			}			

			/* Gets mouse coordinates and stores them in .x .y properties of this.moCoords */
			
			this.moCoords = EventUtils.mouse(e);
			
			/* Gets position of all four edges of the element and uses them to calculate the distance of each from the mouse. 
			Stores the values in this.diff */

			var edges = this._getElPos(this.element);
			var diffL = this.moCoords.x - edges.l;
			var diffT = this.moCoords.y - edges.t;
			var diffR = edges.r - this.moCoords.x;
			var diffB = edges.b - this.moCoords.y;

			this.diff = {l: diffL, r: diffR, t: diffT, b: diffB}

			/* Determines whether either vertical or horizontal window scrollbars are present */			

			var x = (window.scrollMaxX > 0)? true: false; //need to find out what supports scrollMax
			var y = (window.scrollMaxY > 0)? true: false;
			
			/* Sets scrollAutoOn to false if no scrollbars present, and sets its .x .y properties to true or false
			appropriately if either vertical or horizontal scrolling is present */		

			this.scrollAutoOn = (x == false && y == false)? false: {x: x, y: y};

			if(this.element._destined == true) { 

				var id = DDStore.DDs[element.id].destinations;
				var l = id.length;

				/* Makes hidden layer for each destination of the dragging element */

				for (var i=0; i<l; i++)
					this._makeSecretL(id[i]);
			}
	
			/* Attaches ._onMouseMove to mousemove event */

			this._onMouseMove_wrap = EventUtils.wrapListener(this._onMouseMove, this);
			EventUtils.addEventListener(document,'mousemove',this._onMouseMove_wrap);
			
			/* Labels the element as being dragged */
			this.isDragging = true;		
			
			/* Calls optional method */

			this.onDragStart();

			EventUtils.addEventListener(window,'mouseover',this._onMouseUp_wrap);
			EventUtils.stopDefault(e);

		},  	

		onMouseUp: function(e) {

			if(EventUtils.relTarget(e))
				return;

			/* Because this method is attached to the document need to detect which element is being dragged 
			****should think about turning it off for those not needing it**** */

			if(this.isDragging == false)
				return;
			
			/* Remove all hidden layers */
			
			while (document.body.lastChild.id && document.body.lastChild.id.indexOf("SL") != -1) {
				document.body.removeChild(document.body.lastChild);
			}
			
			/* Remove placer element */

			ElementHandler.remove('placer');

			/* Unattach _onMouseMove listener from document */

			EventUtils.removeEventListener(document,'mousemove',this._onMouseMove_wrap);

			/* If element has no destination it is dropped in place. If there's any reason to want an undestined element to
			behave as if destined set this.destined to 'true' */

			if (this.element._destined == false)
				return;

			/* Detects whether element is in valid position for dropping and calls appropriate method */

			if (DDStore.hover != null || DDStore.hoverInt != null) 
				this.defaultValid();
			else
				this.defaultInvalid();
			
			/* Sets isDragging label to false and removes the label which indicates which destination element is being hovered over */

			this.isDragging = false;
			DDStore.hover = null;

		},

		onMouseOver: function(e) {

			/* DDStore.hover is set to null at start, and on mouseout of a destination. So this method doesn't procede 
			if the mouseover is a return to the destination from a hidden layer of an interacting element within the destination */

			if(DDStore.hover != null)
				return;			

			/* Stores the destination which is being hovered over in DDStore.hover */

			var target = EventUtils.targetElement(e).id;
			DDStore.hover = $.id(target.replace(/SL/,""));
			
			/* Makes hidden layers on all children of the destination if present. So destination elements should not contain HTML */

			if (DDStore.hover.hasChildNodes() == true) {

				var cn = DDStore.hover.childNodes;

				for (var i = 0, n = cn.length; i < n; i++) {
					if (this.id != cn[i].id)
						this._makeSecretL(cn[i].id, true);
				}
			}
			
			/* Appends placer element to destination ****need to be able to turn this off**** */			

			ElementHandler.putAtEnd(DDStore.hover,this.makePlacer());

			EventUtils.stopDefault(e);

		},

		makePlacer: function() {
			
			/* 
			CAN OVERRIDE but use 'placer' for the id of your placer element as this id is used for moving and removing it.
			Default creates empty frame of same size and shape as dragged element. ****need to make this easier to override**** 
			*/

			var width = parseInt(DomUtils.getStyle(this.element, 'width'));
			var height = parseInt(DomUtils.getStyle(this.element, 'height'));
			var marginL = parseInt(DomUtils.getStyle(this.oldElement || this.element, 'margin-left'));
			var marginT = parseInt(DomUtils.getStyle(this.oldElement || this.element, 'margin-top'));

			return {tag: 'div', id: 'placer', style: 'width:'+width+'; height:'+height+'; margin-left:'+marginL+'; margin-top:'+marginT+'; position: relative; border: 2px dashed black;'};
		},
			
		onMouseOut: function(e) {
			
			/* Removes placer element and sets hover lable to null only if mouseout is not due to a mouseover of a hidden layer within
			destination element. */

			if(EventUtils.relTarget(e).id.match(/SL/) == null) {
				DDStore.hover = null;
				ElementHandler.remove('placer');
			}
		},

		beDestination: function(elements) {
			
			var elements = (arguments[1] instanceof Array)? arguments[1]: arguments;

			/* Calls DDStore.destinate, which stores this element as a destination and records which elements are intended to
			be dropped there. */

			for(var i = 0; i < elements.length; i++) {
				$.id(elements[i])._destined = true;
				DDStore.destinate(this.id, elements[i]);
			}
		},

		giveDestinations: function(destinations) {
				
			/* Adds a destination to a drag-drop element */

			for(var i = 0; i < arguments.length; i++)
				DDStore.destinate(arguments[i], this.id);
		},

		limit: function(limits) {

			/* Sets limits beyond which the element can't be dragged */

			this.topLimit = limits.top;
			this.bottomLimit = limits.bottom;
			this.leftLimit = limits.left;
			this.rightLimit = limits.right;

			this.limits = (limits == 'none')? 'off': 'on';
		},

		holdX: function() {

			/* Sets the holdX property which if true causes the initial X coordinate of the element to be maintained */

			this.keepX = true;
		},

		holdY: function() {
	
			/* Sets the holdY property which if true causes the initial Y coordinate of the element to be maintained  */
			
			this.keepY = true;

		},

		useRelative: function() {

			/* Sets the relative property, which prevents the element from being made absolute. Useful if wanting to use relative X and Y limits 
			but no good in situations where the element is being dragged under others of a higher z-index and you want it to remain on top */

			this.relative = true;
		},

		scrollAuto: function() {

			if(this.scrollAutoOn == false)
				return;
				
			var v = DomUtils.getViewXY();
			var s = DomUtils.getScroll();

			if(this.scrollAutoOn.x !== false) {
				if(this.moCoords.x + this.diff.r > v.x + s.l + this.scrollThresh) {
					window.scrollTo(s.l + 30, s.t);
				}
				if(s.l > 0 && this.moCoords.x - this.diff.l < s.l + this.scrollThresh) {
					window.scrollTo(s.l - 30, s.t);
				}
			}

			if(this.scrollAutoOn.y !== false) {
				if(this.moCoords.y + this.diff.b > v.y + s.t + this.scrollThresh) {
					window.scrollTo(s.l, s.t + 30);
				}	
				if(s.t > 0 && this.moCoords.y - this.diff.t < s.t + this.scrollThresh) {
					window.scrollTo(s.l, s.t - 30);
				}
			}
			
		}
	}


	/* A class which uses a copy of the drag-drop element for dragging. It inherits from DragDrop and overrides some of its
	methods. The nature of the dragged element can be configured. The default is to use a replica of the original at a specified 
	transparancy. If no transparancy is specified a simple frame with the dimensions of the original element will be used. */

	function DragDropCopy(element, opacity, options) {

		/* Calls the method which makes the element drag-dropable. Stores the specified opacity for the copy if present. */		

		this.turnOnDD(element, options);
		this.opacity = opacity || 0;
	}

	Inheritence.extend(DragDropCopy.prototype, DragDrop.prototype);

	Inheritence.extend(DragDropCopy.prototype, {
		
		/* The opacity of the copy */
		
		copy: null,

		/* The original drag-drop element */		

		oldElement: null,

		/* The id of the original element */		

		oldId: null,
		
		/* Opacity is set to 0.5 if not specified */

		opacity: 0.5,

		_copy: function() {
			
			/* Gets the left and top positions of the element which is being copied */

			var offset = DomUtils.getTrueOffset(this.element); 
			var left = offset.l + "px";
			var top = offset.t + "px";

			/* A copy is made only on the first mousedown event on a drag-drop element. When the copy is done with it is hidden
			and made visible again the next time it is needed. */

			if(!this.oldElement) {

				var copy = this.makeCopy();
			
				/* The copy is given an id and absolute positioning. Its z-index is set lower than that of the hidden layers.  
				Its visibility is set to hidden. */ 

				copy.id = this.id +'copy';
				copy.style.position = 'absolute';
				copy.style.visibility = 'hidden';
				copy.style.zIndex = 989;
				
				/* The copy is appended and stored in this.copy */

				document.body.appendChild(copy);
				this.copy = $.id(this.id +'copy');
			}

			/* The copy is positioned above the orginal element and made visible */

			this.copy.style.left = left;
			this.copy.style.top = top;
			this.copy.style.visibility = 'visible';

			/* The original element and its id are stored in new properties */

			this.oldElement = this.element;
			this.oldId = this.id;
			
			/* this.element is changed to hold the copied element, so that the drag-drop methods now act on this instead */ 

			this.element = this.copy;
			this.element._destined = this.oldElement._destined;
		},

		makeCopy: function() {

			/* CAN OVERRIDE but must return the element you are making */

			if(this.opacity == 0 || isNaN(this.opacity) == true) {
				
				/* An empty frame with the same dimensions as the original element is made */

				var height = parseInt(DomUtils.getStyle(this.element,'height'));
				var width = parseInt(DomUtils.getStyle(this.element,'width'));

				var copy = new Element({tag: 'div', style: 'width:'+width+'; height:'+height+'px; border: 2px solid black; cursor: move;'});
			}

			else {
				/* The drag-drop element is cloned and the clone has the onMouseDown event listener removed, as this is also
				cloned in IE. Its opacity is set to that specified */

				var copy = this.element.cloneNode(true);
				EventUtils.removeEventListener(copy,'mousedown',this._onMouseDown_wrap);
				
				DomUtils.setStyle(copy,'opacity',this.opacity);
			}
			
			/* If you override this method you must RETURN YOUR COPY ELEMENT */			

			return copy;
		},	
	
		defaultValid: function() {
		
			/* CAN OVERRIDE by passing as method of optional object parameter. Default is to place a copy of the original drag-drop element
			in the drop spot. If you want to keep this method but add extra functionality you should override onValidDrop instead */

			this.onValidDrop();
			
			/* Clones original element */

			var drop = this.oldElement.cloneNode(true);
			EventUtils.removeEventListener(drop,'mousedown',this._onMouseDown_wrap);
			
			/* Gives new element an id using the counter in DDStore. Increments counter by 1 */ 		

			drop.id = this.oldId +'Drop'+DDStore.DDs[this.oldId].dropNo;
			
			/* If interacting with a valid element the drop element is placed before this in the DOM. Else it is appended to the destination
			element */

			if(DDStore.hoverInt != null) {
				var parent = DDStore.hoverInt.parentNode;
				parent.insertBefore(drop,DDStore.hoverInt);			

				DDStore.hoverInt = null;
			}

			else {
				DDStore.hover.appendChild(drop);
			}
			
			/* The dropped element is made drag-dropable using the standard DragDrop class. It is given its current destination as its only
			valid destination  */

			drop._destined = true;
			var temp = new DragDrop(drop.id);
			DDStore.destinate(DDStore.hover.id,drop.id);

			/* The copied element is now stored in this.copy and hidden. this.element is reset to store the original element again, and this.id
			to store the original id. */

			this.copy = this.element;
			this.copy.style.visibility = 'hidden';
			this.element = this.oldElement;
			this.id = this.oldId;

			DDStore.DDs[this.oldId].dropNo++;
		},

		defaultInvalid: function() {

			/* CAN OVERRIDE by passing as method of optional object parameter. If you want to keep this method but add extra functionality 
			you should override onInvalidDrop instead */

			this.onInvalidDrop();

			/* The copied element is now stored in this.copy and hidden. this.element is reset to store the original element again, and this.id
			to store the original id. */

			this.copy = this.element;
			this.copy.style.visibility = 'hidden';
			this.element = this.oldElement;
			this.id = this.oldId;
		}
	} )


	function Destination(destination, elements) {
		
		this.beDestination(arguments);

	}

		
	Destination.prototype = {

		beDestination: function(arguments) {
			
		 	var elements = (arguments[1] instanceof Array)? arguments[1]: arguments;
			
			/* Calls DDStore.destinate, which stores this element as a destination and records which elements are intended to
			be dropped there. */

			for(var i = (arguments[1] instanceof Array)? 0:1; i < elements.length; i++) {
				$.id(elements[i])._destined = true;
				DDStore.destinate(arguments[0], elements[i]);
			}
		}
	}	









