/**
 * @author tfuhlroth maxomedia - agentur für crossmedia-kommunikation bsw
 */


var MAXOMEDIA = ($defined(MAXOMEDIA)) ? MAXOMEDIA : {};


/* -------------------------------------------------- */
/* =debug */

MAXOMEDIA.debug = {
		
	init: function () {
		
		this.settings = new Hash.Cookie('settings', {path: '/'});
		if (!this.settings.has('flash')) this.settings.set('flash', true);
		if (!this.settings.has('javascript')) this.settings.set('javascript', true);
		if (!this.settings.has('styles')) this.settings.set('styles', true);
		
		this.uri = new URI();
		var fragment = this.uri.get('fragment');
		if (fragment) {
			fragment = fragment.substring(1, fragment.length - 1);
			var data = fragment.split('/');
			data.forEach(function (query) {
				var valuePair = query.split('=');
				if (this.settings.getKeys().contains(valuePair[0])) {
					switch (valuePair[1]) {
						case 'true':
							this.settings.set(valuePair[0], true);
							break;
						case 'false':
							this.settings.set(valuePair[0], false);
							break;
					}
				}
			}, this);
		}
	},
	
	buildDisplay: function () {
		this.container = new Element('ul', {
			styles: {
				'position': 'absolute',
				'left': 10,
				'top': 10,
				'z-index': 10000,
				'padding': 10,
				'list-style': 'none',
				'background-color': '#fff',
				'border': '5px solid #ccc'
			}
		});
		this.settings.forEach(function (value, key) {
			var listitem = new Element('li', {'html': '<div style="font-weight : bold;">' + key + '</div>'});
			
			var enable = new Element('a').inject(listitem);
			enable.set('html', (value) ? '<strong style="color : #6d6;">true</strong>' : 'true');
			enable.addEvent('click', function () { this.uri.set('fragment', '/' + key + '=true/'); this.uri.go(); window.location.reload(); }.bind(this));
			
			var disable = new Element('a').inject(listitem);
			disable.set('html', (value) ? ' false' : ' <strong style="color : #ff5a5a;">false</strong>');
			disable.addEvent('click', function () { this.uri.set('fragment', '/' + key + '=false/'); this.uri.go(); window.location.reload(); }.bind(this));
			
			listitem.inject(this.container);
		}, this);
		this.container.inject(document.body);
	},
	
	processDOM: function () {
		// styles
		if (!this.settings.get('styles')) {
			// remove stylesheets
			$(document.head).getElements('link').forEach(function (link) {
				if (link.get('type') === 'text/css') link.destroy();
			}, this);
			
			// remove inline-styles
			$$('*[style]').forEach(function (element) {
				element.removeProperty('style');
			}, this);
		}
	}
	
};

MAXOMEDIA.debug.init();
window.addEvent('domready', function () {
	//MAXOMEDIA.debug.buildDisplay();
	//MAXOMEDIA.debug.processDOM();
});




var Site = new (new Class({
	
	Implements: Events,
		
	initialize: function () {
		if (!MAXOMEDIA.debug.settings.get('javascript')) return false;
		this.dict = new Dict.Remote('/DictionaryGet.ashx');
	}

}));


/* -------------------------------------------------- */
/* =mailto */

Site.mailto = {
	
	options: {
		domain: 'maxomedia.ch'
	},
	
	init: function () {
		$$('.email').forEach(function (item) {
			if (item.get('href')) {
				var account = item.get('href').match(/^mailto:(.*)$/)[1];
				var email = account + '@' + this.options.domain;
			} else {
				var email = item.get('text') + '@' + this.options.domain;
				item.set('text', email);
			}
			
			item.set('href', 'mailto:' + email);
		}, this);
	}
	
};

window.addEvent('domready', function () {
	Site.mailto.init();
});


/**
* CompatibilityBar
*/

var CompatibilityBar = new Class({

    Implements: [Options, Events],
     
 options: {
 className: 'compatibilitybar',
 message: 'We\'re sorry, but this web site contains enhanced features not supported by the browser version you are currently using. Please update to a recent Version. <a href="http://browser-update.org/en/update.html" target="_blank">Learn how to update your browser</a>',
 browsers: [
 {alias: 'IE6', name: 'trident', version: 4}
 ]
 },

 initialize: function (options) {
 var showBar = this.options.browsers.some(function (browser) {
 return (Browser.Engine.name == browser.name && Browser.Engine.version <= browser.version);
 }, this);
 if (!showBar) return false;
 if (Cookie.read('compatibilitybar') != 'closed') {
 this.setOptions(options);
 this.build();
 this.show();
 }
 },

 build: function () {
 this.container = new Element('div', {
 'class': this.options.className
 }).set('tween', {transition: 'sine:out'});

 this.message = new Element('div', {
 'class': this.options.className + '-message',
 'html': this.options.message
 }).inject(this.container);

 this.closeButton = new Element('a', {
 'class': this.options.className + '-close',
 'events': {
 'click': this.close.bind(this)
 }
 }).inject(this.container);

 this.container.inject(document.body, 'top');
 },

 show: function () {
 this.container.tween('height', this.message.getSize().y);
 },

 hide: function () {
 this.container.tween('height', 0);
 },

 close: function () {
 Cookie.write('compatibilitybar', 'closed', {path: '/'});
 this.hide();
 }

});
 

