(function($) {
	$.dynamickaGaleria = function(e, options) {
		var self = this;
		self.defaults = {
			galleryWrapper: '.matchGalleryImages',
			nextImgButton: '.nextImgButton',
			prevImgButton: '.prevImgButton',
			minified: false,
			carouselSpeed: 4000,
			carouselRunning: '',
			startWith: 1,
			transitionEffects: {
				on: true,
				/*
				 * available effects: blind, bounce, clip, drop, explode, fade, fold, highlight,
				 * 					  pulsate, puff, scale, size, shake, slide, transfer
				 */
				type: 'fade',
				speed: 1000,
				options: {}
			},
			autostart: true,
			pauseOnMouseOver: true,
			clickThrough: false,
			clickThroughUrl: '',
			stretchToFit: false,
			thumbnails: {
				on: true,
				wrapper: '.galleryThumbnails',
				carousel: true,
				hideButton: true,
				hideButtonDiv: '.hideThumbnailsButton',
				hideButtonHideText: 'hide menu',
				hideButtonShowText: 'show menu'
			},
			description: {
				wrapper: '.galleryCaption',
				toggleButtonDiv: '.descriptionToggle',
				toggleButtonHideText: 'hide description',
				toggleButtonShowText: 'show description'
			},
			buttonsLocked: false,
			notEnoughImages: false,
			sponsorshipSlot: {
				img: 'http://dl.dropbox.com/u/20096030/magic-gallery-rc/images/canon.jpg',
				url: 'http://www.canon.co.uk',
				on: false
			}
		};

		self.sourceElement = e;
		self.options = $.extend({}, self.defaults, options || {});
		self.setup();
	};
	
	$.dynamickaGaleria.fn = $.dynamickaGaleria.prototype = {
		dynamickaGaleria: '0.1'
	};
	
	$.dynamickaGaleria.fn.extend = $.extend;
	
	$.dynamickaGaleria.fn.extend({	
		setup: function() {
			var self = this;
			/*
			 * specifies where the carousel should start
			 */
			var startWith = this.options.startWith-1;
			
			/**
			 * SPONSORSHIP
			 */
			if(this.options.sponsorshipSlot.on) {
				//add element to gallery and to thumbnails
				if(startWith == 0) {
					$(this.options.galleryWrapper+' ul li:eq(0)').before('<li class="sponsorship"><a target="_blank" href="'+this.options.sponsorshipSlot.url+'"><img src="'+this.options.sponsorshipSlot.img+'" class="bigImage"></a></li>');
					if(this.options.thumbnails.on) {
						$(this.options.thumbnails.wrapper+' ul li:eq(0)').before('<li class="sponsorship"><img src="'+this.options.sponsorshipSlot.img+'" class="bigImage"></li>');
					}
				} else {
					$(this.options.galleryWrapper+' ul li:eq('+startWith+')').after('<li class="sponsorship"><a target="_blank" href="'+this.options.sponsorshipSlot.url+'"><img src="'+this.options.sponsorshipSlot.img+'" class="bigImage"></a></li>');
					if(this.options.thumbnails.on) {
						$(this.options.thumbnails.wrapper+' ul li:eq('+startWith+')').after('<li class="sponsorship"><img src="'+this.options.sponsorshipSlot.img+'"></li>');
					}
				}
			}
			
			/**
			 * NUMBERING
			 */
			
			var start = 0;
			//add number class for gallery items
			$(this.options.galleryWrapper+' ul li').each(function() {
				start++;
				var className=(start>9)?start:'0'+start; //start must contain 2 digits so 01,02,03...09,10,11...
				$(this).addClass('item_'+className);
			});
			
			start = 0;
			if(this.options.thumbnails.on) {
				$(this.options.thumbnails.wrapper+' ul li').each(function() {
					start++;
					var className=(start>9)?start:'0'+start; //start must contain 2 digits so 01,02,03...09,10,11...
					$(this).addClass('thumbnail_'+className);
				});
			}
			
			
			/**
			 * THUMBNAILS
			 */	
			 
			if(this.options.thumbnails.on) {
				/*
				 * set whether thumbnail carousel should be animated or not
				 */
				if(this.options.thumbnails.carousel) {
					this.thumbAnimationSpeed = this.options.transitionEffects.speed;
				} else {
					this.thumbAnimationSpeed = -1;
				}
				
				/*
				 * thumbnails hide button visibility on/off
				 */
				if(!this.options.thumbnails.hideButton) {
					$(this.options.thumbnails.wrapper).addClass('noHideButton');
					$('.hideThumbnails').remove();
				}
				
				/*
				 * thumbnails on click
				 */
				$('li', this.options.thumbnails.wrapper).click(function() {
					self.thumbnailClick($(this));
				});
				
				/*
				 * hide menu
				 */
				$(this.options.thumbnails.hideButtonDiv).click(function() {
					self.hideMenu();
				});
				
				/*
				 * set hide menu button text
				 */
				$(this.options.thumbnails.hideButtonDiv).text(this.options.thumbnails.hideButtonHideText);
			}
			
			/*
			 * hide thumbnails when it's turned off
			 */
			if(!this.options.thumbnails.on) {
				$(this.options.thumbnails.wrapper).css('display','none');
			}
			
			/** 
			 * CLICK THROUGH
			 */
			 
			/*
			 * click through link set up
			 */
			if(this.options.clickThrough) {
				$('ul li:not(.sponsorship) img', this.options.galleryWrapper).each(function() {
					$(this).css('cursor','pointer');
					$(this).click(function() {
						window.location.href = ''+self.options.clickThroughUrl;
					});
				});
			}
			
			/**
			 * IMAGE RESIZING
			 */
			$('li img', self.options.galleryWrapper).load(function() { 
				$('li img', self.options.galleryWrapper).each(function() {
					self.resizeImage($(this));
				});
			});
			
			$().ready(function(){
				$('li img', self.options.galleryWrapper).each(function() {
					self.resizeImage($(this));
				});
			});

			/**
			 * CAROUSEL
			 */
			 
			/*
			 * run if autostart is true
			 */ 
			if(this.options.autostart) {
				self.startCarousel();
			}
			
			/*
			 * stop carousel on mouse over
			 */
			if(this.options.pauseOnMouseOver) {
				self.pauseCarousel();
			}
			
			/*
			 * determine whether there is sufficient number of images or not
			 */
			if($('li:eq(7)', this.options.galleryWrapper).length == 0) {
				this.options.notEnoughImages = true;
			}
			
			/*
			 * set classes and specify with which item we should start
			 */
			if(!$('li', this.options.galleryWrapper).hasClass('current')) {
				if($('li:eq(3)', this.options.galleryWrapper).length == 0) {
					self.currentItem = $('li:last', this.options.galleryWrapper).addClass('current');
				} else {
					self.currentItem = $('li:eq(3)', this.options.galleryWrapper).addClass('current');
				}
				self.gotoItem($('li:eq('+startWith+')', this.options.galleryWrapper),false); // go to element we should start with
			}
			
			/*
			 * next button (on click event)
			 */
			$(this.options.nextImgButton).click(function() {
				self.prevNext('next');
			});
			
			/*
			 * prev button (on click event)
			 */
			$(this.options.prevImgButton).click(function() {
				self.prevNext('prev');
			});
			
			/**
			 * GALLERY DESCRIPTION
			 */
			 
			/*
			 * hide/show description
			 */
			$(this.options.description.toggleButtonDiv).click(function() {
				self.descriptionToggle();
			});
		},
		
		/**
		 * LOGIC FOR IMAGE RESIZING
		 */
		resizeImage: function(imgToResize) {
			var self = this;
			
			/*
			 * set hidden elements to display block to retrieve image size (CPA workaround)
			 */
			if($(self.sourceElement).parent().css('display') === 'none') {
				$(self.sourceElement).parent().css({display:'block',visibility:'hidden'});
				$(self.sourceElement).css({display:'block',position:'absolute',left:-10000});
				$(imgToResize).css({display:'block',visibility:'hidden'});
			}
			
			var imgWidth = imgToResize.attr('width');
			var imgHeight = imgToResize.attr('height');

			/*
			 * define maximum width and height of image = gallery width and height
			 */
				var imgMaxWidth = $(self.sourceElement).css('width').replace(/[^-\d\.]/g, '');
				var imgMaxHeight = $(self.sourceElement).css('height').replace(/[^-\d\.]/g, '');
				
				if(!self.options.stretchToFit) { // resize images proportionaly if stretchToFit is 0
					function resizeProportionaly(resizeBy) {
						var resizeBy;
						var imgNewWidth;
						var imgNewHeight;
						switch(resizeBy) {
							case 'height':
								imgNewWidth = Math.ceil(imgWidth / imgHeight * imgMaxHeight);
								imgNewHeight = imgMaxHeight;
								
								imgToResize.attr('width', imgNewWidth);
								imgToResize.attr('height', imgNewHeight);
							break;
							
							case 'width':
								imgNewWidth = imgMaxWidth;
								imgNewHeight = Math.ceil(imgHeight / imgWidth * imgMaxWidth);
								
								imgToResize.attr('width', imgNewWidth);
								imgToResize.attr('height', imgNewHeight);
							break;
							
							case 'both':
								if(imgWidth > imgHeight) {
									imgNewWidth = imgMaxWidth;
									imgNewHeight = Math.ceil(imgHeight / imgWidth * imgMaxWidth);
									if(imgNewHeight > imgMaxHeight) {
										imgNewHeight = imgMaxHeight;
									}
								} else {
									imgNewHeight = imgMaxHeight;
									imgNewWidth = Math.ceil(imgWidth / imgHeight * imgMaxHeight);
									if(imgNewWidth > imgMaxWidth) {
										imgNewWidth = imgMaxWidth;
									}
								}
								
								imgToResize.attr('width', imgNewWidth);
								imgToResize.attr('height', imgNewHeight);
							break;
						}
					}
				
					if(imgHeight > imgMaxHeight && imgWidth <= imgMaxWidth) {
						resizeProportionaly('height');
					} else if(imgWidth > imgMaxWidth && imgHeight <= imgMaxHeight) {
						resizeProportionaly('width');
					} else if(imgHeight > imgMaxHeight && imgWidth > imgMaxWidth) {
						resizeProportionaly('both');
					}
				} else {
					/*
					 * if stretchToFit is true, stretch images to full gallery width and height
					 */
					if(imgWidth !== imgMaxWidth && imgHeight !== imgMaxHeight) {
						imgToResize.attr('width', imgMaxWidth);
						imgToResize.attr('height', imgMaxHeight);
					}
				}
			
			/*
			 * when CPA, set elements back to display none
			 */
			if($(self.sourceElement).width() < 400 && $(self.sourceElement).css('position') === 'absolute') {
				$(imgToResize).css('visibility','visible');
				$(self.sourceElement).parent().css({display:'none',visibility:'visible'});
				$(self.sourceElement).css({display:'block',position:'relative',left:0});
			}
		},
		
		/**
		 * prev/next button onclick event
		 */
		prevNext: function(whereTo, disableInterval) {
			/*
			 * disable carousel interval in case it's running
			 */
			if((typeof disableInterval === 'undefined' || disableInterval !== false) && this.options.carouselRunning !== '') {
				clearInterval(this.options.carouselRunning);
			}
			
			switch(whereTo) {
				case 'next':
					var next = (this.currentItem.next());
					if(next.length === 0) {
						next = $(this.options.galleryWrapper+' li:first');
					}
					return this.gotoItem(next);
				break;
				
				case 'prev':
					var prev = (this.currentItem.prev());
					if(prev.length === 0) {
						prev = $(this.options.galleryWrapper+' li:last');
					}
					return this.gotoItem(prev);
				break;
			}
		},
		
		/**
		 * logic for displaying selected images and thumbnails animation
		 */
		gotoItem: function(newItem, animate) {
			
			if(!this.options.buttonsLocked || ((typeof gallery !== 'undefined') && gallery.Count() > 1)) {
				this.options.buttonsLocked = true; // lock next/prev buttons to prevent animation panic
				if (typeof animate === 'undefined' || animate !== false){
					animate = true;
				}
				var currentClass = this.currentItem.clone().removeClass('current').removeClass('sponsorship').attr('class'); // clone current element
				var currentItemId = parseInt(currentClass.substr(currentClass.length - 2), 10); // substr ID of current element
				var newClass = newItem.clone().removeClass('current').attr('class'); // class for new element
				var newItemId = parseInt(newClass.substr(newClass.length - 2), 10); // substr ID of new element
				if (currentItemId === newItemId) {
					this.options.buttonsLocked = false;//we can not animate to same image as is set
				}else{
					var size = $(this.options.galleryWrapper+' li').length; // check element length
					var diff = currentItemId - newItemId; // get a difference between current element and new (selected) element
					
					var absDiff = Math.abs(diff);
					var goToRight = (diff <0 && absDiff <= size/2) || (diff >=0 && absDiff > size/2);
					if(diff >= 0 && goToRight) { //going over edge on right side from LAST to FIRST
						diff = (size - diff);
					} else if(diff<0 && !goToRight) { //going over edge on left side from FIRST TO LAST
						diff = (size + diff);
					}
					
					var thumbnailWidth = $('img', this.options.thumbnails.wrapper).attr('width');
					var thumbnailWidthWithMargin = thumbnailWidth+5;				
					
					absDiff = Math.abs(diff);
					moveOffset = absDiff * thumbnailWidthWithMargin; // specify offset in px (85 is width of one thumbnail with margin)
					
					if(!goToRight) {
						moveOffset *= -1;
					}
		
					
					
					//copy items e.g. prepend/append them to thumbnails carousel
					var tmp = newItem;
					for(var i = 1; i<=absDiff; i++) {
						var objectToCopy;
						if(goToRight) {
							if(typeof objectToCopy === 'undefined') {
								objectToCopy = $(this.options.thumbnails.wrapper+' li:first');
							} else {
								objectToCopy = objectToCopy.next();
							}
							if(!this.options.notEnoughImages) $(this.options.thumbnails.wrapper+' ul').append(objectToCopy.clone(true));
						} else {
							if(typeof objectToCopy === 'undefined') {
								objectToCopy = $(this.options.thumbnails.wrapper+' li:last');
							} else {
								objectToCopy = objectToCopy.prev();
							}
							if(!this.options.notEnoughImages) $(this.options.thumbnails.wrapper+' ul').prepend(objectToCopy.clone(true));
						}
					}
					
					if(!goToRight) {
						$(this.options.thumbnails.wrapper+' ul').animate({left: '+='+moveOffset},-1);
					}
					
					var self = this;
					
					$(this.options.thumbnails.wrapper+' li.current').removeClass('current');
					$(this.options.thumbnails.wrapper+' li.thumbnail_'+(newItemId<10?'0'+newItemId:newItemId)).addClass('current');

					if(this.options.notEnoughImages) animate = false;
					
						$(this.options.thumbnails.wrapper+' ul').animate({left: '-='+moveOffset},animate?self.thumbAnimationSpeed:-1,function(){
							for(var i = 1; i<=absDiff; i++) {
								if(goToRight) {
									if(!self.options.notEnoughImages) $(self.options.thumbnails.wrapper+' li:first').remove();
								} else {
									if(!self.options.notEnoughImages) $(self.options.thumbnails.wrapper+' li:last').remove();
								}
							}
							if(goToRight) {
								$(self.options.thumbnails.wrapper+' ul').animate({left: '+='+moveOffset},-1);
							}
						});
					
					
					// do the animation for fading current and new item
					this.currentItem.stop(true, true).fadeOut(animate?self.options.transitionEffects.speed:0,function(){
						$(this).removeClass('current');
						self.currentItem = $(self.options.galleryWrapper+' li.item_'+(newItemId<10?'0'+newItemId:newItemId)).addClass('current').css('display','none');
						self.currentItem.fadeIn(animate?self.options.transitionEffects.speed:0,function(){
							self.options.buttonsLocked = false;
						});
					});
				}
			}
		},
		
		/**
		 * thumbnail image onclick event
		 */
		thumbnailClick: function(jQueryElement) {
			this.gotoItem(jQueryElement);
			return true;
		},
		
		/**
		 * set carousel interval
		 */
		startCarousel: function() {
			var self = this;
			this.options.carouselRunning = setInterval(function() { 
				//only move carousel if it's visible
				if($(self.sourceElement).parent().is(":visible")) {
					self.prevNext('next', false); 
				}
			}, this.options.carouselSpeed);
		},
		
		/**
		 * clear carousel interval
		 */
		pauseCarousel: function() {
			var self = this;
			if(this.options.carouselRunning) {
				$('li img', this.options.galleryWrapper).hover(function() {
					clearInterval(self.options.carouselRunning);
				}, function() {
					self.startCarousel();
				});
			}
		},
		
		/**
		 * hide thumbnails panel
		 */
		hideMenu: function() {
			var self = this;
			var thumbnailsHeight = $(this.options.thumbnails.wrapper).height();
			var moveTopOf = thumbnailsHeight-20;
			if($(this.options.thumbnails.wrapper).position().top == 0 ) {
				$(this.options.thumbnails.wrapper).animate({ top: '-'+moveTopOf }, function() {
					$(self.options.thumbnails.hideButtonDiv).text(''+self.options.thumbnails.hideButtonShowText+'');
				});
			} else if($(this.options.thumbnails.wrapper).css('top') === '-'+moveTopOf+'px') {
				$(this.options.thumbnails.wrapper).animate({ top: '0' }, function() {
					$(self.options.thumbnails.hideButtonDiv).text(''+self.options.thumbnails.hideButtonHideText+'');
				});
			}
		},
		
		/**
		 * hide/show image description
		 */
		descriptionToggle: function() {
			var self = this;
			if($(this.options.description.wrapper).css('display')==='none') {
				$(this.options.description.wrapper).slideToggle();
			}else{
				$(this.options.description.wrapper).slideToggle();
			}
			$(this.options.description.toggleButtonDiv).each(function(){
				if ($(this).text()===''+self.options.description.toggleButtonHideText){
					$(this).text(self.options.description.toggleButtonShowText);
					$(this).removeClass('hideDescription');
					$(this).addClass('showDescription');
				}else{
					$(this).text(self.options.description.toggleButtonHideText);
					$(this).removeClass('showDescription');
					$(this).addClass('hideDescription');
				}
			});
		}
	});
	
	$.fn.dynamickaGaleria = function(o) {
		return this.each(function() {
			if(!$(this).data('dynamickaGaleria')) {
				$(this).data('dynamickaGaleria', new $.dynamickaGaleria(this, o));
			} else {
				$(this).data('dynamickaGaleria').setup();
			}
		});
	};
	
})(jQuery);
