/**
 * Javascript code to store data as JSON strings in cookies.
 * It uses prototype.js 1.5.1 (http://www.prototypejs.org)
 *
 * Author : Lalit Patel
 * Website: http://www.lalit.org/lab/jsoncookies
 * License: Creative Commons Attribution-ShareAlike 2.5
 *          http://creativecommons.org/licenses/by-sa/2.5/
 * Version: 0.4
 * Updated: Aug 11, 2007 10:09am
 *
 * Chnage Log:
 *   v 0.4
 *   -  Removed a extra comma in options (was breaking in IE and Opera). (Thanks Jason)
 *   -  Removed the parameter name from the initialize function
 *   -  Changed the way expires date was being calculated. (Thanks David)
 *   v 0.3
 *   -  Removed dependancy on json.js (http://www.json.org/json.js)
 *   -  empty() function only deletes the cookies set by CookieJar
 */

var CookieJar = Class.create();

CookieJar.prototype = {

	/**
	 * Append before all cookie names to differntiate them.
	 */
	appendString: "__CJ_",

	/**
	 * Initializes the cookie jar with the options.
	 */
	initialize: function(options) {
		this.options = {
			expires: 3600,		// seconds (1 hr)
			path: '',			// cookie path
			domain: '',			// cookie domain
			secure: ''			// secure ?
		};
		Object.extend(this.options, options || {});

		if (this.options.expires != '') {
			var date = new Date();
			date = new Date(date.getTime() + (this.options.expires * 1000));
			this.options.expires = '; expires=' + date.toGMTString();
		}
		if (this.options.path != '') {
			this.options.path = '; path=' + escape(this.options.path);
		}
		if (this.options.domain != '') {
			this.options.domain = '; domain=' + escape(this.options.domain);
		}
		if (this.options.secure == 'secure') {
			this.options.secure = '; secure';
		} else {
			this.options.secure = '';
		}
	},

	/**
	 * Adds a name values pair.
	 */
	put: function(name, value) {
		name = this.appendString + name;
		cookie = this.options;
		var type = typeof value;
		switch(type) {
		  case 'undefined':
		  case 'function' :
		  case 'unknown'  : return false;
		  case 'boolean'  :
		  case 'string'   :
		  case 'number'   : value = String(value.toString());
		}
		var cookie_str = name + "=" + escape(Object.toJSON(value));
		try {
			document.cookie = cookie_str + cookie.expires + cookie.path + cookie.domain + cookie.secure;
		} catch (e) {
			return false;
		}
		return true;
	},

	/**
	 * Removes a particular cookie (name value pair) form the Cookie Jar.
	 */
	remove: function(name) {
		name = this.appendString + name;
		cookie = this.options;
		try {
			var date = new Date();
			date.setTime(date.getTime() - (3600 * 1000));
			var expires = '; expires=' + date.toGMTString();
			document.cookie = name + "=" + expires + cookie.path + cookie.domain + cookie.secure;
		} catch (e) {
			return false;
		}
		return true;
	},

	/**
	 * Return a particular cookie by name;
	 */
	get: function(name) {
		name = this.appendString + name;
		var cookies = document.cookie.match(name + '=(.*?)(;|$)');
		if (cookies) {
			return (unescape(cookies[1])).evalJSON();
		} else {
			return null;
		}
	},

	/**
	 * Empties the Cookie Jar. Deletes all the cookies.
	 */
	empty: function() {
		keys = this.getKeys();
		size = keys.size();
		for(i=0; i<size; i++) {
			this.remove(keys[i]);
		}
	},

	/**
	 * Returns all cookies as a single object
	 */
	getPack: function() {
		pack = {};
		keys = this.getKeys();

		size = keys.size();
		for(i=0; i<size; i++) {
			pack[keys[i]] = this.get(keys[i]);
		}
		return pack;
	},

	/**
	 * Returns all keys.
	 */
	getKeys: function() {
		keys = $A();
		keyRe= /[^=; ]+(?=\=)/g;
		str  = document.cookie;
		CJRe = new RegExp("^" + this.appendString);
		while((match = keyRe.exec(str)) != undefined) {
			if (CJRe.test(match[0].strip())) {
				keys.push(match[0].strip().gsub("^" + this.appendString,""));
			}
		}
		return keys;
	}
};

function init(base, language)
{
	if (typeof Prototype === "undefined" || typeof SWFAddress === "undefined")
	{
		throw new Error("This script relies on the Prototype JavaScript framework and SWFAddress.");
	}
	else
	{
		SWFAddress.addEventListener(SWFAddressEvent.INIT, function()
		{
			window.base	= window.location.protocol + '//' + window.location.host + '/';
			window.jar	= new CookieJar({ path: '/', expires: 24*60*60 });
			window.site	= new Site(base, language);
		});
	}
}

function phpAjaxQuery(className, methodName, arguments, mime)
{
	return $H({ iso: site.iso, ajax: $H({ 'class': className, method: methodName, mime: mime ? mime : 'json', arguments: Object.isArray(arguments) ? arguments : [] }) }).toPHPQueryString('cms');
}

var Cookable =
{
	typeCookie: 'array',
	defaultCookie: null,
	countCookie: 0,

	putCookie: function(value)
	{
		return window.jar.put(this.id, value);
	},

	getCookie: function()
	{
		return window.jar.get(this.id);
	},

	initCookie: function()
	{
		if (this.getCookie() === null)
		{
			if (arguments.length > 0)
			{
				this.defaultCookie = arguments[0];
			}
			else
			{
				switch (this.typeCookie)
				{
					case 'string':	this.defaultCookie = ""; break;
					case 'number':	this.defaultCookie = 0; break;
					case 'object':	this.defaultCookie = {}; break;
					case 'array':
					default:	this.defaultCookie = [];
				}
			}

			this.resetCookie();
		}
	},

	addCookie: function(id, after)
	{
		var ids = this.getCookie().without(id);

		after ? ids.push(id) : ids.unshift(id);

		this.maxCookie && (ids = ids.slice(0, this.maxCookie));

		this.putCookie(ids);
	},

	deleteCookie: function(id)
	{
		this.putCookie(this.getCookie().without(id));
	},

	resetCookie: function()
	{
		this.putCookie(this.defaultCookie);
	}
}

