function Dialog(elemId, drawInto, drawCallback) {
		// properties
		this.elemId = elemId;

		this.instance = ++Dialog.instances;
		
		this.timer = null;
		
		this.interval = 30; // in ms
		this.steps = 4;
		
		this.step = 0;
		this.event = null; // will be set by the callers of this.animate()
		
		this.width = null;
		this.height = null;
		this.x = null;
		this.y = null;
		
		this.left = 0;
		this.right = 0;
		this.top = 0;
		this.bottom = 0;
		
		this.visible = false;
		this.loaded = false;
		
		if ( drawInto ) {
			this.drawInto = drawInto;
		}
		else {
			this.drawInto = 'dialogs';
		}
		
		// methods
		this.setPosition = dialogSetPosition;
		this.setSize = dialogSetSize;
		
		this.load = dialogLoad;
		
		this.show = dialogShow;
		this.hide = dialogHide;
		
		this.attach = dialogAttach;
		this.setup = dialogSetup;
		
		this.startAnimation = dialogStartAnimation;
		this.stopAnimation = dialogStopAnimation;
		
		this.transition = dialogTransition;
		
		// event callbacks
		this.onTimer = dialogOnTimer;
		
		if ( drawCallback && typeof(drawCallback) == 'function' ) {
			this.draw = drawCallback;
		}
		else {
			this.draw = dialogDraw;
		}
		
		this.onBeforeLoad = dialogOnBeforeLoad;
		this.onLoad = dialogOnLoad;
		
		this.onBeforeShow = null;
		this.onShowTimer = dialogOnShowTimer;
		this.onShowStep = dialogOnShowStep;
		this.onShow = null;
		
		this.onBeforeHide = null;
		this.onHideTimer = dialogOnHideTimer;
		this.onHideStep = dialogOnHideStep;
		this.onHide = null;
		
		this.generate = dialogGenerate;
		this.redraw = dialogRedraw;
		
		// init
		this.setup(elemId);
		this.attach();
		
		this.transparency = false;
		
		// different data container
		this.data = new Array();
}

Dialog.instances = 0;
Dialog.timers = new Array();


/* moves the dialog to a specified coordonate */
/* 
	@param int x	Defines the horizontal absolute coordonate. If positive, will alter the LEFT position. If negative, will alter the RIGHT position, setting RIGHT = abs(x)
	@param int y	Defines the vertical absolute coordonate. If positive, will alter the TOP position. If negative, will alter the BOTTOM position, setting BOTTOM = abs(y)
*/
function dialogSetPosition(x, y) {
	this.x = x;
	this.y = y;
	
	this.left = 0;
	this.right = 0;
	this.top = 0;
	this.bottom = 0;
	
	this.elem.style.left = '';
	this.elem.style.right = '';
	this.elem.style.top = '';
	this.elem.style.bottom = '';

	if ( x > 0 ) {
		this.left = x;
		this.elem.style.left = this.left + 'px';
	}
	else {
		this.right = (-x);
		this.elem.style.right = this.right + 'px';
	}
	
	if ( y > 0 ) {
		this.top = y;
		this.elem.style.top = this.top + 'px';
	}
	else {
		this.bottom = (-y);
		this.elem.style.bottom = this.bottom + 'px';
	}
}

/* resizes the dialog */
function dialogSetSize(w, h) {
	this.width = w;
	this.height = h;
}

/* loads the dialog contents from an external source via ajax */
function dialogLoad(uri) {
	if ( this.loaded == uri ) {
		return false;
	}
	
	this.uri = uri;
	
	this.server = new Server(this.uri);
	
	this.server.data = new Array();
	this.server.data['dialog'] = this;
	
	this.server.onBeforeLoad = this.onBeforeLoad;
	
	var dialog = this;
	
	this.server.onLoad = function () {
		dialog.loaded = uri;
		
		if ( dialog.onLoad ) {
			dialog.onLoad();
		}
	}
	
	this.server.load('', getObj(this.elemId + 'Content') );
}

/* attaches the dialog to the specified page object, given by id */
function dialogAttach() {
	// deattaching from an old element, if exists
	if ( this.elem ) {
		this.elem.dialog = null;
	}
	
	this.elem.dialog = this;
}

/* displays the dialog, using the specified transition efects */
function dialogShow() {
	if ( this.visible ) {
		//return false;
	}
	
	if ( this.onBeforeShow != null ) {
		if (! this.onBeforeShow() ) {
			return false;
		}
	}
	
	if ( this.debug ) alert("Show " + this.elemId);
	
	this.event = 'show';
	this.startAnimation();
	
	return true;
}

/* hides the dialog, using the specified transition efects */
function dialogHide() {
	if (! this.visible ) {
		//return false;
	}
	
	if ( this.onBeforeHide != null ) {
		if (! this.onBeforeHide() ) {
			return false;
		}
	}
	
	this.event = 'hide';
	this.startAnimation();
	
	return true;
}

/* sets up the dialog before show */
function dialogSetup() {
	if ( elem = getObj(this.elemId) ) {
		// the id is already defined, we use it
		this.elem = elem;
	}
	else {
		// generating the dialog..
		this.generate( this.draw() );
		
		// and storing it..
		this.elem = getObj(this.elemId);
	}
}

/* re-draws the dialog containing html */
function dialogRedraw() {
	this.generate( this.draw() );
}

