// JavaScript Document
var OTOTOI = {}

/*
The player interface is in SVG/VML Script, using Raphaeljs
The player itself uses html 5 when supported (mp3 or ogg), or flash/mp3
*/
//todo
/*
- seek in the track
- show loading of the track ?
- track filled from the center ?
- square player ?

*/
OTOTOI.Player = function(opt){
	var interface,//view (control buttons)
	info_track,//view (timecode & track name)
	subtitles,//view
	engine,//model (functions)
	mode,//html5 mp3, html 5 ogg or flash mp3
	player_id,//html id
	player,//div containing the player
	tracks,//track list data
	color = "ffffff",//color
	background_color = "ffffff",//color
	image_src = "",//ressource
	width = 400,//width
	height = 400,//height
	mid_width,
	mid_height,
	button_width,
	control_width,
	shape = "round",
	direction = "linear",
	transparent = false,
	radio = false;
	
	/*check options or apply default*/
	if(opt.id) player_id = opt.id;
	if(opt.tracks) tracks = opt.tracks;
	if(opt.width) width = height = opt.width;
	if(opt.color) color = opt.color;
	if(opt.background_color) background_color = opt.background_color;
	if(opt.image) image_src = opt.image;
	if(opt.tracks) tracks = opt.tracks;
	if(opt.shape) shape = opt.shape;
	if(opt.direction) direction = opt.direction;
	if(opt.transparent == true && image_src == "") transparent = true;
	if(opt.button_width) button_width = opt.button_width;
	if(opt.control_width) control_width = opt.control_width;
	if(opt.radio) radio = opt.radio;
	
	player = document.getElementById(player_id);
	mid_width = Math.round(width/2) ;
	mid_height = Math.round(height/2) ;
	
	this.player_id = player_id;//html id
	
	//View : tracks 
	RoundPlayer = function(){
		var canvas ,//drawing zone for raphaeljs
		play_button ,
		playpause_button ,
		pause_button ,
		next_button ,
		previous_button ,
		high_button ,
		clip_left ,//half circle background left
		clip_right ,//half circle background right
		cache ,//circle that opens at the beginning
		image ,//
		track_name ,//html div containing info on the track being played
		track_timecode ,//html div containing timecode of the track being played
		precision = 100 ,//to draw the circle point by point
		info = {},//stores values of the info object
		that = this;//keep reference to the object
		//
		this.playpause = function (){
			engine.playpause();
			return false;
		}
		this.playTrack = function (track){
			engine.playTrack(track);
			return false;
		}
		this.changeTrack = function (next){
			engine.changeTrack(next);
			return false;
		}
		this.getTracks = function (){
			return tracks;
		}
		this.getInfo = function (){
			return info;
		}
		this.seekTrack = function (track, pos, clicked){
			
			
				var Xa = mid_width;
				var Xb = mid_width;
				var Xc = clicked.x;
				var Ya = 0;
				var Yb = mid_width;
				var Yc = clicked.y;
			
				AB = Math.sqrt(Math.pow((Xb - Xa),2) + Math.pow((Yb - Ya),2)) ;
				BC = Math.sqrt(Math.pow((Xc - Xb),2) + Math.pow((Yc - Yb),2)) ;
				AC = Math.sqrt(Math.pow((Xc - Xa),2) + Math.pow((Yc - Ya),2)) ;
				//if(AC<0)
				var B_cos = (Math.pow(AB, 2) + Math.pow(BC, 2) - Math.pow(AC, 2)) / (2 * AB * BC);
				var B_angle = Math.acos(B_cos) ;
				if(Xc < 200) B_angle = (Math.PI*2)-B_angle;
				
				if(radio == false){
					//find value with decalage 
					//start right
					B_angle -= (Math.PI/2) ;
					B_angle -=  tracks[track].start_angle ;
					if(B_angle < 0) B_angle = 2*Math.PI + B_angle;
				}
				
				//var B_sin = Math.sin(Math.PI/2 - B_angle);
				var B_angle_deg = (B_angle/(2*Math.PI)) * 360;
				//if(Xc < 200) B_angle_deg = 360-B_angle_deg;
				//console.log (Xa+","+Ya+" / "+ Xb+","+Yb+" / "+Xc+","+Yc+" ////// " +AB+" / "+ BC +" / "+AC+" / "+B_angle+" / "+B_angle_deg+" / "+B_sin);
				var toseek = Math.round((B_angle_deg * tracks[track].duration) / 360);
				
				engine.seekTrack(track, pos, toseek);
			
			return false;
		}
		this.formatTime = function (time){
			var tc = Math.round(time);
			var s = tc % 60;
			var m = Math.floor(tc / 60);
			var h = Math.floor(m / 60);
			m = m % 60;
			if(s < 10) s = "0" + s;
			if(m < 10) m = "0" + m;
			if(h < 10) h = "0" + h;
			if(h > 0) {
				return (h + ":" + m + ":" + s);
			}else{
				return (m + ":" + s);
			}
		}
		this.createInterface = function (){
			/**/
			//remove content for search engines
			player.innerHTML = "";
			//
			//create and insert canvas container
			var contain_canvas = document.createElement("div");
			contain_canvas.setAttribute("id", "contain_canvas_"+player_id);
			contain_canvas.setAttribute("class", "contain_canvas");
			player.appendChild(contain_canvas);
			//create and insert info
			track_name = document.createElement("div");
			track_timecode = document.createElement("div");
			track_name.setAttribute("class", "track_name");
			track_timecode.setAttribute("class", "track_timecode");
			player.appendChild(track_name);
			player.appendChild(track_timecode);
			
			//creates canvas Rafael
			if(radio == true){
				canvas = Raphael("contain_canvas_"+player_id, width + Math.floor(width/4), height);
			}else{
				canvas = Raphael("contain_canvas_"+player_id, width, height);
			}
			if(image_src != ""){
				//cache for the edges of the image (clipping mask not supported by WML) : for this reason th eplayer can be in transparent mode only when no image is used
				clip_left = canvas.path("M " + mid_width + " " + height + " A 100 100 0 0 1 " + mid_width + " 0 L 0 0 L 0 " + height + " L" + mid_width + " " + height).attr({stroke: "#"+background_color, fill:"#"+background_color});
				clip_right = canvas.path("M " + mid_width + " 0 A 100 100 0 0 1 " + mid_width + " " + height + " L " + width + " " + height + " L " + width + " 0 L" + mid_width + " 0").attr({stroke: "#"+background_color, fill:"#"+background_color});
			}
			
			//white cache for the main zone of the image - to be animated when loading is completed
			if(transparent == false) cache = canvas.circle(mid_width, mid_height, Math.round(mid_width/2)).attr({stroke: "#"+background_color,"stroke-width":mid_width});
			
			//play pause buttons
			if(button_width >0){
			}else{
				button_width = Math.round(width / 23);
			}
			if(control_width >0){
			}else{
				control_width = Math.round(width / 25);
			}
			var control_left = Math.round((width/2)-(control_width/2));
			
			playpause_button = canvas.circle(mid_width, mid_height, button_width).attr({fill: "#"+background_color, stroke: "#"+background_color, cursor: 'pointer'});
			
			play_button = canvas.path("M" + (control_left + 2) + " " + control_left + "L" + (control_left + control_width) + " " + Math.round(control_left + (control_width / 2)) +  "L" + (control_left + 2) + " " + (control_left + control_width)).attr({fill: "#"+color, stroke: "#"+color, cursor: 'pointer'});
			pause_button = canvas.path("M" + (control_left + 4) + " " + (control_left + 1) + "L" + (control_left + 4) + " " + Math.round(control_left + control_width - 1) + "M" + (control_left + control_width - 4) + " " + (control_left + 1) + "L" + (control_left + control_width - 4) + " " + (control_left + control_width - 1)).attr({fill: "#"+color, stroke: "#"+color, "stroke-width":4, cursor: 'pointer'});
			
			playpause_button.click(function (event) {
				that.playpause();
			});
			play_button.click(function (event) {
				that.playpause();
			});
			pause_button.click(function (event) {
				that.playpause();
			});
			//will be shown when player activated
			play_button.hide();
			pause_button.hide();
			if(radio == true){
				next_button = canvas.path("M" + (width) + " 0 L 410 0 L 410 10 400 10").attr({fill: "#"+color, stroke: "#"+color, cursor: 'pointer'});
				next_button.click(function (event) {
					that.changeTrack(true);
				});
				
				previous_button = canvas.path("M" + (width) + " 20 L 410 20 L 410 30 400 30").attr({fill: "#"+color, stroke: "#"+color, cursor: 'pointer', 'title': 'précédent'});
				previous_button.click(function (event) {
					that.changeTrack(false);
				});
			}
			//if background-image
			if(image_src != ""){
				//loads image
				var load_image = new Image();
				load_image.src = image_src;
				load_image.onload = function(){
					image = canvas.image(image_src, 0, 0, width, height);
					image.toBack();
					//when image loaded calls fonction to open the cache
					that.openImage();
				}
			}else{
				//if no image and player is not transparent, fills background with color
				if(transparent == false){
					var fill =  canvas.path("M 0 0 L"+(width)+" 0 L"+(width)+" "+(height)+" 0 L0 "+(height)).attr({fill: "#"+color, stroke: "#"+color});
					fill.toBack();
					//and opens the cache
					that.openImage();
				}else{
					//if mode transparent no cache to open
					that.openTracks();
				}
			}
		}
		this.openImage = function (){
			
			cache.animate({"r": width, "stroke-width": 1}, 3000, function(){ that.openTracks();});
		}
		this.openTracks = function (){
			
			//find total duration of all tracks together
			var total = 0;
			for(var i = 0; i < tracks.length; i++){
				total += tracks[i].duration;
			}
			//find available radius (without play button)
			var available_radius = mid_width - button_width - 2;
			//find radius for one second
			var radius_second = available_radius / total;
			var subtotal = button_width + 1;
			//for each track
			for(var i = 0; i < tracks.length; i++){
				if(radio == false){
					var border =  Math.round(radius_second * tracks[i].duration);
				}else{
					var border =  available_radius;
				}
				//find radius
				var radius = subtotal ;
				//stores info in track object
				tracks[i].border_radius = border;
				tracks[i].start_radius = subtotal;
				if(radio == false){
					tracks[i].start_angle = i / 3 * 2;
					subtotal += border;
				}else{
					tracks[i].start_angle = 4.71;
				}
				tracks[i].current_timecode = 0;
				//creates border circle
				tracks[i].border = canvas.circle(mid_width, mid_height, radius+border).attr({stroke: "#"+background_color,"stroke-width":1, opacity:0.01});
				//shows border circle with a delay
				tracks[i].border.animate({opacity: 0.5},100*i);
				//creates path for roll over
				tracks[i].path = canvas.circle(mid_width, mid_height,(radius+ Math.floor(border/2))).attr({stroke: "#000000","stroke-width":border-1, opacity:0.01, cursor: 'pointer'});
				//opacity 0;01 because 0 causes the roll to be inactive in IE
				tracks[i].path.order = i;
				//behavior of roll over
				tracks[i].path.hover(function (event) {
					this.attr({ opacity:0.3});
					var tracks = that.getTracks();
					track_name.innerHTML = tracks[this.order].title;
					track_timecode.innerHTML = that.formatTime(tracks[this.order].duration);
				},function (event) {
					this.attr({ opacity:0.01});
					var tracks = that.getTracks();
					var info = that.getInfo();
					track_name.innerHTML = tracks[info.current_track].title;
					track_timecode.innerHTML = that.formatTime(info.current_timecode) + " / " + that.formatTime(tracks[info.current_track].duration);
				});
				tracks[i].path.mousedown(function (event) {
					that.seekTrack(this.order, "down", {'x':(event.offsetX>0) ? event.offsetX : event.layerX, 'y':(event.offsetY>0) ? event.offsetY : event.layerY});
				});
				tracks[i].path.mouseup(function (event) {
					that.seekTrack(this.order, "up", {'x':(event.offsetX>0) ? event.offsetX : event.layerX, 'y':(event.offsetY>0) ? event.offsetY : event.layerY});
				});
				tracks[i].path.mousemove(function (event) {
					that.seekTrack(this.order, "move", {'x':(event.offsetX>0) ? event.offsetX : event.layerX, 'y':(event.offsetY>0) ? event.offsetY : event.layerY});
				});
				
			}			
			playpause_button.toFront();
			play_button.toFront();
			pause_button.toFront();
			if(radio == true){
				for(var i = 1; i < tracks.length; i++){
					tracks[i].path.attr({ opacity:0});
					tracks[i].border.attr({ opacity:0});
				}
			}
			//activates player
			engine.launch();
		}
		this.updateProgress = function (){
			/*var op = 0;
			if(info.percent_loaded < 10) {
				op = 0.1;
			}else{
				op = info.percent_loaded/100;
			}
			if(transparent == false){
				cache.animate({opacity:op},500);
				if(image_src) image.animate({opacity:op},500);
			}*/
		}
		this.updateVisibleTrack = function (){
			for(var i = 0; i < tracks.length; i++){
				if(i != info.current_track){
					if(tracks[i].fill) tracks[i].fill.attr({ opacity:0});
					tracks[i].path.hide();
					tracks[i].border.hide();
				}else{
					tracks[i].path.show();
					tracks[i].border.show();
				}
			}
		}
		this.updateCurrentTrack = function (){
			//updates playing info
			if(info.current_timecode >= 0){
				//removes old path
				if(tracks[info.current_track].fill) {
					tracks[info.current_track].fill.remove();
				}
				if(info.current_timecode > 0){
					if(radio == true){
						tracks[info.current_track].path.show();
						tracks[info.current_track].border.show();
					}
					if(direction == "radial"){
						var border = Math.round(info.current_timecode * tracks[info.current_track].border_radius / tracks[info.current_track].duration) ;
						var radius = Math.floor(tracks[info.current_track].start_radius + border/2) ;
						tracks[info.current_track].fill = canvas.circle(mid_width, mid_height, radius).attr({stroke: '#'+background_color, 'stroke-width': border, cursor: 'pointer'});
					}else{
						//finds how much of the circle has to be drawn
						tracks[info.current_track].counter_limit = (info.current_timecode * (2 * Math.PI) / tracks[info.current_track].duration) + tracks[info.current_track].start_angle;
						var radius = Math.floor(tracks[info.current_track].start_radius + tracks[info.current_track].border_radius/2) ;
						//default = linear
						var counter = tracks[info.current_track].start_angle;
						var posx = mid_width + Math.cos(counter) * radius;
						var posy = mid_height + Math.sin(counter) * radius;
						var list_coord = "M "+posx+" "+posy;
						do{
							var posx = mid_width + Math.cos(counter) * radius;
							var posy = mid_height + Math.sin(counter) * radius;
							list_coord += " L" + posx + " " + posy;
							counter += (1 / precision);
						}while(counter <= tracks[info.current_track].counter_limit)
						//draws new circle
						tracks[info.current_track].fill = canvas.path(list_coord).attr({stroke: '#'+background_color, 'stroke-width': tracks[info.current_track].border_radius,  cursor: 'pointer'});//
						if(radio != true ) tracks[info.current_track].fill.attr({'stroke-linecap': 'round'});
					}
					tracks[info.current_track].fill.order = info.current_track;
					//gives behavior to new circle
					tracks[info.current_track].fill.mousedown(function (event) {
						that.seekTrack(this.order, "down", {'x':(event.offsetX>0) ? event.offsetX : event.layerX, 'y':(event.offsetY>0) ? event.offsetY : event.layerY});
					});
					tracks[info.current_track].fill.mouseup(function (event) {
						that.seekTrack(this.order, "up", {'x':(event.offsetX>0) ? event.offsetX : event.layerX, 'y':(event.offsetY>0) ? event.offsetY : event.layerY});
					});
					tracks[info.current_track].fill.mousemove(function (event) {
						that.seekTrack(this.order, "move", {'x':(event.offsetX>0) ? event.offsetX : event.layerX, 'y':(event.offsetY>0) ? event.offsetY : event.layerY});
					});
				}
			}
			//updates text info
			track_name.innerHTML = tracks[info.current_track].title;
			track_timecode.innerHTML = this.formatTime(info.current_timecode) + " / " + this.formatTime(tracks[info.current_track].duration);
		}
		this.update = function (info_update){
			if(info.current_status != info_update.current_status){		
				info.current_status = info_update.current_status;
				//if status has changed update buttons
				if(info.current_status == "paused" || info.current_status == "ready" || info.current_status == "init" || info.current_status == "loading"){
					play_button.show();
					pause_button.hide();
				}else if(info.current_status == "playing" ){
					play_button.hide();
					pause_button.show();
				}
			}
			if(info.current_track != info_update.current_track){	
				//if current tracks has changed update it
				info.current_track = info_update.current_track;
				if(radio == true) this.updateVisibleTrack();
				this.updateCurrentTrack();
			}
			if(info.current_timecode != info_update.current_timecode){		
				//if timecode has changed update interface
				info.current_timecode = info_update.current_timecode;
				this.updateCurrentTrack();
			}
			if(info.percent_loaded != info_update.percent_loaded){		
				//if loading has changed
				info.percent_loaded = info_update.percent_loaded;
				this.updateProgress();
			}
		}
		//creation of the object : creates interface
		this.createInterface();
	}
	
	
	
	
	//View : tracks 
	SquarePlayer = function(){
		var canvas ,//drawing zone for raphaeljs
		play_button ,
		playpause_button ,
		pause_button ,
		cache ,//circle that opens at the beginning
		track_name ,//html div containing info on the track being played
		track_timecode ,//html div containing timecode of the track being played
		precision = 100 ,//to draw the circle point by point
		info = {},//stores values of the info object
		that = this;//keep reference to the object
		//
		this.playpause = function (){
			engine.playpause();
			return false;
		}
		this.playTrack = function (track){
			engine.playTrack(track);
			return false;
		}
		this.seekTrack = function (track, up, clicked){
			var xA = mid_width;
			var xB = mid_width;
			var xC = clicked.x;
			var yA = 0;
			var yB = mid_width;
			var yC = clicked.y;
			fA = Sqr(((Xc - Xb) ^ 2) + ((Yc - Yb) ^ 2)) ;//'distance entre b et c
			fB = Sqr(((Xc - Xa) ^ 2) + ((Yc - Ya) ^ 2)) ;//distance entre a et c
			fC = Sqr(((Xb - Xa) ^ 2) + ((Yb - Ya) ^ 2)) ;//'distance entre a et b
			fAngle = ((fA ^ 2) + (fC ^ 2) - (fB ^ 2)) / (2 * fA * fC) * (a2 + c2 - b2) / (2*a*c) ;
			
			alert(fAngle);
			//engine.seekTrack(track, up, percent);
			return false;
		}
		this.formatTime = function (time){
			var tc = Math.round(time);
			var s = tc % 60;
			var m = Math.floor(tc / 60);
			var h = Math.floor(m / 60);
			m = m % 60;
			if(s < 10) s = "0" + s;
			if(m < 10) m = "0" + m;
			if(h < 10) h = "0" + h;
			if(h > 0) {
				return (h + ":" + m + ":" + s);
			}else{
				return (m + ":" + s);
			}
		}
		this.createInterface = function (){
			/**/
			//remove content for search engines
			player.innerHTML = "";
			//
			//create and insert canvas container
			var contain_canvas = document.createElement("div");
			contain_canvas.setAttribute("id", "contain_canvas_"+player_id);
			contain_canvas.setAttribute("class", "contain_canvas");
			player.appendChild(contain_canvas);
			//create and insert info
			track_name = document.createElement("div");
			track_timecode = document.createElement("div");
			track_name.setAttribute("class", "track_name");
			track_timecode.setAttribute("class", "track_timecode");
			player.appendChild(track_name);
			player.appendChild(track_timecode);
			//creates canvas Rafael
			canvas = Raphael("contain_canvas_"+player_id, width, height);
			//white cache for the main zone of the image - to be animated when loading is completed
			if(transparent == false) cache = canvas.path("M " + (mid_width/2) + " " + (mid_height/2) + 
				" L" + (mid_width + mid_width/2) + " " + (mid_height/2) + 
				" L" + (mid_width + mid_width/2) + " " + (mid_height + mid_height/2) + 
				" L" + (mid_width/2) + " " + (mid_height + mid_height/2) + 
				" L" + (mid_width/2) + " " + (mid_height/2) + 
				" L" + (mid_width + mid_width/2) + " " + (mid_height/2)).attr({stroke: "#"+background_color,"stroke-width":mid_width});
			//play pause buttons
			if(button_width >0){
			}else{
				button_width = Math.round(width / 19);
			}
			if(control_width >0){
			}else{
				control_width = Math.round(width / 35);
			}
			//var width_button = height_button = Math.round(width / 25);
			var mid_width_button = Math.round(button_width/2);
			//var left_button = top_button = Math.round((width/2)-(mid_width_button));
			var control_left = Math.round((width/2)-(control_width/2));
			
			playpause_button = canvas.path("M " + (mid_width - mid_width_button) + " " + (mid_height - mid_width_button) + 
				" L" + (mid_width + mid_width_button) + " " + (mid_height - mid_width_button) + 
				" L" + (mid_width + mid_width_button) + " " + (mid_height + mid_width_button) + 
				" L" + (mid_width - mid_width_button) + " " + (mid_height + mid_width_button) + 
				" L " + (mid_width - mid_width_button) + " " + (mid_height - mid_width_button)).attr({fill: "#"+background_color,"stroke-width":0});
			play_button = canvas.path("M" + (control_left) + " " + control_left + " L" + (control_left + control_width) + " " + Math.round(control_left + (control_width/2)) + " L" + (control_left) + " " + (control_left + control_width)).attr({fill: "#"+color, stroke: "#"+color, cursor: 'pointer'});
			pause_button = canvas.path("M" + (control_left + 1) + " " + (control_left ) + " L" + (control_left +1) + " " + Math.round(control_left + control_width) + " M" + (control_left + control_width - 2) + " " + (control_left ) + " L" + (control_left + control_width - 2) + " " + (control_left + control_width)).attr({fill: "#"+color, stroke: "#"+color, "stroke-width":3, cursor: 'pointer'});
			playpause_button.click(function (event) {
				that.playpause();
			});
			play_button.click(function (event) {
				that.playpause();
			});
			pause_button.click(function (event) {
				that.playpause();
			});
			//will be shown when player activated
			play_button.hide();
			pause_button.hide();
			//if background-image
			if(image_src != ""){
				//loads image
				var load_image = new Image();
				load_image.src = image_src;
				load_image.onload = function(){
					image = canvas.image(image_src, 0, 0, width, height);
					image.toBack();
					//when image loaded calls fonction to open the cache
					that.openImage();
				}
			}else{
				//if no image and player is not transparent, fills background with color
				if(transparent == false){
					var fill =  canvas.path("M 0 0 L"+(width)+" 0 L"+(width)+" "+(height)+" 0 L0 "+(height)).attr({fill: "#"+color, stroke: "#"+color});
					fill.toBack();
					//and opens the cache
					that.openImage();
				}else{
					//if mode transparent no cache to open
					that.openTracks();
				}
			}
		}
		this.openImage = function (){
			cache.animate({"scale": "3, 3, mid_width, mid_height"}, 1500, function(){ that.openTracks();});
		}
		this.openTracks = function (){
			//find total duration of all tracks together
			var total = 0;
			for(var i = 0; i < tracks.length; i++){
				total += tracks[i].duration;
			}
			//find available radius (without play button)
			//var button_width = Math.round(playpause_button.getBBox().width/2);
			
			var available_radius = mid_width - (Math.ceil(button_width/2) + 1);
			
			//find radius for one second
			var radius_second = available_radius / total;
			
			var subtotal = Math.ceil(button_width/2) + 1;
			//for each track
			for(var i = 0; i < tracks.length; i++){
				var border =  Math.floor(radius_second * tracks[i].duration);
				//find radius
				var radius = subtotal  ;
				//stores info in track object
				tracks[i].border_radius = border;
				tracks[i].start_radius = subtotal;
				tracks[i].inner_points = [
					{'x':Math.floor(mid_width - subtotal), 'y':Math.floor(mid_height - subtotal)}, 
					{'x':Math.floor(mid_width + subtotal), 'y':Math.floor(mid_height - subtotal)}, 
					{'x':Math.floor(mid_width + subtotal), 'y':Math.floor(mid_height + subtotal)}, 
					{'x':Math.floor(mid_width - subtotal), 'y':Math.floor(mid_height + subtotal)} ];
				tracks[i].outer_points = [
					{'x':Math.floor(mid_width - (subtotal+border)), 'y':Math.floor(mid_height - (subtotal+border))}, 
					{'x':Math.floor(mid_width + (subtotal+border)), 'y':Math.floor(mid_height - (subtotal+border))}, 
					{'x':Math.floor(mid_width + (subtotal+border)), 'y':Math.floor(mid_height + (subtotal+border))}, 
					{'x':Math.floor(mid_width - (subtotal+border)), 'y':Math.floor(mid_height + (subtotal+border))} ];
				/*tracks[i].middle_points = [
					{'x':Math.floor(tracks[i].outer_points[0].x + (border/2)), 'y':Math.floor(tracks[i].outer_points[0].y + (border/2))}, 
					{'x':Math.floor(tracks[i].inner_points[1].x + (border/2)), 'y':Math.floor(tracks[i].outer_points[1].y + (border/2))}, 
					{'x':Math.floor(tracks[i].inner_points[2].x + (border/2)), 'y':Math.floor(tracks[i].inner_points[2].y + (border/2))}, 
					{'x':Math.floor(tracks[i].outer_points[3].x + (border/2)), 'y':Math.floor(tracks[i].inner_points[3].y + (border/2))} ];*/
				tracks[i].outer_perimeter = (tracks[i].outer_points[1].x - tracks[i].outer_points[0].x) * 4; 
				tracks[i].inner_perimeter = (tracks[i].inner_points[1].x - tracks[i].inner_points[0].x) * 4; 
				tracks[i].current_timecode = 0;
				//creates border circle
				var points = tracks[i].outer_points;
				tracks[i].border = canvas.path("M " + points[0].x + " " + points[0].y + 
				" L" + points[1].x + " " + points[1].y + 
				" L" + points[2].x + " " + points[2].y + 
				" L" + points[3].x + " " + points[3].y + 
				" L " + points[0].x + " " + points[0].y).attr({stroke: "#"+background_color,"stroke-width":1, opacity:0.01});
				
				//shows border circle with a delay
				tracks[i].border.animate({opacity: 0.5},100*i);
				var subtotaltemp = subtotal + border / 2;
				//creates path for roll over
				tracks[i].path = canvas.path("M " + (mid_width - subtotaltemp) + " " + (mid_height - subtotaltemp) + 
				" L" + (mid_width + subtotaltemp) + " " + (mid_height - subtotaltemp) + 
				" L" + (mid_width + subtotaltemp) + " " + (mid_height + subtotaltemp) + 
				" L" + (mid_width - subtotaltemp) + " " + (mid_height + subtotaltemp) + 
				" L " + (mid_width - subtotaltemp) + " " + (mid_height - subtotaltemp) +
				" L" + (mid_width + subtotaltemp) + " " + (mid_height - subtotaltemp)).attr({stroke : "#000000", "stroke-width" : border-1, opacity : 0.01, cursor : 'pointer'});
				//canvas.circle(mid_width, mid_height,(radius+ Math.floor(border/2))).attr({stroke: "#000000","stroke-width":border-1, opacity:0.01, cursor: 'pointer'});
				//opacity 0;01 because 0 causes the roll to be inactive in IE
				tracks[i].path.order = i;
				//behavior of roll over
				tracks[i].path.hover(function (event) {
					this.attr({ opacity:0.3 });
					track_name.innerHTML = tracks[this.order].title;
					track_timecode.innerHTML = that.formatTime(tracks[this.order].duration);
				},function (event) {
					this.attr({ opacity:0.01 });
					track_name.innerHTML = tracks[info.current_track].title;
					track_timecode.innerHTML = that.formatTime(info.current_timecode) + " / " + that.formatTime(tracks[info.current_track].duration);
				});
				tracks[i].path.mousedown(function (event) {
					that.playTrack(this.order, false, {'x':event.pageX, 'y':event.pageY});
				});
				tracks[i].path.mouseup(function (event) {
					that.playTrack(this.order, true, {'x':event.pageX, 'y':event.pageY});
				});
				tracks[i].path.click(function (event) {
					that.playTrack(this.order);
				});
				subtotal += border;
			}
			
			playpause_button.toFront();
			play_button.toFront();
			pause_button.toFront();
			//activates player
			engine.launch();
		}
		this.updateCurrentTrack = function (){
			//updates playing info
			if(info.current_timecode > 0){
				
				if(direction == "radial"){
					var border = Math.round(info.current_timecode * tracks[info.current_track].border_radius / tracks[info.current_track].duration) ;
					var radius = Math.ceil(tracks[info.current_track].start_radius + border/2) ;
					tracks[info.current_track].fill = canvas.path("M " + (mid_width-radius) + " " + (mid_height-radius) + " L " + (mid_width+radius) + " " + (mid_height-radius) + " L " + (mid_width+radius) + " " + (mid_height+radius) + " L " + (mid_width-radius) + " " + (mid_height+radius) + " L " + (mid_width-radius) + " " + (mid_height-radius) ).attr({stroke: '#'+background_color, 'stroke-width': border,  'stroke-linecap': 'square', cursor: 'pointer'});
				}else{
				
					
					
					//finds how much of the circle has to be drawn
					var outer_counter = Math.floor(info.current_timecode * tracks[info.current_track].outer_perimeter / tracks[info.current_track].duration);
					var inner_counter = Math.floor(info.current_timecode * tracks[info.current_track].inner_perimeter / tracks[info.current_track].duration);
					
					//removes old path
					if(tracks[info.current_track].fill) tracks[info.current_track].fill.remove();
					
					var counter = 0;
					var list_coord = "" ;
	
					var outer_side = tracks[info.current_track].outer_perimeter/4;
					var inner_side = tracks[info.current_track].inner_perimeter/4;
					list_coord += " M"+tracks[info.current_track].outer_points[0].x+" "+tracks[info.current_track].outer_points[0].y;
					//console.log(list_coord);
					if(outer_counter > outer_side) {
						var pos_x_1 = tracks[info.current_track].outer_points[1].x;
						var pos_x_2 = tracks[info.current_track].inner_points[1].x;
					}else{
						var pos_x_1 = tracks[info.current_track].outer_points[0].x + outer_counter;
						var pos_x_2 = tracks[info.current_track].inner_points[0].x + inner_counter;
					}
					list_coord += " L" + pos_x_1 + " "+tracks[info.current_track].outer_points[1].y;
					list_coord += " L" + pos_x_2 + " "+tracks[info.current_track].inner_points[1].y;
					list_coord += " L" + tracks[info.current_track].inner_points[0].x + " " + tracks[info.current_track].inner_points[0].y;
					
					if(outer_counter > outer_side) {
						if(outer_counter > outer_side * 2) {
							var pos_y_1 = tracks[info.current_track].outer_points[2].y;
							var pos_y_2 = tracks[info.current_track].inner_points[2].y;
						}else{
							var pos_y_1 = tracks[info.current_track].outer_points[1].y + outer_counter - outer_side ;
							var pos_y_2 = tracks[info.current_track].inner_points[1].y + inner_counter - inner_side;
						}
						list_coord += " M"+ tracks[info.current_track].outer_points[1].x + " " + tracks[info.current_track].outer_points[1].y;
						list_coord += " L"+ tracks[info.current_track].outer_points[1].x + " " + pos_y_1 ;
						list_coord += " L"+ tracks[info.current_track].inner_points[1].x + " " + pos_y_2 ;
						list_coord += " L" + tracks[info.current_track].inner_points[1].x + " " + tracks[info.current_track].inner_points[1].y;
					}
					if(outer_counter > outer_side * 2) {
						if(outer_counter > outer_side * 3) {
							var pos_x_1 = tracks[info.current_track].outer_points[3].x;
							var pos_x_2 = tracks[info.current_track].inner_points[3].x;
						}else{
							var pos_x_1 = tracks[info.current_track].outer_points[2].x - (outer_counter - (outer_side * 2));
							var pos_x_2 = tracks[info.current_track].inner_points[2].x - (inner_counter - (inner_side * 2));
						}
						list_coord += " M"+ tracks[info.current_track].outer_points[2].x + " " + tracks[info.current_track].outer_points[2].y;
						list_coord += " L" + pos_x_1 + " "+tracks[info.current_track].outer_points[2].y;
						list_coord += " L" + pos_x_2 + " "+tracks[info.current_track].inner_points[2].y;
						list_coord += " L" + tracks[info.current_track].inner_points[2].x + " " + tracks[info.current_track].inner_points[2].y;
					}
					if(outer_counter > outer_side *3) {
						var pos_y_1 = tracks[info.current_track].outer_points[3].y - (outer_counter - (outer_side * 3)) ;
						var pos_y_2 = tracks[info.current_track].inner_points[3].y - (inner_counter - (inner_side * 3));
						
						list_coord += " M"+ tracks[info.current_track].outer_points[3].x + " " + tracks[info.current_track].outer_points[3].y;
						list_coord += " L"+ tracks[info.current_track].outer_points[3].x + " " + pos_y_1 ;
						list_coord += " L"+ tracks[info.current_track].inner_points[3].x + " " + pos_y_2 ;
						list_coord += " L" + tracks[info.current_track].inner_points[3].x + " " + tracks[info.current_track].inner_points[3].y;
					}
					
					//draws new circle
					tracks[info.current_track].fill = canvas.path(list_coord).attr({fill: '#'+background_color, 'stroke-width': 0,  cursor: 'pointer'});
				}
				tracks[info.current_track].fill.order = info.current_track;
				//gives behavior to new circle
				tracks[info.current_track].fill.click(function (event) {
					that.playTrack(this.order);
				});
			}
			//updates text info
			track_name.innerHTML = tracks[info.current_track].title;
			track_timecode.innerHTML = this.formatTime(info.current_timecode) + " / " + this.formatTime(tracks[info.current_track].duration);
		}
		this.update = function (info_update){
			if(info.current_status != info_update.current_status){			
				info.current_status = info_update.current_status;
				//if status has changed update buttons
				if(info.current_status == "paused" || info.current_status == "ready" || info.current_status == "init"|| info.current_status == "loading"){
					play_button.show();
					pause_button.hide();
				}else{
					play_button.hide();
					pause_button.show();
				}
			}
			if(info.current_track != info_update.current_track){	
				//if current tracks has changed update it
				info.current_track = info_update.current_track;
			}
			
			if(info.current_timecode != info_update.current_timecode){		
				//if timecode has changed update interface
				info.current_timecode = info_update.current_timecode;
				this.updateCurrentTrack();
			}
		}
		//creation of the object : creates interface
		this.createInterface();
	}
	
	
	//View : subtitles 
	Subtitle = function(){
		var subtitle_text ,//html div containing info on the track being played
		info = {},//stores values of the info object
		that = this;//keep reference to the object
		//
		
		this.createInterface = function (){
			/**/
			//
			//create and insert subtitle container
			subtitle_text = document.createElement("div");
			subtitle_text.setAttribute("class", "subtitle");
			player.appendChild(subtitle_text);		
			
		}
		
		this.updateSubtitle = function (){
			//updates playing info
			if(info.current_timecode > 0 &&  tracks[info.current_track].subtitles){
				subtitle_text.innerHTML = "";
				for(var i=0; i < (tracks[info.current_track].subtitles.length); i++){
					if(info.current_timecode >= tracks[info.current_track].subtitles[i].start && info.current_timecode <= tracks[info.current_track].subtitles[i].end){
						subtitle_text.innerHTML = tracks[info.current_track].subtitles[i].text;
					}
				}
			}
		}
		this.update = function (info_update){
			if(info.current_status != info_update.current_status){			
				info.current_status = info_update.current_status;
			}
			if(info.current_track != info_update.current_track){	
				//if current tracks has changed update it
				info.current_track = info_update.current_track;
			}
			
			if(info.current_timecode != info_update.current_timecode){		
				//if timecode has changed update interface
				info.current_timecode = info_update.current_timecode;
				this.updateSubtitle();
			}
		}
		//creation of the object : creates interface
		this.createInterface();
	}
	
	
	//Model : core of the program
	Engine = function(){
		var current_status = 'init',//init-playing-pause-buffering-loading
		previous_status,
		current_track = 0,//
		last_move,//
		first_click,//
		current_time,
		current_url,
		interval_count,
		flag_seek,
		timecode_toseek = 0,//for seek
		percent_loaded = 0,
		audio,//player html or flash
		views = [];//list of views to be updated with changes
		//addView
		this.addView = function(view){
			views.push(view);
			
		}
		this.bind = function(method){
			var _this = this; 
			return(
				 function(){
				 return(method.apply( _this, arguments));
				 }
			);
		}
		this.count = function(position){
			//alert("count");
			if(current_status != "loading"){
				last_move ++;
				if((mode == 'flash' || current_status == "seeking") && position >= 0 ){
					current_time = position;
				}
			}
			if(flag_seek == false){
				if(previous_status == "playing"){
					if(mode == "flash"){
						audio.pauseSound();
					}else{
						audio.pause();
					}
				}
				flag_seek = true;
			}
			if(current_status == "seeking"){	
				var date = new Date();
				if(date.getTime() - first_click >250){
					//this.seek(timecode_toseek);
					this.setCurrentTime(timecode_toseek);
				}
			}
			tracks[current_track].current_timecode = this.getCurrentTime();
			this.updateViews();
		}
		//launch
		this.launch = function(){
			//console.log("launch");
			audio = document.createElement("audio");
			if (!!(audio.canPlayType && audio.canPlayType('audio/mpeg;').replace(/no/, ''))){
				mode = 'html_mp3';
			}
			else if(tracks[current_track].src.ogg && !!(audio.canPlayType && audio.canPlayType('audio/ogg; codecs="vorbis"').replace(/no/, ''))){
				mode = 'html_ogg';
			}else{
				//flash version reading mp3
				mode = 'flash';
				//creates a div to hold the content
				var div = document.createElement("div");
				//
				//necessary for ExternalInterface to work on IE
				if (navigator.appName.indexOf ("Microsoft") !=-1) {
					div.setAttribute("id",'flash_' + player_id);
					player.appendChild(div);
					swfobject.embedSWF('media/sound.swf?player=' + player_id , 'flash_' + player_id , "1", "1", "10.0.0");
				}else{
					var audio_code = '<object width="1" height="1" wmode="transparent" data="media/sound.swf?player=' + player_id + '"  allowscriptaccess="always" name="flash_' + player_id + '"  type="application/x-shockwave-flash"></object>';
					//insert flash player
					div.innerHTML = audio_code;
					player.appendChild(div);
				}
				//reference to the player
				if (window.document["flash_"+player_id]) {
					audio = window.document["flash_"+player_id];
				}else{
					audio = document.getElementById("flash_"+player_id);
				}
				/*if (document.getElementById("flash_"+player_id)) {
					audio = document.getElementById("flash_"+player_id);
				}else{
					audio = window.document["flash_"+player_id];
				}*/
			}
			if(mode == 'flash'){
				
			}else{
				player.appendChild(audio);
				audio.addEventListener('canplay', function(){ engine.isReady(); } , false);
				//audio.addEventListener('progress', function(e){ engine.progress(e); } , false);
				audio.addEventListener('timeupdate', function(){ engine.count(); } , false);
				//audio.addEventListener('pause', function(){ engine.autopaused(); } , false);
				//audio.addEventListener('play', function(){ engine.played(); } , false);
				audio.addEventListener('ended', function(){ engine.ended(); } , false);
				this.changeTrackUrl();
			}
			this.updateViews();
		}
		//init
		this.init = function(){
			//the flash player is ready
			this.changeTrackUrl();
			this.updateViews();
		}
		//isReady
		this.isReady = function(){
			//console.log("IS READY YYYY "+timecode_toseek);
			if(timecode_toseek != 0 && mode != "flash"){
				this.seek(timecode_toseek);//does not work on iPhone, to check (error line 958)
				timecode_toseek = 0;
			}else if(current_status != "init" && current_status != "paused"){
				this.seek(1);
				timecode_toseek = 1;
			}
			if(mode == "flash" && current_status != "init" && (radio == false || (radio == true && previous_status == "playing"))){
				//this.play();
			}
			percent_loaded = 100;
			this.updateViews();
		}
		this.progress = function(percent){
			percent_loaded = percent;
			this.updateViews();
		}
		//play
		this.play = function(){
			if(mode == "flash"){
				audio.playSound();
			}else{
				audio.play();
			}
			this.played();
		}
		//played
		this.played = function(){
			current_status = "playing";
			previous_status = "";
			//this.updateViews();	
		}
		//playpause
		this.pause = function(){
			if(mode == "flash"){
				audio.pauseSound();
			}else{
				audio.pause();
			}
			this.paused();
		}
		//playpause
		this.paused = function(){
			current_status = 'paused';
			this.updateViews();
		}
		//autopaused
		this.autopaused = function(){
			if(this.getCurrentTime() >= tracks[current_track].duration) this.changeTrack(true);
		}
		//playpause
		this.playpause = function(){
			if(current_status == 'playing'){
				this.pause();
			}else{
				this.play();			
			}			
		}
		//ended
		this.ended = function(){
			this.changeTrack(true);
		}
		//stop
		this.stopTrack = function(){
			current_status = "stopped";
			this.pause();
			//this.seek(0);
			this.updateViews();
		}
		//change Track
		this.changeTrack = function(next){
			
			//console.log("current_track before "+current_track);
			if(next){
				if(current_track < tracks.length-1) {
					this.playTrack(current_track + 1);
				}else{
					this.stopTrack();
				}
			}else{
				//previous function ?
				if(current_track > 0) {
					this.playTrack(current_track - 1);
				}else{
					this.stopTrack();
				}
			}
			//console.log("current_track after "+current_track);
			this.updateViews();
		}
		//change Track
		this.changeTrackUrl = function(){
		
			if(!tracks[current_track].src.mp3){
				tracks[current_track].src = {"mp3" : tracks[current_track].src};
			}
			if(mode == "html_ogg"){
				var new_url = tracks[current_track].src.ogg;
				
			}else{
				var new_url = tracks[current_track].src.mp3;
				
			}
			
			if(this.getCurrentUrl() != new_url){
				if(mode == "flash"){
					//change track in the flash
					if(previous_status == "playing" || previous_status == "paused"){
						
						var start_playing = true;
						current_status = "playing";
					}else{
						var start_playing = false;
					}
					current_url = new_url;
					//audio.setUrl(new_url, start_playing,tracks[current_track].current_timecode);
					audio.setUrl(new_url, start_playing,0);
				}else{
					audio.setAttribute("src", new_url);
					audio.load();
				}
				//
				current_time = 0;
				timecode_toseek = 0;//tracks[current_track].current_timecode;
				//$(document).trigger('soundLoad', [tracks[playlist][current_track].id, this.getCurrentTime(), current_track, tracks.selection.length, player_id]);
				
				if(current_status != "init" && mode != "flash" && previous_status == "playing") this.play();
				
				this.updateViews();
				
			}
			
		}
		//playTrack
		this.playTrack = function(i){
			//unactivate one track mode
			if(i != current_track){
				//console.log("cas a : changeTrackUrl");
				previous_status = current_status;
				if(current_status == "playing") this.pause();
				current_track = i;			
				this.changeTrackUrl();
			}else if (current_status != "playing"){ 
				this.play();
			}else if (current_status == "playing"){
				this.pause();
			}
			//this.updateViews();
		}
		//getCurrentUrl
		this.getCurrentUrl = function(){
			if(mode == 'flash' ){
				return current_url;
			}else{
				return (audio.src);
			}
		}
		//seekTrack
		this.seekTrack = function(i, pos, toseek){
			if(i != current_track  || current_status == "init"){
				if(pos == "up") {
					if(current_status == "init") current_status = "paused";
					this.playTrack(i);
				}
			}else{
				if(percent_loaded == 100){
					if(pos == "move" && current_status != "seeking") return ;
					if(pos == "down"){
						var date = new Date();
						first_click = date.getTime();
						timecode_toseek = toseek;
						previous_status = current_status;
						current_status = "seeking";
						//if(previous_status != "playing"){
							var closure = this.bind(this.count);
							clearInterval(interval_count);
							interval_count = setInterval(closure,100);  	
						//}
						flag_seek = false;
					}else if(pos == "move"){
						var date = new Date();
						if(date.getTime() - first_click>250){
							timecode_toseek = toseek;
						}
					}else{
						
						clearInterval(interval_count);
						current_status = previous_status;
						previous_status = "";
						var date = new Date();
						if(date.getTime() - first_click > 250){
							this.seek(toseek);
							this.play();
						}else{
							this.playpause();	
						}
						timecode_toseek = 0;
						flag_seek = false;
					}
				}else if(pos == "up"){
					current_status = previous_status;
					previous_status = "";
					this.playpause();
				}
			}
			this.updateViews();
		}
		//seek
		this.seek = function(tc){
			if(mode == 'flash'){
				audio.seekSound(tc);
			}else{
				audio.currentTime = (tc);
			}
			this.updateViews();
		}
		//seek
		this.getCurrentTime = function(){
			if(mode == 'flash' || current_status == "seeking"){
				return current_time;
			}else{
				return (audio.currentTime);
			}
		}
		//seek
		this.setCurrentTime = function(time){
			if(mode == 'flash' || current_status == "seeking"){
				current_time = time;
			}else{
				audio.currentTime = time;
			}
		}
		//updateViews
		this.updateViews = function(){
			//alert(views.length);
			for(var i = 0, max = views.length ; i < max ; i++){
				var upd = {
					'current_status' : current_status,
					'current_timecode' : this.getCurrentTime(),
					'current_track' : current_track,
					'percent_loaded' : percent_loaded
				};
				//console.log(upd);
				views[i].update(upd);
			}
		}
		
	}
	OTOTOI.list_players.push(this);
	//creation of the objects 
	engine = new Engine();
	if(shape == "square"){
		interface = new SquarePlayer();
	}else{
		interface = new RoundPlayer();
	}
	engine.addView(interface);
	subtitles = new Subtitle();
	engine.addView(subtitles);
	//
	this.engine = engine;
}
OTOTOI.list_players = [];

OTOTOI.talkToPlayer = function(player_id, function_name, param){
	//alert("je te parle" +function_name + " / "+player_id);
	for(var i = 0; i < OTOTOI.list_players.length; i ++){
		if(OTOTOI.list_players[i].player_id == player_id){
			eval("OTOTOI.list_players[" + i + "]."+function_name+"("+param+")");
		}
	}
}
