var globalZIndex = 5000;
var ctComponentConfig = {
	message: {
		type: {
			0: {className: 'error', hold: true},
			1: {className: 'warning', hold: true},
			2: {className: 'message', hold: false},
			strongest: 2
		}
	}
};

var CtComponent_Abstract = Class.create({

	id: null,
	element: null,
	type: 'CtComponent',

	initialize: function() {
		throw 'initialize() must be redifined';
	},

	refresh: function() {
		throw 'refresh() must be redifined';
	},



	smoothClear: function(callback) {
		Effect.Queues.get(this.id).each(function(effect) { effect.cancel(); });
		callback = !callback ? Prototype.emptyFunction : callback;

		if (this.wrapper) {
			if (this.element.getHeight() > 0) {
				new Effect.Opacity(this.wrapper, {to: 0, duration: 0.5, queue: {scope: this.id, position: 'end'}, afterFinish: callback});
			} else {
				this.wrapper.setOpacity(0);
				callback();
			}
		} else {
			callback();
		}
	},

	smoothUpdate: function(element, content, callback) {
		callback = !callback ? Prototype.emptyFunction : callback;

		var heightOld = element.getHeight();
		this.wrapper = new Element('div');

		this.wrapper.update(content);
		element.appendChild(this.wrapper);
		var heightNew = this.wrapper.getHeight();
		$$('body')[0].appendChild(this.wrapper);
		this.wrapper.hide();
		this.wrapper.setOpacity(0);

		if (heightOld != heightNew) {
			new Effect.Morph(this.element, {
				style: {height: heightNew + 'px'},
				duration: 0.5,
				afterFinish: function() {
					this.element.setStyle({height: 'auto'});
					element.update(this.wrapper);
					this.wrapper.show();
				}.bind(this),
				queue: {scope: this.id, position: 'end'}
			});
		} else {
			element.update(this.wrapper);
			this.wrapper.show();
		}

		new Effect.Opacity(this.wrapper, {
			to: 1,
			duration: 0.5,
			queue: {scope: this.id, position: 'end'},
			afterFinish: callback
		});
	}

});



var CtComponent_Locker = Class.create(CtComponent_Abstract, {

	firstRun: null,
	container: null,

	initialize: function() {
		this.element = new Element('div', {style: 'display: none; position: absolute; top: 0; left: 0;'});
//		this.element.setStyle({zIndex: globalZIndex++});
		this.id = this.element.identify();
		this.firstRun = true;
		this.container = $$('body')[0];
	},


	refresh: function() {
		var viewportDimensions = document.viewport.getDimensions();
		var bodyDimensions = $$('body')[0].getDimensions();
		var width = viewportDimensions.width > bodyDimensions.width ? viewportDimensions.width : bodyDimensions.width;
		var height = viewportDimensions.height > bodyDimensions.height ? viewportDimensions.height : bodyDimensions.height;
		this.element.setStyle({width: '100%', height: height + 'px', overflow: 'hidden'});
//		this.element.setStyle({top: '0px', left: '0px', rigth: '0px', overflow: 'hidden'});
	},

	show: function() {
		if (this.firstRun) {
			$$('body')[0].appendChild(this.element);
			this.firstRun = false;
		}
		this.refresh();
		if (Prototype.Browser.IE) {
			($$('body')[0]).select('select').each(function(element) {
				Element.addClassName(element, 'ctComponent-locker-descendant-hidden');
			});
		}
		this.element.show();
	},


	hide: function() {
		this.element.hide();
		if (Prototype.Browser.IE) {
			($$('body')[0]).select('select').each(function(element) {
				Element.removeClassName(element, 'ctComponent-locker-descendant-hidden');
			});
		}
	}

});

var CtComponent_PageLocker = Class.create(CtComponent_Locker, {

	initialize: function($super) {
		$super();
		this.element.addClassName('ctComponent-pageLocker');
		this.element.setOpacity(0.6);
	}
});

var CtComponent_FormLocker = Class.create(CtComponent_Locker, {

	initialize: function($super, form) {
		$super();
		this.element.addClassName('ctComponent-formLocker');
		this.element.setOpacity(0.5);

		this.container = form.element;
	},

	refresh: function() {
		var dimensions = this.container.getDimensions();
		var offsets = this.container.cumulativeOffsetFixed();

		this.element.setStyle({
			width: dimensions.width + 'px',
			height: dimensions.height + 'px',
			top: offsets.top + 'px',
			left: offsets.left + 'px'
		});
	}

});