/* -------------------------------------------------- */
/* =background */

Site.background = {
	
	init: function () {
		if (!MAXOMEDIA.debug.settings.get('flash')) return false;
		if (!MAXOMEDIA.debug.settings.get('javascript')) return false;
		
		this.container = $('flash-container');
		this.adjustSize();
		this.isReady = false;
		this.swiff = new Swiff('/_swf/background.swf', {
			width: '100%',
			height: '100%',
			params: {
				wMode: 'opaque'
			},
			callBacks: {
				onLoad: this.onLoad.bind(this)
			},
			container: this.container
		});
		Site.addEvent('resize', function () {
			if (this.isReady) this.setShadow();
		}.bind(this));
	},
	
	onLoad: function () {
		this.isReady = true;
		$('main-container').addEvents({
			'mouseenter': this.setCursorMode.pass(true, this),
			'mouseleave': this.setCursorMode.pass(false, this)
		});
		this.setShadow();
	},
	
	setShadow: function () {
		var headerSize = $('header-container').getSize();
		var bodySize = $('body-container').getSize();
		this.swiff.remote('shadowSize', headerSize.x, headerSize.y + bodySize.y);
	},
	
	setColor: function (color) {
		this.swiff.remote('colorize', color);
	},
	
	setCursorMode: function (bool) {
		this.swiff.remote('onHTML', bool);
	},
	
	adjustSize: function () {
		this.container.setStyle('height', window.getScrollSize().y);
	}
	
};

Site.addEvent('ready', function () {
	//if (!Browser.Engine.presto) Site.background.init();
});


Site.fader = {
		
	init: function () {
		if (!MAXOMEDIA.debug.settings.get('flash')) return false;
		if (!MAXOMEDIA.debug.settings.get('javascript')) return false;
		
		this.values = [0, 1, 2, 3, 4, 5, 7, 8, 9, 'a', 'b', 'c', 'd', 'e', 'f'];
		
		this.current = '';
		this.next = '';
		
		this.loop.periodical(10000, this);
	},
	
	loop: function () {
		while (this.current === this.next) this.next = this.randomize();
		this.current = this.next;
		Site.background.setColor(this.current);
	},
	
	randomize: function () {
		var value = '';
		(6).times(function () {
			value += this.values.getRandom();
		}, this);
		return value;
	}
	
};

window.addEvent('domready', function () {
	//Site.fader.init();
});


/* -------------------------------------------------- */
/* =mainnav */

Site.mainnav = {
	
	init: function () {
		if (!MAXOMEDIA.debug.settings.get('javascript')) return false;
		
		this.container = $('mainnav');
		this.buttons = this.container.getElements('a');
		this.buttons.each(function (button, index) {
			if (!button.getParent().hasClass('active')) {
				button.set('tween', {link: 'cancel', duration: 350, transition: 'sine:out'});
				button.get('tween').set('background-position', button.getSize().x + ' 0');
				button.addEvents({
					'mouseover': button.tween.pass(['background-position', '0 0'], button),
					'mouseout': button.tween.pass(['background-position', button.getSize().x + ' 0'], button)
				});
			}
		}, this);
	}
	
};

window.addEvent('domready', function () {
	Site.mainnav.init();
});


/* -------------------------------------------------- */
/* =contextnav */

/*
	TODO: review tabs-fx, especially hiding on init
*/

Site.contextnav = {
	
	init: function () {
		if (!MAXOMEDIA.debug.settings.get('javascript')) return false;
		
		this.container = $('contextnav');
		this.tabs = this.container.getElements('li');
		this.buttons = this.container.getElements('a');
		this.backgrounds = this.container.getElements('span');
		this.buttons.forEach(this.setupTab, this);
	},
	
	setupTab: function (button, index) {
		if (!button.get('href')) {
			this[this.tabs[index].get('class')] = button;
			this.tabs[index].set('tween', {property: 'margin-left', link: 'cancel', transition: 'sine:out'});
			this.tabs[index].get('tween').set(-22);
		}
		this.backgrounds[index].set('tween', {link: 'cancel', duration: 350, transition: 'sine:out'});
		button.addEvents({
			'mouseover': this.backgrounds[index].tween.pass(['margin-left', 0], this.backgrounds[index]),
			'mouseout': this.backgrounds[index].tween.pass(['margin-left', -22], this.backgrounds[index]),
			'show': this.showTab.pass(index, this),
			'hide': this.hideTab.pass(index, this)
		});
	},
	
	addTab: function (label) {
		var tab = new Element('li', {'class': label.toLowerCase() });
		this.tabs.push(tab);
		
		var button = new Element('a').inject(tab);
		this.buttons.push(button);
		
		var background = new Element('span', {
			'text': label
		}).inject(button);
		this.backgrounds.push(background);
		
		this.setupTab(button, this.buttons.indexOf(button));
		
		this.container.adopt(tab);
	},
	
	showTab: function (index) {
		this.tabs[index].tween(0);
	},
	
	hideTab: function (index) {
		this.tabs[index].tween(-22);
	}
	
};

