/**
 * Klasa jsWindowManager
 * Klasa ta umożliwia proste zarządzanie oknami (generowanymi przez js)
 * umożliwia tworzenie okien różnych typów, przenoszenie na wierzch, 
 * różnego typu zarządzanie itp.
 * 
 * interfejs:
 * jsWindowManager.Window( {string} title, {string} content, {object} newOptions )
 *     // konstruktor, tworzy okno na warstwie, zwraca obiekt do sterowania nim
 *     // opis opcji jakie można ustawić znajduje się poniżej, wszystkie są opcjonalne
 * jsWindowManager.Window.close()
 * 		// zamyka okno
 * jsWindowManager.Window.moveOnTop()
 * 		// przenosi na wierzch
 * jsWindowManager.Window.getId()
 * 		// zwraca id okna
 * jsWindowManager.Window.$( {string} className )
 * 		// zwraca pierwszy obiekt posiadający podaną klasę wewnątrz okna
 * 		// UWAGA! używanie id jest niezalecane, jeśli używasz id to pamiętaj, 
 * 		// żeby nie dało się otworzyć dwóch okien z tą samą zawartością
 * jsWindowManager.Window.$$( {string} cssRule )
 * 		// zwraca wszystkie elementy spełniające podaną regułę css i 
 * 		// znajdujące się wewnątrz okna
 * 
 * jsWindowManager.getWindow( {string} id ) : jsWindowManager.Window
 * 		// zwraca obiekt okna o podanym id, jeśli okna nie ma to zwracane jest false
 * jsWindowManager.closeAll( ) 
 * 		// zamyka wszyskie okna
 * 
 * options = {
 *	'type'		: 'window',
 * 	'id'		: '',
 * 	'width'		: 0,
 * 	'autohide'	: 0,
 *  'overlay'   : true,
 *  'position'	; 'auto',
 * 	'top'		: 0,
 * 	'left'		: 0
 * }
 * możliwe typy: window, info, error, tempInfo
 * pole 'id': Jeśli jest podane to system nie pozwoli na utworzenie dwóch okien o takim samym id
 * autohide: czas w sekundach po którym okienko samo zniknie, 0 = wyłączone
 * 
 */

/**
 * obiekt do zarządzania okienkami
 */
