/*
HTML5 audio spec:
http://dev.w3.org/html5/spec/Overview.html#attr-media-controls
*/

var _tag=this;

// load dependencies
var escripts=[
	[window.sack, '/taglib/javascript/ajax.js'],
	[window.hasH5mp4, '/taglib/javascript/util.js'],
	[window.swfobject, '/taglib/javascript/swfobject22.js'],
	[window.DetectFlashVer, '/taglib/javascript/AC_OETags.js'],
	[window.isMobile, '/taglib/javascript/mobile_detect.js']
];
for(var i=0;i<escripts.length;i++){
	if(!escripts[i][0]) document.write('<scr'+'ipt type="text/javascript" src="'+escripts[i][1]+'"></sc'+'ript>');
}

if(!window.ajaxObjects)	var ajaxObjects=new Array();
if(!window.imageCache) var imageCache=new Array();

_tag.Audio=function(args){

	var me=this;
	
	this.defaults={
		player_skin: '',
		timer_width: 50,
		width: 400,
		fontFamily: 'verdana',
		fontSize: '10px',
		fontWeight: 'bold'
	};
	
	for(var i in this.defaults) this[i]=args[i]||this.defaults[i];

	// globals
	this.args_ori=args;
	this.container=document.getElementById(args.container);
	this.playing=false;
	this.dragging=false;
	this.touch_pos=0;
	this.duration=0;
	this.buffered_frac=0;
	this.zero=0;
	this.dragzero=0;

	// init

	this.profile={
		html5: hasH5mp3(),
		flash: (args.noflash ? false : DetectFlashVer(9,0,128)),
		mobile: isMobile(),
		ipad: isIpad()
	};
	
//	this.profile.ipad=true;
	
	if(this.profile.mobile){
		if(this.profile.ipad){
			this.playerType='html5';
		}else{
			this.playerType='none';
		}
	}else if(this.profile.flash){
		this.playerType='flash';
	}else if(this.profile.html5){
		this.playerType='html5';
	}else{
		this.playerType='none';
	}

	if(this.playerType!='none') this.playerCreate();

};