window.addEvent('domready', function () {
	Site.contextnav.init();
});


/* -------------------------------------------------- */
/* =Slideshow */

MAXOMEDIA.Slideshow = new Class({

	Implements: [Events, Options],
	
	options: {
		timeout: 2000,
		onLoad: $empty,
		onShow: $empty,
		onHide: $empty
	},
	
	initialize: function (container, elements, options) {
		if (!MAXOMEDIA.debug.settings.get('flash')) return false;
		
		this.container = $(container);
		this.setOptions(options);
		
		this.build();
		
		this.fx = new Fx.Tween(this.element, {property: 'opacity', link: 'cancel', transition: 'sine:out'}).set(0);
		this.elements = $$(elements);
		this.elements.each(function (element) {
			element.addEvent('click', function () {
				this.fireEvent('click');
			}.bind(this));
		}, this);
		
		this.bound = {
			hide: this.hide.bindWithEvent(this)
		};
	},
	
	build: function () {
		this.element = new Element('div', {id: 'media-container'}).inject(this.container);
		Site.contextnav.addTab('Back');
	},
	
	load: function (workID) {
		this.swiff = new Swiff('/_swf/slideshow.swf', {
			width: '100%',
			height: '100%',
			container: this.element,
			vars: {
				timeout: this.options.timeout
			},
			callBacks: {
				onLoad: function () {
					this.getData(workID);
				}.bind(this)
			}
		});
		this.show();
		this.fireEvent('load');
	},
	
	getData: function (workID) {
		new Request.JSON({
			url: '/_service/GetWorkImages.ashx',
			method: 'get',
			data: 'id=' + workID,
			link: 'cancel',
			onSuccess: function (responseJSON, responseText) {
				this.swiff.remote('setData', responseJSON);
			}.bind(this)
		}).send();
	},
	
	show: function () {
		Site.contextnav.back.addEvent('click', this.bound.hide);
		Site.contextnav.back.fireEvent('show');
		this.element.setStyle('display', 'block');
		this.fx.start(1);
		this.fireEvent('show');
	},
	
	hide: function (event) {
		event.stop();
		Site.contextnav.back.removeEvent('click', this.bound.hide);
		Site.contextnav.back.fireEvent('hide');
		this.fx.start(0).chain(function () {
			this.element.setStyle('display', 'none');
		}.bind(this));
		this.fireEvent('hide');
	}

});

/* -------------------------------------------------- */
/* =JWPlayer */

var player = null;

MAXOMEDIA.JWPlayer = new Class({

	Implements: [Events, Options],

	options: {
		timeout: 2000,
		onLoad: $empty,
		onShow: $empty,
		onHide: $empty
	},

	initialize: function(container, elements, options, backIntegrate) {
		if (!MAXOMEDIA.debug.settings.get('flash')) return false;

		this.setOptions(options);

		if (backIntegrate === true)
			this.build();

		if (elements != null && elements != undefined) {
			this.elements = $$(elements);
			this.elements.each(function(element) {
				element.addEvent('click', function() {
					this.fireEvent('click');
				} .bind(this));
			}, this);
		}
	},

	build: function() {
		Site.contextnav.addTab('Back');
	},

	load: function(fileName) {

		//this.element = new Element('div', {id: 'media-container2'}).inject(this.container);

		this.so = new SWFObject('../_swf/player.swf', 'jwplayer', '520', '460', '9');
		this.so.addParam('allowfullscreen', 'false');
		this.so.addParam('allowscriptaccess', 'always');
		this.so.addParam('wmode', 'opaque');
		this.so.addVariable('file', fileName);
		this.so.addVariable('screencolor', 'FFFFFF');
		this.so.addVariable('autostart', 'true');
		this.so.write('media-container2');

		this.play();
	},
	play: function() {
		Site.contextnav.back.addEvent('click', this.stop);
		Site.contextnav.back.fireEvent('show');
		this.element = $('media-container2');
		this.element.setStyle('display', 'block');

		//this.fireEvent('show');
	},
	stop: function() {
		Site.contextnav.back.removeEvent('click', this.stop);
		Site.contextnav.back.fireEvent('hide');
		player.sendEvent("STOP");

		this.element = $('media-container2');
		this.element.setStyle('display', 'none');
		this.element.innerHTML = "";
		player = null;
		//this.fireEvent('hide');
	}

});
function playerReady (thePlayer)
{
    player=document.getElementById(thePlayer.id);
}

/* -------------------------------------------------- */
/* =Drag.Flick */

