Array.implement({  
	shuffle: function() {  
		//destination array  
		for(var j, x, i = this.length; i; j = parseInt(Math.random() * i), x = this[--i], this[i] = this[j], this[j] = x);  
		return this;  
	}
});

/**
 * a List fetches its children
 */
List = function(type) {
	this.list = [];
	this.type = type;
	
	this.list.random = function() {
		return this[$random(0, this.length - 1)];
	}.bind(this.list);
};
List.prototype = {
	load_from_json: function(url, onFinish) {
		onFinish = onFinish || null;
		try {
			var json_req = new Request.JSON({'url': url,
				'onSuccess':function(r, onFinish){
					// pull all media
					try {
						for (var i=0; i < r.media_list.length; i++) {
							var media = new this.type(r.media_list[i]);
							this.list.push(media);
						}
						if ($chk(onFinish)) onFinish(this.list, r);
					} catch(e) {
						// some error
					}
				}.bindWithEvent(this, onFinish),
				'onFailure':function(r){
					window.console.log(r);
				}.bind(this)
			}).get();
		} catch(e) {
			// some error
		}		
	}
};


File = function(data) {
	if ($defined(data)) $extend(this, data);
};
File.prototype = {
	id: 0,
	mediaId: 0,
	fileName: '',
	url:'',
	width: 0,
	height: 0,
	type: null,
	use: null
};
Media = function (data) {
	if ($defined(data)) $extend(this, data);
	this.file_types = {};
	this.file_uses = {};
	for (var i = 0; i < this.files.length; i++) {
		var file = new File(this.files[i]);
		
		this.file_types[file.type] = this.file_types[file.type] || [];
		this.file_types[file.type].push(file);
		
		this.file_uses[file.use || 'NORMAL'] = this.file_uses[file.use || 'NORMAL'] || [];
		this.file_uses[file.use || 'NORMAL'].push(file);
		
		this.files[i] = file;
	}
};
Media.prototype = {
	id: null,
	title: '',
	description: '',
	credits: '',
	displayOrder: 0,
	copyleft:false,
	visible: false,
	releaseDate: null,
	type: null,
	files: [],
	file_types: {},
	file_uses: {},
	
	create_thumb_view: function(attrs) {
		var defaults = {
			'id':this.id,
			'src':this.file_uses['THUMBNAIL'][0].url || ''
		};
		
		if (attrs) {
			$extend(defaults, attrs);
		}
		var view = new Element('img', defaults);
		return view;
	},
	create_view: function(attrs) {
		var defaults = {
			'id':this.id,
			'class':'slide',
			'src':this.file_uses['NORMAL'][0].url || ''
		};
		
		if (attrs) {
			$extend(defaults, attrs);
		}
		var view = new Element('img', defaults);
		
		view.addEvent('click', function(){
			this.show();
		}.bind(this));
		
		return view;
	},
	buffer_view: function(attrs) {
		this.view = this.create_view(attrs);
	},
	get_view: function(attrs) {
		if (this.view) return this.view;
		else return this.create_view(attrs);
	},
	/**
	 * show this media in a separate layer
	 */
	show: function () {
		openIbox(contextPath + '/media/showLayer/' + this.id + '.page','height=' + (this.file_uses['NORMAL'][0].height+300) + '&width=' + (this.file_uses['NORMAL'][0].width+30) );
	}
};

/**
 * preloads a randomized buffer of medias 
 */
RandomBuffer = function(list, size, buffer_cb) {
	this.size = size;
	this.list = list;
	this.seeded = this.seed();
	this.buffers = [];
	this.cb = buffer_cb;
	this.current_buffer = [];
	this.increase(2);
};
RandomBuffer.prototype = {
	current_buffer: [],
	shift: function() {
		if (!this.current_buffer.length && (this.buffers.length > 1 || this.increase())) {
			this.current_buffer = this.buffers.shift();
		}
		return this.current_buffer.shift();
	},
	/**
	 * we increase the preload-buffer by count times
	 * @return the new buffers length
	 */
	increase: function(count) {
		count = count || 1;
		var current_buffers = this.buffers.length;
		
		// seed new media
		if (this.seeded.length < this.size * count * 2) {
			var f = function() {
				this.seeded.combine(this.seed());
			};
			f.delay(1, this);
		}
		for (var j = 0; j < count; j++) {
			var new_buffer = [];
			for (var i = 0; i < this.size; i++) {
				var buffered = this.list[this.seeded.shift()];
				// async call to buffer
				var t_id = this.cb.delay(1, buffered);
				// put into queue
				new_buffer.push(buffered);
			}
			this.buffers.push(new_buffer);
		}
		return this.buffers.length;
	},
	/**
	 * @return a randomized array 
	 */
	seed: function () {
		var ground = [];
		for (var i = 0; i < this.list.length; ground.push(i++)); 
		return ground.shuffle();
	}
};

Gallery = function() {};
Gallery.prototype = {
	/**
	 * creates the view as a table
	 */
	create_table_view: function(list, columns) {
		var table = new Element('table',{'class':'grid'}).grab(tbody = new Element('tbody'));
		var i = 0;
		var current_row = null;
		while (i < list.length) {
			var current_media = list[i];
			if (!current_media.visible) {
				i++;
				continue;
			}
			if (i % columns == 0) {
				if (current_row) tbody.grab(current_row);
				var current_row = new Element('tr');
			}
			current_row.grab(
				new Element('td').grab(
					wrap = new Element('div',{
						'class':'wrap',
						'styles':{
							'padding':'5px'
						}
					})
				)
			);
			wrap.grab(current_media.create_thumb_view({'width':(650 - columns * 10)/ columns})
				.addEvent('mouseover', function(e){
						this.addClass('hover');
					}.bindWithEvent(wrap)
				)
				.addEvent('mouseout', function(e){
						this.removeClass('hover');
					}.bindWithEvent(wrap)
				)
				.addEvent('click', function(e){
						this.show();
					}.bindWithEvent(current_media)
				)
			);
			i++;
		}
		return table;
	},
	create_slide_show: function(list, period){
		period = period || 6000;
		var stage = new Element('div', {'class':'stage'});
		$extend(stage, {
			current_slide: null,
			random_buffer: new RandomBuffer(list, 5, function(){
				this.buffer_view({'styles':{'opacity':'0'}});
			}),
			shift: function() {
				this.grab(this.current_slide = this.random_buffer.shift().get_view({'styles':{'opacity':'0'}}));
				var fx = new Fx.Tween(this.current_slide);
				fx.start('opacity', '0', '1');
			}
		});
		stage.shift();
		this.slide_show_timer = function(list){
			var next_slide = this.random_buffer.shift().get_view();
			this.grab(next_slide);
			var fxUp = new Fx.Tween(next_slide);
			fxUp.start('opacity', '0', '1');

			if (this.current_slide) {
				var fxDown = new Fx.Tween(this.current_slide);
				fxDown.addEvent('complete', function(e){
					e.dispose();
				}.pass(this.current_slide));
				fxDown.start('opacity', '1', '0');
			}
			this.current_slide = next_slide;
			
		}.periodical(period, stage, [list]);
		return stage;
	}
};