var CtComponent_BlockLocker = Class.create(CtComponent_Locker, {

	initialize: function($super, container) {
		$super();
		this.element.addClassName('ctComponent-blockLocker');
		this.element.setOpacity(0.5);

		this.container = $(container);
	},

	refresh: function() {
		var dimensions = this.container.getDimensions();
		var offsets = this.container.cumulativeOffsetFixed();

		this.element.setStyle({
			width: dimensions.width + 'px',
			height: dimensions.height + 'px',
			top: offsets.top + 'px',
			left: offsets.left + 'px'
		});
	}

});


var CtComponent_Error = new (Class.create(CtComponent_Abstract, {

	firstRun: null,
	pageLocker: null,

	initialize: function() {
		this.element = new Element('div', {className: 'ctComponent-error', style: 'display: none'});
		this.id = this.element.identify();
		this.firstRun = true;
		this.pageLocker = new CtComponent_PageLocker();
	},


	hide: function() {
		this.element.hide();
		this.pageLocker.hide();
		this.element.update(null);
	},


	show: function() {
		this.pageLocker.show();

		if (this.firstRun) {
			this.pageLocker.element.insert({after: this.element})
//			$$('body')[0].appendChild(this.element);
			Event.observe(this.element, 'dblclick', this.hide.bindAsEventListener(this));
			this.firstRun = false;
		}
		this.element.show();
	},

	refresh: function(response) {
		var errorText = response.content.stripScripts();
//		var errorText = response.content.stripScripts().stripTags();
//		var errorText = response.content.escapeHTML();
		this.element.update(errorText);
		this.show();
		this.element.fire('CtComponent:refresh', {sender: this});
	}


}));




var CtComponent_ModalBox = Class.create(CtComponent_Abstract, {

	firstRun: null,
	closeCallback: Prototype.emptyFunction,
	closeButton: null,
	container: null,
	pageLocker: null,
	afterShowCallBack: null,
	effectDuration: null,

	initialize: function(ident) {

		this.container = new Element('div', {className: 'ctComponent-modalBox', style: 'display: none; position: absolute;'});

		this.element = new Element('div');
		if(ident) {
			this.element = new Element('div', {id: ident});
		} else {
			this.element = new Element('div');
		}

		this.container.appendChild(this.element);

		this.closeButton = new Element('a', {className: 'controls controls-delete', style: 'position: absolute; top: 5px; right: 5px; padding: 0; margin: 0;'});
		this.container.appendChild(this.closeButton);

		this.id = this.element.identify();
		this.firstRun = true;

		this.pageLocker = new CtComponent_PageLocker();

//		this.container.setStyle({zIndex: globalZIndex++});
	},


	hide: function(event) {
		Event.stop(event);

		if (!this.effectDuration) {
			this.container.hide();
			this.closeCallback();
			this.element.update();
			this.pageLocker.hide();
		} else {
			Effect.Queues.get('modalBox').each(function(effect) {effect.cancel();});
			this.container.firstDescendant().update();
			new Effect.Fade(this.container, {
				queue: {position: 'end', scope: 'modalBox'},
				duration: this.effectDuration,
				afterFinish: function() {
					this.pageLocker.hide();
					this.closeCallback();
					this.element.update();
				}.bind(this)
			});
		}
	},


	show: function(effectDuration) {

		this.pageLocker.show();
		if (this.firstRun) {
			this.pageLocker.element.insert({after: this.container})
//			var body = $$('body')[0];
//			body.appendChild(this.container);
			Event.observe(this.closeButton, 'click', this.hide.bindAsEventListener(this));
			Event.observe(this.element, 'CtComponent:refresh', function(event) {
				this.pageLocker.refresh();
				//e('CtComponent:refresh in CtComponent_ModalBox', event.memo.sender, this.pageLocker.element.getDimensions());
			}.bind(this));

			this.firstRun = false;
		}

		if (!effectDuration) {
			this.container.show();
			if (this.afterShowCallBack) {
				this.afterShowCallBack();
			}
		} else {
			Effect.Queues.get('modalBox').each(function(effect) {effect.cancel();});
			this.effectDuration = effectDuration;
			new Effect.Appear(this.container, {
				duration: effectDuration,
				queue: {position: 'end', scope: 'modalBox'},
				afterFinish: function() {
					if (this.afterShowCallBack) {
						this.afterShowCallBack();
					}
				}.bind(this)
			});
		}
	},


	refresh: function(response) {
		var errorText = response.content.stripScripts().stripTags();
//		var errorText = response.content.escapeHTML();
		this.element.update(errorText);
		this.show();
		this.element.fire('CtComponent:refresh', {sender: this});
	}


});