var ModelBase = Class.create(
{
	initialize: function(id, model)
	{
		this.id		= id;
		this.container	= $(id);
		this.state	= null;
		this.model	= model;
		this.queue	= new ModelBase.Queue(this);

		this.model.register.set(this.id, this);

		this.initCookie && this.initCookie();

		document.observe('language:change', function() { this.language && this.resetstate(); }.bind(this));
	},

	handlefailure: function(request)
	{
	},

	getdata: function(options)
	{
		options	= options || {};

		options.element		= (options.element ? options.element : this.id);
		options.state		= (options.state ? options.state : this.id);
		options.ignore		= (options.ignore ? options.ignore : false);
		options.queue		= (options.queue ? options.queue : false);
		options.abort		= (options.abort !== undefined ? options.abort : true);
		options.parameters	= (options.parameters ? options.parameters : null);
		options.script		= (options.script ? options.script : 'ajax.php');
		options.callback	= (options.callback ? options.callback : this.ondata);
		options.method		= (options.method ? options.method : 'post');

		if (options.queue)
		{
			this.queue.add(arguments.callee, options);
		}
		else
		{
			if (this.cache && this.cache.get(options.state))
			{
				options.callback.call(this, options, this.cache.get(options.state));
			}
			else
			{
				document.fire(options.element + ':loading');

				options.abort && this.request && this.request.transport.abort();

				this.request = new Ajax.Request(options.script, { method: options.method, parameters: options.parameters, onSuccess: options.callback.bind(this, options), onFailure: this.handlefailure } );
			}
		}
	},

	getstaticdata: function(options)
	{
		options	= options || {};

		options.element		= (options.element ? options.element : this.id);
		options.script		= '/site/' + site.base.ID + '/html/' + (this.language ? site.iso + '/' : '') + options.element + '.html';
		options.method		= 'get';

		this.getdata(options);
	},

	getalldata: function(ids, after)
	{
		Object.isArray(ids) && ids.each(function (id) { this.addCookie(id, after); }, this);

		if (Object.isArray(this.getCookie()) && (this.countCookie = this.getCookie().size()))
		{
			this.getCookie().each(function (id) { this.getdata({ state: id, abort: false, dir: this.id }); }, this);
		}
		else
		{
			this.countCookie = 1;

			this.ondata({ element: this.id, state: null });
		}
	},

	nodata: function()
	{
		this.ondata({ element: this.id });
	},

	ondata: function(query, request)
	{
		this.cache && query.state && request && !request.cached && (request.cached = true) && this.cache.set(query.state, request);

		!query.ignore && (this.state = query.state);

		this.loaded(query.element);

		this.fire(query, request);

		this.queue.process();
	},

	fire: function(query, request)
	{
		document.fire(query.element + ':loaded', { request: request, state: query.state });
	},

	refresh: function(element)
	{
		element = element || this.id;

		this.onrefresh(element);
	},

	onrefresh: function(element)
	{
		element = element || this.id;

		document.fire(element + ':refresh');
	},

	collect: function()
	{
		return Object.isArray(this.getCookie()) ? this.getCookie().collect(function(id) { return this.retrieve(id); }, this).join('') : null;
	},

	retrieve: function(id)
	{
		return this.cache.get(id);
	},

	loaded: function(element)
	{
		!this.model.loaded && this.model.elementloaded(element);
	},

	resetstate: function()
	{
		this.state = null;
	}
} );

ModelBase.Queue = Class.create(
{
	object: null,
	queue: [],
	element: null,
	running: false,

	initialize: function(object)
	{
		this.object = object;
	},

	add: function(callback, query)
	{
		this.queue.push({ callback: callback, query: query });

		this.check();
	},

	remove: function(state)
	{
		if (this.element && this.element.query.state == state)
		{
			this.object.request && this.object.request.transport.abort();
		}
		else
		{
			this.queue = this.queue.reject(function(element) { return element.query.state == state; });
		}
	},

	clear: function()
	{
		this.object.request && this.object.request.transport.abort();

		this.queue = [];

		this.end();
	},

	start: function()
	{
		this.running = true;

		this.process();
	},

	end: function()
	{
		this.running = false;
	},

	check: function()
	{
		!this.running && this.queue.size() > 0 && this.start();
	},

	process: function()
	{
		if (this.element = this.queue.shift())
		{
			this.element.query.queue = false;

			this.element.callback.call(this.object, this.element.query);
		}
		else
		{
			this.end();
		}
	}
} );

var AutocompleteModel = Class.create(ModelBase,
{
	language: true,

	initialize: function($super, id, model)
	{
		$super(id, model);

		this.clear();
	},

	getkeydata: function(event)
	{
		var cache, json, send = true, prev = event.memo.key.length - 1;

		prev > 0 && (cache = this.cache.get(prev)) && (json = cache.responseJSON) && !$H(json.payload).inject(0, function(memo, element) { return memo + element.value.size(); }) && (send = false);

		if (event.memo.key && send)
		{
			this.getdata({ state: event.memo.key.length, queue: true, parameters: phpAjaxQuery('thing', 'GetSearchData', [event.memo.key]) });
		}
		else
		{
			this.ondata({ element: this.id, state: event.memo.key.length }, send ? null : { responseJSON: { success: true, payload: null, error: [] } });
		}
	},

	clear: function(event)
	{
		if (event && event.memo.key)
		{
			this.queue.remove(event.memo.key);

			this.cache.unset(event.memo.key);
		}
		else
		{
			this.cache = new Hash();
		}
	}
} );

