function GalleryItem( jElement, gallery ) {
	this.toString	= function() {
		return getUid( this.element.attr( 'src' ) );
	}
	this.unbind		= function() {
		this.element.parent().unbind( 'click', this.onClick );
		this.element.parent().unbind( 'mouseover', this.onMouseOver );
		this.element.parent().unbind( 'mouseout', this.onMouseOut );

		var ref	= this;
		this.element.parent().fadeOut( 'fast', function() {
			ref.notify( GalleryItem.Events.Unbind, {} );
		} );
	}
	this.onClick		= function( evt ) {
		evt.preventDefault();
		new ZoomBox().setSource( evt.data.ref.element.attr( 'src' ).replace( /thumbnail/, 'original' ) ).setMargin( 30 ).bind();
	}
	this.onMouseOver	= function( evt ) {
		evt.preventDefault();
		evt.data.ref.zoom.show();
	}
	this.onMouseOut		= function( evt ) {
		evt.preventDefault();
		evt.data.ref.zoom.hide();
	}
	this.bind		= function() {
		this.element.wrap( jQuery( '<div class="gallery_item_container" />' ) );
		this.element.parent().append( this.zoom.hide() );

		this.element.addClass( 'gallery_item' );

		this.element.parent().bind( 'click', { ref: this }, this.onClick );
		this.element.parent().bind( 'mouseover', { ref: this }, this.onMouseOver );
		this.element.parent().bind( 'mouseout', { ref: this }, this.onMouseOut );

		this.notify( GalleryItem.Events.Bind, {} );
	}
	this.getBounds	= function() {
		return this.bounds;
	}
	this.setBounds	= function( o ) {
		var animate_props	= [];
		var map				= {
			x:	'left',
			y:	'top',
			w:	'width',
			h:	'height'
		};
		for( var i in o ) {
			if ( null != this.bounds[ i ] && this.bounds[ i ] != o[ i ] ) {
				animate_props.push( [ map[ i ], o[ i ] ] );
			}
			this.bounds[ i ] = o[ i ];
		}
		this.updateUI( animate_props );
	}
	this.updateUI	= function( animate_props ) {
		if ( animate_props.length > 0 ) {
			var o	= {};
			for( var i=0; i<animate_props.length; i++ ) {
				o[ animate_props[ i ][ 0 ] ] = animate_props[ i ][ 1 ];
			}
			this.element.parent().animate( o );
		} else {
			this.element.parent().css( {
				top:		this.bounds.y,
				left:		this.bounds.x
			} );
		}
		this.zoom.css( {
			top:		this.bounds.h - 20
		} );
	}
	this.setPage	= function( pg ) {
		this.page	= pg;
	}
	this.getPage	= function() {
		return this.page;
	}

	this.gallery		= gallery;
	this.page			= null;
	this.element		= jElement;
	this.bounds			= {
		x:	null,
		y:	null,
		w:	null,
		h:	null
	}
	this.zoom			= jQuery( '<div class="zoom_mark" title="Zoom">Zoom</div>' );

	jQuery.extend( this, new Observable() );
}
GalleryItem.Events	= {
	Bind:	'onItemBound',
	Unbind:	'onItemUnbound'
}

