/**
	Cобытия на контейнере:

	Gallery:loadStart - индикация начала загрузки фотки
	Gallery:loadFinish - индикация окончания загрузки фотки
	NOTE: в event.memo.thumb помещен соответствующий объект Gallery_Thumb

*/

/**
	Общий конфиг (со значениями по-умолчанию)
	Может переопределяться частными конфигами (для каждой отдельной галереи)
	Частный конфиг может переопределять любые параметры общего конфига
	Частный конфиг задается по идентификатору контейнера галереи в нотации CamelCase. Т.е. для галереи id="thumbList" - galleryConfig.thumbList = { ... }
*/
var galleryConfig = {


	slideshowTimeout: 1, // задержка перед показом следующей фотки (отсчитывается только после полной загрузки текущей фотографии)

	loadFirst: false, // загружать ли первую фотку, если ни одной не выбрано


	thumbEffectFocus: {to: 1, duration: 0.5}, // параметры эффекта фокусировки на тумб (эффект Opacity)
	thumbEffectBlur: {duration: 0.5}, // параметры эффекта ухода с тумба (эффект Opacity)
	thumbInactiveOpacity: 0.3, // прозрачность
	thumbCurrentPosition: 'center', // позиция текущего тумбика на ленте ['begin' / 'center' / 'end']
	thumbEmpty: null, // урл картинки, на которую заменяется неподгружаемые тумбы (обычно /img/empty.gif, прозрачный 1х1px)


	photoContainer: null, // id контейнера, в который будет подгружаться фотография (содержимое не удаляется)
	photoEffectFade: {duration: 0.5, transition: Effect.Transitions.linear}, // настройки эффекта скрытия фотки
	photoEffectAppear: {duration: 0.5, transition: Effect.Transitions.linear}, // настройки эффекта появления фотки

	photoControls: false, // создавать контролы для фотки (вперед/назад/слайдшоу) [true / false]
	photoControlsOpacity: 0.7, // прозрачность контролов
	photoControlsEffectAppear: {duration: 0.3, delay: 0.3}, // настройки эффекта появления контролов
	photoControlsEffectFade: {duration: 0.3} // настройки эффекта скрытия контролов


}


/**
	Класс работы со слайдшоу
*/
var Gallery_Slideshow = Class.create({

	gallery: null, // ссылка на галерею, с которой взаимодействует объект слайдшоу
	listener: null,
	timer: null, // текущий таймер. По его срабатыванию начинается подгрузка следующей фотки
	isWorking: false, // флаг, определяющий, включен ли сейчас режим слайдшоу

	config: {},


	initialize: function(gallery, config) {
		this.gallery = gallery;
		this.listener = this.next.bindAsEventListener(this);
		this.timer = null;
		this.isWorking = false;
		this.config = config;
	},


	/*
		Запуск слайдшоу
	*/
	start: function() {
		Event.observe(this.gallery.element, 'Gallery:loadFinish', this.listener);
		this.next();

		this.isWorking = true;
	},


	/*
		Остановка слайдшоу
	*/
	stop: function() {
		Event.stopObserving(this.gallery.element, 'Gallery:loadFinish', this.listener);
		clearTimeout(this.timer);

		this.isWorking = false;
	},


	/*
		Запуск или остановка слайдшоу (перевод в противоположное состояние)
	*/
	toggle: function() {
		if (this.isWorking) {
			this.stop();
		} else {
			this.start();
		}
	},


	/*
		Создание следующего таймера и вызов по таймауту следующей фотки
	*/
	next: function() {
		this.timer = setTimeout(function() {
			this.gallery.next();
		}.bind(this), this.config.slideshowTimeout * 1000);
	}


});