jsWindowManager =
{
	windows : {},
    windowsStack : [],
	hideMessageText : 'Zamknij',
	
	/**
	 * zwraca okno o podanym id, jeśli nie ma takiego okna zwracane jest false
	 * @param {string} id
	 * @return jsWindowManager.Window
	 */
	getWindow : function( id )
	{
		if( ! jsWindowManager.windows[ id ] ){
			return false;
		} else {
			return jsWindowManager.windows[ id ];
		}
	},
	
    /**
     * Zamyka wszystkie istniejące okna
     */
    closeAll : function()
    {
        for( myWindow in jsWindowManager.windows ){
            if( jsWindowManager.windows[ myWindow ] ){
                jsWindowManager.windows[ myWindow ].close();
            }
        }
    },
    
	/**
	 * zwraca wymiary strony, kod z quirksmode.org
	 */
	getPageDimensions : function()
	{
		var xScroll, yScroll;
		
		if (window.innerHeight && window.scrollMaxY) {	
			xScroll = window.innerWidth + window.scrollMaxX;
			yScroll = window.innerHeight + window.scrollMaxY;
		} else if (document.body.scrollHeight > document.body.offsetHeight){ // all but Explorer Mac
			xScroll = document.body.scrollWidth;
			yScroll = document.body.scrollHeight;
		} else { // Explorer Mac...would also work in Explorer 6 Strict, Mozilla and Safari
			xScroll = document.body.offsetWidth;
			yScroll = document.body.offsetHeight;
		}
		
		var windowWidth, windowHeight;
	
		if (self.innerHeight) {	// all except Explorer
			if(document.documentElement.clientWidth){
				windowWidth = document.documentElement.clientWidth; 
			} else {
				windowWidth = self.innerWidth;
			}
			windowHeight = self.innerHeight;
		} else if (document.documentElement && document.documentElement.clientHeight) { // Explorer 6 Strict Mode
			windowWidth = document.documentElement.clientWidth;
			windowHeight = document.documentElement.clientHeight;
		} else if (document.body) { // other Explorers
			windowWidth = document.body.clientWidth;
			windowHeight = document.body.clientHeight;
		}	
		
		// for small pages with total height less then height of the viewport
		if(yScroll < windowHeight){
			pageHeight = windowHeight;
		} else { 
			pageHeight = yScroll;
		}
		// for small pages with total width less then width of the viewport
		if(xScroll < windowWidth){	
			pageWidth = xScroll;		
		} else {
			pageWidth = windowWidth;
		}
		return {
				'pageWidth'		: pageWidth,
				'pageHeight'	: pageHeight,
				'windowWidth'	: windowWidth,
				'windowHeight'	: windowHeight
			};
	},
	
	/**
	 * zwraca dane o przewinięciu strony, kod z quirksmode.org
	 */
	getPageScroll : function()
	{
		var xScroll, yScroll;
		if (self.pageYOffset) {
			yScroll = self.pageYOffset;
			xScroll = self.pageXOffset;
		} else if (document.documentElement && document.documentElement.scrollTop){	 // Explorer 6 Strict
			yScroll = document.documentElement.scrollTop;
			xScroll = document.documentElement.scrollLeft;
		} else if (document.body) {// all other Explorers
			yScroll = document.body.scrollTop;
			xScroll = document.body.scrollLeft;	
		}
		return { 'x' : xScroll, 'y' : yScroll };
	},
	
    /**
     * zamyka okno o podanym id
     * funkcja bindowana jest do przycisku zamykania okna, zwykły user może używać bez problemów
     * metody close okna 
     * @private
     * @param {Event} event
     * @param {string} windowId
     */
    closeWindow : function( event, windowId )
    {
        if (event) {
            Event.stop(event);
        }
        var window = jsWindowManager.getWindow( windowId );
        if(window.close){
            window.close();
        }
    },
    
    /**
     * przesuwa okno o podanym id na wierzch, resztę układa pod nim
     * @param {Object} windowId
     */
    moveOnTop : function( windowId )
    {
        jsWindowManager.windowsStack = jsWindowManager.windowsStack.without( windowId );
        jsWindowManager.windowsStack.unshift( windowId );
        var i;
        for( i=0; i<jsWindowManager.windowsStack.length; i++ ){
            $( jsWindowManager.windowsStack[i] ).style.zIndex = 1000-(i*2)+1;
            if($( jsWindowManager.windowsStack[i]+'_overlay' )){
                $( jsWindowManager.windowsStack[i]+'_overlay' ).style.zIndex = 1000-(i*2);
            }
        }
    },
    
    /**
     * metoda nasłuchuje zdarzenia kliknięcia na okno
     * @param {Object} event
     * @param {string} windowId
     */
    windowOnClickListener : function( event, windowId )
    {
        jsWindowManager.moveOnTop( windowId );
    },
	
	/**
	 * Tworzy okienko o podanych parametrch, okienko jest pokazywane
	 * 
	 * w obiekcie options można podać typ okienka, domyślnie jest 'window', 
	 * opcje: 'window', 'error', 'info', 'tempInfo'
	 * okienka różnią się wyglądem
	 * 
	 * jeśli podane jest id system będzie pilnował, żeby nie powstały dwa okna 
	 * o jednakowym id, jeśli okno o takim id istnieje zostanie rzucony wyjątek
	 * 
	 * @throw Exception - gdy istnieje już okno o podanym id
	 * @constructor
	 * @param {string} title
	 * @param {string} content
	 * @param {Object} newOptions
	 */
	Window : function( title, content, newOptions )
	{
		var options = { 
			'type'		: 'window',
			'id'		: '',
			'width'		: 0,
			'autohide'	: 0,
            'overlay'   : true,
            'position'	: 'auto',
            'top'		: 0,
            'left'		: 0
		};
		options = Object.extend( options, newOptions );
		var template = null;
		var closeingInProgress = false;
		
		options = checkOptions( options );
		template = new Template( getTemplate( options ) );
		
		new Insertion.Bottom( document.body, template.evaluate( {'title':title, 'content':content} ) );
		
        setPosition( options );
        attachEvents( options );
		
		new Effect.Appear( $(options.id), { duration:0.3 } );
        if($(options.id+'_overlay')){
		    //new Effect.Appear( $(options.id+'_overlay'), { duration:0.3, to:0.4} );
		    $(options.id+'_overlay').show();
        }
        jsWindowManager.moveOnTop( options.id );
        
        // zarejestrowanie okienka w menedżerze
        jsWindowManager.windows[ options.id ] = this;
		
		
		/**
		 * zwraca pierwszy obiekt HTML znajdujący się wewnątrz okna i posiadający określoną klasę
		 * UWAGA! niezaleca się używania elementów id, ponieważ nie mogą istnieć dwa takie same 
		 * identyfikatory, używanie klas eliminuje ten problem
		 * @param {string} className
		 * @return {HTMLElement}
		 */
		this.$ = function( className )
		{
			return $$('div#'+options.id+' .'+className)[0];
		}
		
		/**
		 * zwraca tablicę obiektów znajdujących się wewnątrz okna i spełniających podaną regułę
		 * @param {string} cssRule
		 * @return {Array}
		 */
		this.$$ = function( cssRule )
		{
			return $$('div#'+options.id+' '+cssRule);
		}
		
		/**
		 * zamyka okienko
		 */
		this.close = function( )
		{
			if( closeingInProgress ){
                return;
            }
            closeingInProgress = true;
			new Effect.Fade( $(options.id), { duration:0.4, afterFinish: function(eff){ if(eff.element){ eff.element.remove() } } } );
            jsWindowManager.windows[ options.id ] = false;
            jsWindowManager.windowsStack = jsWindowManager.windowsStack.without( options.id );
            if($(options.id+'_overlay')){
                //new Effect.Fade( $(options.id+'_overlay'), { duration:0.4, from:0.3, afterFinish: function(eff){ if(eff.element){ eff.element.remove() } } } );
                $(options.id+'_overlay').remove();
            }
		}
		
        /**
         * przenosi okienko na wierzch
         */
        this.moveOnTop = function()
        {
            jsWindowManager.moveOnTop( options.id );
        }
        
        /**
         * zwraca id okna
         * @return {string} id
         */
        this.getId = function()
        {
            return options.id;
        }
        
		/**
		 * ustawia opcje okna w zależności od tego, jaki jest typ okna
		 * @throw Exception - gdy jest już okno o takim id
         * @param {Object} options
         * @return {Object} options
		 */
		function checkOptions( options )
		{
			var myWindow;
			if( ! options.id.blank() ){
				myWindow = jsWindowManager.getWindow( options.id )
				if( myWindow ){
					throw 'window with id "'+options.id+'" allready exists!';
				}
			} else {
				options.id = 'dragWindow'+Math.round( Math.random()*100000000 );
			}
			switch( options.type ){
				case 'window':
					options.width = options.width || 500;
					break;
				case 'error':
					options.width = options.width || 350;
					break;
				case 'info':
					options.width = options.width || 350;
					break;
				case 'tempInfo':
					options.width = options.width || 250;
					break;
			}
			return options;
		}
		
        /**
         * zwraca szablon dla podanych opcji
         * @param {Object} options
         * @return {string} template
         */
		function getTemplate( options )
		{
            var template = '';
            if(options.overlay){
	    		template += '<div id="'+options.id+'_overlay" class="dragWindowOverlay" '+
                        'style="display:none; height: '+jsWindowManager.getPageDimensions().pageHeight+'px"></div>';
            }
	        template += '<div id="'+options.id+'" class="dragWindow '+options.type+'Box" '+
                        'style="display:none; width: '+options.width+'px; position:absolute">';
			switch( options.type ){
				case 'window':
					template += '<div class="dragWindowTitle">' +
							'<a href="#" class="dragWindowClose" style="float:right;">'+
                                    '<img src="/images/index/panelClose.png" alt="[x]"/></a>' +
							'#{title}' +
							'<div style="clear:both"></div>' +
						'</div>' +
						'<div class="dragWindowContent">#{content}</div>';
					break;
				case 'error':
				case 'info':
					template += '<div class="dragWindowTitle">' +
							'#{title}' +
						'</div>' +
						'<div class="dragWindowContent">' +
							'<div>#{content}</div>' +
							'<a href="#" class="dragWindowClose">'+jsWindowManager.hideMessageText+'</a>' +
						'</div>';
					break;
				case 'tempInfo':
					template += '<div class="dragWindowContent">' +
							'<strong>#{title}</strong>' +
							'#{content}' +
						'</div>';
					break
			}
	        template += '</div>';
			return template;
		}
	    
        /**
         * ustawia okienko na stronie (pozycja)
         * @param {Object} options
         */
        function setPosition( options )
        {
    		var height = 0;
    		height = $( options.id ).getHeight();
    		dimensions = jsWindowManager.getPageDimensions();
    		topPx = (dimensions.windowHeight - height)/2;
    		offset = jsWindowManager.getPageScroll();
    		if( topPx < 10 ){
    			topPx = 10;
    		}
            var ie = false;
            /*@cc_on @*/
            /*@if (@_jscript)
            ie = true;
            @end @*/
            if(((height<dimensions.windowHeight-20 && options.position!='absolute') || options.position=='fixed') && !ie){
                $( options.id ).style.position = 'fixed';
              	$( options.id ).style.top = (options.top || topPx)+'px';
        		$( options.id ).style.left = (options.left || ((dimensions.windowWidth-options.width)/2))+'px';
            } else {
        		$( options.id ).style.top = (options.top || (topPx+offset.y))+'px';
        		$( options.id ).style.left = (options.left || ((dimensions.windowWidth-options.width)/2+offset.x))+'px';
            }
        }
        
        /**
         * zaczepia zdarzenia do przenoszenia okna i do zamykania
         * @param {Object} options
         */
        function attachEvents( options )
        {
    		var temp = $$('div#'+options.id+' .dragWindowTitle')[0]; 
    		if (!temp) {
                temp = $(options.id);
            }
			new Draggable( $(options.id), {handle:temp, starteffect: false, endeffect: false } );
			temp.style.cursor = 'move';
            
    		temp = $$('div#'+options.id+' .dragWindowClose')[0];
    		if( temp ){
    			temp.observe( 'click', jsWindowManager.closeWindow.bindAsEventListener(this, options.id) );
    		}
            $( options.id ).observe('click', jsWindowManager.windowOnClickListener.bindAsEventListener(jsWindowManager, options.id) );
            if( options.autohide != 0 ){
                setTimeout( jsWindowManager.closeWindow.bind( jsWindowManager, null, options.id ), options.autohide*1000 );
            }
        }
    }
}