/* animates the dialog display */
function dialogStartAnimation() {
	// stop the last timer if set
	
	if ( this.timer ) {
		this.stopAnimation();
	}
	
	var dialog = this;
	
	this.timer = setInterval(
		function() {
			dialog.step++;
			if (! dialog.onTimer() ) {
				dialog.stopAnimation();
			}
		}
		,
		this.interval
	);
	
	if ( this.debug ) alert("Timer set for " + this.event + '!');
	
	this.step = 0;
}

/* stops the animation timer */
function dialogStopAnimation() {
	if ( this.timer ) {
		clearInterval(this.timer);
		this.timer = null;
		
		if ( this.debug ) alert("Timer cleared for " + this.event + "!");
	}

	this.step = 0;
}

function dialogOnTimer() {
	if ( this.event == 'show' ) {
		return this.onShowTimer();
	}
	else if ( this.event == 'hide' ) {
		return this.onHideTimer();
	}
	else {
		return false;
	}
}

function dialogOnShowTimer(dialog) {
	if ( this.step == 1 ) {
		this.elem.style.marginLeft = 0;
		this.elem.style.marginRight = 0;
		this.elem.style.marginTop = 0;
		this.elem.style.marginBottom = 0;
		
		this.elem.className = 'dialogLoading';
	}
	
	this.onShowStep();
	
	if ( this.step == this.steps ) {
		this.elem.className = 'dialog';
		this.visible = true;
		if ( this.onShow ) {
			this.onShow();
		}
		return false;
	}
	else {
		return true;
	}
}

function dialogOnHideTimer(dialog) {
	if ( this.step == 1 ) {
		this.elem.style.marginLeft = 0;
		this.elem.style.marginRight = 0;
		this.elem.style.marginTop = 0;
		this.elem.style.marginBottom = 0;
		this.elem.className = 'dialogLoading';
	}
	
	this.onHideStep();
	
	if ( this.step == this.steps ) {
		this.elem.className = 'dialogHidden';
		this.visible = false;
		if (  this.onHide ) {
			this.onHide();
		}
		return false;
	}
	else {
		return true;
	}
}

function dialogOnShowStep() {
	this.transition( this.step / this.steps );
}

function dialogOnHideStep() {
	this.transition( (this.steps - this.step) / this.steps );
}

function dialogTransition(amountOpen) {
	var w = Math.ceil( amountOpen * this.width );
	var h = Math.ceil( amountOpen * this.height );
	var marginH = Math.ceil( (this.width - w) / 2 );
	var marginV = Math.ceil( (this.height - h) / 2 );
	
	this.elem.style.width = w + 'px';
	this.elem.style.height = h + 'px';
	
	if ( this.x > 0 ) {
		this.elem.style.marginLeft = marginH + 'px';
	}
	else {
		this.elem.style.marginRight = marginH + 'px';
	}
	
	if ( this.y > 0 ) {
		this.elem.style.marginTop = marginV + 'px';
	}
	else {
		this.elem.style.marginBottom = marginV + 'px';
	}
	
	if ( this.debug ) alert(
		  "this.transition (" + this.event + ")\nClass: " + this.elem.className + "\n" + amountOpen
		  	+ "\nTop: " + this.elem.style.top
		  	+ "\nLeft: " + this.elem.style.left
			 + "\nRight: " + this.elem.style.right
		  + "\nMargin: " + this.elem.style.marginTop + ' ' + this.elem.style.marginRight + ' ' + this.elem.style.marginBottom + ' ' + this.elem.style.marginLeft
		  );
		  
	if ( this.transparency ) {
		var opacity = Math.ceil(amountOpen * 90 );
		setOpacity(this.elem, opacity);
	}
	else {
		setOpacity(this.elem, 100);
	}
}

function dialogDraw() {
	var content = 
		''
		+ '<div class="dialogHidden" id="' + this.elemId + '">'
			+ '<div class="br">'
				+ '<div class="bl">'
					+ '<div class="tl">'
						+ '<div class="tr">'
							+ '<a class="close" href="javascript:void(0)" onclick="hideDialog(\'' + this.elemId + '\')">'
							+ '</a>'
							+ '	<div class="content" id="' + this.elemId + 'Content">'
							+ '	</div>'
						+ '</div>'
					+ '</div>'
				+ '</div>'
			+ '</div>'
		+ '</div>'
	;
	
	return content;
}

function dialogGenerate(content) {
	getObj(this.drawInto).innerHTML = content;
}

function dialogOnBeforeLoad() {
	var content = getObj(this.data['dialog'].elemId+'Content');
	content.innerHTML = '<div class="loading"><img src="images/loading.gif"></div>';
}

function dialogOnLoad() {
	this.server.__draw();
}

/************************************************/

function getDialog(elemId, drawInto, drawCallback) {
	if ( ( elem = getObj(elemId) ) && elem.dialog )  {
		dialog = elem.dialog;
	}
	else {
		dialog = new Dialog(elemId, drawInto, drawCallback);
	}
	
	return dialog;
}

function showDialog(elemId, width, height, x, y, loadFromUri) {
	dialog = getDialog(elemId);
	dialog.setSize(width, height);
	
	if ( x && y ) {
		dialog.setPosition(x, y);
	}
	
	if ( loadFromUri ) {
		dialog.load(loadFromUri);
	}
	
	dialog.show();
}

function hideDialog(elemId) {
	dialog = getDialog(elemId);
	dialog.hide();
}