var CtComponent_Popup = Class.create(CtComponent_Abstract, {

	firstRun: null,
	closeCallback: Prototype.emptyFunction,
	closeButton: null,
	moveButton: null,
	container: null,
	titleText: null,

	initialize: function() {

		this.titleText = null;
		this.container = new Element('div', {className: 'ctComponent-popup', style: 'display: none; position: absolute;'});
		this.element = new Element('div');
		this.title = new Element('div', {className: 'ctComponent-popup-title'});
		this.container.appendChild(this.title);
		this.container.appendChild(this.element);

		this.closeButton = new Element('a', {href: 'javascript:void(0);', className: 'controls controls-delete', style: 'position: absolute; top: 5px; right: 5px; padding: 0; margin: 0;'}).update('&nbsp;');
		this.container.appendChild(this.closeButton);

		var titleId = this.title.identify();

		new Draggable(this.container, {
			handle: 'ctComponent-popup-title',
			starteffect: function(element) {Draggable._dragging[element] = true;},
			endeffect: function(element) {Draggable._dragging[element] = false;}
		});

		this.id = this.element.identify();
		this.firstRun = true;
	},


	hide: function(delay) {
		Effect.Queues.get(this.id).each(function(effect) { effect.cancel(); });

		if (!delay || delay < 0) {
			delay = 0;
		}
		new Effect.Fade(this.container, {
			delay: delay,
			duration: 0.3,
			queue: {scope: this.id, position: 'end'},
			afterFinish: this.closeCallback.bind(this)
		})
	},

	closeButtonClickHandler: function(event) {
		Event.stop(event);
		this.hide();
	},

	show: function(title) {
		if (title) {
			this.titleText = title;
		}

		if (this.firstRun) {
			var body = $$('body')[0];
			body.appendChild(this.container);
			Event.observe(this.closeButton, 'click', this.closeButtonClickHandler.bindAsEventListener(this));
			this.firstRun = false;
		} else {
			Effect.Queues.get(this.id).each(function(effect) { effect.cancel(); });
		}

		this.title.update(this.titleText);

		new Effect.Appear(this.container, {
			duration: 0.3,
			queue: {scope: this.id, position: 'end'}
		})
	},

	move: function() {
		var left, top;
		if (arguments.length == 2) {
			left = arguments[0];
			top = arguments[1];
		} else if (arguments.length == 1) {
			left = arguments[0][0];
			top = arguments[0][1];
		} else if (arguments.length == 0) {
			offset = this.container.cumulativeOffsetFixed();
			left = offset[0];
			top = offset[1];
		}
		if (!left || !top) {
			return;
		}



		var viewport = document.viewport.getDimensions();
		var dimensions = this.container.getDimensions();
		width = dimensions.width;
		height = dimensions.height;

		left = left > 0 ? left : 0;
		top = top > 0 ? top : 0;

		if (isIE6()) {
			scrollOffset = document.viewport.getScrollOffsets();
			left = ((left + width) < viewport.width) ? left : (viewport.width - width);
	//			top = ((top + height) < scrollOffset.top + viewport.height) ? top : (scrollOffset.top + viewport.height - height);
		} else {
			left = ((left + width) < viewport.width) ? left : (viewport.width - width);
	//			top = ((top + height) < viewport.height) ? top : (viewport.height - height);
		}

//		new Effect.Move(this.container, {duration: 0.5, x: left, y: top, mode: 'absolute'});
		this.container.setStyle({top: top + 'px', left: left + 'px'});

	},

	setLoader: function() {
		this.container.addClassName('ctComponent-popup-loader');
	},

	resetLoader: function() {
		this.container.removeClassName('ctComponent-popup-loader');
	},


	refresh: function(response) {
		var errorText = response.content.stripScripts().stripTags();
//		var errorText = response.content.escapeHTML();
		this.element.update(errorText);
		this.show();
		this.element.fire('CtComponent:refresh', {sender: this});
	}


});


