/**
 *	Object: Aktor
 */
var Aktor = {
	Name: 'Aktor',
	Codename: 'Grizzly',
	Version: '0.1.8',
	Build: {
		Date: '20100603-0852',
		Release: 'beta'
	},
	Authors: [
		{ Name: 'Robin Grass', Email: 'robin.grass@davelo.se' }
	]
};



/**
 *	Constants: General
 */
var AKTOR_DEBUG = true;



/**
 *	Object: Aktor.currentInstance
 */
Aktor.currentInstance = null;



/**
 *	Object: Aktor.currentChrome
 */
Aktor.currentChrome = null;



/**
 *	Function: Aktor.setInstance
 */
Aktor.setInstance = function(instance) {
	Aktor.currentInstance = instance;
};



/**
 *	Function: Aktor.log
 */
/*Aktor.log = function() {
	if(console) {
		if(console.log && AKTOR_DEBUG) {
			if(arguments.length == 1)
				console.log(arguments[0]);
			else
				console.log(arguments);
		}
	}
};*/



/**
 *	Object: Aktor.currentInstance
 */
Aktor.Timeline = {

	toSeconds: function(time) {
		var parts = time.split('.');
		var regex = new RegExp(/^(?:(?:(\d+):)?(\d+):)?(\d+)$/);
		var matches = regex.exec(parts[0]);
		var seconds = String((3600 * matches[1]|0) + (60 * matches[2]|0) + (matches[3]|0));
		seconds = String(seconds);
		if(seconds)
			seconds +=  (parts[1]) ? '.' + parts[1] : '.0';
	return Number(seconds);
	},
	
	toTimestamp: function(seconds) {
		var _seconds = seconds.round();
		var hours = (_seconds / 3600).floor();
		_seconds %= 3600;
		var minutes = (_seconds / 60).floor();
		var seconds = (_seconds % 60).floor();
		
		if(_seconds <= 0)
				return '00:00';
				
		return (
			(hours > 0 ? hours.toString().pad(2, '0', 'left') + ':' : '') +
			(minutes > 0 ? minutes.toString().pad(2, '0', 'left') + ':' : '00:') +
			(seconds > 0 ? seconds.toString().pad(2, '0', 'left') : '')
		);
	}

};



/**
 *	Object: Aktor.Events
 *
 *	These events are fired from Flash.
 */
Aktor.Events = {
	
	onCreate: function() { 
		Aktor.currentInstance._onCreate();
	},
	
	onDestroy: function() {
		Aktor.currentInstance._onDestroy();
	},
	
	onAttach: function() {
		Aktor.currentInstance._onAttach();
	},
	
	onDetach: function() {
		Aktor.currentInstance._onDetach();
	},
	
	onLoad: function(mediaURL, width, height) {
		Aktor.currentInstance._onLoad(mediaURL, width, height);
	},
	
	onUnload: function() {
		Aktor.currentInstance._onUnload();
	},
	
	onBuffer: function() {
		Aktor.currentInstance._onBuffer();
	},
	
	onBufferChange: function() {
		Aktor.currentInstance._onBufferChange();
	},
	
	onError: function(errorType, errorMessage) {
		Aktor.currentInstance._onError(errorType, errorMessage);
	},
	
	onPlay: function() {
		Aktor.currentInstance._onPlay();
	},
	
	onPause: function() {
		Aktor.currentInstance._onPause();
	},
	
	onStop: function() {
		Aktor.currentInstance._onStop();
	},
	
	onPlaybackEnd: function() {
		Aktor.currentInstance._onPlaybackEnd();
	},
	
	onSeek: function(seconds) {
		Aktor.currentInstance._onSeek(seconds);
	},
	
	onTimeUpdate: function(seconds) {
		Aktor.currentInstance._onTimeUpdate(seconds);
	},
	
	onTimeEvent: function(seconds) {
		Aktor.currentInstance._onTimeEvent(seconds);
	},
	
	onTimeDuration: function(seconds) {
		Aktor.currentInstance._onTimeDuration(seconds);
	},
	
	onVolumeUpdate: function(volume) {
		Aktor.currentInstance._onVolumeUpdate(volume);
	},
	
	onSizeUpdate: function(width, height) {
		Aktor.currentInstance._onSizeUpdate(width, height);
	},

	onBytesTotal: function(bytesTotal) {
		Aktor.currentInstance._onBytesTotal(bytesTotal);
	},
	
	onBytesLoaded: function(bytesLoaded) {
		Aktor.currentInstance._onBytesLoaded(bytesLoaded);
	},
	
	onFullyLoaded: function() {
		Aktor.currentInstance._onFullyLoaded();
	}

};