Drag.Flick = new Class({
	
	Extends: Drag.Move,
		
	options: {
		snap: 0
	},
	
	flickOptions: {
		link: 'cancel',
		duration: 1000,
		transition: 'circ:out'
	},
	
	initialize: function (element, options, flickOptions) {
		this.parent(element, options);
		this.fx = new Fx.Morph(this.element, $merge(this.flickOptions, flickOptions));
		this.history = [];
		this.viewport = this.container || this.element.getDocument().body;
		this.calcLimits();
		this.addEvent('start', this.clearHistory.bind(this));
		this.addEvent('drag', this.logHistory.bind(this));
		this.addEvent('complete', this.slide.bind(this));
	},
	
	calcLimits: function () {
		if (this.container || this.needsLimits) {
			var elementSize = {x: this.element.getStyle('width').toInt(), y: this.element.getStyle('height').toInt()};
			var containerSize = {x: this.viewport.getStyle('width').toInt(), y: this.viewport.getStyle('height').toInt()};
			if (elementSize.x >= containerSize.x || elementSize.y >= containerSize.y) {
				this.container = false;
				this.needsLimits = true;
				this.options.limit = {
					x: (elementSize.x >= containerSize.x) ? [containerSize.x - elementSize.x, 0] : [0, containerSize.x - elementSize.x],
					y: (elementSize.y >= containerSize.y) ? [containerSize.y - elementSize.y, 0] : [0, containerSize.y - elementSize.y]
				};
			}
		}
	},
	
	logHistory: function () {
		this.history.push({pos: $merge(this.value.now), time: $time()});
		if (this.history.length > 6) this.history.shift();
	},
	
	clearHistory: function () {
		this.fx.cancel();
		this.history = [];
	},
	
	calcVelocity: function () {
		var start = this.history[0];
		var end = this.history.getLast();
		var newVel = Math.Vector.subtract(end.pos, start.pos);
		return newVel.scale(200 / (end.time - start.time));
	},
	
	slide: function () {
		if (this.history.length >= 2) {
			var vel = this.calcVelocity();
			var x = this.element.getPosition(this.viewport).x + vel.x;
			var y = this.element.getPosition(this.viewport).y + vel.y;
			if (this.options.limit) {
				x = x.toInt().limit(this.options.limit.x[0], this.options.limit.x[1]);
				y = y.toInt().limit(this.options.limit.y[0], this.options.limit.y[1]);
			}
			this.fx.start({'left': x, 'top': y});
		}
	}	
	
	
});


/* -------------------------------------------------- */
/* =Viewer */

Element.Events.cursorkey = {
	base: 'keyup',
	condition: function (event) {
		return (['up', 'right', 'down', 'left'].contains(event.key));
	}	
};