var CtComponent_ConfirmBox = Class.create(CtComponent_Abstract, {


	question: null,
	hr: null,
	yes: null,
	no: null,
	yesCallback: null,
	noCallback: null,

	pageLocker: null,

	firstRun: null,

	initialize: function() {
		this.firstRun = true;

		this.element = new Element('div', {className: 'ctComponent-confirmBox', style: 'display: none; position: fixed;'});
		this.id = this.element.identify();
		this.yesCallback = Prototype.emptyFunction;
		this.noCallback = Prototype.emptyFunction;

		this.question = new Element('b', {className: 'ctComponent-confirmBox-question controls-text controls-discuss'});
		this.yes = new Element('a', {className: 'ctComponent-confirmBox-yes controls-text controls-ok', href: '#'});
		this.yes.update('Yes');
		this.no = new Element('a', {className: 'ctComponent-confirmBox-no controls-text controls-stop', href: '#'});
		this.no.update('No');

		this.element.update(this.question);
		this.element.appendChild(this.yes);
		this.element.appendChild(this.no);

		this.pageLocker = new CtComponent_PageLocker();
//		this.element.setStyle({zIndex: globalZIndex++});
	},

	refresh: function() {
	},

	show: function(question, yesCallback, noCallback) {
		this.pageLocker.show();

		if (this.firstRun) {
			this.pageLocker.element.insert({after: this.element})
			this.yes.observe('click', this.yesHandler.bindAsEventListener(this));
			this.no.observe('click', this.noHandler.bindAsEventListener(this));
			this.firstRun = false;
		}

		this.question.update(question);
		this.yesCallback = yesCallback ? yesCallback : this.yesCallback;
		this.noCallback = noCallback ? noCallback : this.noCallback;

		var viewportDimensions = document.viewport.getDimensions();


		this.element.show();
		var elementDimensions = this.element.getDimensions();



		var left = (viewportDimensions.width - elementDimensions.width) / 2;
		var top = (viewportDimensions.height - elementDimensions.height) / 2;
		this.element.setStyle({top: top + 'px', left: left + 'px'});
	},


	yesHandler: function(event) {
		Event.stop(event);
		this.element.hide();
		this.pageLocker.hide();
		this.yesCallback();

	},


	noHandler: function(event) {
		Event.stop(event);
		this.element.hide();
		this.pageLocker.hide();
		this.noCallback();
	}


});



var CtComponent_ContextMenu = Class.create(CtComponent_Abstract, {
	centerX: null,
	centerY: null,
	distanceXMin: null,
	distanceYMin: null,
	distanceXMax: null,
	distanceYMax: null,

	hideListener: null,
	modifyOpacityListener: null,

	initialize: function(htmlElement) {
		this.element = $(htmlElement);

		if (!this.element) {
			this.element = new Element('div');
		}

		this.id = this.element.identify();

		this.element.addClassName('ctComponent-contextMenu');
		this.element.setStyle({opacity: 0, display: 'none', position: 'absolute', zIndex: 30000});

		$$('body')[0].appendChild(this.element);

		this.hideListener = this.hide.bindAsEventListener(this);
		this.modifyOpacityListener = this.modifyOpacityHandler.bindAsEventListener(this);

		this.centerX = null;
		this.centerY = null;
		this.distanceXMin = null;
		this.distanceYMin = null;
		this.distanceXMax = null;
		this.distanceYMax = null;

	},


	show: function(x, y) {
		var left = x + 15;
		var top = y - this.element.getHeight() - 15;

		this.element.setStyle({top: top + 'px', left: left + 'px'});

		var dimensions = this.element.getDimensions();

		this.centerX = left + dimensions.width / 2;
		this.centerY = top + dimensions.height / 2;
		this.distanceXMin = dimensions.width / 2 + 10;
		this.distanceYMin = dimensions.height / 2 + 10;
		this.distanceXMax = this.distanceXMin + 50;
		this.distanceYMax = this.distanceYMin + 50;

		this.modifyOpacity(x, y);
		this.element.show();

		document.observe('click', this.hideListener);
		document.observe('mousemove', this.modifyOpacityListener);
	},


	modifyOpacityHandler: function(event) {
		this.modifyOpacity(Event.pointerX(event), Event.pointerY(event));
	},


	modifyOpacity: function(x, y) {
		var distanceX = Math.abs(this.centerX - x);
		var distanceY = Math.abs(this.centerY - y);
		var opacity = 0;

		if (distanceX > distanceY) {
			opacity = 1 - (distanceX - this.distanceXMin) / this.distanceXMax;
		} else {
			opacity = 1 - (distanceY - this.distanceYMin) / this.distanceYMax;
		}

		opacity = opacity > 1 ? 1 : (opacity < 0 ? 0 : opacity);
		this.element.setOpacity(opacity * 0.9);
		if (!opacity) {
			this.hide();
		}
	},


	hide: function() {
		document.stopObserving('click', this.hideListener);
		document.stopObserving('mousemove', this.modifyOpacityListener);
		this.element.hide();
	},

	refresh: function(response) {
		if (this.element && this.element.update) {
			this.element.update(response.content);
		}
		this.element.fire('CtComponent:refresh', {sender: this});
	}


});