/**
 *	Abstract Class: Aktor.PlayerAbstract
 */
Aktor.PlayerAbstract = new Class({

	Implements: [Options, Events],
	
	options: {
		onCreate: nil,
		onDestroy: nil,
		onAttach: nil,
		onDetach: nil,
		onLoad: nil,
		onUnload: nil,
		onBuffer: nil,
		onBufferChange: nil,
		onError: nil,
		onPlay: nil,
		onPause: nil,
		onStop: nil,
		onSeek: nil,
		onTimeUpdate: nil,
		onTimeDuration: nil,
		onTimeEvent: nil,
		onVolumeUpdate: nil,
		onSizeUpdate: nil,
		onBytesTotal: nil,
		onBytesLoaded: nil,
		onFullyLoaded: nil,
		onChromeCreate: nil,
		onChromeDestroy: nil
	},
	
	timeline: nil,
	
	chrome: nil,
	
	setTimeline: function(timeline) {
		this.timeline = timeline;
	},
	
	setChrome: function(chrome) {
		this.chrome = chrome;
	},
	
	loadChrome: function() {
		var self = this;
		if(this.chrome) {
			var request = new Request.JSON({
				url: 'chrome/' + this.chrome + '/manifest.json',
				method: 'get',
				onFailure: function() {
					//Aktor.log('[Aktor] Request could not be sent.');
				},
				onSuccess: function(chrome) {
					//Aktor.log('[Aktor] Requested chrome.');
					Aktor.chromeJSON = chrome;
					Asset.javascript(chrome.Resources.javascript);
				}
			}).send();
		}
	},
	
	unloadChrome: function() {
		if(Aktor.currentChrome)
			Aktor.currentChrome.destroy();
	},
	
	_onCreate: function() { 
		this.fireEvent('onCreate');
	},
	
	_onDestroy: function() {
		this.fireEvent('onDestroy');
	},
	
	_onAttach: function() {
		this.fireEvent('onAttach');
	},
	
	_onDetach: function() {
		this.fireEvent('onDetach');
	},
	
	_onLoad: function(mediaURL) {
		this.fireEvent('onLoad', mediaURL);
		this.unloadChrome();
		this.loadChrome();
	},
	
	_onUnload: function() {
		this.fireEvent('onUnload');
		this.unloadChrome();
	},
	
	_onBuffer: function() {
		this.fireEvent('onBuffer');
	},
	
	_onBufferChange: function() {
		this.fireEvent('onBufferChange');
	},
	
	_onError: function(errorType, errorMessage) {
		this.fireEvent('onError', [errorType, errorMessage]);
	},
	
	_onPlay: function() {
		this.fireEvent('onPlay');
	},
	
	_onPause: function() {
		this.fireEvent('onPause');
	},
	
	_onStop: function() {
		this.fireEvent('onStop');
	},
	
	_onSeek: function(time) {
		this.fireEvent('onSeek', time);
	},
	
	_onTimeUpdate: function(time) {
		this.fireEvent('onTimeUpdate', time);
	},
	
	_onTimeDuration: function(time) {
		this.fireEvent('onTimeDuration', time);
	},
	
	_onTimeEvent: function(time) {
		var time = time.round(1);
		if(this.timeline) {
			var obj = this.timeline.get(String(time));
			if(obj) {
				if(typeOf(obj) == 'function') {
					this.fireEvent('onTimeEvent', Number(time));
					obj.attempt();
				} else if(typeOf(obj) == 'object') {
					if(obj.callback && obj.arguments) {
						this.fireEvent('onTimeEvent', Number(time));
						obj.callback.attempt(obj.arguments);
					}
				}
			}
		}
	},
	
	_onVolumeUpdate: function(volume) {
		this.fireEvent('onVolumeUpdate', volume);
	},
	
	_onSizeUpdate: function(width, height) {
		this.fireEvent('onSizeUpdate', [width, height]);
	},

	_onBytesTotal: function(bytesTotal) {
		this.fireEvent('onBytesTotal', bytesTotal);
	},
	
	_onBytesLoaded: function(bytesLoaded) {
		this.fireEvent('onBytesLoaded', bytesLoaded);
	},
	
	_onFullyLoaded: function() {
		this.fireEvent('onFullyLoaded');
	}

});



