
	var majWidgets = {
		container: false,
		active: false
	};

	/**
	 * Основа виджета
	 * 
	 * @author Alexander Osin, dev.majesty@gmail.com
	 * @package MajUI
	 */
	var majWidget = new Class({
		Implements: [Options],
		options: {
			id:           false,
			className:    false,
			modal:        true,
			modalOpacity: '0.5',
			title:        'Title',
			draggable:    true,
			resizable:    true,
			close:        true,
			minimize:     false,
			maximize:     false,
			tray:         false,
			on_top:       false,
			min_width:    120,
			min_height:   80,
			callShow: function(){},
			callHide: function(){},
			callClose: function(){}
		},
		elements: {
			widget:     false,
			wrap:       false,
			header:     false,
			headerText: false,
			content:    false,
			overlay:    false,
			controls:   false,
			close:      false,
			minimize:   false,
			maximize:   false,
			unmaximize: false,
			tray:       false
		},
		effects: {},
		is_hidden: true,
		initialize: function(options)
		{
			this.setOptions(options);
			
			var object = this;
			if (!majWidgets.container)
			{
				majWidgets.container = new Element('div').set('id', 'majWidget-container').inject(document.body);
			}
				
			this.elements.overlay  = this._createOverlay(majWidgets.container);
			this.elements.widget   = this._createWidget(object, majWidgets.container);
			this.elements.wrap     = this._createWrap(this.elements.widget);
			
			this.elements.header     = this._createHeader(this.elements.wrap);
			this.elements.headerText = this._createHeaderText(this.elements.header);
			this.elements.controls   = this._createControls(this.elements.header);
			this.elements.minimize   = this._createMinimize(this.elements.controls);
			this.elements.maximize   = this._createMaximize(this.elements.controls);
			this.elements.unmaximize = this._createUnmaximize(this.elements.controls);
			this.elements.close      = this._createClose(this.elements.controls);
			this.elements.content    = this._createContent(this.elements.wrap, this.elements.header);
			
			/**
			 * Кнопка сворачивает окно
			 */
			if (this.options.minimize)
			{
				this._makeMinimizable(this.options.tray, this);
			}
			
			/**
			 * Кнопка распахивает окно
			 */
			if (this.options.maximize)
			{
				this._makeMaximizable(this);
			}
			
			if (this.options.close)
			{
				/**
				 * Кнопка закрывает окно
				 */
				this.elements.close.addEvent('mousemove', function(e){return false;});
				this.elements.close.addEvent('click', function(e){
					object.close();
					return false;
				});
				
				/**
				 * Esc закрывает окно
				 */
				window.addEvent('keypress', function(e){
					if (e.code == 27){
						if (majWidgets.active) return majWidgets.active.close();
						return false;
					}
				});
			}
			
			/**
			 * Делает виджет перетягиваемым
			 */
			if (this.options.draggable) this._makeDraggable();
			
			/**
			 * Добавляет возможность изменения размера окна
			 */
			if (this.options.resizable) this._makeResizable();
			
			majWidgets.active = object;
		},
		/**
		 * Создает наложение
		 */
		_createOverlay: function(container) {
			if (!this.options.modal) return false;
			
			var overlay = new Element('div').inject(container, 'before');
			overlay.set('opacity', 0);
			overlay.setStyle('visibility', 'hidden');
			overlay.addClass('majWidget-overlay');
			
			return overlay;
		},
		/**
		 * Создает контейнер виджета
		 */
		_createWidget: function(object, container)
		{
			var widget = new Element('div').inject(container);
			widget.setStyle('visibility', 'hidden');
			widget.set('opacity', 0);
			widget.addClass('majWidget');
			
			if (this.options.id) {
				widget.set('id', this.options.id);
			}
			
			if (this.options.className) {
				widget.addClass(this.options.className);
			}
			
			widget.addEvent('mousedown', function(){
				if (!object.options.on_top) object.pushToTop();
			});
			
			return widget;
		},
		/**
		 * Создает обертку для содержимого
		 */
		_createWrap: function(widget)
		{
			var wrap = new Element('div').inject(widget);
			wrap.addClass('majWidget-wrap');
			
			return wrap;
		},
		/**
		 * Создает заголовок
		 */
		_createHeader: function(wrap)
		{
			var header = new Element('div').inject(wrap);
			header.addClass('majWidget-header');
			
			return header;
		},
		/**
		 * Создает контейнер для текста заголовка
		 */
		_createHeaderText: function(header)
		{
			var headerText = new Element('span').inject(header);
			headerText.set('text', this.options.title);
			headerText.addClass('majWidget-header-text');
			
			return headerText; 
		},
		/**
		 * Создает контейнер для управляющих кнопок
		 */
		_createControls: function(header)
		{
			var controls = new Element('div').inject(header);
			controls.addClass('majWidget-controls');
			
			return controls; 
		},
		/**
		 * Создает кнопку сворачивания
		 */
		_createMinimize: function(controls)
		{
			if (!this.options.minimize) return false;
			
			var minimize  = new Element('span').inject(controls);
			minimize.addClass('majWidget-minimize');
			
			return minimize;
		},
		/**
		 * Создает кнопку развертывания
		 */
		_createMaximize: function(controls)
		{
			if (!this.options.maximize) return false;
			
			var maximize  = new Element('span').inject(controls);
			maximize.addClass('majWidget-maximize');
			
			return maximize;
		},
		/**
		 * Создает кнопку возврата к предыдущему размеру
		 */
		_createUnmaximize: function(controls)
		{
			if (!this.options.maximize) return false;
			
			var unmaximize  = new Element('span').inject(controls);
			unmaximize.addClass('majWidget-unmaximize');
			unmaximize.setStyle('display', 'none');
			
			return unmaximize;
		},
		/**
		 * Создает кнопку скрывания
		 */
		_createClose: function(controls)
		{
			if (!this.options.close) return false;
				
			var close  = new Element('span').inject(controls);
			close.addClass('majWidget-close');
			
			return close;
		},
		/**
		 * Создает контейнер для содержимого
		 */
		_createContent: function(wrap, header)
		{
			var content = new Element('div').inject(wrap);
			content.addClass('majWidget-content');
			content.setStyle('height', (wrap.getSize().y-header.getSize().y)+'px');
			
			return content;
		},
		/**
		 * Делает виджет перетягиваемым
		 */
		_makeDraggable: function() {
			this.effects.drag = new majUi.draggable({
				element: this.elements.widget,
				holder: this.elements.header,
				position: this.position,
				dimensions: this.dimensions
			});
		},
		/**
		 * Добавляет возможность изменения размера окна
		 */
		_makeResizable: function()
		{
			var object = this;
			
			this.effects.resize = new majUi.resizable({
				element: this.elements.wrap,
				container: this.elements.widget,
				min_width: this.options.min_width,
				min_height: this.options.min_height,
				callback: function(resize)
				{
					object.elements.content.setStyle('height', (object.elements.wrap.getSize().y-object.elements.header.getSize().y)+'px');
				}
			});
		},
		/**
		 * Делает окно сворачиваемым
		 */
		_makeMinimizable: function(tray, object)
		{
			object.elements.minimize.addEvent('mousemove', function(){return false;});
			object.elements.minimize.addEvent('click', function(){
				object.hide();
				if (tray) object.elements.tray.removeClass('majWidget-tray-active');
				majWidgets.active = false;
			});
			
			if (!tray) return false;
			
			object.elements.tray = new Element('div').inject(tray);
			object.elements.tray.set('text', this.options.title);
			object.elements.tray.addClass('majWidget-tray');
			object.elements.tray.addClass('majWidget-tray-active');
			
			object.resetActive();
			
			object.elements.tray.addEvent('click', function(e){e.preventDefault();});
			object.elements.tray.addEvent('click', function(){
				if (object.is_hidden)
				{
					object.show();
					object.elements.tray.addClass('majWidget-tray-active');
				}
				else
				{
					if (majWidgets.active != object)
					{
						object.pushToTop();
					}
					else
					{
						object.hide();
						object.elements.tray.removeClass('majWidget-tray-active');
						majWidgets.active = false;
					}
				}
			});
		},
		/**
		 * Делает окно разворачиваемым
		 */
		_makeMaximizable: function(object){
			var widget = object.elements.widget;
			var wrap = object.elements.wrap;
			var header = object.elements.header;
			var content = object.elements.content;
			var maximize = object.elements.maximize;
			var unmaximize = object.elements.unmaximize;
			
			var resize = new Fx.Morph(wrap, {duration: 'normal'});
			var cr     = new Fx.Morph(content, {duration: 'normal'});
			var margin = new Fx.Morph(widget, {duration: 'normal'});
			
			var widgetSize = 0;
			var wrapSize   = 0;
			var headerSize = 0;
			var wrapDifX   = 0;
			var wrapDifY   = 0;
			var marginTop  = 0;
			var marginLeft = 0;
			
			maximize.addEvent('mousemove', function(){return false;});
			maximize.addEvent('click', function(){
				var documentSize = document.getSize();
				var coords = widget.getCoordinates();
				
				widgetSize = widget.getSize();
				wrapSize = wrap.getSize();
				headerSize = header.getSize();
				wrapDifX = widgetSize.x - wrapSize.x;
				wrapDifY = widgetSize.y - wrapSize.y;
				marginTop = widget.getStyle('margin-top').toInt();
				marginLeft = widget.getStyle('margin-left').toInt(); 
				
				resize.start({'height': documentSize.y-wrapDifY,'width': documentSize.x-wrapDifX});
				cr.start({'height': documentSize.y-wrapDifY-headerSize.y});
				margin.start({'margin-top': coords.top/-1+marginTop, 'margin-left': coords.left/-1+marginLeft});
				
				maximize.setStyle('display', 'none');
				unmaximize.setStyle('display', 'block');
			});
			
			unmaximize.addEvent('mousemove', function(){return false;});
			unmaximize.addEvent('click', function(){
				resize.start({'height': wrapSize.y,'width': wrapSize.x});
				cr.start({'height': wrapSize.y-headerSize.y});
				margin.start({'margin-top': marginTop, 'margin-left': marginLeft});
				
				unmaximize.setStyle('display', 'none');
				maximize.setStyle('display', 'block');
			});
		},
		/**
		 * Показывает виджет
		 */
		show: function(callback)
		{
			this.pushToTop();
			callback = callback || this.options.callShow;
			
			if (this.options.modal)
			{
				this.elements.overlay.setStyle('visibility', 'visible');
				this.elements.overlay.fxFade({opacity: this.options.modalOpacity}).show();
			}
			this.elements.widget.setStyle('visibility', 'visible');
			this.elements.widget.fxFade({callShow: callback}).show();
			
			this.is_hidden = false;
			
			return this;
		},
		/**
		 * Скрывает виджет
		 */
		hide: function(callback)
		{
			if (this.is_hidden) return true;
			callback = callback || this.options.callHide;
			
			this.elements.widget.fxFade({callHide: callback}).hide();
			if (this.options.modal)
			{
				this.elements.overlay.fxFade({opacity: this.options.modalOpacity}).hide();
			}
			this.is_hidden = true;
			
			return this;
		},
		/**
		 * Закрывает виджет
		 */
		close: function()
		{
			var object = this;
			var close = function(){
				if (object.options.modal) object.elements.overlay.dispose();
				if (object.elements.tray) object.elements.tray.dispose();
				object.elements.widget.dispose();
				object.options.callClose();
			}
			
			this.hide(close);
			
			return this;
		},
		/**
		 * Автоматически показывает или скрывает виджет
		 */
		toggle: function()
		{
			this.is_hidden ? this.show() : this.hide();
			
			return this;
		},
		resetActive: function()
		{
			if (majWidgets.active && majWidgets.active != this && majWidgets.active.elements.tray)
			{
				majWidgets.active.elements.tray.removeClass('majWidget-tray-active');
			}
			
			if (this.elements.tray) this.elements.tray.addClass('majWidget-tray-active');
			
			majWidgets.active = this;
		},
		pushToTop: function()
		{
			if (majWidgets.active != this)
			{
				this.elements.widget.inject(majWidgets.container, 'bottom');
				this.resetActive();
			}
			majWidgets.active = this;
		}
	});
	
	/**
	* Подтверждение
	*/
	var majWidgetConfirm = new Class({
		Implements: [Options],
		options: {
			id:           'confirm',
			modal:        true,
			modalOpacity: '0.5',
			title:        'Title',
			draggable:    true,
			resizable:    false,
			close:        true,
			maximize:     false,
			min_width:    120,
			min_height:   80,
			callShow: function(){},
			callClose: function(){},
			callProceed: false,
			text: 'Вы действительно хотите продолжить?',
			proceed: 'Продолжить',
			cancel: 'Отмена'
		},
		window: false,
		initialize: function(element, options)
		{
			this.setOptions(options);
			
			var object = this;
			
			function createWindow(proceed)
			{
				object.window = new majWidget(object.options);
				
				var data = new Element('div').addClass('majWidget-content-data').inject(object.window.elements.content);
				
				data.set('text', object.options.text);
				
				var box = new Element('div').addClass('majWidget-buttons').inject(data, 'bottom');
				var confirm = new Element('input').set('type', 'button').addClass('button').set('value', object.options.proceed).inject(box, 'bottom');
		    	var cancel = new Element('input').set('type', 'button').addClass('button').set('value', object.options.cancel).inject(box, 'bottom');
		    	
		    	confirm.addEvent('click', function(){
		    		proceed();
		    		object.window.close();
		    	});
		    	
		    	cancel.addEvent('click', function(){
		    		object.window.close();
		    	});
				
				object.window.show();
			}
			
			var proceed = this.options.callProceed;
			
			if(element.tagName == 'FORM')
			{
				proceed = proceed ? proceed : function(){element.submit();}
				element.addEvent('submit', function(){
					createWindow(proceed);
					return false;
				});
			}
			
			if(element.tagName == 'A' || element.tagName == 'BUTTON')
			{
				proceed = proceed ? proceed : function(){document.location=element.get('href');}
				element.addEvent('click', function(){
					createWindow(proceed);
					return false;
				});
			}
		}
	});
	
	/**
	 * Расширение функциональности элемента
	 */
	Element.implement({
		mwConfirm: function(options) {return new majWidgetConfirm(this, options);}
	});