MAXOMEDIA.Viewer = new Class({

	Implements: [Events, Options],

	options: {
		itemSize: { x: 0, y: 0 },
		onDragStart: $empty,
		onSnap: $empty,
		placeholderData: {}
	},

	settings: {},

	initialize: function(container, data, options) {

		this.setOptions(options);
		this.settings.itemSize = this.options.itemSize;
		this.currentState = 'snap';

		this.data = new Hash(data);
		this.placeholderData = new Hash(this.options.placeholderData);

		// element references
		this.container = $(container);
		this.element = this.container.getElement('.flick-element');
		this.items = { source: this.element.getElements('.flick-item') };
		this.items.active = $A(this.items.source);
		this.items.source.forEach(function(item) {
			item.store('info', new MAXOMEDIA.Info(item.getElement('.infos')));
			item.addEvent('relocate', this.scrollToItem.pass(item, this));
		}, this);

		// preload images
		if (Browser.Engine.presto) {
			this.loadImagesForOpera();
		} else {
			this.preloadImages();
		}

		// setup placeholders
		this.items.placeholders = [];
		this.placeholderData.forEach(function(value, key) {
			var item = $(key);
			if (item) {
				item.inject(this.element);
				item.store('info', new MAXOMEDIA.Info(item.getElement('.infos')));
				item.addEvent('relocate', this.scrollToItem.pass(item, this));
				item.dispose();
				this.items.placeholders.push(item);
			}
		}, this);

		this.setup();

		this.flicker = new Drag.Flick(this.element, {
			container: this.container,
			onStart: this.dragStart.bind(this)
		}, {
			onComplete: this.switchStates.bind(this)
		});

		this.radar = new MAXOMEDIA.Radar(this.container, {
			getViewerItems: this.getActiveItems.bind(this),
			getViewerGridSize: this.passGridSize.bind(this)
		});

		this.bound = {
			scrollByCursor: this.scrollByCursor.bind(this)
		};
		this.enableCursorNavigation();

		this.filter();

	},

	preloadImages: function() {
		var keys = [];
		var sources = [];
		this.loader = new Loader();
		this.data.forEach(function(value, key) {
			if (value.Image) {
				keys.push(key);
				sources.push(value.Image);
			}
		}, this);

		this.loader.show();
		new Asset.images(sources, {
			onProgress: function(counter, index) {
				this.loader.update({ counter: counter, total: sources.length });
				this.items.source.some(function(item) {
					if (item.get('id') === keys[counter]) {
						item.setStyle('background-image', 'url(' + sources[counter] + ')');
						return true;
					} else {
						return false;
					}
				}, this);
			} .bind(this),
			onComplete: function() {
				this.loader.update({ counter: sources.length, total: sources.length });
				this.loader.hide();
				this.fireEvent('loaded');
			} .bind(this)
		});
	},

	loadImagesForOpera: function() { // sucker
		this.data.forEach(function(value, key) {
			if (value.Image) {
				$(key).setStyle('background-image', 'url(' + value.Image + ')');
			}
		}, this);
		(function() {
			this.fireEvent('loaded');
		}).delay(500, this);
	},

	setup: function() {
		// calc sizes
		this.settings.gridSize = this.getGridSize();
		this.settings.elementSize = {
			x: this.settings.itemSize.x * this.settings.gridSize.x,
			y: this.settings.itemSize.y * this.settings.gridSize.y
		};
		this.element.setStyle('width', this.settings.elementSize.x);
	},

	filter: function(queryString) {
		if (queryString) {
			var query = new Hash(queryString.parseQueryString());
			this.items.active = this.items.source.filter(function(item) {
				item.dispose();
				var entry = this.data.get(item.get('id'));
				var hasProperties = query.every(function(value, key) {
					return entry[key].toLowerCase() === value.toLowerCase();
				}, this);
				if (hasProperties) item.inject(this.element);
				return hasProperties;
			}, this);
		} else {
			$$(this.items.source).inject(this.element);
			this.items.active = $A(this.items.source);
		}

		this.setup();

		// fill empty slots with placeholders
		$$(this.items.placeholders).dispose();
		this.items.placeholders.shuffle();
		(this.settings.gridSize.r).times(function(index) {
			var placeholder = this.items.placeholders[index];
			if (placeholder) {
				var pos = $random(0, this.items.active.length - 1);
				placeholder.inject(this.items.active[pos], 'before');
				this.items.active.splice(pos, 0, placeholder);
			}
		}, this);

		this.flicker.calcLimits();
		this.radar.update();
	},

	getGridSize: function() {
		var gridSize = { x: this.items.active.length.sqrt().toInt()};
		gridSize.y = (this.items.active.length / gridSize.x).toInt();
		gridSize.r = (gridSize.x * gridSize.y) - this.items.active.length;

		while (this.items.active.length % gridSize.x !== 0) {
			var checkedGridSize = this.checkGridSize({ x: gridSize.x + 1, y: gridSize.y });
			if (checkedGridSize) {
				gridSize = checkedGridSize;
				break;
			}
			gridSize.x++;
		}

		return gridSize;
	},

	checkGridSize: function(gridSize) {
		gridSize.r = (gridSize.x * gridSize.y) - this.items.active.length;
		if (this.items.placeholders.length <= (gridSize.x * gridSize.y)) {
			return gridSize;
		} else {
			return false;
		}
	},

	passGridSize: function() {
		return this.settings.gridSize;
	},

	dragStart: function() {
		this.currentState = 'drag';
		if (this.currentItem) {
			var info = this.currentItem.retrieve('info');
			if (info.isVisible) info.hidePanel();
		}
		this.fireEvent('dragStart');
	},

	switchStates: function() {
		switch (this.currentState) {
			case 'drag': this.adjust(); break;
			case 'snap':
				if (this.currentItem) {
					var info = this.currentItem.retrieve('info');
					if (!MAXOMEDIA.Info.closedByUser) info.showPanel();
				}
				break;
		}
	},

	adjust: function() {
		this.scrollToOffset(this.getOffsetFromPosition());
	},

	scrollToItem: function(item) {
		this.scrollToIndex(this.items.active.indexOf(item));
	},

	scrollToIndex: function(index) {
		if (this.currentItem) {
			var info = this.currentItem.retrieve('info');
			if (info.isVisible) info.hidePanel();
		}
		this.scrollToOffset(this.getOffsetFromIndex(index));
	},

	scrollToOffset: function(offset) {
		this.setCurrentItem(offset);
		this.flicker.fx.start({
			'left': -(offset.x * this.settings.itemSize.x),
			'top': -(offset.y * this.settings.itemSize.y)
		});
		this.currentState = 'snap';
		this.fireEvent('snap', this.currentItem);
	},

	scrollByCursor: function(event) {
		var index = this.items.active.indexOf(this.currentItem);
		switch (event.key) {
			case 'up': index -= this.settings.gridSize.x; break;
			case 'right': index++; break;
			case 'down': index += this.settings.gridSize.x; break;
			case 'left': index--; break;
		}
		if (index >= 0 && index < this.items.active.length) this.scrollToIndex(index);
		this.fireEvent('scrollByCursor');
	},

	enableCursorNavigation: function() {
		window.document.addEvent('cursorkey', this.bound.scrollByCursor);
	},

	disableCursorNavigation: function() {
		window.document.removeEvent('cursorkey', this.bound.scrollByCursor);
	},

	getOffsetFromPosition: function() {
		var x = (-this.flicker.element.getPosition(this.flicker.viewport).x / this.settings.itemSize.x).round();
		var y = (-this.flicker.element.getPosition(this.flicker.viewport).y / this.settings.itemSize.y).round();
		return { x: x, y: y };
	},

	getOffsetFromIndex: function(index) {
		var y = (index / this.settings.gridSize.x).toInt();
		return { x: index - (this.settings.gridSize.x * y), y: y };
	},

	getIndexFromOffset: function(offset) {
		return this.settings.gridSize.x * offset.y + offset.x;
	},

	getCurrentItem: function(offset) {
		return this.items.active[this.settings.gridSize.x * offset.y + offset.x];
	},

	setCurrentItem: function(offset) {
		this.currentItem = this.getCurrentItem(offset);
		this.radar.setActive(this.getIndexFromOffset(offset));
	},

	getActiveItems: function() {
		return this.items.active;
	}

});


