
var lightgallery = (function(){
var dx,
	dy,
	options = {
		showOverlay		: true,
		overlayColor	: '#000',
		overlayOpacity	: .85,
		zoomStep		: .2,
		animate			: true,
		framesNumber	: 20,
		speed			: 30,
		resizeSync		: false,	
		enableZoom		: true,
		fadeImage		: true,
		alias			: 'lightgallery',
		fullSize		: false,
		minPadding		: 15		
	},
	langVars = { 
		next	: 'Next',
		prev	: 'Previous',
		zoomIn	: 'Zoom In',
		zoomOut	: 'Zoom Out',
		fullSize: 'Full Size',
		fitScreen: 'Fit screen',
		close	: 'Close',
		image	: 'Image',
		of	: 'of'
	},

	container,		
	titleBar,		
	prevBtn,		
	nextBtn,		
	imgIndex,		
	fullSizeBtn,	

	loaderImage,	
	picture,		
	gallery,
	isOpen,			
	current,		
	
	overlay,
	overlayWidth,	
	overlayHeight,	
	
	hidden = 'hidden',
	visible = 'visible',
	block = 'block',
	none = 'none',
	DIV = 'div',
	
	images = [];	

var G = {

	setLangVars : function(vars){
		extend(langVars, vars);
	},


	
	init : function(opts){
		extend(options, opts);
		options.fullSize = options.fullSize ? 1:0;

	
		var	imgs = document.getElementsByTagName('a'),
			regx = new RegExp('^'+options.alias+'\\[([a-zA-Z]+)\\]|'+options.alias+'$'),
			r;		
		
		for (var i=0; i<imgs.length; i++) {
			if(imgs[i].rel && (r = imgs[i].rel.match(regx))){
				addEvent(imgs[i],'click', G.showImage);
				if(r = r[1]){
					imgs[i].__gallery__ = r;
					if(!images[r])
						images[r] = [];

					imgs[i].__index__ = images[r].push(imgs[i]) - 1;
				}
			}
		}

		var b=document.getElementsByTagName('body')[0];
		
		if (options.showOverlay){
			b.appendChild( overlay = _(DIV,{
				id:'LG_overlay',
				events:{click: G.close}
				})
			);
		}
		
		b.appendChild( container = createContainer() );

		if (b.attachEvent)
			addEvent(b,'keypress',keyPressHandler);	
		else
			addEvent(window,'keypress',keyPressHandler);

		(loaderImage = _('img')).onload=function(){
			hideLoadingIcon();
			loaderImage.__is_loaded__=true;
			picture.setAttribute("src", loaderImage.src);
			setContPos(options.fullSize);
			G.preload(current);
		}

		dy = container.offsetHeight;
		dx = 0;
		
		css(overlay, {
			background:(options.overlayColor)
		});
		setOpacity(overlay, options.overlayOpacity);
	},

	open : function(){

		var	ar = getPageSize();

		if (overlay){
			css(overlay, {
				width:(G.overlayWidth = ar[0]) + "px",
				height: (G.overlayHeight = ar[1]) + "px", display:block
			});
			fadeIn(overlay, 0, options.overlayOpacity*100, 9);
		}

		picture.style.display=block;
		setContPos();
		css(container, {visibility:visible, display:block});
		isOpen = true;
	},

	close : function(){
		if (overlay){
			overlay.style.display = none;
		}
		css(container, {visibility:hidden,display:none});
		isOpen = false;

		loaderImage.src=picture.src='';
		loaderImage.__is_loaded__=false;
	},

	zoomIn : function(){
		G.Zoom(1 + options.zoomStep);
	},

	zoomOut : function(){
		G.Zoom(1 - options.zoomStep);
	},

	zoomNormal : function(){
		if(this.$disabled)
			return;

		G.Zoom(
			picture.width == loaderImage.width && picture.height == loaderImage.height ? 0 : 1
		);
	},

	Zoom : function(coef){
		hideContent();
		setContPos(coef)
	},

	preload : function(index){
		//if(window.opera) return;

		var gal = images[gallery];
		if(!gal)
			return;
		(new Image).src = (gal[index+1]) ? gal[index+1].href : '';
		(new Image).src = (gal[index-1]) ? gal[index-1].href : '';
	},

	showImage : function(e){
		var i = this.__index__, e = e || window.event;
		stopDefault(e);

		if (this.__gallery__ && i > -1) {
			gallery = this.__gallery__;
			G.show(i);
		} else {
			G.showSingle(this);
		}
	},

	showSingle : function(elem){
		if(!isOpen)
			G.open();

		hideContent();
		showLoadingIcon();
		loaderImage.__is_loaded__=false;

		loaderImage.src=elem.href;
		titleBar.innerHTML = elem.title;
		imgIndex.innerHTML = '';
		prevBtn.style.visibility = hidden;
		nextBtn.style.visibility = hidden;
	},

	show : function(index){
		if(!index && gallery === null)
			return;

		if(!isOpen)
			G.open();

		var gal = images[gallery],
			ns = nextBtn.style,
			ps = prevBtn.style;

		if(index < 0 || index > gal.length-1)
			return;

		hideContent();
		showLoadingIcon();

		loaderImage.__is_loaded__=false;
		loaderImage.src=gal[index].href;
		titleBar.innerHTML = gal[index].title;
		imgIndex.innerHTML = langVars.image+' '+(index+1)+' '+langVars.of+' '+gal.length;

		if(index === 0){
			setOpacity(prevBtn, 0);
			nextBtn.$active = !(prevBtn.$active = false);
			ps.visibility = hidden;
			ns.visibility = visible;
		}else if(index === gal.length-1){
			setOpacity(nextBtn, 0);
			nextBtn.$active = !(prevBtn.$active = true);
			ps.visibility = visible;
			ns.visibility = hidden;
		}else if(index > 0 || index < gal.length-1){
			prevBtn.$active = nextBtn.$active = true;
			ps.visibility = ns.visibility = visible;
		}
		current = index;
		window.focus();
	},

	next : function(){
		if(current < images[gallery].length-1)
			G.show(++current);
	},

	prev : function(){
		if(current > 0)
			G.show(--current)
	}
}

function setContPos(vScale){
	var	notFitScreen, fsTitle, w,h,
		padding = options.minPadding*2,
		framesNumber = options.framesNumber,
		ar = getPageSize(),

		contWidth = loaderImage.width + dx + padding,
		contHeight = loaderImage.height + dy + padding,

		wScr = ar[2],
		hScr = ar[3],

		dim_scr = wScr/hScr,
		dim_pic = contWidth/contHeight;

	if(loaderImage.__is_loaded__ && !vScale){
		if (contWidth > wScr || contHeight > hScr) {
			if (dim_pic > dim_scr) {
				contWidth = wScr;
				contHeight = wScr*contHeight/contWidth;
			} else {
				contWidth = hScr*contWidth/contHeight;
				contHeight = hScr;
			}
		}
		picture.width = (w = contWidth-padding) - dx;
		picture.height = (h = contHeight-padding) - dy;
	}else if(vScale==1){
		w = (picture.width = loaderImage.width) + dx;
		h = (picture.height = loaderImage.height) + dy;
	}else if(vScale < 1 || vScale > 1){
		w = (picture.width *= vScale) + dx;
		h = (picture.height *= vScale) + dy;
	}else{
		w = h = 300;
		var disableAnimate = true;
	}


	if ( notFitScreen = ( contWidth > wScr || contHeight > hScr ) ) {
		fsTitle = langVars.fitScreen;
		fsClass = 'LG_fitScreen';
	} else {
		fsTitle = langVars.fullSize;
		fsClass = 'LG_zoomNormal';
	}

	fullSizeBtn.$disabled = false;
	if (picture.width == loaderImage.width) {
		if (notFitScreen) {
			fullSizeBtn.className = fsClass;
			fullSizeBtn.setAttribute('title', fsTitle);
		} else {
			fullSizeBtn.className = 'LG_zoom_disabled';
			fullSizeBtn.$disabled = true;
		}
	} else {
		fullSizeBtn.className = 'LG_zoomNormal';
		fullSizeBtn.setAttribute('title', langVars.fullSize);
	}

	w = Math.max(w,300);
	
	var pWidth = w + padding,
		pHeight = h + padding;

	css(overlay, {
		width:	( pWidth > G.overlayWidth ? w + padding : G.overlayWidth) + 'px',
		height:	( pHeight > G.overlayHeight ? h + padding : G.overlayHeight) + 'px'
	});

	var	scr = getScrollXY(),
		y = (hScr>pHeight ? (hScr - h)/2 : options.minPadding) + scr[1],
		x = (wScr>pWidth ? (wScr - w)/2 : options.minPadding) + scr[0],

		nw = (w/3) + 'px',
		nh = (h - dy - 10) + 'px';

	css(nextBtn, {width:nw, height:nh});
	css(prevBtn, {width:nw, height:nh});

	if(options.animate && !disableAnimate){
		var anime = new Movie(container, framesNumber, options.speed);
		if (options.resizeSync) {
			anime.addThread('width', null, w, 0, framesNumber)
			.addThread('left', null, x, 0, framesNumber)
			.addThread('height', null, h, 0, framesNumber)
			.addThread('top', null, y, 0, framesNumber);
		} else {
			var middle = Math.ceil(framesNumber / 2);
			anime.addThread('width', null, w, 0, middle)
			.addThread('left', null, x, 0, middle)
			.addThread('height', null, h, middle, framesNumber)
			.addThread('top', null, y, middle, framesNumber);
		}
		anime.addAction(function(){
			showContent()
		},options.framesNumber-1);
		anime.run();
	}else{
		css(container, {top: y+"px", left: x+"px", width: w+"px", height: h+"px"});
		showContent();
	}
}

function showContent(){
	var	nodes = container.childNodes,
		showLoop = function(){
				for (var i=nodes.length; --i>-1;)
					nodes[i].style.display = block;
			};
	if(options.fadeImage){
		(new Movie(picture, 8, options.speed))
			.addThread('opacity', 0, 100)
			.addAction(showLoop, 0)
			.run();
	}else{
		showLoop();
		setOpacity(picture, 100);
	}
}

function hideContent(){
	for (var i=container.childNodes.length; --i>-1;)
		container.childNodes[i].style.display = none;

	setOpacity(picture, 0);
}

function showLoadingIcon(){
	container.className='LG_loading';
}

function hideLoadingIcon(){
	container.className = '';
}

function createContainer(){
	var zoomIn, zoomOut;
	if (options.enableZoom) {
		zoomIn = _(DIV, {
			'class': 'LG_zoomIn',
			title: langVars.zoomIn,
			events: {
				click: G.zoomIn
			}
		});
		zoomOut = _(DIV, {'class':'LG_zoomOut',title:langVars.zoomOut,
			events:{click:G.zoomOut}
		})
	}
	return _(DIV, {id:'LG_container'},
				_(DIV,0,
						zoomIn, zoomOut,
						fullSizeBtn = _(DIV, {'class': 'LG_zoomNormal',title: langVars.fullSize,
								events: {click: G.zoomNormal}
							}),
						imgIndex = _(DIV, {'class':'LG_imgIndex'}),
						_(DIV,{'class':'LG_closeBtn',title:langVars.close,
								events:{'click':G.close}
							}),_('br',{clear:'all'})
					),
					picture = _('img', {id:'LG_pic',width:300,height:300}),
					titleBar = _(DIV, {'class':'LG_titleBar'}),
					prevBtn = _(DIV, {'class':'LG_prevLink',title:langVars.prev,
										events:{
											click:G.prev,
											mouseover:showBtn,
											mouseout:hideBtn
										}
									}),
					nextBtn = _(DIV,{'class':'LG_nextLink',title:langVars.next,
										events:{
											click:G.next,
											mouseover:showBtn,
											mouseout:hideBtn
										}
									})
	)
}

function keyPressHandler(e){
	if(!isOpen)
		return;
	var	e=e||window.event,
		code=e.keyCode?e.keyCode:(e.which?e.which:e.charCode);
	switch(code){
		case 110:G.next();break;		
		case 98: G.prev();break;		
		case 102: G.zoomNormal();break;	
		case 43: G.zoomIn();break;		
		case 45: G.zoomOut();break;		
		case 27: G.close();				
	}

	stopDefault(e);
}

function showBtn(){
	if (this.$active)
		fadeIn(this,0,100)
}

function hideBtn(){
	if (this.$active)
		fadeOut(this,100,0)
}

function fadeIn(elem, levelStart, levelEnd, frames, speed){
	fade(elem, levelStart || 0, levelEnd || 100, frames, speed);
}
function fadeOut(elem, levelStart, levelEnd, frames, speed){
	fade(elem, levelStart || 100, levelEnd || 0, frames, speed);
}
function fade(elem, levelStart, levelEnd, frames, speed){
	if (options.animate)
		(new Movie(elem, frames || 5, speed || 40)).addThread('opacity', levelStart, levelEnd).run();
	else
		setOpacity(elem, levelEnd);
}

function stopDefault(e){
	if(e.preventDefault)
		e.preventDefault();
	else
		e.returnValue=false;
}

function addEvent(obj,type,fn){
	if (obj.addEventListener)
		obj.addEventListener( type, fn, false );
	else {
		obj["e"+type+fn] = fn;
		obj[type+fn] = function() {obj["e"+type+fn]( window.event )}
		obj.attachEvent( "on"+type, obj[type+fn] )
	}
}

function extend (target, source) {
	for (var i in source)
		target[i] = source[i];
}

function css(elem, styles){
	if (elem){
		extend(elem.style, styles);
	}
}

function getPageSize(){
	var xScroll, yScroll, windowWidth, windowHeight, b = document.body, de = document.documentElement;
	if (window.innerHeight && window.scrollMaxY) {
		xScroll = b.scrollWidth;
		yScroll = window.innerHeight + window.scrollMaxY;
	} else if (b.scrollHeight > b.offsetHeight){
		xScroll = b.scrollWidth;
		yScroll = b.scrollHeight;
	} else if (de && de.scrollHeight > de.offsetHeight){ 
		xScroll = de.scrollWidth;
		yScroll = de.scrollHeight;
	} else {
		xScroll = b.offsetWidth;
		yScroll = b.offsetHeight;
	}

	if (self.innerHeight) { 
		windowWidth = self.innerWidth;
		windowHeight = self.innerHeight;
	} else if (de && de.clientHeight) {
		windowWidth = de.clientWidth;
		windowHeight = de.clientHeight;
	} else if (b) {
		windowWidth = b.clientWidth;
		windowHeight = b.clientHeight;
	}

	var pageHeight = yScroll < windowHeight? windowHeight : yScroll;

	var pageWidth = xScroll < windowWidth? windowWidth : xScroll;

	return [pageWidth,pageHeight,windowWidth,windowHeight]
}

function getScrollXY() {
	var scrOfX = 0, scrOfY = 0, b = document.body, de = document.documentElement;
	if( typeof( window.pageYOffset ) == 'number' ) {
		scrOfY = window.pageYOffset;
		scrOfX = window.pageXOffset;
	} else if( b && ( b.scrollLeft || b.scrollTop ) ) {
		scrOfY = b.scrollTop;
		scrOfX = b.scrollLeft;
	} else if( de && ( de.scrollLeft || de.scrollTop ) ) {
		scrOfY = de.scrollTop;
		scrOfX = de.scrollLeft;
	}
	return [ scrOfX, scrOfY ];
}

function getStyle(elem, name) {
	var d = document.defaultView;
	if (elem.style[name])
		return elem.style[name];	

	else if (elem.currentStyle)
		return elem.currentStyle[name];

	else if (d && d.getComputedStyle) {
		name = name.replace(/([A-Z])/g,"-$1");
		name = name.toLowerCase();

		var s = d.getComputedStyle(elem,"");
		return s && s.getPropertyValue(name);
	}
	return null;
}

function setOpacity() {
	setOpacity = arguments[0].filters ?
		function(elem,level){elem.style.filter = "alpha(opacity="+level+")"} :
		function(elem,level){elem.style.opacity = level / 100}
	setOpacity(arguments[0],arguments[1]);
}

function _(tag, attr){

	var elem = document.createElement(tag);

	if (attr){
		for (var name in attr){
			if(name == 'events'){
				for(var j in attr[name])
					addEvent(elem, j, attr[name][j]);
			}else{
				var value = attr[name];
				if ( typeof value != "undefined" ) {
					if(name == 'class' || name == 'for'){
						name = { "for": "htmlFor", "class": "className" }[name] || name;
						elem[name] = value;
					} else
						elem.setAttribute(name, value);
				}
			}
		}
	}

	for(var i=2, len=arguments.length; i<len; i++){
		switch (typeof arguments[i]) {
			case 'string':elem.innerHTML += arguments[i];break;
			case 'object':elem.appendChild(arguments[i]);break;
		}
	}

	return elem;
}

function Movie(elem, num_frames, speed){
	if (!elem)
		return null;

	this.elem = elem;
	this.numFrames = num_frames || 0;
	this.frames = [];		
	this.speed = speed || 10;
}

Movie.prototype = {
addThread : function(style, startValue, endValue, startFrame, endFrame){
	if (!style || endValue === 'undefined' || endValue === null) return;

	if(style !== 'opacity')
		startValue = parseFloat(getStyle(this.elem, style));

	startFrame = startFrame || 0;
	endFrame = endFrame || this.numFrames;

	var	elem = this.elem,						
		F = this.frames,						
		count = (endFrame - startFrame) || 1,	
		step = (startValue-endValue)/count;

	for (startFrame; startFrame<endFrame; startFrame++){
		if (!F[startFrame])
			F[startFrame] = new MovieFrame;
		F[startFrame].addStyle([elem,style,startValue -= step]);
	}
	return this;
},

/*createAction : function(elem, name, value){
	return name == 'opacity'?
		function(){setOpacity(elem, value)} :
		function(){elem.style[name] = value+'px'}
},*/

addAction : function(func, frameNumber){
	this.frames[frameNumber].addAction(func);
	return this;
},

step : function(){
	var frame = this.frames.shift();

	if (frame)
		frame.exec();
	else
		clearInterval(this.interval);
},

run : function(){
	clearInterval(this.interval);
	this.step();

	var t = this;
	if (this.numFrames>1)
		this.interval = setInterval(function(){t.step()}, this.speed);
}
}


function MovieFrame(){
	this.actions = [];
	this.styles = [];
}

MovieFrame.prototype = {

	addAction : function(f){
		this.actions.push(f)
	},

	addStyle : function(aStyle){
		this.styles.push(aStyle);
	},

	exec : function(){
		var s = this.styles, act, i;
		for (i=s.length; --i>-1;){
			if(s[i][1]=='opacity')
				setOpacity(s[i][0],s[i][2]);
			else
				s[i][0].style[s[i][1]]=s[i][2]+'px';
		}

		if(act = this.actions.shift()) act();
	}
}

return G;
})();