/*
	Класс работающей с отдельной галереей
	Объект автоматически создается фабрикой Gallery

*/
var Gallery_Element = Class.create({

	element: null, // DOM-элемент галереи, контейнер с тумбиками
	photo: null, // объект Gallery_Photo
	thumbs: [], // нумерованный массив тумбиков (объектов Gallery_Thumb)
	selectedIndex: -1, // текущий выбранный тумбик
	slideshow: null, // объект Gallery_Slideshow
	restoreId: null, // ID фотографии, которую требуется восстановить (берется из хэша)
	restoreThumb: null, // объект Gallery_Thumb, который требуется восстановить
	config: {},

	loadStart: Prototype.emptyFunction, // Callback, вызывающийся в тот момент, когда новая фотка начинает подгружаться
										// Первым параметром приходит объект Gallery_Thumb
	loadFinish: Prototype.emptyFunction, // Callback, вызывающийся в тот момент, когда новая фотка окончательно подгружена
										// Первым параметром приходит объект Gallery_Thumb


	/*
		Создаем класс. На этапе создания все тумбики, позиция которых выходит за пределы видимости заменяются на пустые картинки
		Долджен запускаться ДО window.onload
	*/

	initialize: function(htmlElement, config) {
		this.thumbs = [];
		this.element = $(htmlElement);
		this.config = config;

		var pos = Element.getStyle(this.element, 'position');
		if (pos == 'static' || !pos) {
			this.element.setStyle({position: 'relative'});
		}


		this.selectedIndex = -1;

		var photoContainer = this.config.photoContainer;
		if (!photoContainer) {
			photoContainer = new Element('div');
			this.element.insert({after: photoContainer});
		}

		this.photo = new Gallery_Photo(photoContainer, config);

		var dimensions = this.element.getDimensions();
		this.element.width = dimensions.width;
		this.element.height = dimensions.height;

		this.restoreId = null;
		var restoreId = null;
		if (location.hash.length) {
			restoreId = location.hash.replace('#', '');
		}

		thumbs = this.element.select('.gallery-thumb');
		for (var i = 0; i < thumbs.length; i++) {
			var thumb = new Gallery_Thumb(thumbs[i], i, config);

			if (thumb.offset.left > this.element.width || thumb.offset.top > this.element.height) {
				thumb.preventLoading();
			}

			this.thumbs[i] = thumb;
			this[thumb.imageId] = thumb;

			if (restoreId == thumb.imageId) {
				this.selectedIndex = i;
				this.restoreId = restoreId;
			}

		}

		if (!this.restoreId && this.config.loadFirst) {
			this.selectedIndex = 0;
			this.restoreId = this.thumbs[0].imageId;
		}

		this.slideshow = new Gallery_Slideshow(this, config);
	},



	/*
		Подписываем все необходимые элементы на события, рассчитываем размеры/оффсеты и т.п.
		Выполняем все то, что нельзя было сделать до window.onload
	*/
	start: function() {
		Event.observe(this.element, 'BlockScroller:scrollFinish', this.scrollFinish.bindAsEventListener(this));

		if (this.config.photoControls) {
			Event.observe(this.photo.next, 'click', this.next.bind(this));
			Event.observe(this.photo.previous, 'click', this.previous.bind(this));
			Event.observe(this.photo.slideshow, 'click', this.slideshow.toggle.bind(this.slideshow));
		}

		Event.observe(this.photo.element, 'Gallery_Photo:load', this.loadFinishHandler.bindAsEventListener(this));

		var lastThumb = this.thumbs[this.thumbs.length - 1].element;
		var lastThumbOffset = lastThumb.positionedOffset();
		var lastThumbDimensions = lastThumb.getDimensions();

		var wrapperWidth = lastThumbOffset.left + lastThumbDimensions.width;
		var wrapperHeight = lastThumbOffset.top + lastThumbDimensions.height;

		for (var i = 0; i < this.thumbs.length; i++) {
			this.thumbs[i].start(this.thumbs[i].id, wrapperWidth, wrapperHeight);

			if (!this.restoreId && this.thumbs[i].selected) {
				this.selectedIndex = i;
				this.thumbs[this.selectedIndex].element.fire('Gallery_Thumb:focus');
				this.scrollTo(this.selectedIndex);

				this.photo.cacheAdd(this.thumbs[this.getPreviousIndex(this.selectedIndex)]);
				this.photo.cacheAdd(this.thumbs[this.getNextIndex(this.selectedIndex)]);
			}


			Event.observe(this.thumbs[i].element, 'click', this.clickHandler.bindAsEventListener(this, i));
		}

		if (this.restoreId) {
			this.loadPhoto();
		}

	},


	/*
		Обработка события окончания загрузки фотографии
	*/
	loadFinishHandler: function(event) {
		Event.stop(event);
		this.element.fire('Gallery:loadFinish', {thumb: this.thumbs[this.selectedIndex]});
		this.loadFinish(this.thumbs[this.selectedIndex]);
	},


	/*
		Рассчитываем позицию текущего тумбика и отправляем событие блокСкроллеру
	*/
	scrollTo: function(index) {
		var correction = {top: 0, left: 0};

		switch (this.config.thumbCurrentPosition) {
			case 'begin':
				correction.left = 0;
				break;
			case 'center':
				correction.left = -this.element.width / 2 + this.thumbs[index].element.getWidth() / 2;
				break;
			case 'end':
				correction.left = -this.element.width + this.thumbs[index].element.getWidth();
				break;
		}

		this.element.fire('BlockScroller:scrollTo', {position: this.thumbs[index].position, correction: correction});
	},


	/*
		Загрузка следующей фотки
	*/
	next: function() {
		if (this.thumbs[this.selectedIndex]) {
			this.thumbs[this.selectedIndex].element.fire('Gallery_Thumb:blur');
		}
		this.selectedIndex = this.getNextIndex(this.selectedIndex);
		this.loadPhoto();
	},


	/*
		Загрузка предыдущей фотки
	*/
	previous: function() {
		if (this.thumbs[this.selectedIndex]) {
			this.thumbs[this.selectedIndex].element.fire('Gallery_Thumb:blur');
		}
		this.selectedIndex = this.getPreviousIndex(this.selectedIndex);
		this.loadPhoto();
	},


	/*
		Загрузка фотки по порядковому номеру тумбика
	*/
	loadByIndex: function (index) {
		index = index * 1;
		if (!this.thumbs[index] || this.selectedIndex == index) {
			return;
		}

		if (this.thumbs[this.selectedIndex]) {
			this.thumbs[this.selectedIndex].element.fire('Gallery_Thumb:blur');
		}
		this.selectedIndex = index;
		this.loadPhoto();
	},


	/*
		Загрузка фотки по ее ID
	*/
	loadById: function (id) {
		id = id * 1;
		if (!this[id] || this.selectedIndex == this[id].index) {
			return;
		}

		if (this.thumbs[this.selectedIndex]) {
			this.thumbs[this.selectedIndex].element.fire('Gallery_Thumb:blur');
		}
		this.selectedIndex = this[id].index;
		this.loadPhoto();

	},


	/*
		Получение (безопасное) индекса следующего тумбика
	*/
	getNextIndex: function(index) {
		if (!this.thumbs[index] || index == (this.thumbs.length - 1)) {
			return 0;
		}

		return index + 1;
	},


	/*
		Получение (безопасное) индекса предыдущего тумбика
	*/
	getPreviousIndex: function(index) {
		if (!this.thumbs[index] || !index) {
			return (this.thumbs.length - 1);
		}

		return index - 1;
	},


	/*
		Обработка события от блокСкроллера (подгрузка видимых тумбиков)
	*/
	scrollFinish: function(event) {
		var currentThumb = Math.floor((this.thumbs.length - 1) * event.memo.position.left);
		var elementOffset = this.element.viewportOffset();
		var leftMargin = elementOffset.left;
		var rightMargin = elementOffset.left +  this.element.width;


		for (var i = currentThumb; i < this.thumbs.length; i++) {
			if (this.thumbs[i].isLoaded) {
				continue;
			}
			var thumbOffset = this.thumbs[i].element.viewportOffset();
			if (thumbOffset.left > rightMargin) {
				break;
			}

			this.thumbs[i].loadThumb();
		}

		for (var i = currentThumb; i >= 0; i--) {
			if (this.thumbs[i].isLoaded) {
				continue;
			}
			var thumbOffset = this.thumbs[i].element.viewportOffset();
			if (thumbOffset.left + this.thumbs[i].element.getWidth() < leftMargin) {
				break;
			}

			this.thumbs[i].loadThumb();
		}

	},


	/*
		Обработчик клика по тумбику
	*/
	clickHandler: function(event, index) {
		Event.stop(event);
		this.loadByIndex(index);
	},


	/*
		Загрузка фотки, обновление location.hash, кэширование соседних фоток
	*/
	loadPhoto: function() {

		this.element.fire('Gallery:loadStart', {thumb: this.thumbs[this.selectedIndex]});
		this.loadStart(this.thumbs[this.selectedIndex]);

		location.hash = this.thumbs[this.selectedIndex].imageId;

		this.thumbs[this.selectedIndex].element.fire('Gallery_Thumb:focus');
		this.scrollTo(this.selectedIndex);

		this.photo.load(this.thumbs[this.selectedIndex]);

		this.photo.cacheAdd(this.thumbs[this.getPreviousIndex(this.selectedIndex)]);
		this.photo.cacheAdd(this.thumbs[this.getNextIndex(this.selectedIndex)]);

	}



});