/* -------------------------------------------------- */
/* =Loader */

var Loader = new Class({
	
	Implements: [Options, Events],
	
	options: {
		opacity: 0.6,
		message: '{counter} of {total}'
	},
	
	initialize: function (options) {
		this.setOptions(options);
		this.container = $('loader-container').set('tween', {link: 'cancel', transition: 'sine:out'});
		this.bar = $('loader-bar').set('tween', {link: 'cancel', transition: 'sine:out'});
		this.label = $('loader-label');
	},
	
	show: function () {
		this.container.tween('opacity', this.options.opacity);
	},
	
	hide: function () {
		this.container.tween('opacity', 0);
	},
	
	update: function (values) {
		var width = 200;
		var pos = -(width - ((values.counter / values.total) * width).round());
		this.bar.tween('background-position', pos);
		this.label.set('text', this.options.message.substitute(values));
	}
	
});


/* -------------------------------------------------- */
/* =Radar */

MAXOMEDIA.Radar = new Class({
	
	Implements: [Events, Options],
	
	options: {
		itemSize: {x: 10, y: 10},
		offset: {x: 5, y: 5},
		delay: 15,
		opacity: 0.4,
		getViewerItems: $lambda([]),
		getViewerGridSize: $lambda({x: 0, y: 0})
	},
	
	settings: {},
	
	initialize: function (container, options) {
		this.parentContainer = $(container);
		this.setOptions(options);
		this.isActive = false;
		this.build();
		this.update();
		
		this.show();
	},
	
	build: function () {
		
		this.container = new Element('div', {'id': 'radar-container'});
		this.element = new Element('ul', {'class': 'radar'}).set('tween', {property: 'opacity', transition: 'sine:out'}).set('opacity', 0).inject(this.container);
		
		['topright', 'bottomright', 'bottomleft', 'topleft'].forEach(function (pos) {
			new Element('img', {
				'src': '/_gfx/icon_radar-' + pos + '_black.gif',
				'class': pos,
				'styles': {
					'opacity': 0.5
				}
			}).inject(this.element);
		}, this);
		
		this.items = [];
		
		this.btn = new Element('a', {'class': 'btn'}).inject(this.container);
		this.btn.addEvent('click', this.toggle.bind(this));
		
		this.container.inject(this.parentContainer);
		
		this.tips = new Tips(false, {'className': 'tooltip'});		
	},
	
	update: function () {
		this.tips.detach(this.items);
		this.items.empty();
		this.element.getChildren('li').destroy();
		
		this.settings.gridSize = this.options.getViewerGridSize();
		this.options.getViewerItems().forEach(function (parentItem, index) {
			var item = new Element('li', {
				'title': parentItem.getElement('.flick-title').get('text'),
				'styles': {
					'width': this.options.itemSize.x,
					'height': this.options.itemSize.y
				}
			});
			item.addEvent('click', this.relocate.pass(parentItem, this));
			item.addEvent('click', this.setActive.pass(index, this));
			item.addEvent('click', this.fireEvent.pass('navigate', this));
			item.set('morph', {transition: 'sine:out'}).set({'opacity': this.options.opacity});
			item.inject(this.element);
			this.items.push(item);
		}, this);
		this.tips.attach(this.items);
			
		this.arrange();
		
		this.settings.elementSize = {
			x: ((this.options.itemSize.x + this.options.offset.x) * this.settings.gridSize.x) - this.options.offset.x,
			y: ((this.options.itemSize.y + this.options.offset.y) * this.settings.gridSize.y) - this.options.offset.y
		};
		this.element.set('styles', {
			'width': this.settings.elementSize.x,
			'height': this.settings.elementSize.y
		});	
	},
	
	arrange: function () {
		this.items.forEach(function (item, index) {
			var offset = this.getOffsetFromIndex(index);
			item.set('styles', {
				'left': (this.options.itemSize.x + this.options.offset.x) * offset.x,
				'top': (this.options.itemSize.y + this.options.offset.y) * offset.y
			});
		}, this);
	},
	
	toggle: function () {
		(this.isActive) ? this.hide() : this.show();
	},
	
	show: function () {
		this.isActive = true;
		this.btn.addClass('active');
		this.element.setStyle('display', 'block');
		this.element.get('tween').start(1);
	},
	
	hide: function () {
		this.isActive = false;
		this.btn.removeClass('active');
		this.element.get('tween').start(0).chain(function () {
			this.element.setStyle('display', 'none');
		}.bind(this));		
	},
	
	getOffsetFromIndex: function (index) {
		var y = (index / this.settings.gridSize.x).toInt();
		return {x: index - (this.settings.gridSize.x * y), y: y};
	},
	
	relocate: function (parentItem) {
		parentItem.fireEvent('relocate');
	},
	
	setActive: function (index) {
		if (this.active) {
			this.active.removeClass('active');
			this.active.morph({'opacity': this.options.opacity});
		}
		if (this.items[index]) {
			this.active = this.items[index];
			this.active.addClass('viewed');
			this.active.addClass('active');
			this.active.morph({'opacity': 1});
		}
		this.fireEvent('setActive');
	}
	
});