var CtComponent_Message = Class.create(CtComponent_Abstract, {

	wrapper: null,
	close: null,

	messages: null,

	initialize: function(htmlElement) {
		this.element = $(htmlElement);
		if (!this.element) {
			this.element = new Element('div', {className: 'ctComponent-message', style: 'display: none'});
		}
		this.id = this.element.identify();

		this.messages = null;

		this.wrapper = new Element('div', {className: 'ctComponent-message-wrapper'});
		this.close = new Element ('a', {href: 'javascript:void(0)', className: 'controls controls-delete', style: 'position: absolute; right: 5px; top: 5px; padding: 0; margin: 0;'});

		this.element.update(this.wrapper);
		this.element.appendChild(this.close);

		Event.observe(this.close, 'click', this.closeClickHandler.bindAsEventListener(this));
	},

	closeClickHandler: function(event) {
		Event.stop(event);
		this.hide();
	},


	_render: function(scrollTo) {
		this.element.className = 'ctComponent-message';
		this.wrapper.update(null);
		if (this.messages && this.messages.length) {

			var messageTypeStrongest = ctComponentConfig.message.type.strongest;

			for (var i = 0; i < this.messages.length; i++) {
				var messageType = this.messages[i][1];
				var messageText = this.messages[i][0];
				if (messageType < messageTypeStrongest) {
					messageTypeStrongest = messageType;
				}
				this.wrapper.appendChild(new Element('p', {className: ctComponentConfig.message.type[messageType].className}).update(messageText));
			}
			this.element.addClassName('ctComponent-message-' + ctComponentConfig.message.type[messageTypeStrongest].className);

			var queue = {scope: this.id, position: 'end'};

			this.element.setStyle({height: 'auto', display: 'block'});

			if (scrollTo) {
				if (Prototype.Browser.Opera) {
					Element.scrollTo(this.element);
				} else if (this.element.viewportOffset().top < 0) {
					Element.scrollTo(this.element);
				}
			}

		} else {
			this.hide();
		}

		this.element.fire('CtComponent:refresh', {sender: this});
	},

	hasErrors: function(messages) {
		var messageTypeStrongest = ctComponentConfig.message.type.strongest;
		if (messages && messages.length) {
			for (var i = 0; i < messages.length; i++) {
				if (ctComponentConfig.message.type[messages[i][1]].hold) {
					return true;
				}
			}
		}

		return false;
	},


	show: function(messages) {
		this.messages = messages;

		var scrollTo = arguments.length == 2 ? arguments[1] : true;

		var lastEffect = Effect.Queues.get(this.id).effects.last();
		if (lastEffect && lastEffect.options) {
			lastEffect.options.afterFinish = this._render.bind(this, scrollTo);
		} else {
			this._render(scrollTo);
		}
	},


	refresh: function(response) {
		if (response && response.json && response.json.messages) {
			this.show(response.json.messages);
		}
	},



	hide: function() {
		this.prepare();
	},

	prepare: function() {
		var height = this.element.getHeight();
		if (this.element) {
			if (height > 0) {
				new Effect.BlindUp(this.element, {
					duration: 0.5,
					afterFinish: function() {this.wrapper.update(null);}.bind(this),
					queue: {scope: this.id, position: 'end'}
				});
			} else {
				this.element.hide();
			}
		}
	}



});



var CtComponent_Default = Class.create(CtComponent_Abstract, {

	initialize: function(htmlElement) {
		this.element = $(htmlElement);
		if (this.element && this.element.identify) {
			this.id = this.element.identify();
		} else {
			this.id = null;
		}
	},

	refresh: function(response) {
		if (this.element && this.element.update) {
			this.element.update(response.content);
			this.element.fire('CtComponent:refresh', {sender: this});
		}
	}

});

var CtComponent_Comments = Class.create(CtComponent_Abstract, {

	initialize: function(htmlElement) {
		this.element = $(htmlElement);
		if (this.element && this.element.identify) {
			this.id = this.element.identify();
		} else {
			this.id = null;
		}
	}

});



CtPage.registerScript("CtComponent");

