var FrontImages = Class.create({

	// The div that contains all images
	imagesContainer: null,
	
	// The current image in focus, is faded-to-top and has the caption shown
	focusImage: null,
	
	// The last image that has had a mouse over effect -> will become the focus image unless superseded with a new lastSelected 
	lastSelected: null,
	
	// The list of images in  "frontpagepic" format supplied to the class through the constructor 
	frontpagepics: null,
	
	// The prefix to add to all images generated by this class 
	idPrefix: "",
	
	captionHandler: null,
	
	dragger: null,
	
	editMode: false,
	
	draggedUpdated: function(fpp) {
	},
	
	onGetCaptionHandlerSettings: function() {
		return {
				className: 'frontImageCaption',
				editMode: false
			};		
	},
	
	/*
	Constructor. creates an image manager that 
	- displays all the images on the correct location
	- fades-them-to-top when mouse moving over them
	- shows caption with description when moving over them	
	
	@param containerId Id of the master container (div) to contain the images
	@param images a list/array of images in "frontpagepic" format
	@param extra Any extra properties to be set, or functions to override. optional.  
	
	@note "frontpagepic" format:
	{ image: "<url>", width: 320, height: 240, x: 10, y: 10, description: "<description>", link: "<url or empty>" },
	*/
	initialize: function(containerId, frontpagepics, extra) {
		var container = $(containerId);
		this.imagesContainer = container;
		this.frontpagepics = frontpagepics;
		
		// extend with extra properties if the arg is supplied				
		if (typeof(extra) != "undefined") {
			Object.extend(this, extra);
			extra._super = this;
		}

		this.captionHandler = new CaptionHandler(this.onGetCaptionHandlerSettings());
		
		if (this.editMode) {
			// enable dragger 
			var dragStart = this.dragStart.bind(this);
			var dragStop = this.dragStop.bind(this);			
			var dragging = this.dragging.bind(this);
			var maxX = this.imagesContainer.getWidth();
			var maxY = this.imagesContainer.getHeight();
			this.dragger = new Dragger({ onDragStart: dragStart, onDragStop: dragStop, onDragging: dragging, mbrMax: new Coords(maxX, maxY) });
		}

		
		// make an image for every front page pic
		for (var i = frontpagepics.length - 1; i >= 0; i--) {
			var fpp = frontpagepics[i];
			
			this.initializeFpp(fpp);
		}
	},
	
	initializeFpp: function(fpp) {
		// create the image representation for the frontpage img.
		var img = document.createElement("img");			
		img.src = fpp.image;
		img.id = $id(this.idPrefix, fpp.id);
		img.style.position = "relative";
		img.style.width = $px(fpp.width);
		img.style.height = $px(fpp.height);		
		img.style.marginRight = $px(- fpp.width);
		img.style.marginBottom = $px(- fpp.height);
		img.style.left = $px(fpp.x);
		img.style.top = $px(fpp.y);
		this.imagesContainer.appendChild(img);
		fpp.imgInstance = img;
		
		if (this.editMode == true) {
			this.dragger.register(img);
		} 
		
		Event.observe(img, 'mouseover', this.onMouseOver.bindAsEventListener(this));
	},
	
	addItem: function(fpp) {
		// skip if already added
		if (this.getIndexById(fpp.id) >= 0) return;
		// add fpp
		this.frontpagepics.push(fpp);
		this.initializeFpp(fpp);
	},
	
	removeItem: function(id) {
		var i = this.getIndexById(id);
		if (i < 0) return;
		var fpp = this.frontpagepics[i];
		this.imagesContainer.removeChild(fpp.imgInstance);
		this.frontpagepics.splice(i, 1);
	},
	
	/*
	Returns the index of the frontpagepic that matches the supplied id. If id is prefixed, 
	it will be unprefixed correctly. 
	
	@param id The id of the frontpagepic that is requested 
	
	@return The index of the matching frontpagepic or -1. 
	*/
	getIndexById: function(id) {
		id = $unid(this.idPrefix, id);
		for (var i = 0; i < this.frontpagepics.length; i++) {
			if (this.frontpagepics[i].id == id) return i;
		}
		return -1;
	},

	/*
	Fades in an image to the front. 
	After the fade in has been completed, an no other image has been
	selected in the mean time, the this.focusImage field will be set to 
	this image.
	
	@param img The image that needs to fade-in. (Actually creates a new image)
	@return void
	*/
	fadeIn: function(img) {
		if (this.focusImage) {
				this.fadeOut(this.focusImage);
		}
		params = {
			from: 0.0, 
			to: 1.0, 
			afterFinish: function(obj){ 
				// check if no other element has replaced this image as 
				// the focus image now the fade in has been completed 
				if (this.lastSelected == obj.element) {
				   // this is still the last selected image, so register it as focus image 
					this.focusImage = obj.element;
				} else {
				   // nope already new kid on the block. just fade it out. 
					this.fadeOut(obj.element);
				}
			}.bind(this)
		};
		new Effect.Opacity(img, params);
	},
	
	/*
	Fades out and removes the supplied image.
	
	@param img !!! The image that needs to be removed (actually the duplicate created to do the fade in in the first place)
	 
	*/
	fadeOut: function(img) {
		if (img == this.focusImage) { 
			this.focusImage = undefined;
		}
		params = {
			from: 1.0, 
			to: 0.0, 
			afterFinish: function(obj){
				if (this.editMode == true) {
					// Remove dragging handlers
					this.dragger.unregister(obj.element);
				}
				//object is already removed by previous or other event? skip...
				if (!obj.element.parentNode) {
					return;
				} 
				obj.element.parentNode.removeChild(obj.element); 
			}
		};
		new Effect.Opacity(img, params);
	},
	
	onMouseOver: function(event) {
		var elem = Event.element(event);

		var fppIdx = this.getIndexById(elem.id);
		if (fppIdx < 0) return; 
		var description = this.frontpagepics[fppIdx].description;
		var url = this.frontpagepics[fppIdx].link;
		
		if (!this.editMode) {
			// create a copy of the image on the very top Z-level that
			// fade's in (fade-to-top effect)
			var img = elem.cloneNode(false);
			this.lastSelected = img;
			img.style.zIndex = "10";
			img.setOpacity(0.0);
			this.imagesContainer.appendChild(img);
			
			// start the fade in effect
			this.fadeIn(img);

			// show caption 
			this.captionHandler.showCaptionForImage(img, description, url);
		} else {
			if (!this.dragger.isDragging()) {
				// show the caption
				this.captionHandler.showCaptionForImage(elem, description, url);
			}
		}	 
	},
	
	dragStart: function(item) {
		//item.parentNode.removeChild(item);
		var captionDiv = this.captionHandler.getCaptionDiv();
		if (captionDiv != null) {
			captionDiv.insert({ before: item });
		} else {   
			this.imagesContainer.insert(item);
		}
	},
	
	dragStop: function(item) {
		var idx = this.getIndexById(item.id);
		if (idx < 0) return;
		var fpp = this.frontpagepics[idx];
		fpp.x = $unpx(item.style.left);
		fpp.y = $unpx(item.style.top);
		this.draggedUpdated(fpp);
	},
	
	dragging: function(item) {
		this.captionHandler.updateCaptionPosition(item);
	}
	
});