var ContactModel = Class.create(ModelBase,
{
	language: true,
	
	initialize: function($super, id, model)
	{
		$super(id, model);
	}
} );

var FirstModel = Class.create(ModelBase,
{
	initialize: function($super, id, model)
	{
		$super(id, model);
	}
} );

var FooterModel = Class.create(ModelBase,
{
	language: true,

	initialize: function($super, id, model)
	{
		$super(id, model);
	}
} );

var HeaderModel = Class.create(ModelBase,
{
	language: true,

	initialize: function($super, id, model)
	{
		$super(id, model);
	}
} );

var LanguageModel = Class.create(ModelBase,
{
	initialize: function($super, id, model)
	{
		$super(id, model);
	},

	getdata: function(options)
	{
		options	= options || {};

		this.ondata({ element: this.id, state: options.state }, { responseJSON: { success: true, payload: window.site.language, error: [] } });
	}
} );

var ListModel = Class.create(ModelBase,
{
	language: true,

	initialize: function($super, id, model)
	{
		$super(id, model);
	}
} );

var LogoModel = Class.create(ModelBase,
{
	initialize: function($super, id, model)
	{
		$super(id, model);
	}
} );

var SearchModel = Class.create(ModelBase,
{
	init: false,
	language: true,

	initialize: function($super, id, model)
	{
		$super(id, model);
	}
} );

var TagModel = Class.create(ModelBase,
{
	language: true,

	initialize: function($super, id, model)
	{
		$super(id, model);
	}
} );

var Model = Class.create(
{
	allregistered: false,
	loaded: false,
	register: new Hash(),
	elements: new Hash(),

	initialize: function(type)
	{
		this.search 		= new SearchModel('search', this);
		this.autocomplete 	= new AutocompleteModel('autocomplete', this);
		this.tag 			= new TagModel('tag', this);
		this.logo	 		= new LogoModel('logo', this);
		this.contact		= new ContactModel('contact', this);
		this.header 		= new HeaderModel('header', this);
		this.first 			= new FirstModel('first', this);
		this.list 			= new ListModel('list', this);
		this.footer 		= new FooterModel('footer', this);
		this.language		= new LanguageModel('language', this);

		this.allregistered = true;
	},

	elementloaded: function(id)
	{
		this.register.get(id) && this.elements.set(id, true);

		this.allregistered && this.check();
	},

	check: function()
	{
		if (this.elements.keys().size() == this.register.keys().size())
		{
			this.loaded = true;

			document.fire('model:loaded');
		}
	}
} );

var Site = Class.create(
{
	version: 0.8,

	state:
	{
		path: null,
		dirs: [],
		iso: null,
		type: null,
		ids: null,
		parameters: null
	},

	initialize: function(base, language)
	{
		this.base	= base;
		this.language	= language;
		this.iso	= null;
		this.window	= window;
		this.main	= $('main');

		this.model	= new Model()
		this.view	= new View();

		document.observe('view:ready', this.ready.bind(this));
		document.observe('autocomplete:key', this.model.autocomplete.getkeydata.bind(this.model.autocomplete));
		document.observe('autocomplete:clear', this.model.autocomplete.clear.bind(this.model.autocomplete));
		document.observe('first:update', function(event) { this.model.first.ondata({ element: this.model.first.id, state: this.state.type }, { responseJSON: { success: true, payload: [event.memo.element], error: [] }}); }.bind(this));
		document.observe('title:set', this.settitle.bindAsEventListener(this));
		document.observe('selectstart', function(event) { event.stop(); });
		
		$('loader').observe('click', function(e) { $('loader').hide(); });

		SWFAddress.addEventListener(SWFAddressEvent.CHANGE, this.update.bind(this));
	},

	update: function(event)
	{
		this.state.path		= SWFAddress.getPath();
		this.state.dirs		= this.state.path.split('/').slice(1);
		this.state.iso		= this.state.dirs[0];
		this.state.type		= this.state.dirs[1];
		this.state.ids		= this.state.dirs[2];		this.state.ids || (this.state.ids = '');
		this.state.parameters	= SWFAddress.getQueryString();

		!this.model.language.state && this.model.language.getdata();

		if (!this.checklanguage())
		{
			this.view.language.redirect();
		}
		else
		{
			Math.dice(20) && this.model.tag.resetstate();

			!this.model.logo.state		&& this.model.logo.getstaticdata();
			!this.model.header.state	&& this.model.header.getdata({ parameters: phpAjaxQuery('tag', 'GetTagsByCat', [1]) });
			!this.model.search.state	&& this.model.search.getstaticdata();
			!this.model.autocomplete.state	&& this.model.autocomplete.getstaticdata();
			!this.model.tag.state		&& this.model.tag.getdata({ parameters: phpAjaxQuery('tag', 'GetCloud', [50]) });
			!this.model.contact.state	&& this.model.contact.getstaticdata();
			!this.model.footer.state	&& this.model.footer.getstaticdata();

			switch (this.state.type)
			{
				case 'things':
					this.model.list.getdata({ state: this.state.type, parameters: phpAjaxQuery('thing', 'GetRelatedThingDataByID', [this.state.ids, this.view.list.max ? this.view.list.max - 1 : null]) });

					break;
				case 'tags':
					this.model.list.getdata({ state: this.state.type, parameters: phpAjaxQuery('thing', 'GetThingDataByTagID', [this.state.ids, this.view.list.max]) });

					break;
				case 'search':
					this.model.list.getdata({ state: this.state.type, parameters: phpAjaxQuery('thing', 'GetThingDataByFTS', [this.state.ids, this.view.list.max]) });

					break;
				default:
					this.model.list.getdata({ state: this.state.type, parameters: phpAjaxQuery('thing', 'GetThingDataByID', [null, false, this.view.list.max]) });
			}
		}
	},

	checklanguage: function()
	{
		this.state.iso !== this.iso && document.fire('language:change');

		return this.iso = this.state.iso;
	},

	settitle: function(event)
	{
		var title = this.base.title + ' | ' + event.memo.title;

		SWFAddress.setTitle(title);
	},

	ready: function()
	{
		$('loader').hide().stopObserving('click');

		this.resize();

		Event.observe(window, 'resize', this.resize.bind(this));

		document.fire('window:ready');
	},

	resize: function()
	{
		var dims = document.viewport.getDimensions();

		if (this.window.width != dims.width || this.window.height != dims.height)
		{
			this.window.width	= dims.width;
			this.window.height	= dims.height;

			document.fire('window:resized');
		}
	}
} );