_tag.Audio.prototype={
	
	playerCreate: function(){
		if(this.args_ori.file){
			this.file=this.args_ori.file;
			this.autoplay=false;
		}else if(this.container.getElementsByTagName('A').length){
			this.file=this.container.getElementsByTagName('A')[0].href;
			this.autoplay=false;
		}else{
			this.autoplay=true;
		}
		this.container.innerHTML='';
		switch(this.playerType){
			case 'html5':
				this.playerInitH5();
				break;
			case 'flash':
				this.playerInitFlash();
				break;
		}
	},
	
	playerDeploy: function(){
		if(arguments.length>0){
			this.file=arguments[0];
		}
		switch(this.playerType){
			case 'html5': this.playerDeployH5(arguments); break;
			case 'flash': this.playerDeployFlash(arguments); break;
		}
	},

	/* Flash player
	******************************/

	playerInitFlash: function(){
		var me=this;
		
		// execute alternate flash player function if any
		if(this.args_ori.fn_flashplayer){
			this.args_ori.fn_flashplayer(this.file);
			return;
		}
		// determine player height from controlbar background image
		this.skin_image_path=this.player_skin.match(/^(.+?)[^\/]+$/)[1]+'controlbar/';
		imageCache[0]=new Image();
		addEvent(imageCache[0], 'load', function(){me.flashImageLoaded();}, false);
		imageCache[0].src=this.skin_image_path+'background.png';
	},
	
	flashImageLoaded: function(){
		this.height=imageCache[0].height;
		if(this.file){
			this.playerDeployFlash();
		}
	},
	
	playerDeployFlash: function(){
		this.playerDestroy();
		var newdiv=document.createElement('DIV');
		newdiv.id='tag_audio';
		this.container.appendChild(newdiv);
	
		var flashvars = {
			autostart: this.autoplay,
			skin: this.player_skin,
			width: this.width,
			height: this.height
		};
		if(this.file){
			flashvars.file=this.file;
		}

		var params = {
			wmode: "transparent"
		};
		
		var attributes = {
			id: 'tag_audio',
			name: 'tag_audio'
		};

		swfobject.embedSWF("/taglib/swf/player-licensed.swf", 'tag_audio', this.width, this.height, "9.0.115", false, flashvars, params, attributes);
	},

	/* HTML5 player
	******************************/

	playerInitH5: function(){
		var me=this;
		this.skin_image_path=this.player_skin.match(/^(.+?)[^\/]+$/)[1]+'controlbar/';
		var ajaxIndex=ajaxObjects.length;
		ajaxObjects[ajaxIndex]=new sack();
		with(ajaxObjects[ajaxIndex]){
			requestFile=this.player_skin;
			onCompletion=function(){me.playerCreateH5GetImages(ajaxIndex);};
			runAJAX();
		}
	},
	
	playerCreateH5GetImages: function(index){
		var me=this;
		var xml=ajaxObjects[index].response;
		xml=xml.replace(/[\n\r]/g,'');
		var xml_cb=xml.match(/<component name="controlbar">(.*?)<\/component>/)[1];
		var keys=['background','capLeft','capRight','divider','playButton','playButtonOver','pauseButton','pauseButtonOver','stopButton','timeSliderRail','timeSliderBuffer','timeSliderProgress','timeSliderThumb'];
		this.skin_images=new Array();
		this.skin_image_queue=0;
		for(var i=0;i<keys.length;i++){
			var key=keys[i];
			re=new RegExp('<element name="'+keys[i]+'" src="(.+?)"');
			if(xml_cb.match(re)){
				this.skin_images[keys[i]]=new Array();
				this.skin_images[keys[i]]['url']=this.skin_image_path+RegExp.$1;
				this.skin_image_queue++;
			}
		}
		for(var key in this.skin_images){
			this.skin_images[key]['img']=new Image();
			var ind=imageCache.length;
			imageCache[ind]=new Image();
			imageCache[ind].id='ic_'+key;
			addEvent(imageCache[ind], 'load', function(ev){me.skinImageLoaded(ev);}, false);
			imageCache[ind].src=this.skin_images[key]['url'];
		}
	},
	
	skinImageLoaded: function(ev){
		var srcElem=ev.target||ev.srcElement;
		var key=srcElem.id.match(/^ic_(.+)$/)[1];
		this.skin_images[key]['width']=srcElem.width;
		this.skin_images[key]['height']=srcElem.height;
		this.skin_image_queue--;
		if(this.skin_image_queue==0){
			this.playerCreateH5Init();
		}
	},
	
	playerCreateH5Init: function(){
		var me=this;

		this.height=this.skin_images.background.height;
		// determine sizes
		var size_used=0;
		if(this.skin_images.capLeft) size_used+=this.skin_images.capLeft.width;
		size_used+=this.skin_images.playButton.width;
		size_used+=this.skin_images.divider.width;
		size_used+=this.timer_width;
		this.zero=size_used;
		size_used+=this.timer_width;
		if(this.skin_images.capRight) size_used+=this.skin_images.capRight.width;
		this.shuttle_size=this.width-size_used;

		if(this.file){
			this.playerDeployH5();
		}

		return;

		// Temporary debugging stuff
		for(var key in this.skin_images){
			dbg('<img src="'+this.skin_images[key].url+'" />');
			dbg(key+ "\n url: "+this.skin_images[key].url+"\n width: "+this.skin_images[key].width+"\n height: "+this.skin_images[key].height+"\n");
		}
	},
	
	playerDestroy: function(){
		this.playing=false;
		this.container.innerHTML='';
		if(this.playerType=='html5'){
			this.duration=0;
			this.buffered_frac=0;
		}
	},
	
	playerDeployH5: function(){
		var me=this;
		
		this.playerDestroy();

		// Shell
		this.player_shell=this.objBuild({
			elem: 'DIV',
			width: this.width+'px',
			height: this.height+'px',
			position: 'relative',
			backgroundImage: 'url('+this.skin_images.background.url+')',
			backgroundRepeat: 'repeat-x'
		});
		if(this.args_ori.id) this.player_shell.id=this.args_ori.id;
		
		// Left cap
		if(this.skin_images.capLeft){
			this.player_shell.appendChild(this.objBuild({
				elem: 'IMG',
				src: this.skin_images.capLeft.url,
				cssFloat: 'left'
			}));
			/*
			this.player_shell.appendChild(this.objBuild({
				elem: 'DIV',
				backgroundImage: 'url('+this.skin_images.capLeft.url+')',
				width: this.skin_images.capLeft.width+'px',
				height: this.skin_images.capLeft.height+'px',
				cssFloat: 'left'
			}));
			*/
		}
		
		// Play/Pause button
		this.playpause=this.objBuild({
			elem: 'IMG',
			src: this.skin_images.playButton.url,
			cssFloat: 'left'
		});
		this.player_shell.appendChild(this.playpause);
		
		// Divider
		this.player_shell.appendChild(this.objBuild({
			elem: 'IMG',
			src: this.skin_images.divider.url,
			cssFloat: 'left'
		}));
		
		// Progress time display
		var pad_right=parseInt(this.skin_images.timeSliderThumb.width/2)+5;
		this.timer_progress=this.objBuild({
			elem: 'DIV',
			width: (this.timer_width-pad_right)+'px',
			height: this.height+'px',
			color: '#fff',
			fontFamily: this.fontFamily,
			fontSize: this.fontSize,
			fontWeight: this.fontWeight,
			lineHeight: this.height+'px',
			textAlign: 'right',
			paddingRight: pad_right+'px',
			innerHTML: '0:00',
			cssFloat: 'left'
		});
		this.player_shell.appendChild(this.timer_progress);

		// Control bar
		var railtop=parseInt((this.height-this.skin_images.timeSliderRail.height)/2)+1;
		this.controlbar=this.objBuild({
			elem: 'DIV',
			width: this.shuttle_size+'px',
			height: this.height+'px',
			position: 'relative',
			cssFloat: 'left'
		});

		// Slider rail
		this.controlbar.appendChild(this.objBuild({
			elem: 'IMG',
			src: this.skin_images.timeSliderRail.url,
			position: 'absolute',
			width: this.shuttle_size+'px',
			height: this.skin_images.timeSliderRail.height+'px',
			top: railtop+'px'
		}));
		
		// Buffer rail
		this.rail_buffer=this.objBuild({
			elem: 'IMG',
			src: this.skin_images.timeSliderBuffer.url,
			position: 'absolute',
			width: '0px',
			height: this.skin_images.timeSliderBuffer.height+'px',
			top: railtop+'px'
		});
		this.controlbar.appendChild(this.rail_buffer);
		
		// Progress rail
		this.rail_progress=this.objBuild({
			elem: 'IMG',
			src: this.skin_images.timeSliderProgress.url,
			position: 'absolute',
			width: '0px',
			height: this.skin_images.timeSliderProgress.height+'px',
			top: railtop+'px'
		});
		this.controlbar.appendChild(this.rail_progress);
		this.player_shell.appendChild(this.controlbar);

		// Remaining time display
		this.timer_remaining=this.objBuild({
			elem: 'DIV',
			width: (this.timer_width-5)+'px',
			height: this.height+'px',
			color: '#fff',
			fontFamily: this.fontFamily,
			fontSize: this.fontSize,
			fontWeight: this.fontWeight,
			lineHeight: this.height+'px',
			textAlign: 'right',
			paddingRight: '5px',
			innerHTML: '0:00',
			cssFloat: 'left'
		});
		this.player_shell.appendChild(this.timer_remaining);
		
		// Handle
		this.handle=this.objBuild({
			elem: 'IMG',
			src: this.skin_images.timeSliderThumb.url,
			width: this.skin_images.timeSliderThumb.width+'px',
			height: this.skin_images.timeSliderThumb.height+'px',
			position: 'absolute',
			left: this.zero+'px',
			top: (parseInt(this.height-this.skin_images.timeSliderThumb.height)/2)+'px',
			marginLeft: '-'+parseInt(this.skin_images.timeSliderThumb.width/2)+'px'
		});
		this.player_shell.appendChild(this.handle);

		// Right cap
		if(this.skin_images.capRight){
			this.player_shell.appendChild(this.objBuild({
				elem: 'IMG',
				src: this.skin_images.capRight.url,
				cssFloat: 'left'
			}));
		}
		
		// Build player
		this.player=document.createElement('AUDIO');
		
		// player events
		addEvent(this.player,'timeupdate',function(){me.timeUpdate()},false);
		addEvent(this.player,'progress',function(){me.bufferUpdate()},false);
		addEvent(this.player,'loadeddata',function(){me.loadeddataUpdate()},false);
		addEvent(this.player,'ended',function(){me.playbackEnded()},false);
		addEvent(this.player,'play',function(){me.playButtonUpdate('pause')},false);
		addEvent(this.player,'pause',function(){me.playButtonUpdate('play')},false);

		//this.player.src=this.file;
		this.player.style.display='none';
		
		// interface events

		addEvent(this.playpause,'click',function(){me.playPause()},false);
		
		if(this.profile.mobile){

			addEvent(this.controlbar,'touchstart',function(e){
				e.preventDefault();
				me.touchStarted(e.changedTouches[0]);
			},false);
		
			addEvent(this.handle,'touchstart',function(e){
				e.preventDefault();
				me.touchStarted(e.changedTouches[0]);
			},false);
		
			addEvent(this.controlbar,'touchmove',function(e){
				e.preventDefault();
				me.touchMoved(e.changedTouches[0]);
			},false);
			
			addEvent(this.handle,'touchmove',function(e){
				e.preventDefault();
				me.touchMoved(e.changedTouches[0]);
			},false);
			
			addEvent(this.controlbar,'touchend',function(e){
				e.preventDefault();
				me.scrubEnded();
			},false);
	
			addEvent(this.handle,'touchend',function(e){
				e.preventDefault();
				me.scrubEnded();
			},false);
			
		}else{

			addEvent(this.controlbar,'mousedown',function(e){
				e.preventDefault();
				me.mouseStarted(e);
			},false);

			addEvent(this.controlbar,'mousemove',function(e){
				e.preventDefault();
				me.mouseMoved(e);
			},false);

			addEvent(this.handle,'mousedown',function(e){
				e.preventDefault();
				me.mouseStarted(e);
			},false);

			addEvent(this.handle,'mousemove',function(e){
				e.preventDefault();
				me.mouseMoved(e);
			},false);

			addEvent(window,'mouseup',function(e){
				e.preventDefault();
				me.scrubEnded();
			},false);
	
		}

		this.container.appendChild(this.player_shell);
		this.container.appendChild(this.player);
		if(this.file){
			this.player.src=this.file;
		}
		if(this.autoplay){
			//this.player.load();
			this.playPause();
		}
		this.dragzero=getObjPos(this.player_shell).x+this.zero;
	},
	
	/* iPad touch driver
	******************************/
	
	touchStarted: function(touch){
		if(this.duration==0) return false;
		this.dragzero=getObjPos(this.player_shell).x+this.zero;
		this.dragging=true;
		this.touch_pos=touch.pageX-this.dragzero;
		this.handleMove(this.touch_pos);
	},
	
	touchMoved: function(touch){
		if(this.duration==0) return false;
		var touch_pos_new=touch.pageX-this.dragzero;
		this.handleMove(touch_pos_new);
	},
	
	/* Mouse driver
	******************************/

	mouseStarted: function(ev){
		this.dragging=true;
		this.touch_pos=getMousePos(ev).x-this.dragzero;
		this.handleMove(this.touch_pos);
	},
	
	mouseMoved: function(ev){
		if(!this.dragging) return false;
		var touch_pos_new=getMousePos(ev).x-this.dragzero;
		this.handleMove(touch_pos_new);
	},
	
	/* Shared drivers
	******************************/
	
	playPause: function(){
		this.bufferUpdate();
		if(this.playing){
			this.playpause.src=(this.skin_images.playButtonOver?this.skin_images.playButtonOver.url:this.skin_images.playButton.url);
			this.playing=false;
			this.player.pause();
		}else{
			this.playpause.src=(this.skin_images.pauseButtonOver?this.skin_images.pauseButtonOver.url:this.skin_images.pauseButton.url);
			this.playing=true;
			if(!this.duration){
				this.duration=this.player.duration;
			}
			this.player.play();
		}
	},
	
	scrubEnded: function(){
		if(!this.dragging) return false;
		this.dragging=false;
		var frac=this.handleMove(this.touch_pos);
		try {
			this.player.currentTime=this.duration*frac;
		}catch(ex){}
	},

	playbackEnded: function(){
		this.playing=false;
		this.playpause.src=this.skin_images.playButton.url;
		this.handle.style.left=this.zero+'px';
		this.rail_progress.style.width='0px';
		this.timer_progress.innerHTML='0:00';
		this.timer_remaining.innerHTML=this.timeFormat(this.duration);
	},

	handleMove: function(value){
		var hpos_new;
		hpos_new=value;
		if(hpos_new<0){
			hpos_new=0;
		}else if(hpos_new>this.buffered_frac*this.shuttle_size){
			hpos_new=parseInt(this.buffered_frac*this.shuttle_size);
		}
		this.handle.style.left=(this.zero+hpos_new)+'px';
		this.touch_pos=hpos_new;
		this.timer_progress.innerHTML=this.timeFormat(this.duration*hpos_new/this.shuttle_size);
		return hpos_new/this.shuttle_size;
	},

	/* HTML5 player skin interface
	******************************/
	
	timeUpdate: function(){
		if(!this.duration) return false;
		this.timer_remaining.innerHTML=this.timeFormat(this.duration-this.player.currentTime);
		if(!this.dragging){
			this.timer_progress.innerHTML=this.timeFormat(this.player.currentTime);
			var pixel_width=parseInt(this.shuttle_size*this.player.currentTime/this.duration);
			this.handle.style.left=(this.zero+pixel_width)+'px';
			this.rail_progress.style.width=pixel_width+'px';
		}
	},
	
	bufferUpdate: function(){
		try {
			var buffered=this.player.buffered.end(0);
		}catch(ex){
			return false;
		}
		if(this.duration==0) return false;
		this.buffered_frac=buffered/this.duration;
		try {
			this.rail_buffer.style.width=parseInt(this.shuttle_size*this.buffered_frac)+'px';
		}catch(ex){}
	},
	
	loadeddataUpdate: function(){
		this.duration=this.player.duration;
	},
	
	playButtonUpdate: function(what){
		this.playpause.src=this.skin_images[what+'Button'].url;
	},
	
	/* Utility
	******************************/
	
	objBuild: function(params){
		var obj=document.createElement(params.elem);
		delete params.elem;
		for(var key in params){
			switch(key){
				case 'src': obj.src=params[key]; break;
				case 'id': obj.id=params[key]; break;
				case 'innerHTML': obj.innerHTML=params[key]; break;
				default: obj.style[key]=params[key];
			}
		}
		return obj;
	},
	
	timeFormat: function(secs){
		if(isNaN(secs)) return '0:00';
		secs=parseInt(secs);
		var mins=parseInt(secs/60);
		secs-=mins*60;
		return mins+':'+(secs<10?'0':'')+secs;
	}

}

