/**
 * Create namespace
 */
if (!JS.Components) {
	JS.Components = {};
}


/**
 * Lightbox
 *
 * @param {Object} config Configuration
 */
JS.Components.Lightbox = function (config) {
	//Set configuration
		this.config = JS.extend({
			owner: null,
			autoDiscover: true,
			preloadTimeout: 5000,		//Image preload timeout
			showTitle: false
		}, config);
		
		this.config.timer = null;
		this.config.image = null;
		this.config.owner = JS.Dom.get(this.config.owner) || document.body;
		
	//Set images
		this.images = {};
	
	//Create needed html
		this.elements = {
			image_container: null
		};
		
		this._createHtml();
		
	//Create panel
		this.panel = new JS.Components.Panel(this.elements.container, {
			className: 'component-panel lightbox-preview',
			fixedCenter: true,
			cssZIndex: 9999
		});
		this.panel.hide();
	
	//Functions
		var self = this;
		
		//Clicking on document closes lightbox
		JS.Event.addListener(document.body, 'click', function () {
			self.hide();
		});
		
		this.functions = {
			//Handle image link click, which will open lightbox
			openLightbox: function (ev) {
				JS.Event.stopEvent(ev);
				self.elements.image2.style.display = 'block';

				var href = this.getAttribute('href');
				self.show(href);
			},
			//Handle image preload complete after lightbox has been shown
			showImage: function (image) {
				if (image.path_image == self.config.image) {
					self.elements.image2.style.display = 'none';
					
					if (!image.error_occured) {
						self.elements.image1.src = image.path_image;
					} else {
						self.elements.image1.src = '/img/px.gif';
						image.width = 100;
						image.height = 100;
					}
					
					var h = image.height;
					
					if (self.config.showTitle) {
						self.elements.container_title.innerHTML = '<div>' + image.title + '</div>';
						h+= self.elements.container_title.offsetHeight;
					}
					
					self.elements.image1.width = image.width;
					self.elements.image1.height = image.height;
					self.elements.container.style.width = image.width + 'px';
					self.elements.container_image.style.height = image.height + 'px';
					
					self.panel.resetPosition();
				}
			}
		};
		
	//Auto discover lightbox items
		if (this.config.autoDiscover) {
			//Get links
			var a = this.config.owner.getElementsByTagName('A');
			
			for(var i=0,j=a.length; i<j; i++) {
				var rel = a[i].getAttribute('rel');
				if (rel == 'lightbox') {
					this.addImageByAnchorNode(a[i]);
				}
			}
		}
};

//Configuration
JS.Components.Lightbox.prototype.config = null;

//Valid image extension list
JS.Components.Lightbox.prototype.validImageExtensions = ['jpg', 'jpeg', 'png', 'gif', 'bmp'];

//Images
JS.Components.Lightbox.prototype.images = {};

//Panel
JS.Components.Lightbox.prototype.panel = null;

//Elements
JS.Components.Lightbox.prototype.elements = {};

//Functions
JS.Components.Lightbox.prototype.functions = {};

/**
 * Show lightbox
 */
JS.Components.Lightbox.prototype.show = function (image_id) {
	if (!image_id) {
		//Get first image id
		for(var i in this.images) {
			if (this.images.hasOwnProperty(i)) { 
				image_id = i; break;
			}
		}
	}

	this.panel.show();
	
	this.config.image = image_id;
	this.preload(image_id, this.functions.showImage);
};

/**
 * Hide lightbox
 */
JS.Components.Lightbox.prototype.hide = function () {
	this.panel.hide();
	
	this.elements.image2.style.display = 'none';
	this.elements.image1.src = '/img/px.gif';
	
	this.elements.image1.width = 100;
	this.elements.image1.height = 100;
	this.elements.container.style.width = 300 + 'px';
	this.elements.container_image.style.height = 200 + 'px';
};

/**
 * Create lightbox html
 */
JS.Components.Lightbox.prototype._createHtml = function () {
	var self = this;
	
	//Main container
	this.elements.container = document.createElement('DIV');
		JS.Dom.addClassName(this.elements.container, 'lightbox-inner');
		
		//Image container div
		this.elements.container_image = document.createElement('DIV');
			JS.Dom.addClassName(this.elements.container_image, 'image');
			this.elements.container.appendChild(this.elements.container_image);
		
		//Title container div
		if (this.config.showTitle) {
			this.elements.container_title = document.createElement('DIV');
				JS.Dom.addClassName(this.elements.container_title, 'title');
				this.elements.container.appendChild(this.elements.container_title);
		}
		
		//Image
		this.elements.image2 = document.createElement('IMG');
			this.elements.image2.src = '/img/ajax-loader.gif';
			this.elements.image2.alt = '';
			JS.Dom.addClassName(this.elements.image2, 'image-2');
			this.elements.container_image.appendChild(this.elements.image2);
			
		this.elements.image1 = document.createElement('IMG');
			this.elements.image1.src = '/components/backoffice/images/px.gif';
			this.elements.image1.alt = '';
			JS.Dom.addClassName(this.elements.image1, 'image-1');
			this.elements.container_image.appendChild(this.elements.image1);
			
			//Hide when clicked on image
			JS.Event.addListener(this.elements.image1, 'click', function () {
				self.hide();
			});
			
};