/*
	Класс описывающий тумбик. Объекты создаются при создании галереи
*/
var Gallery_Thumb = Class.create({

	index: null, // порядковый номер тумбика в массиве тумбиков

	element: null, // DOM-элемент тумбика (обычно ссылка с картинкой внутри)
	offset: null, // отступы тумбика от контейнера (по ним определяется видимость тумбика)
	img: null, // DOM-элемент картинки (img внутри тумбика)
	srcOriginal: null, // УРЛ реальной картинки тумбика
	srcFull: null, // УРЛ большой фотографии, которая загружается по клику
	isLoaded: true, // флаг, определяющий, загружена ли реальная картинка тумбика или нет (для невидимых тумбиков изначально устанавливается в false)
	id: null, // ID DOM-элемента тумбика. Если он не задан, то задается автоматически
	title: null, // Краткое описание фотки (задается параметром title ссылки тумбика)
	imageId: null, // Реальный ID фотографии
	alt: null, // alt-аттрибут картинки тумбика
	selected: false, // флаг, определяющий, текущий ли тумбик
	position: null, // процентная позиция тумбика внутри контейнера

	config: {},


	/*
		В момент создания объекта сохраняем все необходимые параметры, которые нам доступны до window.onload
	*/
	initialize: function(htmlElement, index, config) {
		this.config = config;
		this.index = index;

		this.element = $(htmlElement);
		this.offset = this.element.positionedOffset();
		this.img = this.element.down('img');
		this.srcOriginal = this.img.readAttribute('src');
		this.srcFull = this.element.readAttribute('href');
		this.isLoaded = true;
		this.id = this.element.identify();
		this.title = this.element.readAttribute('title');
		this.imageId = this.element.readAttribute('rel');
		this.alt = this.img.readAttribute('alt');
		this.position = null;

		if (this.element.hasClassName('gallery-thumb-selected')) {
			this.selected = true;
		} else {
			this.selected = false;
		}

	},


	/*
		Делаем рассчеты позиции тумбика, переопределяем ссылку на DOM-элемент и т.д. Все что нельзя сделать до window.onload
	*/
	start: function(htmlElement, wrapperWidth, wrapperHeight) {

		// после window.onload необходимо переопределять заново ссылки на ДОМ-элементы. Иначе размеры и оффсеты считаются некорректно!
		this.element = $(htmlElement);

		var offset = this.element.positionedOffset();
		this.position = {top: offset.top / wrapperHeight, left: offset.left / wrapperWidth};

		this.img = this.element.down('img');

		this.img.setOpacity(this.config.thumbInactiveOpacity);

		Event.observe(this.element, 'Gallery_Thumb:focus', this.focusHandler.bindAsEventListener(this));
		Event.observe(this.element, 'Gallery_Thumb:blur', this.blurHandler.bindAsEventListener(this));
	},


	/*
		Запрещаем загрузку реальной картинки тумбика, подменяем ее на пустую картинку, сбрасываем флаг
	*/
	preventLoading: function() {
		this.img.src = this.config.thumbEmpty;
		this.element.addClassName('gallery-thumb-empty');
		this.isLoaded = false;
	},


	/*
		Загружаем реальную картинку тумбика. Но флаг загруженности устанавливаем только после реальной загрузки картинки
	*/
	loadThumb: function() {
		Element.observe(this.img, 'load', this.onloadHandler.bindAsEventListener(this));
		this.img.src = this.srcOriginal;
	},


	onloadHandler: function(event) {
		Element.stopObserving(this.img, 'load');
		this.element.removeClassName('gallery-thumb-empty');
		this.isLoaded = true;
	},


	/*
		Обработчик фокусировки на тумбик
	*/
	focusHandler: function(event) {
		this.element.addClassName('gallery-thumb-selected');

		Effect.Queues.get(this.id).each(function(effect) { effect.cancel(); });

		this.config.thumbEffectFocus.queue = {scope: this.id, position: 'end', limit: 1};
		new Effect.Opacity(this.img, this.config.thumbEffectFocus);
	},


	/*
		Обработчик ухода с тумбика
	*/
	blurHandler: function(event) {
		this.element.removeClassName('gallery-thumb-selected');

		Effect.Queues.get(this.id).each(function(effect) { effect.cancel(); });

		this.config.thumbEffectBlur.queue = {scope: this.id, position: 'end', limit: 1};
		this.config.thumbEffectBlur.to = this.config.thumbInactiveOpacity;
		new Effect.Opacity(this.img, this.config.thumbEffectBlur);
	}


});




