/**

 */

var Gallery = Base.extend({

	loader: null,		// String, path to image preloader loading gif;
	secondary: null,	// HTMLElement(s), ref secondary gallery content;
	primary: null,		// String, (url) ref to primary gallery content;
	target: null,		// HTMLElement, current clicked element;
	$: null,			// jQuery; 
	width: null,        // Number, gallery width;

    constructor: function() {},
     
    init: function( $ ){
		if( ! $ ){ 
		    return false; 
		};
        this.$ = $;
        this.loader = "../SiteImages/Common/loading.gif";
        this.bind();
        this.build();
	},
	
    /**
     * builds the following dom structure and binds event handlers;
     * <div class="ui-overlay"></div>
	 * <div class="ui-gallery">
	 *		<div class="head"></div>
	 *		<div class="main"></div>
	 *		<div class="foot">
	 *			<a>Close</a>
	 *		</div>
	 * </div>
     */
    build: function(){
		var root = this.$( "body" );
		var self = this;

		this.$( "<div></div>" )
			.addClass( "ui-overlay" )
			.appendTo( root )		
			.bind( "click", function( e ){
				self.handler.call( self, e, "hide" );
				return stopDefault( e );
			});
						
		var gallery = this.$( "<div></div>" )
						.addClass( "ui-gallery" )
						.appendTo( root )
						.hide();	
						
		var head =	this.$( "<div></div>" )
						.addClass( "head clear" )
						.appendTo( gallery );
												
		var main =	this.$( "<div></div>" )
						.addClass( "main" )
						.appendTo( gallery );
						
		var gutter = this.$( "<div></div>" )
						.addClass( "gutter clear" )
						.appendTo( main );

		var foot =	this.$( "<div></div>" )
						.addClass( "foot clear" )
						.appendTo( gallery );	
										
		/*
			var title =	this.$( "<p></p>" )	
						.css({ visibility: "hidden" })
						.appendTo( foot );
		*/			

		this.$( "<a>Close</a>" )	
			.attr( "href", "#" )
			.addClass( "close" )		
			.appendTo( foot )
			.bind( "click", function( e ){
				self.handler.call( self, e, "hide" );
				return stopDefault( e );
			});	
						
		var loader = this.$( "<div></div>" )
						.addClass( "ui-preloader" )
						.appendTo( root )
						.hide();	
						
		this.$( "<img></img>" )
			.attr( "src", this.loader )
			.attr( "width", 126 )
			.attr( "height", 22 )
			.appendTo( loader );	
						
		// keep window centered;				
		this.$( window ).resize( function(){
			self.adjust( gallery );
		});
		this.$( window ).scroll( function(){
			self.adjust( gallery );
		});	
    },
    
    /**
     * adds previous and next navigation if required,
     * first checks to see if the gallery exists if
     * not fires it's self recursively;
     */
    setNavigation: function(){
		var gallery = this.$(".ui-gallery");
		var foot = this.$( ".foot", gallery );
		var self = this;
		if( foot.length < 1 ){
			 setTimeout( function(){
                self.setNavigation();
                return false;
            }, 50 );
		}else{
			this.$( "<a>&laquo Prev</a>" )	
				.attr( "href", "#" )	
				.addClass( "prev" )
				.appendTo( foot )
				.bind( "click", function( e ){
					self.handler.call( self, e, "prev" );
					this.blur();
					return stopDefault( e );
				});	

			this.$( "<a>Next &raquo</a>" )	
				.attr( "href", "#" )
				.addClass( "next" )	
				.appendTo( foot )
				.bind( "click", function( e ){
					self.handler.call( self, e, "next" );
					this.blur();
					return stopDefault( e );
				});	
		};
    },
    
    /**
     * bind the child links of all elements with 
     * a parent of class gallery;
     */
    bind: function(){
		var self = this;
		// collect all in page galleries...;
	    this.$( ".genericGallery" ).each( function( i, val ){
			// ..and bind click handlers;
			self.$( "a", val ).bind( "click", function( e ){
				self.handler.call( self, e );
				this.blur();
				return stopDefault( e );
			}); 
	    });
    },
    
    /**
     * all gallery events are filter though this function 
     * giving a centeralised point for event deligation;
     * @param	event{Object}	event type;
     * @param	type{String}	optional, provides a greater
	 *							level of granularity;
     */
    handler: function( event, type ){
		switch( type ){
			case "hide":
				this.hide();
				break;
			case "prev":
				this.prev();
				break;
			case "next":
				this.next();
				break;
			default:
				this.target = event.target.parentNode;
				this.setContent();
				break;
		};
    },
    
    next: function(){
		var node = this.getSibling( "next" );
		if( node ){
		    this.target = node;
		    this.setContent();
		};
    },
    
    prev: function(){
		var node = this.getSibling( "prev" );
		if( node ){
		    this.target = node;
		    this.setContent();
		};
    },
    
    getSibling: function( direction ){
		// HACK: get parent li elem next 
		// sibling, not very clever!!;
		var node =	this.$( this.target )
					.parent()
					[direction]();
		if( node.length > 0 ){
			return link = this.$( "a", node )
						  .get();
		}else{
			return false;
		};
    },
    
    setContent: function(){
		this.hide();
		this.clear();
		this.primary = this.$( this.target ).attr( "href" );
		this.setPrimary( this.primary );
		this.setSecondary();
    },
    
    clear: function(){
		var gallery = this.$( ".ui-gallery" );
		this.$( ".gutter", gallery )
			.empty();
    },
    
    /**
     * primary gallery content, project specific implimentation;
     * @param	url{String}	path to current image;
     */
    setPrimary: function( url ){
		this.loadImage( url );
    },
    
    /**
     * secondary gallery content, project specific implimentation;
     */
    setSecondary: function(){
		var elems = {};
		var elem =	this.$( this.target )
					.parent()
					.parent();
		elems.header =	this.$( "h3", elem )
						.clone( true );
		elems.paras =	this.$( "p", elem )
						.clone( true );
		return this.secondary = elems;
    },
    
    /**
	 * preload new image;
	 * @param	image{String}	ref to new image;
	 */	
	loadImage: function( url ){
		var self = this;
		var image = new Image();
		image.onload = function(){
			self.loaded.call( self, image );
		};
		image.src = url;
		var loader = this.$( ".ui-preloader" );
		loader.show();
		this.adjust( loader );
		this.setOverlay();
	},
	
	show: function(){
		this.$( ".ui-gallery" )
			.show();
	},
	
	hide: function(){
		this.$( ".ui-overlay" )
			.hide(); 
		this.$( ".ui-gallery" )
			.hide();	
	},
	
	hideOverlay: function(){
		this.$( ".ui-overlay" )
			.hide();	
	},
    
    /**
	 * declarative only, provides a brief pause before displaying image;
	 * @param	image{Object}	ref to new image;	
	 */
	loaded: function( image ){
	    var self = this;
	    this.width = image.width;
        setTimeout( function(){
                self.showContent( image );
            }, 500, image );
	},
	
	/**
	 * preps the gallery ready for new content;
	 * @param	elem{Object}	new primary content;	
	 */
	showContent: function( elem ){
		this.$( ".ui-preloader" ).hide();
		var gallery = this.$( ".ui-gallery" );
		if( this.width ){
		    gallery.width( this.width );
		};
		var main = this.$( ".gutter", gallery );
		this.addPrimary( main, elem );
		// if secondary content availible;
		if( this.secondary ){
		    this.addSecondary( main );
		};
		gallery.show();
		this.adjust( gallery );
	},
	
	/**
	 * add primary content to gallery;
	 * @param	container{Object}	content container;
	 * @param	content{Object}	    new primary content;
	 */
	addPrimary: function( container, content ){
		// add new content...;
		container.prepend( content );
		// ..and fade in;
	    this.$( content, container )
	        .css( "opacity", 0 )
	        .fadeTo( "slow", 1 ); 
	},
	
	/**
	 * add additional content if required;
	 * @param	content{Object}	    new additional content;
	 */
	addSecondary: function( content ){
		this.secondary.header.appendTo( content );
		this.secondary.paras.appendTo( content );
	},
    
    /**
     * center the gallery in the browser on load of 
     * new image, resize of browser and page scroll;
     */
    adjust: function( elem ){
		var self = this;
        var width = elem.width();
        var height = elem.height();
        var l = this.scrollX() + 
			( this.windowWidth()/2 ) - ( width/2 );
        var t = this.scrollY() + 
			( this.windowHeight()/2 ) - ( height/2 );
        l = ( l < 0 ) ? 0 : l;
        t = ( t < 0 ) ? 0 : t;  
        elem.css({ left: l, top: t });
        // resize overlay if visible;
        if( this.$(".ui-overlay").css( "display" ) == "block" ){
			self.setOverlay();
		}
    },
    
    /**
     * reset overlay size on browser resize, scroll etc;
     */
    setOverlay: function(){
        var h = this.pageHeight();
        var w = this.pageWidth();
		this.$(".ui-overlay").css({
			width:	w + "px",
			height:	h + "px",
			opacity: .75
		}).show();
	},
	
	pageHeight: function(){
	    return document.body.scrollHeight;
	},
	
	pageWidth: function(){
	    return document.body.scrollWidth;
	},
    
    scrollX: function(){
	    var de = document.documentElement;
	    return self.pageXOffset ||
	        ( de && de.scrollLeft ) ||
	            document.body.scrollLeft;
	},
	
	scrollY: function(){
	    var de = document.documentElement;
	    return self.pageYOffset ||
	        ( de && de.scrollTop ) ||
	            document.body.scrollTop;
	},
	
	windowWidth: function(){
		var de = document.documentElement;
		return self.innerWidth || 
			( de && de.clientWidth ) ||
				document.body.clientWidth;
	},
	
	windowHeight: function(){
		var de = document.documentElement;
		return self.innerHeight || 
			( de && de.clientHeight ) ||
				document.body.clientHeight;
	}
});