/**
 *	Abstract Class: Aktor.ApiAbstract
 */
Aktor.ApiAbstract = new Class({
	
	Implements: [Options, Events, Aktor.PlayerAbstract],
	
	options: {},
	
	initialize: function(options) {
		this.setOptions(options);
		Aktor.setInstance(this);
	},
	
	toElement: function() {
		if(!Browser.Engine.trident)
			return this.$swiff.toElement();
		else {
			return document[this.options.player.id];
		}
	},
	
	toParent: function() {
		return this.$swiff.options.container;
	},
	
	toChrome: function() {
		return this.toParent().getElement('div');
	},
	
	create: function(parent, properties, position) {
		this.$element = new Element('div', {
			id: this.options.id,
			styles: Object.merge(this.options.styles, { 'position': 'relative' })
		}).inject(parent, position || 'bottom');
		
		if(Browser.ie7)
			this.$element.addClass('ie7');
		if(Browser.ie8)
			this.$element.addClass('ie8');
		if(Browser.firefox)
			this.$element.addClass('firefox');
		if(Browser.safari)
			this.$element.addClass('safari');
		if(Browser.chrome)
			this.$element.addClass('chrome');
		
		var properties = Object.merge(this.options.flash, {
			id: this.options.player.id,
			container: this.$element
		});
		
		this.$swiff = new Swiff(this.options.player.engine, properties);
		
		this._onCreate();
	},
	
	destroy: function() {
		if(this.$element) {
			this.$element.empty();
			this.$element.destroy();
			this._onDestroy();
		}
	},
	
	attach: function(parent, position) {
		if(typeOf(parent) == 'element')
			parent.grab(this.$element, position || 'bottom');
		this.$element = parent;
		
		document.id(this.options.player.id).setProperty('type', 'application/x-shockwave-flash');
		
		this._onAttach();
	},
	
	detach: function() {
		this.$element = this.$element.dispose();
		this._onDetach();
	},
	
	load: function(mediaURL, width, height) {
		this.toElement().load(mediaURL, width, height);
		this.setSize(width, height);
	},
	
	unload: function() {
		this.toElement().load('', 1, 1);
		this._onUnload();
	},
	
	setSize: function(width, height) {
		this.toElement().setSize(width, height);
		if(!Browser.Engine.trident) {
			this.toElement().set({
				'width': width,
				'height': height
			});
		} else {
			this.toElement().setAttribute('width', width);
			this.toElement().setAttribute('height', height);
		}
	},
	
	getSize: function() {
		return new Hash(this.toElement().getProperties('width', 'height')).map(function(value, key) {
			return value.toInt();
		});
	},
	
	getElapsed: function() {
		return this.toElement().getElapsed().round(2);
	},
	
	getElapsedPercent: function() {
		return ((this.getElapsed() / this.getDuration()) * 100).round();
	},
	
	getDuration: function() {
		return this.toElement().getDuration().round(2);
	},
	
	getRemaining: function() {
		return (this.getElapsed() - this.getDuration()).round(2);
	},
	
	setVolume: function(volume) {
		this.toElement().setVolume(volume.limit(0, 100));
	},
	
	getVolume: function() {
		return this.toElement().getVolume();
	},
	
	toggleMute: function() {
		return this.toElement().toggleMute();
	},
	
	play: function() {
		return this.toElement().startMedia();
	},
	
	togglePlay: function() {
		return this.toElement().togglePlay();
	},
	
	pause: function() {
		return this.toElement().pause();
	},
	
	stop: function() {
		return this.toElement().rewindMedia();
	},
	
	seek: function(seconds) {
		return this.toElement().seek(seconds.limit(0, this.getDuration()));
	},
	
	setTime: function(seconds) {
		this.seek(seconds);
		this.pause();
	},
	
	isPlaying: function() {
		var paused = this.toElement().isPaused();
		if(paused)
			return false;
		else return true;
	},
	
	isMuted: function() {
		return this.toElement().isMuted();
	}

});



Aktor.Player = new Class({

	Extends: Aktor.ApiAbstract,
	
	options: {
		id: 'aktor_player',
		styles: {},
		flash: {},
		player: {
			id: 'aktor_player_object',
			engine: 'AktorPlayer.swf'
		}
	},
	
	initialize: function(options) {
		this.parent(options);
	}

});