/**
 * Add image to the list
 * 
 * @param {String} image_preview_path
 * @param {String} image_path
 * @param {String} image_title
 */
JS.Components.Lightbox.prototype.addImage = function (path_thumbnail, path_image, title) {
	if (path_image) {
		if (typeof title != 'string') title = '';
		
		this.images[path_image] = {
			title: title,
			path_thumbnail: (path_thumbnail ? path_thumbnail : null),
			path_image: path_image,
			
			preloading: false,	//image is not beeing preloaded at the moment
			timeout: 60000,		//time when image preloading will timeout, default is 1 minute
			
			loaded: false,		//image has been preloaded
			image: null,		//Image object
			callbacks: [],		//list of callback functions
			width: 0,			//image width
			height: 0			//image height
		};
		
		return true;
	}
	
	return false;
};

/**
 * Add image to the list by anchor node. Function tries to find title, thumbnail and image
 * 
 * @param {Object} link_node
 */
JS.Components.Lightbox.prototype.addImageByAnchorNode = function (link_node) {
	var link_node = JS.Dom.get(link_node);
	if (link_node) {
		var img = link_node.getElementsByTagName('IMG');
		if (img.length) {
			img = img[0];
			
			var targ = link_node.getAttribute('href');
			var thumbnail = img.getAttribute('src');
			var title = img.getAttribute('alt');

			if (this.addImage(thumbnail, targ, title)) {
				JS.Event.addListener(link_node, 'click', this.functions.openLightbox);
				return true;
			}
		}
	}
	
	return false;
};

/**
 * Returns internal image object by image id
 * 
 * @param {String} image_id
 * @return {Object}
 */
JS.Components.Lightbox.prototype.getImage = function (image_id) {
	if (this.images[image_id]) {
		return this.images[image_id];
	} else {
		return null;
	}
};

/**
 * Searches for image, which hasn't been preloaded yet and preloads it
 */
JS.Components.Lightbox.prototype._preloadNextImage = function () {
	for(var i in this.images) {
		if (this.images.hasOwnProperty(i)) {
			if (!this.images[i].preloading && !this.images[i].loaded) {
				this.preload(i);
				return true;
			}
		}
	}
	
	return false;
};

/**
 * Execute clalbacks
 */
JS.Components.Lightbox.prototype._preloadComplete = function (image) {
	image.preloading = false;
	image.loaded = true;
	
	image.width = parseInt(image.image.width);
	image.height = parseInt(image.image.height);
	
	for(var i=0,j=image.callbacks.length; i<j; i++) {
		image.callbacks[i](image);
	}
	
	image.callbacks = [];
};

/**
 * Check for images, which has completed preload or has timed out
 * onload event not used to capture timeout
 */
JS.Components.Lightbox.prototype._preloadCheck = function () {
	var now = (new Date()).getTime();
	var img_cnt = 0;
	
	for(var i in this.images) {
		if (this.images[i].preloading) {
			if (this.images[i].image.complete) {
				this._preloadComplete(this.images[i]);
				continue;
			} else if (this.images[i].timeout <= now) {
				//Preload has timed out, restart
				this.preload(i, null, true);
			}
			
			img_cnt++;
		}
	}
	
	if (!img_cnt) {
		//All images are preloaded
		clearInterval(this.config.timer);
		this.config.timer = null;
		
		//No images beeing preloaded, preload image which hasn't been preloaded yet
		this._preloadNextImage();
		
	} else if (!this.config.timer) {
		//Set timer
		var self = this;
		this.config.timer = setInterval(function () { self._preloadCheck(); }, 200);
	}
};

/**
 * Handle preload error
 */
JS.Components.Lightbox.prototype._preloadError = function (image_id) {
	if (!this.images[image_id].loaded && this.images[image_id].preloading) {
		this.images[image_id].loaded = true;
		this.images[image_id].preloading = false;
		this.images[image_id].error_occured = true;
		
		this._preloadComplete(this.images[image_id]);
	}
};

/**
 * Preload image
 * 
 * @param {Object} image_id
 * @param {Object} callback
 */
JS.Components.Lightbox.prototype.preload = function (image_id, callback, force) {
	var self = this;
	
	if (this.images[image_id]) {
		var c = false;
		
		if (!this.images[image_id].loaded)
		{
			if (!this.images[image_id].preloading || force) {
				if (this.images[image_id].image) {
					this.images[image_id].image.src = 'about:blank';
				} else {
					this.images[image_id].image = new Image();
					this.images[image_id].image.targ = this.images[image_id];
				}
				
				this.images[image_id].image.src = this.images[image_id].path_image;
				this.images[image_id].image.alt = '';
				this.images[image_id].preloading = true;
				this.images[image_id].timeout = (new Date()).getTime() + this.config.preloadTimeout;
				
				//Handle errors
				this.images[image_id].image.onerror = function (ev) { self._preloadError(image_id); };
				this.images[image_id].image.onabort = function (ev) { self._preloadError(image_id); };
				
				c = true;
			}
			
			//Assign callback
			if (JS.Object.isFunction(callback)) {
				this.images[image_id].callbacks.push(callback);
			}
			
			//Check should be runned after callback is assigned
			if (c) {
				this._preloadCheck();
			}
		} else {
			if (JS.Object.isFunction(callback)) {
				callback(this.images[image_id]);
			}
		}
	}
};