function GalleryPage( gallery ) {
	this.onItemUnbound	= function( gItem ) {
		var gi_bounds	= gItem.getBounds();
		gItem.element.parent().remove();

		var item_index		= -1;
		for( var i=0; i<this.items.length; i++ ) {
			if ( this.items[ i ] == gItem ) {
				item_index	= i;
				break;
			}
		}

		if ( item_index != -1 ) {
			this.items[ item_index ].removeObserver( this );
			this.items.splice( item_index, 1 );
		}

		if ( this.items.length < 1 ) {
			this.gallery.removePage( this );
		} else {
			this.repaint();
		}

		this.notify( GalleryPage.Events.ItemDelete, {
			target: gItem
		} );
	}
	this.onItemBound	= function( gItem ) {
		gItem.setPage( this );
		gItem.element.show();
		this.items.push( gItem );
	}
	this.removeItem		= function( gItem ) {
		for( var i=0; i<this.items.length; i++ ) {
			if ( this.items[ i ] == gItem ) {
				this.items[ i ].unbind();
				break;
			}
		}
	}
	this.shift			= function() {
		if ( 0 == this.items.length ) {
			return null;
		}
		var rv	= this.items[ 0 ];
		rv.removeObserver( this );
		this.items.splice( 0, 1 );
		return rv;
	}
	this.push			= function( gItem ) {
		gItem.setPage( this );
		gItem.addObserver( this );
		this.items.push( gItem );
		this.container.append( gItem.element.parent() );
		this.repaint();
	}
	this.repaint		= function() {
		this.current_x	= 0;
		this.current_y	= 0;

		var item_bounds;
		for( var i=0; i<this.items.length; i++ ) {
			item_bounds	= this.items[ i ].getBounds();

			if ( this.current_x != item_bounds.x || this.current_y != item_bounds.y ) {
				this.items[ i ].element.css( {
					zIndex:	this.items.length - i
				} );
				this.items[ i ].setBounds( {
					x:	this.current_x,
					y:	this.current_y
				} );
			}

			this.current_x	+= item_bounds.w;

			if ( this.current_x > this.max_w ) {
				this.current_x	= 0;
				this.current_y	+= item_bounds.h;
			}
		}
	}
	this.isComplete	= function() {
		this.notify( GalleryPage.Events.PageLoaded, {} );
	}
	this.add		= function( gItem ) {
		if ( -1 == this.max_x && -1 == this.max_y ) {
			this.max_w	= this.container.width();
			this.max_h	= this.container.height();
		}

		if ( this.current_y >= this.max_h ) {
			this.isComplete();
			return false;
		}

		//	A ne pas d�placer car apr�s le append, width() && height() vaudront 0
		//	car le container de GalleryPage est masqu�
		//	(pour le moment element est dans le conteneur "visible" de Gallery)
		var item_w	= gItem.element.width();
		var item_h	= gItem.element.height();

		this.container.append( gItem.element );
		gItem.addObserver( this );
		gItem.bind();

		//	Solution simple :)
		if ( 'undefined' != typeof GalleryItemBackOffice ) {
			GalleryItemBackOffice( gItem );
		}

//	jQuery('body').append( '{ x: ' + this.current_x + ', y: ' + this.current_y + ', width: ' + item_w + ', height: ' + item_h + ' }<br />' );
		gItem.setBounds( {
			x:	this.current_x,
			y:	this.current_y,
			w:	item_w,
			h:	item_h
		} );

		this.current_x	+= item_w;

		if ( this.current_x > this.max_w ) {
			this.current_x	= 0;
			this.current_y	+= item_h;
		}

		return true;
	}
	this.show		= function() {
		this.container.fadeIn();
	}
	this.hide		= function() {
		this.container.fadeOut();
	}
	this.getPageNumber	= function() {
		return this.page_number;
	}
	this.setPageNumber	= function( page_number ) {
		this.page_number	= page_number;
	}

	this.gallery		= gallery;
	this.page_number	= -1;
	this.container		= jQuery( '<div class="gallery_page" />' ).hide();
	this.max_x			= -1;
	this.max_y			= -1;
	this.current_x		= 0;
	this.current_y		= 0;
	this.items			= [];

	jQuery.extend( this, new Observable() );
}
GalleryPage.Events	= {
	ItemDelete:	'onItemDelete',
	PageLoaded:	'onPageLoaded'
}