var SlideShow = Class.create(
{
	index: null,
	pe: null,

	initialize: function(images, size, interval, duration, callback)
	{
		this.images	= images;
		this.length	= this.images.size();
		this.size	= size;
		this.interval	= interval;
		this.duration	= duration;
		this.callback	= callback;

		this.length > 0 && this.init();
	},

	init: function()
	{
		this.images.each(function(element) { element.hide(); element.setOpacity(0); });

		this.show();

		this.length > 1 && this.start();
	},

	show: function()
	{
		var morph = this.index !== null;

                this.index = (morph ? ++this.index%this.length : 0);

		this.images[this.index].show();

		morph && new Effect.Opacity(this.images[(this.length + this.index - 1)%this.length], { from: 1.0, to: 0.0, duration: this.duration, afterFinish: function(effect) { effect.element.hide(); } });
		new Effect.Opacity(this.images[this.index], { from: 0.0, to: 1.0, duration: morph ? this.duration : 0 });
	},

	start: function()
	{
		this.pe = new PeriodicalExecuter(this.show.bind(this), this.interval);
	},

	stop: function()
	{
		this.pe && this.pe.stop();
	}
});

var ViewBase = Class.create(
{
	initialize: function(id, view)
	{
		this.id		= id;
		this.container	= $(this.id);
		this.content	= this.container.down();
		this.view	= view;

		this.view && this.view.register.set(this.id, this);

		document.observe(this.id + ':loaded', this.populate.bind(this));
		document.observe(this.id + ':refresh', this.scan.bind(this, this.activate));
	},

	populate: function(event)
	{
		if (request = event.memo.request)
		{
			if (request.responseJSON)
			{
				request.responseJSON.error.size() > 0	&& debug(request.responseJSON.error);
				request.responseJSON.success		&& this.process(request.responseJSON.payload, event.memo.state);
			}
			else
			{
				this.process(request.responseText, event.memo.state);
			}
		}
		else
		{
			this.content.html = null;
		}

		if (this.content.html)
		{
			this.fill();
		}
		else
		{
			this.empty();
		}

		this.ready();

		document.fire(this.id + ':ready');
	},

	process: function(data, state)
	{
		this.content.html = (Object.isArray(data) ? data.serialize() : data);
	},

	fill: function()
	{
		this.wrapper = new Element('div', { 'class': 'wrapper'});

		this.content.update(this.wrapper.update(this.content.html));

		this.scan(this.link);
	},

	empty: function()
	{
		this.content.update(null);
	},

	scan: function(callback)
	{
		this.content.select('a').each(callback, this);
	},

	link: function(element)
	{
		if (element.rel && ('/' + element.readAttribute("href").replace(/^\//, '')) == element.rel)
		{
			this.activate(element);

			element.observe('click', function(event) { window.scrollTo(0, 0); event.preventDefault(); SWFAddress.setValue(element.rel); });
		}
		else
		{
			element.href == window.base && element.observe('click', function(event) { event.preventDefault(); });
		}
	},

	activate: function(element)
	{
		// handle activation. must be overridden in subclass
	},

	ready: function()
	{
		this.view && !this.view.ready && this.view.elementready(this.id);
	},

	sifr: function(style, definition)
	{
		typeof sIFR == "function" && sIFR.replaceElement(style, definition);
	},

	show: function()
	{
		this.container.show();
	},

	hide: function()
	{
		this.container.hide();
	}
} );

var AutocompleteView = Class.create(ViewBase,
{
	fadeDuration: 0.1,
	scaleDuration: 0,
	prev: null,

	initialize: function($super, id, view)
	{
		$super(id, view);

		//this.reset();
	},

	init: function(search)
	{
		this.search = search;
		this.search.box.observe('keyup', this.handlekey.bindAsEventListener(this));

		document.observe(this.id + ':loading', this.search.loading.bind(this.search, true));
		document.observe(this.search.id + ':reset', this.reset.bind(this));
		this.search.box.observe('click', function() { document.fire(this.id + ':clear'); }.bind(this));

		return true;
	},

	process: function(data)
	{
		if (Object.isString(data))
		{
			this.message = data;
		}
		else
		{
			this.items = [];
			this.index = null;

			var hash = $H(data);

			this.content.html = new Element('ul');

			if (hash.inject(0, function(memo, element) { return memo + element.value.size(); } ))
			{
				hash.each(function(pair)
				{
					Object.isArray(pair.value) && pair.value.each(function(data) { this.iterate(data, pair.key); }, this);
				}, this);
			}
			else
			{
				this.content.html.insert(new Element('li').insert(this.message));
			}
		}
	},

	iterate: function(data, type)
	{
		this.items.push(this.markup(data, type));
	},

	markup: function(data, type)
	{
		var html = new Element('li', { 'class': type }).insert(new Element('a', { href: '/' + site.iso + '/' + type + '/' + data.ID + '/' + data.title.seo(), rel: '/' + site.iso + '/' + type + '/' + data.ID + '/' + data.title.seo(), title: data.title }).update(data.title));

		this.content.html.insert(html);

		return html;
	},

	fill: function($super, id)
	{
		$super(id);

		new Effect.Opacity(this.container, { from: 0.0, to: 1.0, duration: .1 });

		this.search.loading(false);
	},

	link: function(element)
	{
		element.observe('click', function(event) { this.search.setbox(element.title); window.scrollTo(0, 0); event.preventDefault(); SWFAddress.setValue(element.rel); }.bind(this));
	},

	handlekey: function(event)
	{
		event.preventDefault();

		var key		= this.search.box.value;
		var code	= event.keyCode;

		code == Event.KEY_DOWN		&& this.hilite(1);
		code == Event.KEY_UP		&& this.hilite(-1);
		code == Event.KEY_ESC		&& this.hilite(null);
		code == Event.KEY_RETURN	&& this.enter(key);
		code == Event.KEY_BACKSPACE	&& document.fire(this.id + ':clear', { key: this.prev.length });
		code == Event.KEY_LEFT		&& document.fire(this.id + ':clear', { key: this.prev.length });
		code == Event.KEY_DELETE	&& document.fire(this.id + ':clear');

		(code == Event.KEY_BACKSPACE || code == Event.KEY_SPACE || code >= Event.KEY_DELETE) && document.fire(this.id + ':key', { key: key });

		this.prev = key;
	},

	hilite: function(direction)
	{
		var prev;

		if (this.items.size() > 0)
		{
			(prev = this.index) === null || this.items[prev].removeClassName('selected');

			if ((this.index = direction ? (this.index === null ? (direction > 0 ? 0 : this.items.size()) : (this.items.size() + this.index + direction)%this.items.size()) : null) !== null)
			{
				this.items[this.index].addClassName('selected');
			}
		}
	},

	enter: function(key)
	{
		this.reset();

		if (this.index === null)
		{
			SWFAddress.setValue('/' + site.iso + '/' + this.search.id + '/' + encodeURIComponent(key));
		}
		else
		{
			this.search.setbox(this.items[this.index].down().title);

			SWFAddress.setValue(this.items[this.index].down().rel);
		}
	},

	reset: function()
	{
		this.empty();

		document.fire(this.id + ':clear');
	}
} );

var ContactView = Class.create(ViewBase,
{
	initialize: function($super, id, view)
	{
		$super(id, view);
	}
} );

var FirstView = Class.create(ViewBase,
{
	size: '791x350^',
	popupSize: "1000x1000",
	popupSizeVideo: "794x459",
	slideshow: null,
	duration: .3,
	menuTransition: .3,
	menuEffect: null,
	linkTransition: .3,
	linkEffect: null,

	initialize: function($super, id, view)
	{
		$super(id, view);
	},

	process: function(data)
	{
		this.slideshow && this.slideshow.stop();

		if (data = data.shift())
		{
			this.content.html = new Element('div');

			document.fire('title:set', { title: data.title });

			this.markup(data);

			this.slideshow = new SlideShow(data.content.image.pluck('html'), this.size, 10, 1);
		}
		else
		{
			this.content.html = null;
		}
	},

	link: function(element)
	{
		element.observe('click', this.click.bindAsEventListener(this));
	},

	click: function(event)
	{
		Event.findElement(event).up("#description") == undefined && event.preventDefault();

		var options = { duration: .5, queue: 'end' }
	},

	fill: function($super)
	{
		$super();

		new Effect.Morph(this.textwrapper.up(), { style: "height: " + this.textwrapper.getHeight() + "px;", duration: this.duration });
	},

	markup: function(data)
	{
		this.media		= new Element('div', { 'id' : 'media' });

		var description		= new Element('div', { 'id' : 'description' });
		var header		= new Element('p', { 'id': 'descr_par' });
		var buttons		= new Element('div', { 'id' : 'media_icons' });
		var text		= new Element('div', { 'id' : 'text' } );

		header.insert(new Element('h2').update(data.title))
		      .insert(new Element('h3').update(data.subtitle))
		      .insert(new Element('div', { 'class': 'date' }).update(data.date ? data.date : ''))
		      .insert(buttons);

		if (data.content.image.size())
		{
			data.content.image.each(function(element)
			{
				element.cache = new Image();
				element.cache.src = '/image.php?' + $H({ source: element.file, size: this.size, crop: element.file_crop ? element.file_crop : '' }).toPHPQueryString('cms');
				element.html = Element('img', { 'class': 'slideshow', src: element.cache.src });

				this.media.insert(element.html);

			}, this);
		}
		
		text.insert(this.textwrapper = new Element('div'));

		if (data.content.text.size()) { data.content.text.each(function(element) { this.textwrapper.insert(new Element('h3').update(element.title)).insert(new Element('div', { 'class' : 'text' }).update(element.text)); }, this); }

		delete data.content.text;

		this.menuContainer = new Element('div', { id: "menu" }).toggle().observe('mouseleave', this.menu.bind(this));

		var menuBackground 	= new Element('div', { id: "background" }).setOpacity(.57);
		var menuContent 	= new Element('div', { id: "content" });
		var colWrapper		= new Element('div', { id: "menuColWrapper" });

		var type, counter = 0, button = 0, highlightFirst = 1;
		$H(data.content).select(function(pair) { return pair.value.size() > 0; }).each(function(pair)
		{
			type = pair.key;

			var menuCol = new Element('p', { className: "menuCol" });
				menuCol.observe('mouseenter', this.menuCol.bindAsEventListener(this)).observe('mouseleave', this.menuCol.bindAsEventListener(this));
			var menuColLinks = new Element('div', { className : 'menuColLinks' });
				highlightFirst ? menuCol.addClassName("menuColHover") : menuColLinks.toggle();

			pair.value.each(function(element, index)
			{
					var file 	= element && element.file ? (element.file.indexOf("upload") > 0  ? element.file : '/upload/' + window.site.base.ID + '/' + type + '/' + element.file) : element.url ? element.url : "";
					var href	= type == "audio" || type == "video" ? "admin/player/flvplayer.swf" : (type == "image" ? '/image.php?' + $H({ source: element.file, size: this.popupSize }).toPHPQueryString('cms') : (type == "file" ? '/file.php?' + $H({ source: element.file }).toPHPQueryString('cms') : file) );
					var options	= "viewport: true, slideshow: false, autosize: false"+(type != "image" ? ", width:"+this.popupSizeVideo.split('x').shift() : "")+(type != "image" ? ", height:"+this.popupSizeVideo.split('x').pop() : "")+", flashvars:'file="+file+"&skin=admin/player/skin.swf&controlbar=over&autostart=true"+(type == 'audio' ? "&image=/site/2/images/audio_background.jpg" : "")+"'";

					menuColLinks.insert(new Element('a', { 'id' : type+'_' + element.ID, 'class' : 'first_menu_links', 'alt' : element.title+" :: :: "+options, 'rel' : (type == "image" ? "gallery" : "set")+'['+type+']', 'href' : href, 'title' : element.title}).insert(element.title ? element.title : type).observe('click', this.initmedia.bind(this, type)));
					
					counter++;
			}, this);

			menuCol.insert( new Element('h1').insert(type) ).insert(menuColLinks);
			colWrapper.insert( new Element('div', { className: "menuCol" }).insert(menuCol) );
			
			highlightFirst = false;

		}, this);

		this.menuContainer.insert(menuBackground).insert(menuContent.insert(colWrapper));

		this.media.observe('mouseenter', this.menu.bind(this));
		
		this.content.html.observe('mouseleave', this.menuHide.bind(this));

		counter && this.content.html.insert(this.menuContainer);

		this.content.html.insert(this.media).insert(description.insert(header).insert(text));
		
		document.observe('lightview:hidden', this.titleswap.bind(this));
	},

	initmedia: function(type, event)
	{
		switch (type)
		{
			case 'video':
			case 'audio':
			case 'image':
				this.titleswap(event);
				Lightview.show(event.target);
				break;
			case 'file':
				window.open(event.target.href);
				break;
			case 'link':
				window.open(event.target.href, event.target.target);
				break;
			default:
		}
	},
	
	titleswap: function(event)
	{
		$$('.first_menu_links').each(function(el) { var t = el.title; el.title = el.readAttribute("alt"); el.writeAttribute("alt", t); });
	},

	menu: function(event)
	{
		this.menuEffect && this.menuEffect.cancel();
		
		this.menuEffect = event.type == "mouseenter" || event.type == "mouseover" ? new Effect.Appear(this.menuContainer, { duration: this.menuTransition, queue: 'start' }) : new Effect.Fade(this.menuContainer, { duration: this.menuTransition, queue: 'end' });
	},
	
	menuHide: function(event)
	{
		this.menuEffect && this.menuEffect.cancel();
		
		this.menuEffect = this.menuContainer.visible() ? new Effect.Fade(this.menuContainer, { duration: this.menuTransition, queue: 'end' }) : this.menuEffect;
	},
	
	over: function(event)
	{
		new Effect.Fade(this.menuContainer, { duration: this.menuTransition, queue: 'end' });
	},
	
	menuCol: function(event) 
	{
		(event.type == "mouseenter" || event.type == "mouseover") && this.menuContainer.select('.menuCol').invoke('removeClassName', 'menuColHover') && this.menuContainer.select(".menuColLinks").invoke('hide');
		(event.type == "mouseenter" || event.type == "mouseover") && Event.findElement(event, '.menuCol').addClassName("menuColHover").select('.menuColLinks').shift().show();  
	}
} );

var FooterView = Class.create(ViewBase,
{
	initialize: function($super, id, view)
	{
		$super(id, view);
	},

	process: function($super, data)
	{
		var template = new Template(data);

		$super(template.evaluate({ site: base.split('.').slice(-2).join('.').replace(/\//, ''), version: site.version, date: (new Date).getFullYear() }));
	}
} );

var HeaderView = Class.create(ViewBase,
{
	inputs: [],
	ids: [],
	single: null,

	initialize: function($super, id, view)
	{
		$super(id, view);

		document.observe(this.id + ':update', this.update.bind(this));
	},

	process: function(data)
	{
		this.form = new Element('form');
		this.list = new Element('ul');

		this.content.html = this.form.insert(this.list);

		data.each(function(value)
		{
			var checkbox	= new Element('div', { 'class' : 'checkbox checkbox_unchecked', id: "checkbox_" + value.ID });
			var input	= new Element('input', { 'class': 'hidden', type: 'checkbox', name: 'tags', value: value.ID });
			var a		= new Element('a', { href: '#', rel: value.ID }).update(value.title);

			this.inputs.push(input);

			checkbox.observe('click', this.clickbox.bind(this, checkbox, false));
			input.observe('click', this.redirect.bind(this, input, false));
			a.observe('click', this.redirect.bind(this, input, true));

			this.list.insert(new Element('li').insert(checkbox).insert(input).insert(a));
		}, this);
	},

	clickbox: function(element, link, event)
	{
		element.next().checked ? element.removeClassName("checkbox_checked") : element.addClassName("checkbox_checked");
		element.next().click();
	},

	redirect: function(element, link, event)
	{
		if (link)
		{
			event.preventDefault();

			var ids;

			if (element.value == this.single)
			{
				this.single = null;

				ids = this.ids;
			}
			else
			{
				this.single = element.value;

				ids = [element.value];
			}

			this.ids = this.select(ids);
		}

		SWFAddress.setValue('/' + site.iso + '/' + this.gettags());
	},

	select: function(ids)
	{
		return this.inputs.inject([], function(array, element) { element.checked && array.push(element.value); element.checked = ids.member(element.value); checkbox = element.previous(); element.checked ? (checkbox && checkbox.addClassName("checkbox_checked")) : (checkbox && checkbox.removeClassName("checkbox_checked")); return array; });
	},

	update: function(event)
	{
		this.select(event.memo);
	},

	gettags: function()
	{
		var hash	= $H(this.form.serialize(true));
		var key		= hash.keys().shift();
		var ids		= hash.values().shift(); Object.isArray(ids) || (ids = [ids]);

		return (key ? key + '/' + ids.join(',') : "/tags");
	}
} );


var LanguageView = Class.create(ViewBase,
{
	languages: $H(),
	iso: null,

	initialize: function($super, id, view)
	{
		$super(id, view);
	},

	process: function(data, state)
	{
		data.each(function(language) { this.languages.set(language.ISO, language); }, this);

		this.iso = this.languages.keys().first();

		this.content.html = new Element('div');

		this.languages.each(function(pair)
		{
			var iso		= pair.key;
			var language	= pair.value;
			var a		= new Element('a', { 'class': 'language', href: '#', rel: iso, title: language.title }).update(language.flag);

			this.content.html.insert(a);
		}, this);
	},

	link: function(element)
	{
		element.observe('click', function(event) { event.preventDefault(); this.redirect(element.rel); }.bindAsEventListener(this));
	},

	redirect: function(iso)
	{
		SWFAddress.setValue('/' + (iso ? iso : this.iso) + '/' + SWFAddress.getPath().split('/').slice(2).join('/'));
	}
} );

var ListView = Class.create(ViewBase,
{
	rows: [3, 5, 6, 7, 8, 9, 10],
	factor: 8,
	ratio: 3/5,
	cutoff: 2,
	opacity: 0.75,
	duration: 0.25,
	delay: 0.04,
	containers: [],
	colors: $H({ black: $H({ opacity: 12 }), orange: $H({ opacity: 100 }) }),

	initialize: function($super, id, view)
	{
		$super(id, view);

		Event.observe(window, 'scroll', this.scroll.bind(this));
		document.observe('window:resized', this.scroll.bind(this));

		this.max = (Prototype.Browser.MobileSafari ? this.rows.inject(0, function(total, n) { return total + n; }) + 1 : null);

		this.getcolors();
	},

	process: function(data, state)
	{
		var tags = [];

		if (data.size() > 0)
		{
			(tags = data.pluck('tags').flatten().pluck('ID').uniq()).size() > 0 && document.fire('header:update', tags);

			if (site.state.type != 'things' && data.size() == 1)
			{
				data = data.shift();

				SWFAddress.setValue('/' + site.iso + '/things/' + data.ID + '/' + data.title.seo());
			}
			else
			{
				document.fire('first:update', { element: data.shift(), state: state });

				this.content.html = new Element('div');

				var list, slice, row = 0;

				while ((slice = data.splice(0, this.rows[Math.min(row++, this.rows.size() - 1)])).size() > 0)
				{
					list = new Element('ul');

					slice.each(function(data) { this.iterate(data, list); }, this);

					this.content.html.insert(list);
				}
			}
		}
		else
		{
			this.content.html = null;
		}
	},

	iterate: function(data, list)
	{
		list.insert(this.markup(data));
	},

	fill: function($super)
	{
		$super();

		var counter = 0;

		this.content.html.childElements().each(function(list, index_list) { list.childElements().each(function(element, index_element) { this.morph(element, Math.min(index_list, this.rows.size() - 1), counter++, index_element); }, this); }, this);

		this.scroll();
	},

	morph: function(element, row, counter, index)
	{
		var width	= (this.container.getWidth()/this.rows[row]).floor();
		var delta	= this.container.getWidth() - this.rows[row]*width;
		var container	= element.down();

		element.width	= width + Math.min((index/(this.rows[row] - delta)/2).round(), 1);
		element.opacity = 1.0 - this.opacity*this.scale(row);
		element.setStyle({ width: element.width + 'px' });

		container.width		= width - this.factor*(row + 1);
		container.height	= (container.width*this.ratio).ceil();
		container.size		= container.width + 'x' + container.height;
		container.offset	= (container.color == 'orange' ? 2 : 1)*container.height;
		container.left		= (element.width - container.width)*index/(this.rows[row] - 1);
		container.top		= ((this.container.getWidth() - this.rows[row]*container.width)/(this.rows[row] - 1)).floor();
		container.visible	= false;

		container.setStyle({ width: container.width + 'px', height: container.height + 'px', marginTop: container.top + 'px', marginLeft: container.left + 'px' } );
		(container.showimage || row > this.cutoff) && container.update(null);

		if (container.showimage)
		{
			container.styler = { backgroundPosition: '0px ' + -container.offset + 'px', backgroundImage: 'url("/image.php?' + $H({ source: container.image.file, size: container.size + '^', crop: container.image.file_crop ? container.image.file_crop : '', colors: this.colors.values() }).toPHPQueryString('cms') + '")' };

			this.containers.push(container);
		}

		this.addhandlers(element);

		new Effect.Opacity(element, { from: 0.0, to: element.opacity, duration: this.duration, delay: this.delay*counter });
	},

	scroll: function()
	{
		var offset = document.viewport.getHeight();

		this.containers.each(function(element) { this.getimage(element, offset); }, this);
	},

	getimage: function(container, offset)
	{
		!container.visible && container.viewportOffset().top < offset && (container.visible = true) && container.setStyle(container.styler);
	},

	addhandlers: function(element)
	{
		container = element.down();

		container.observe('mouseover', this.handler.bind(this, container, 'over'));
		container.observe('mouseout', this.handler.bind(this, container, 'out'));
	},

	handler: function(container, state)
	{
		container.up().setOpacity(state == 'over' ? 1.0 : container.up().opacity);

		if (container.image)
		{
			container.childElements().each(function(element) { state == 'over' ? element.addClassName('hidden') : element.removeClassName('hidden'); } );

			container.setStyle({ backgroundPosition: '0px ' + (state == 'over' ? 0 : -container.offset) + 'px' });
		}
	},

	markup: function(data)
	{
		var element		= new Element('li');
		var color		= this.colors.keys()[Math.dice(10)/1];
		var container		= new Element('a', { 'class': 'liwrapper ' + color, href: '/' + site.iso + '/things/' + data.ID + '/' + data.title.seo(), rel: '/' + site.iso + '/things/' + data.ID + '/' + data.title.seo(), title: data.title });

		container.ID		= data.ID;
		container.color		= color;
		container.image		= (data.content.image.size() > 0 ? data.content.image.first() : null);
		container.showimage	= !!container.image; //(data.content_behaviorID == 6 && container.image);

		element.insert(container);

		var title	= new Element('h3', { 'class': 'title' }).update(data.title);
		var subtitle	= new Element('h4', { 'class': 'subtitle' }).update(data.subtitle);
		var date	= new Element('div', { 'class': 'date' }).update(data.date ? data.date : '');

		container.insert(title);
		container.insert(subtitle);
		container.insert(date);

		element.setOpacity(0);

		return element;
	},

	scale: function(number)
	{
		return 2*Math.atan(number)/Math.PI;
	},

	getcolors: function()
	{
		var element;

		this.colors.each(function(pair)
		{
			element	= new Element('div', { 'class': pair.key });
			pair.value.set('color', element.getStyle('backgroundColor').gsub(' ', ''));
			delete element;
		}, this);
	}
} );

var LogoView = Class.create(ViewBase,
{
	initialize: function($super, id, view)
	{
		$super(id, view);
	}
} );

var SearchView = Class.create(ViewBase,
{
	filled: false,

	initialize: function($super, id, view)
	{
		$super(id, view);
	},

	scan: function($super, callback)
	{
		$super(callback);

		this.box	= this.content.select('.box').shift();
		this.status	= this.content.select('.status').shift();

		this.box.observe('click', this.empty.bind(this));
		this.box.observe('blur', this.blur.bind(this));
		this.status.observe('click', this.reset.bind(this));

		this.box.old_value = this.box.value;

		this.view.autocomplete.init(this);
	},

	setbox: function(value)
	{
		this.box.value = (value ? value : '');
	},

	blur: function()
	{
		this.box.value.length > 0 || this.reset();
	},

	empty: function()
	{
		if (!this.filled)
		{
			this.filled = true;

			this.status.addClassName('filled');

			this.setbox();
		}
	},

	reset: function()
	{
		if (this.filled)
		{
			this.filled = false;

			this.status.removeClassName('filled');

			this.setbox(this.box.old_value);

			document.fire(this.id + ':reset');
		}
	},

	loading: function(loading)
	{
		loading ? this.status.addClassName('loading') : this.status.removeClassName('loading');
	}
} );

var TagView = Class.create(ViewBase,
{
	Xmax: 200,
	scrollSpeed: 50, /* constant which determines how fast the tags will scroll on the x scale */

	initialize: function($super, id, view)
	{
		$super(id, view);
	},

	process: function(data, state)
	{
		if (data.size() > 0)
		{
			this.content.html = new Element('ul');

			//this.Xmax = data.pluck('popularity').map(function(element) { return parseInt(element); }).max();

			data.each(this.iterate, this);
		}
		else
		{
			this.content.html = null;
		}
	},

	link: function($super, element)
	{
		$super(element);

		this.addhandlers(element);
	},

	addhandlers: function(element)
	{
		element.observe('mouseover', this.scroll.bind(this, element, -1));
		element.observe('mouseout', this.scroll.bind(this, element, 1));
	},

	scroll: function(element, direction)
	{
		var overflow = element.getWidth() - this.container.getWidth();

		if (overflow > 0)
		{
			var boundary	= Math.min(direction*overflow, 0);
			var offset	= boundary - parseInt(element.getStyle('left'));
			var duration	= Math.abs(offset)/this.scrollSpeed;

			element.effect && element.effect.cancel();
			element.effect = new Effect.Move(element, { x: offset, y: 0, duration: duration, transition: Effect.Transitions.spring });
		}
	},

	iterate: function(data)
	{
		this.content.html.insert(this.markup(data));
	},

	markup: function(data)
	{
		var li	= new Element('li');
		var a	= new Element('a', { href: '/' + site.iso + '/tags/' + data.ID + '/' + data.title.seo(), rel: '/' + site.iso + '/tags/' + data.ID + '/' + data.title.seo(), style: 'font-size: ' + this.scale(data.popularity, 1, this.Xmax, 10, 24).round() + 'px' }).update(data.title);

		li.setOpacity(this.scale(data.popularity, 1, this.Xmax, 0.25, 1));

		return li.insert(a);
	},

	scale: function(x, Xmin, Xmax, Ymin, Ymax)
	{
		return Ymin + (Ymax - Ymin)*2*Math.atan((x - Xmin)/Xmax)/Math.PI;
		//return Ymin + (x - Xmin)*(Ymax - Ymin)/(Xmax - Xmin);
	}
} );


var View = Class.create(
{
	allregistered: false,
	ready: false,
	register: new Hash(),
	elements: new Hash(),

	initialize: function(type)
	{
		this.search 		= new SearchView('search', this);
		this.autocomplete 	= new AutocompleteView('autocomplete', this);
		this.tag 			= new TagView('tag', this);
		this.logo 			= new LogoView('logo', this);
		this.contact		= new ContactView('contact', this);
		this.header 		= new HeaderView('header', this);
		this.first 			= new FirstView('first', this);
		this.list 			= new ListView('list', this);
		this.footer 		= new FooterView('footer', this);
		this.language		= new LanguageView('language', this);

		this.allregistered = true;
	},

	elementready: function(id)
	{
		this.elements.set(id, true);

		this.allregistered && this.check();
	},

	check: function()
	{
		if (this.elements.keys().size() == this.register.keys().size())
		{
			this.ready = true;

			document.fire('view:ready');
		}
	}
} );

