function gallery(optionArr){
	if(!gallery.instance){
		gallery.instance = this;
	}else if(gallery.instance.properties.singleton){
		return gallery.instance;
	}
	

	this.properties = {
		singleton: 1,
		url: 'ajax_backend.php',
		gallery_url: 'gallary.php',
		id: 'gallery',
		column_width: 95,
		row_height: 305,
		columns_per_line: 9,
		lines_per_req: 3,
		margins: 5,
		button_title: 'More...',
		onInit: function(){},
		onPhotoClick: function(){},
		load_on_scroll: 1,
		id_category: 0
	}
	
	this.properties.blocks = {
		block1: {
			columns: 3,
			rnd_weight: 8,
			images: ['big']
		},
		block2: {
			columns: 2,
			rnd_weight: 3,
			images: ['small', 'small', 'medium']
		},
		block3: {
			columns: 2,
			rnd_weight: 3,
			images: ['medium', 'small', 'small']
		},
		block4: {
			columns: 1,
			rnd_weight: 1,
			images: ['small', 'small', 'small']
		}
	}
	
	var blocks_count;
	var all_loaded = 0;
	var loading_status = 0;
	var img_n = 0;
	var last_id = 0;

	var _self = this;
	$.extend(_self.properties, optionArr);

	
	this.init = function(){
		blocks_count = 0;
		for(var i in _self.properties.blocks){
			if(_self.properties.blocks.hasOwnProperty(i)) blocks_count++;
		}
		var wrapper_width = _self.properties.columns_per_line * (_self.properties.column_width + _self.properties.margins * 2);
		$('#'+_self.properties.id)
			.append('<div class="photogallery_wrapper_cont"><div class="photogallery_wrapper" style="width: '+wrapper_width+'px"></div></div>')
			.append('<div class="photogallery_button_cont" style="display:none;"><input type="button" value="'+_self.properties.button_title+'" /></div>')
			.on('click', '.photogallery_button_cont input[type="button"]', function(){_self.loadLines();})
			.on('mouseenter', '.photogallery_block_item', function(){$(this).find('.photogallery_block_item_info').fadeIn(150);})
			.on('mouseleave', '.photogallery_block_item', function(){$(this).find('.photogallery_block_item_info').fadeOut(150);})
			.on('click', '.photogallery_block_item img, .photogallery_zoom_icon', function(){
				var img_obj = $(this).get(0).tagName == 'IMG' ? $(this) : $(this).parents('.photogallery_block_item').find('img');
				var src = $(img_obj).attr('src');
				var id_icon = $(img_obj).attr('id_icon');
				src = src.replace('gal_big_thumb_','').replace('big_thumb_','').replace('thumb_','');
				launchWindow(_self.properties.url, 'sel=photo_popup&id_photo='+id_icon, 800, 550, false, true);
			});

		if(_self.properties.load_on_scroll){
			setTimeout(function(){_self.setLoadOnScroll(1, 1);}, 500);
		}
		
		_self.properties.onInit();
		
		return this;
	}
	
	
	this.setLoadOnScroll = function(load_on_scroll, is_init){
		is_init = is_init || 0;
		if(load_on_scroll && (!_self.properties.load_on_scroll || is_init)){
			_self.properties.load_on_scroll = 1;
			/*if($(window).scrollTop() > $('#'+_self.properties.id).offset().top){
				$(window).scrollTop($('#'+_self.properties.id).offset().top);
			}*/
			$(window).scrollTop(0);
			$(window).bind('scroll', function(){
				var offset = $('#'+_self.properties.id).find('.photogallery_button_cont').offset();
				var window_height = window.innerHeight ? window.innerHeight : $(window).height();
				if(offset && $(window).scrollTop() >= offset.top - window_height + 100){
					_self.loadLines();
				}
			});
		}else{
			_self.properties.load_on_scroll = 0;
			$(window).unbind('scroll');
		}
	}
	
	
	this.loadLines = function(params){
		if(all_loaded || loading_status){
			return this;
		}
		params = params || {};
		loading_status = 1;
		var lines_html = '';
		var lines_obj;
		var lines_images = [];
		var line;
		img_n = 0;
		for(var i=0; i<_self.properties.lines_per_req; i++){
			line = _self.generateLine(1,0);
			lines_html += line.data;
			for(var k=0; k<line.images.length; k++){
				lines_images.push(line.images[k]);
			}
		}
		lines_obj = $('<div class="photogallery_line_cont">'+lines_html+'</div>');
		var post_data = $.extend({from_id: last_id, icons: lines_images, id_category: _self.properties.id_category}, params);
		
		$.ajax({
			type: 'POST',
			url: _self.properties.url,
			data: {
				sel: 'gallery', 
				data: {gallery_icons: post_data}
			},
			success: function(data){
				resp = data.gallery_icons;
				if(resp.adult_req){
					$('#'+_self.properties.id).find('.photogallery_button_cont').hide();
					$('#'+_self.properties.id).find('.photogallery_wrapper').html(resp.adult_html);
				}else{
					$('#'+_self.properties.id).find('.photogallery_button_cont').show();
					all_loaded = resp.all_loaded;
					if(resp.count && resp.msg){
						if(all_loaded){
							for(var n=resp.count; n<resp.requested_count; n++){
								$(lines_obj).find('img[num="'+n+'"]').parent('.photogallery_block_item').remove();
							}
							$(lines_obj).find('.photogallery_block:empty').remove();
							$(lines_obj).find('.photogallery_line:empty').remove();
							$(lines_obj).find('.photogallery_line:last').find('.photogallery_block').css('float', DEFAULT_LEFT);
							$('#'+_self.properties.id).find('.photogallery_button_cont input[type="button"]').hide();
						}
						for(var n=0; n<resp.count; n++){
							last_id = (last_id > resp.msg[n].id || last_id == 0) ? resp.msg[n].id : last_id;
							$(lines_obj).find('img[num="'+n+'"]').attr({'src': resp.msg[n].icon, 'id_icon': resp.msg[n].id});
							var category_name_elem = (resp.msg[n].id_category == _self.properties.id_category) ? resp.msg[n].gallery_name : '<a href="'+resp.msg[n].category_link+'" title="'+resp.msg[n].gallery_name+'">'+resp.msg[n].gallery_name+'</a>';
							$(lines_obj).find('img[num="'+n+'"]').parent().find('.photogallery_block_item_info').html('<div><a href="'+resp.msg[n].profile_link+'" target="_blank" title="'+resp.msg[n].name+'">'+resp.msg[n].name+'</a></div><div>'+category_name_elem+'</div><div class="photogallery_zoom_icon"></div>');
						}
						$('#'+_self.properties.id).find('.photogallery_wrapper').append(lines_obj);
					}
					if(all_loaded){
						$('#'+_self.properties.id).find('.photogallery_button_cont input[type="button"]').hide();
					}
					if(!resp.count_all && resp.text_msg){
						$('#'+_self.properties.id).find('.photogallery_wrapper').append('<div>'+resp.text_msg+'</div>');
					}
				}
				loading_status = 0;
			},
			error: function(jqXHR, textStatus, errorThrown){
				loading_status = 0;
				if(typeof(console)!=='undefined'){
					console.log(errorThrown);
				}
			},
			dataType: 'json',
			backend: 0
		});
		return this;
	}

	
	this.generateLine = function(with_html, html_as_obj){
		with_html = with_html || 0;
		html_as_obj = html_as_obj || 0;
		var free_columns = _self.properties.columns_per_line;
		var result_blocks = [];
		var line_images = [];
		while(free_columns > 0){
			var rnd_weights = [];
			var allowed_blocks = [];
			for(var i in _self.properties.blocks){
				if(_self.properties.blocks.hasOwnProperty(i) && _self.properties.blocks[i].columns <= free_columns){
					allowed_blocks.push(_self.properties.blocks[i]);
					for(var k=0; k<_self.properties.blocks[i].rnd_weight; k++){
						rnd_weights.push(allowed_blocks.length-1);
					}
				}
			}
			if(rnd_weights.length){
				var rnd = Math.floor((Math.random()*rnd_weights.length));
				result_blocks.push(allowed_blocks[rnd_weights[rnd]]);
				for(var i=0; i<allowed_blocks[rnd_weights[rnd]].images.length; i++){
					line_images.push(allowed_blocks[rnd_weights[rnd]].images[i]);
				}
				free_columns -= allowed_blocks[rnd_weights[rnd]].columns;
			}else{
				free_columns = 0;
			}
		}
		if(with_html){
			return {data: _self.getLineHtml(result_blocks, html_as_obj), images: line_images};
		}else{
			return {data: result_blocks, images: line_images};
		}
	}
	
	
	this.getLineHtml = function(blocks, html_as_obj){
		html_as_obj = html_as_obj || 0;
		var block_width, block_items;
		var elements = [];
		var block_html = ''
		for(var i=0; i<blocks.length; i++){
			block_items = '';
			block_width = blocks[i].columns * _self.properties.column_width + ((blocks[i].columns)*_self.properties.margins*2);
			for(var k=0; k<blocks[i].images.length; k++){
				block_items += '<div class="photogallery_block_item photogallery_block_item_'+blocks[i].images[k]+'" style="padding: '+_self.properties.margins+'px"><img num="'+img_n+'" class="photogallery_block_item_img_'+blocks[i].images[k]+'" /><div class="photogallery_block_item_info"></div></div>';
				img_n++;
			}
			var rnd_float = Math.random() > 0.5 ? 'left' : 'right';
			block_html += '<div class="photogallery_block" style="width: '+block_width+'px; float: '+rnd_float+';">'+block_items+'</div>';
		}
		var line_html = '<div class="photogallery_line" style="overflow: hidden;">'+block_html+'</div>';
		
		if(html_as_obj){
			return $(line_html);
		}else{
			return line_html;
		}
	}
	
};