function Gallery( jContainer ) {
	this.onPageLoaded		= function( page ) {
		if ( page.getPageNumber() == this.current_page ) {
			page.show();
		}
	}
	this.onItemDelete	= function( page, context ) {
		var next_page = null;
		for( var i=0; i<this.pages.length; i++ ) {
			if ( this.pages[ i ] == page ) {
				if ( i < this.pages.length - 1 ) {
					next_page	= this.pages[ i + 1 ];
				}
				break;
			}
		}

		if ( null != next_page ) {
			var item	= next_page.shift();
			if ( null != item ) {
				page.push( item );

				if ( next_page.items.length < 1 ) {
					next_page.gallery.removePage( next_page );
				} else {
					next_page.repaint();
				}
			}
		}
	}
	this.removePage		= function( pg ) {
		var pg_index	= -1;
		for( var i=0; i<this.pages.length; i++ ) {
			if ( this.pages[ i ] == pg ) {
				pg_index	= i;
				this.pages[ i ].container.remove();
				this.pages.splice( i, 1 );
				this.n_pages--;
				if ( this.current_page >= pg_index ) {
					this.current_page--;
				}
				break;
			}
		}
		if ( -1 != pg_index ) {
			if ( null != this.pagination.top ) {
				this.pagination.top.setMaxPage( this.n_pages + 1 );
			}
			if ( null != this.pagination.bottom ) {
				this.pagination.bottom.setMaxPage( this.n_pages + 1 );
			}
		}
		if ( this.pages.length > 0 ) {
			this.pages[ this.current_page ].show();
		}
	}
	this.getPageAt		= function( i ) {
		if ( 'undefined' == typeof this.pages[ i ] ) {
			var page		= new GalleryPage( this );
			page.setPageNumber( this.pages.length );
			page.addObserver( this );
			this.container.append( page.container );
			this.pages[ i ]	= page;
		}
		return this.pages[ i ];
	}
	this.onImageLoaded	= function( jElement ) {
		this.container.append( jElement.hide() );

		var item_w	= jElement.width();
		var item_h	= jElement.height();

		var page	= this.getPageAt( this.n_pages );

		var gItem	= new GalleryItem( jElement, this );

		if ( !page.add( gItem ) ) {
			page	= this.getPageAt( ++this.n_pages );
			page.add( gItem );
		}

		this.n_items--;
		if ( 0 == this.n_items ) {
			this.bind();
		}
	}
	this.onImageError	= function( jElement ) {
		this.n_items--;
		if ( 0 == this.n_items ) {
			this.bind();
		}
	}
	this.onPaginationBarUpdate	= function( target, context ) {
		var new_current_page	= target.getCurrentPage();

		if ( new_current_page != this.current_page ) {
			if ( 'undefined' != typeof this.pages[ new_current_page ] ) { 
				this.pages[ this.current_page ].hide();
				this.pages[ new_current_page ].show();
				this.current_page	= new_current_page;
			}
		}

		if ( target == this.pagination.top ) {
			this.pagination.bottom.setCurrentPage( new_current_page );
		} else if ( target == this.pagination.bottom ) {
			this.pagination.top.setCurrentPage( new_current_page );
		}

		target.repaint();
	}
	this.bind			= function() {
		this.pages[ this.pages.length - 1 ].isComplete();

		var struct	= {
			top:	'left',
			bottom:	'center'
		}
		for( var k in struct ) {
			this.pagination[ k ]	= new PaginationBar( struct[ k ], this.n_pages + 1 );
			this.pagination[ k ].addObserver( this );

			var o					= jQuery( 'div.pagination ul.' + struct[ k ] );
			if ( null != o.html() ) {
				this.pagination[ k ].setContainer( o );
			}

			this.pagination[ k ].render();
		}

		this.render();
	}
	this.start			= function() {
		var ref	= this;

		jQuery.ajax( {
			type:		'GET',
			dataType:	'xml',
			url:		this.container.attr( 'mg:xml' ),
			success:	function( xml ) {
				var pictures	= jQuery(xml).find('picture');
				ref.n_items	= pictures.length;
				pictures.each( function( i ) {
					new ImagePreloader( jQuery(this).attr( 'src' ), ref,  jQuery(this).attr( 'alt' ) ).start();
				} );
			}
		} );
	}
	this.render			= function() {
		var struct	= {
			top:	'insertBefore',
			bottom:	'insertAfter'
		}
		for( var k in struct ) {
			if ( null != this.pagination[ k ] ) {
				this.pagination[ k ][ struct[ k ] ]( this.container );
			}
		}
		/*
		if ( 'undefined' != typeof this.pages[ this.current_page ] ) {
			this.pages[ this.current_page ].show();
		}
		*/
	}

	this.container		= jContainer;
	this.n_items		= 0;
	this.pages			= [];
	this.current_page	= 0;
	this.n_pages		= 0;
	this.pagination		= {
		'top':		null,
		'bottom':	null
	};
}

jQuery(document).ready( function( e ) {
	//	On supprime les images d�j� pr�sentes dans la page
	jQuery( 'img.patchwork' ).remove();
	jQuery( 'div.pagination' ).hide();

	new Gallery( jQuery( 'div#images div.block_item_content' ) ).start();
} );