/* -------------------------------------------------- */
/* =Info */

MAXOMEDIA.Info = new Class({
	
	closedByUser: false,
	
	settings: {},
	
	initialize: function (element) {
		this.element = $(element);
		this.settings.height = this.element.getSize().y;
		this.element.set('styles', {
			'opacity': 0.9
		});
		this.container = new Element('div', {
			'class': 'infos-container',
			'styles': {
				'margin-bottom': -this.settings.height
			}
		}).wraps(this.element);
		
		this.fx = new Fx.Tween(this.container, {'property': 'margin-bottom', 'link': 'cancel', transition: 'sine:out'});
		this.button = new Element('a', {
			'class': 'button show',
			'events': {
				'click': this.togglePanel.bind(this)
			}
		}).inject(this.container);
		
		this.isVisible = false;
	},
	
	showPanel: function () {
		this.isVisible = true;
		this.fx.start(0);
		this.button.removeClass('show').addClass('hide');
	},
	
	hidePanel: function () {
		this.isVisible = false;
		this.fx.start(-this.settings.height);
		this.button.removeClass('hide').addClass('show');
	},
	
	togglePanel: function () {
		if (this.isVisible) {
			MAXOMEDIA.Info.closedByUser = true;
			this.hidePanel();
		} else {
			MAXOMEDIA.Info.closedByUser = false;
			this.showPanel();
		}
	}
	
});


/* -------------------------------------------------- */
/* =URIFragmentManager */

var URIFragmentManager = new Class({
	
	Implements: [Options, Events],
	
	options: {
		interval: 250	
	},
	
	initialize: function (urlpatterns, options) {
		this.urlpatterns = urlpatterns;
		this.patternKeys = urlpatterns.map(function (item) {
			return item.key;
		}, this);
		
		this.setOptions(options);
		this.uri = new URI('http://');
		this.startCheck();
	},
	
	startCheck: function () {
		this.timer = this.check.periodical(this.options.interval, this);
	},
	
	stopCheck: function () {
		this.timer = $clear(this.timer);
	},
	
	check: function () {
		if (this.uri.toString() !== window.location.href) {
			this.uri = new URI(window.location.href);
			var pattern = this.getPattern();
			if (pattern) {
				this.fireEvent(pattern[0], pattern[1]);
				this.fireEvent('change', [pattern]);
			}
		}
	},
	
	addPattern: function (pattern, position) {
		if (!this.patternKeys.contains(pattern.key)) {
			position = $pick(position, this.urlpatterns.length);
			this.urlpatterns.splice(position, 0, pattern);
			this.patternKeys.splice(position, 0, pattern.key);
		}
	},
	
	setPattern: function (patternKey, values) {
		if (this.patternKeys.contains(patternKey)) {
			var pattern = this.urlpatterns[this.patternKeys.indexOf(patternKey)];
			var values = new Hash(values);
			var hasRequiredInfos = pattern.groups.every(function (group) {
				return values.has(group);
			}, this);
			if (hasRequiredInfos) {
				var currentIndex = 0;
				var fragment = pattern.regex.replace(/(\(.*?\))/g, function () {
					var value = values.get(pattern.groups[currentIndex]);
					currentIndex++;
					return value;
				});
				fragment = fragment.match(/[^^].+[^$]/)[0];
				var uri = new URI(window.location.href);
				uri.set('fragment', fragment.toLowerCase());
				uri.go();
			}
		}
	},
	
	getPattern: function () {
		var uri = new URI(window.location.href);
		var fragment = uri.get('fragment');
		var matchedPattern = false;
		this.urlpatterns.some(function (pattern) {
			var match = new RegExp(pattern.regex, 'i').exec(fragment);
			if (match) {
				match.shift();
				matchedPattern = [pattern.key, match.associate(pattern.groups)];
				
				// validator
				if ($defined(pattern.validators)) {
					var isValid = new Hash(pattern.validators).every(function (validator, validatorKey) {
						return validator.contains(matchedPattern[1][validatorKey]);
					}, this);
					if (!isValid) return false;
				}
				
			}
			return match;
		}, this);
		return matchedPattern;
	},
	
	setValue: function (valueKey, value) {
		var pattern = this.getPattern();
		if (pattern) {
			pattern[1][valueKey] = value;
			this.setPattern(pattern[0], pattern[1]);
		}
	},
	
	getValue: function (valueKey) {
		var pattern = this.getPattern();
		if (pattern) {
			var value = pattern[1][valueKey]
			return (value) ? value : false;
		}
	},
	
	clear: function () {
		this.uri.set('fragment', '/');
		this.uri.go();
	}
	
});