/*
	Класс для работы с "большой" фотографией
*/
var Gallery_Photo = Class.create({


	element: null, // DOM-элемент, контейнер для фотки
	wrapper: null, // DOM-элемент, враппер для фотки (эффекты применяются к нему)
	id: null, // ID контейнера фотки. Если нет, задается автоматом
	cache: {}, // Кэш подгруженных ранее фотографий. Не зависит от кэша браузера

	next: null, // DOM-элемент кнопки перехода к следующей фотке
	previous: null, // DOM-элемент кнопки перехода к предыдущей фотке
	slideshow: null, // DOM-элемент кнопки запуска/остановки слайдшоу

	image: null, // DOM-элемент image (текущей загруженной картинки)

	config: {},


	initialize: function(htmlElement, config) {
		this.element = $(htmlElement);
		this.element.addClassName('gallery-photo');

		this.config = config;

		this.wrapper = new Element('div', {className: 'gallery-photo-wrapper'});
		this.wrapper.setStyle({overflow: 'hidden', position: 'relative'});

		var children = this.element.immediateDescendants();
		for (var i = 0; i < children.length; i++) {
			this.wrapper.appendChild(children[i]);
		}
		this.element.appendChild(this.wrapper);

		this.image = this.wrapper.down('img.gallery-photo-image');
		if (this.image) {
			this.wrapper.setStyle({width: this.image.width + 'px'});
		}

		this.id = this.element.identify();
		this.cache = {};

		if (this.config.photoControls) {
			this.next = new Element('div', {className: 'gallery-photo-next', style: 'display: none; position: absolute;'});
			this.previous = new Element('div', {className: 'gallery-photo-previous', style: 'display: none; position: absolute;'});
			this.slideshow = new Element('div', {className: 'gallery-photo-slideshow', style: 'display: none; position: absolute;'});
			this.wrapper.appendChild(this.next);
			this.wrapper.appendChild(this.previous);
			this.wrapper.appendChild(this.slideshow);

			Event.observe(this.wrapper, 'mouseover', this.mouseoverHandler.bindAsEventListener(this));
			Event.observe(this.wrapper, 'mouseout', this.mouseoutHandler.bindAsEventListener(this));
		}

	},


	/*
		Отображаем контролы
	*/
	mouseoverHandler: function(event) {

		if (event.relatedTarget == null || event.relatedTarget == this.wrapper || Element.descendantOf(event.relatedTarget, this.wrapper) == true) {
			return;
		}
		Effect.Queues.get(this.id + 'navigation').each(function(effect) { effect.cancel(); });

		var effects = [];


		effects.push(new Effect.Appear(this.next, {to: this.config.photoControlsOpacity, sync: true}));
		effects.push(new Effect.Appear(this.previous, {to: this.config.photoControlsOpacity, sync: true}));
		effects.push(new Effect.Appear(this.slideshow, {to: this.config.photoControlsOpacity, sync: true}));


		this.config.photoControlsEffectAppear.queue = {scope: this.id + 'navigation', position: 'end', limit: 1};
		new Effect.Parallel(effects, this.config.photoControlsEffectAppear);
	},


	/*
		Скрываем контролы
	*/
	mouseoutHandler: function(event) {
		if (event.relatedTarget == null || event.relatedTarget == this.wrapper || Element.descendantOf(event.relatedTarget, this.wrapper) == true) {
			return;
		}
		Effect.Queues.get(this.id + 'navigation').each(function(effect) { effect.cancel(); });



		var effects = [];
		effects.push(new Effect.Fade(this.next, {sync: true}));
		effects.push(new Effect.Fade(this.previous, {sync: true}));
		effects.push(new Effect.Fade(this.slideshow, {sync: true}));


		this.config.photoControlsEffectFade.queue = {scope: this.id + 'navigation', position: 'end', limit: 1};
		new Effect.Parallel(effects, this.config.photoControlsEffectFade);

	},


	/*
		Загружаем фотку по тумбику, сначала добавляем ее в кэш, потом отображаем
	*/
	load: function(thumb) {
		this.cacheAdd(thumb);
		this.showImage(this.cache[thumb.id]);
	},


	/*
		Добавляем в кэш фотку по тумбику
	*/
	cacheAdd: function(thumb) {
		if (this.cache[thumb.id]) {
			return;
		}
		var image = new Image();
		image.isLoaded = false; // флаг, загружена ли реальная картинка
		image.onload = this.cacheFinish.bindAsEventListener(this, image);
		image.src = thumb.srcFull;
		image.title = thumb.title;
		image.alt = thumb.alt;
		this.cache[thumb.id] = image;
	},


	/*
		Как только реальная фотка подгружена, кидаем соответствующее событие и устанавливаем флаг
		Т.к. события могут бросать только элементы из ДОМа, то подгруженную картинку сначала добавляем в боди и скрываем
	*/
	cacheFinish: function(event, image) {
		var image = $(image);
		image.addClassName('hidden');
		$$('body')[0].appendChild(image);

		image.fire('Gallery_Photo:cache');
		image.isLoaded = true;
	},


	/*
		Скрываем враппер до полной прозрачности
		и как только враппер становится невидимым (либо у него изначально высота нулевая, либо закончился эффект скрытия)
		апдейтим враппер новой картинкой
	*/
	showImage: function(image) {
		Effect.Queues.get(this.id).each(function(effect) {effect.cancel();});

		var wrapperHeight = this.wrapper.getHeight();
		this.wrapper.setStyle({height: wrapperHeight + 'px'});
		if (wrapperHeight == 0) {
			this.updateWrapper(image);
			this.wrapper.setOpacity(0);
			return;
		}

		this.config.photoEffectFade.to = 0;
		this.config.photoEffectFade.queue = { position: 'end', scope: this.id };
		this.config.photoEffectFade.afterFinish = function() {this.updateWrapper(image);}.bind(this);
		new Effect.Opacity(this.wrapper, this.config.photoEffectFade);

	},


	/*
		Хитрый апдейт враппера. Если картинка еще не загружена, то начинаем ждать соответствующего события
	*/
	updateWrapper: function(image) {
		if (!image.isLoaded) {
			Event.observe(image, 'Gallery_Photo:cache', this.updateWrapper2Handler.bindAsEventListener(this, image));
		} else {
			this.updateWrapper2(image);
		}

	},


	/*
		Вот теперь, когда картинка загружена делаем безусловный апдейт враппера
	*/
	updateWrapper2Handler: function(event, image) {
		this.updateWrapper2(image);
	},



	/*
		Безусловный апдейт враппера. К этому моменту картинка уже наверняка загружена!
	*/
	updateWrapper2: function(image) {
		Effect.Queues.get(this.id).each(function(effect) {effect.cancel();});
		Event.stopObserving(image, 'Gallery_Photo:cache');
		Element.removeClassName(image, 'hidden');

		if (this.image) {
			this.image.replace(image);
		} else {
			this.wrapper.appendChild(image);
		}
		this.image = $(image);
		this.image.addClassName('gallery-photo-image');
		this.image.setStyle({display: 'block'});

		var effects = [];

		var wrapperDimensions = this.wrapper.getDimensions();
		if (image.height != wrapperDimensions.height || image.width != wrapperDimensions.width) {
			effects.push(
				new Effect.Morph(this.wrapper, {
					sync: true,
					style: {height: image.height + 'px', width: image.width + 'px'}
				})
			);
		}
		effects.push(new Effect.Opacity(this.wrapper, {sync: true, to: 1, transition: Effect.Transitions.linear}));

		this.config.photoEffectAppear.afterFinish = function() {this.element.fire('Gallery_Photo:load');}.bind(this);
		this.config.photoEffectAppear.queue = {position: 'end', scope: this.id};
		new Effect.Parallel(effects, this.config.photoEffectAppear);

	}







});






/*
	Фабрика
	Помимо нумерованного массива галерей, содержит хэш галерей
	Доступ к каждой галереи осуществляется по ID галереи внутри объекта фабрики.

	Например, для id="photoList" доступ к этой галерее осуществляется через ссылку gallery.photoList или gallery.elements[_index_].
	Однако извне _index_ неизвестен

*/
var Gallery = Class.create({

	elements: [], // нумерованный массив объектов галерей

	initialize: function() {
		Event.observe(window, 'load', this.start.bind(this));

		var elements = $$('.ctGallery');

		for (var i = 0; i < elements.length; i++) {
			var id = elements[i].identify().camelize();


			var config = Object.extend(galleryConfig, (galleryConfig[id]) ? galleryConfig[id] : {});
			var galleryElement = new Gallery_Element(elements[i], config);
			this[id] = galleryElement;
			this.elements.push(galleryElement);
		}

	},

	start: function() {
		this.elements.each(function(element) {element.start();});
	}




});

ScriptsManager.registerScript("Gallery");