/* -------------------------------------------------- */
/* =Menu */

var Menu = new Class({
	
	Implements: [Options, Events],
	
	options: {
		className: 'menu',
		closeDelay: 750
	},
	
	initialize: function (container, data, options) {
		this.container = $(container);
		this.data = new Hash(data);
		this.setOptions(options);
		
		this.timer = null;
		this.openItems = [];
		
		this.build();
		if (this.data.Nodes.length) {
			this.element.adopt(this.buildList(this.data.Nodes));
			this.element.addEvents({
				'mouseenter': this.mouseenter.bind(this),
				'mouseleave': this.mouseleave.bind(this),
				'mouseover': this.mouseover.bind(this),
				'click': this.select.bind(this)
			});
		}
	},
	
	build: function () {
		this.element = new Element('div', {'class': this.options.className}).inject(this.container);
	},
	
	buildList: function (data) {
		var list = new Element('ul');
		data.forEach(function (item) {
			var listitem = new Element('li');
			var anchor = new Element('a', {
				'text': item.Label
			}).inject(listitem);
			if (item.Nodes && item.Nodes.length) listitem.adopt(this.buildList(item.Nodes));
			
			listitem.store('item', item);
			listitem.inject(list);
		}, this);
		return list;
	},
		
	mouseenter: function () {
		this.timer = (this.timer) ? $clear(this.timer) : null;
	},
	
	mouseleave: function () {
		this.timer = this.clear.delay(this.options.closeDelay, this);
	},
	
	clear: function () {
		this.openItems.forEach(function (listitem) {
			this.hide(listitem.getElement('ul'));
		}, this);
		this.openItems.empty();
		this.fireEvent('clear');
	},
	
	mouseover: function (event) {
		if (event.target.get('tag') === 'a') {
			var listitem = event.target.getParent('li');
			
			if (this.openItems.length) {
				$A(this.openItems).reverse().some(function (openItem) {
					if (openItem.hasChild(listitem)) {
						return true;
					} else {
						this.hide(openItem.getElement('ul'));
						this.openItems.pop();
						return false;
					}
				}, this);
			}
			
			var item = listitem.retrieve('item');
			if (item.Nodes && item.Nodes.length) {
				this.show(listitem.getElement('ul'));
				this.openItems.push(listitem);
			}
		}
	},
		
	show: function (list) {
		list.setStyle('display', 'block');
	},
	
	hide: function (list) {
		list.setStyle('display', 'none');
	},
	
	select: function (event) {
		if (event.target.get('tag') === 'a') {
			var listitem = event.target.getParent('li');
			var item = listitem.retrieve('item');
			this.fireEvent('select', item);
		}
	}	
	
});


/* -------------------------------------------------- */
/* =Filter */

MAXOMEDIA.Filter = new Class({
	
	Implements: [Options, Events],
	
	options: {
		className: 'filter'
	},
	
	initialize: function (container, data, options) {
		this.container = $(container);
		this.setOptions(options);
		
		this.isVisible = false;
		this.build();
		
		this.menu = new Menu(this.element, data);
		this.menu.relayEvent('select', this);
		this.menu.addEvent('clear', this.hide.bind(this));
		this.setWidth();
	},
	
	build: function () {
		this.element = new Element('div', {'class': this.options.className})
		this.button = new Element('a', {
			'class': 'button',
			'events': {
				'click': this.toggle.bind(this),
				'mouseout': this.buttonout.bind(this)
			}
		}).inject(this.element, 'top');
		this.element.inject(this.container);
	},
	
	setMenuContainer: function (container) {
		this.menuContainer = $(container);
	},
	
	setWidth: function () {
		this.element.setStyle('width', this.menu.element.getSize().x - 10);
	},
	
	setLabel: function (label) {
		this.button.set('text', label);
	},
	
	buttonout: function () {
		if (this.isVisible) this.menu.mouseleave();
	},
	
	show: function () {
		this.menu.element.setStyle('visibility', 'visible');
		this.container.addClass('isVisible');
		this.isVisible = true;
		this.fireEvent('show');
	},
	
	hide: function () {
		this.menu.element.setStyle('visibility', 'hidden');
		this.container.removeClass('isVisible');
		this.isVisible = false;
		this.fireEvent('hide');
	},
	
	toggle: function () {
		(this.isVisible) ? this.hide() : this.show();
	}
		
});


/* -------------------------------------------------- */
/* =Instructions */

var Instructions = new Class({
	
	initialize: function () {
		this.isClosed = false;
		this.build();
	},
	
	build: function () {
		this.container = new Element('div', {id: 'instructions-container'}).inject($('body-content'));
		this.swiff = new Swiff('/_swf/instructions.swf', {
			width: '100%',
			height: '100%',
			params: {
				wMode: 'transparent'
			},
			container: this.container
		});
	},
	
	close: function () {
		if (!this.isClosed) {
			this.isClosed = true;
			this.container.destroy();
		}
	}
	
});
