var g_player_process = null;
var g_audio_render = null;
var g_video_callback_map = {};
var g_delay_callback_map = {};

var script_path = document.getElementsByTagName('script')[document.getElementsByTagName('script').length -1].src;
var js_fname = script_path.split('/')[script_path.split('/').length-1];
var script_path_base = script_path.replace(js_fname, '');
var libplayer_js_path = script_path_base + "libplayer.js";
var audio_render_js_path = script_path_base + "audio_render.js";

function num2str(num) {
	var str = String(Math.floor(num * 1000));
	while (str.length <= 3) {
		str = "0" + str;
	}
	return (str.substring(0, str.length - 3)) + "." + str.substring(str.length - 3);
}

function onfullscreenchange(e) {
	if (!document.fullscreenElement) {
		g_player_process.postMessage({user_cmd:"exitfullscreen"});
	}
}

function fullscreen(layer_name) {
	if (document.fullscreenElement) {
		document.exitFullscreen();
	} else {
		let canvas_obj = document.getElementById("canvas_" + layer_name);
		canvas_obj.requestFullscreen();
		g_player_process.postMessage({user_cmd:"fullscreen", layer_name:layer_name, width:window.screen.width, height:window.screen.height});
	}
}

function show_ability() {
	g_player_process.postMessage({user_cmd:"show_ability"});
}

function save_blob(filename, blob) {
	var link = document.createElement('a');
	link.href = URL.createObjectURL(blob);
	link.download = filename;
	link.click();
	URL.revokeObjectURL(link.href);
}
function save_file(filename, content) {
	var blob = new Blob([content], {type: "application/octet-stream"});
	save_blob(filename, blob);
}
function save_bitmap(filename, bitmap) {
	var cvs_obj = document.createElement("canvas");
	var cvs_ctx = cvs_obj.getContext("2d");
	cvs_obj.width = bitmap.width;
	cvs_obj.height = bitmap.height;
	cvs_ctx.drawImage(bitmap, 0, 0);
	cvs_obj.toBlob(blob => { save_blob(filename, blob);});
}

function PIMediaPlayer_msg_handler(e) {
	var ret = 1;
	switch (e.data["user_cmd"]) {
		case "audio_process_resp":
			g_audio_render.worklet.port.postMessage(e.data); // transfer to worklet
			break;
		case "media_play_control":
			if (g_audio_render) {
				g_audio_render.play_control(e.data["command"], e.data["arg"]);
			}
			break;
		case "set_audio_play_sample_rate":
			if (!g_audio_render) {
				g_audio_render = new PIAudioRender();
			}
			g_audio_render.set_sample_rate(e.data["sample_rate"]);
			break;
		case "video_callback":
			if (g_video_callback_map.hasOwnProperty(e.data["media_name"])) {
				g_video_callback_map[e.data["media_name"]](e.data["media_name"], e.data["yuvdata"], e.data["width"], e.data["height"], e.data["pts"], e.data["orig_stamp"]);
			}
			break;
		case "delay_callback":
			if (g_delay_callback_map.hasOwnProperty(e.data["media_name"])) {
				g_delay_callback_map[e.data["media_name"]](e.data["media_name"], e.data["delay_ms"]);
			}
			break;
		case "save_bitmap":
			save_bitmap(e.data["fname"], e.data["bitmap"]);
			break;
		case "save_file":
			save_file(e.data["filename"], e.data["content"]);
			break;
		default:
			// console.log("message from player: ", e.data);
			ret = 0;
			break;
	}
	return ret;
}

function PIMediaPlayer_set_display_rotate(media_name, degree) {
	if (g_player_process) {
		g_player_process.postMessage({user_cmd:"set_display_rotate", media_name:media_name, stream_name:"video0", degree:degree});
	}
}
function PIMediaPlayer_set_video_callback(media_name, callback) {
	if (g_player_process) {
		if (callback && callback != null) {
			g_video_callback_map[media_name] = callback;
			g_player_process.postMessage({user_cmd:"set_video_callback", media_name:media_name, stream_name:"video0", value:1});
		} else if (g_video_callback_map.hasOwnProperty(media_name)) {
			delete g_video_callback_map[media_name];
			g_player_process.postMessage({user_cmd:"set_video_callback", media_name:media_name, stream_name:"video0", value:0});
		}
	}
}
function PIMediaPlayer_set_delay_callback(media_name, callback) {
	if (callback && callback != null) {
		console.warn("deprecated PIMediaPlayer_set_delay_callback, use qoeinfo instead");
		g_delay_callback_map[media_name] = callback;
	} else if (g_delay_callback_map.hasOwnProperty(media_name)) {
		delete g_delay_callback_map[media_name];
	}
}
function PIMediaPlayer_set_display_size(layer_name, width, height) {
	if (g_player_process) {
		g_player_process.postMessage({user_cmd:"resize", layer_name:layer_name, width:width, height:height});
	}
}
function PIMediaPlayer_save_screenshot(fname, media_name, width=0, height=0, degree=0) {
	if (g_player_process) {
		g_player_process.postMessage({user_cmd:"save_screenshot", fname:fname, media_name:media_name, stream_name:"video0", width:width, height:height, degree:degree});
	}
}
function PIMediaPlayer_init(callback, pthread_pool_size) {
	if (g_player_process) {
		console.error("g_player_process inited already");
	} else {
		var poolsize = (typeof(pthread_pool_size) == "undefined") ? 24 : pthread_pool_size;
		g_player_process = new Worker(libplayer_js_path, {name:"PIMediaPlayer[pool="+poolsize+"]"});
		g_player_process.onmessage = callback;
		document.addEventListener("fullscreenchange", onfullscreenchange);
	}
}
function PIMediaPlayer_create(media_name, url, module_url) {
	if (g_player_process) {
		g_player_process.postMessage({user_cmd:"create", media_name:media_name, url:url, module_url:module_url});
	}
}
function PIMediaPlayer_destroy(media_name) {
	if (g_audio_render) {
		g_audio_render.play_control("suspend", 0);
	}
	if (g_player_process) {
		g_player_process.postMessage({user_cmd:"destroy", media_name:media_name});
	}
}
function PIMediaPlayer_set_ptcp_log_level(level) {
	if (g_player_process) {
		g_player_process.postMessage({user_cmd:"set_ptcp_log_level", level:level});
	}
}
function PIMediaPlayer_set_pslstreaming_log_level(level) {
	if (g_player_process) {
		g_player_process.postMessage({user_cmd:"set_pslstreaming_log_level", level:level});
	}
}
function PIMediaPlayer_set_psdemux_log_level(level) {
	if (g_player_process) {
		g_player_process.postMessage({user_cmd:"set_psdemux_log_level", level:level});
	}
}
function PIMediaPlayer_add_canvas(canvas_list, layers) {
	var offscreen_list = [];
	for (var i = 0; i < canvas_list.length; i++) {
		offscreen_list.push(canvas_list[i]["offscreen"]);
	}
	g_player_process.postMessage({user_cmd:"add_canvas", canvas_list:canvas_list, layers:layers}, offscreen_list);
}
function PIMediaPlayer_del_canvas(layer_names) {
	if (g_player_process) {
		g_player_process.postMessage({user_cmd:"del_canvas", "layers": layer_names});
	}
}
function PIMediaPlayer_update_binds(binds) {
	if (g_player_process) {
		g_player_process.postMessage({user_cmd:"update_binds", binds:binds});
	}
}
function PIMediaPlayer_set_volume(volume) {
	if (!g_audio_render) {
		g_audio_render = new PIAudioRender();
	}
	g_audio_render.set_volume(volume); /* volume 0~100 */
}
function PIMediaPlayer_set_dbgopt(opt) {
	if (g_player_process) {
		g_player_process.postMessage({user_cmd:"set_dbgopt", opt:opt});
	}
}
function get_file(filename) {
	if (g_player_process) {
		g_player_process.postMessage({user_cmd:"get_file", filename:filename});
	}
}

class PIAudioRender {
	constructor() {
		this.audio_ctx;
		this.gain_node;
		this.sample_rate = 48000;
		this.volume = 100;
		this.worklet;
		this.has_audio = false;
		this.state = "ready";
		var btn_obj = document.createElement("input");
		btn_obj.setAttribute("type", "button");
		btn_obj.setAttribute("value", "play");
		// document.getElementById("audio_btns").appendChild(btn_obj);
		let render = this;
		btn_obj.addEventListener("click", function(e) {
			render.play_toggle();
		});
		this.control_btn = btn_obj;
	}
	create_worklet(sample_rate) {
		if (sample_rate) {
			this.sample_rate = sample_rate;
		}
		if (typeof(this.worklet) != "undefined") {
			return;
		}
		var worklet_process = new AudioWorkletNode(this.audio_ctx, "audio_render");
		worklet_process.port.onmessage = this.worklet_msg_handler.bind(this);
		var buff = this.audio_ctx.createBuffer(2, 20, this.sample_rate); // length doesn't matter, just start play
		for (var i = 0; i < buff.numberOfChannels; i++) {
			var channel = buff.getChannelData(i);
			channel.fill(0); // content doesn't matter, just start play
		}
		var buff_src = this.audio_ctx.createBufferSource();
		buff_src.buffer = buff;
		buff_src.loop = true;
		buff_src.connect(worklet_process);
		this.gain_node = this.audio_ctx.createGain();
		worklet_process.connect(this.gain_node);
		this.gain_node.connect(this.audio_ctx.destination);
		this.gain_node.gain.value = this.volume / 100;
		buff_src.start(0);
		this.worklet = worklet_process;
	}
	set_sample_rate(sample_rate) {
		if (!this.has_audio) {
			this.audio_ctx = new AudioContext();
			this.has_audio = true;
			this.audio_ctx.audioWorklet.addModule(audio_render_js_path).then(ret => {
				this.create_worklet(sample_rate);
			});
		} else {
			this.create_worklet(sample_rate);
		}
		this.play_control("resume", 0);
	}
	set_volume(volume) {
		if (!this.has_audio) {
			this.audio_ctx = new AudioContext();
			this.has_audio = true;
			this.audio_ctx.audioWorklet.addModule(audio_render_js_path).then(ret => {
				this.create_worklet();
			});
		} else {
			this.create_worklet();
		}
		this.volume = volume;
		if (this.gain_node) {
			this.gain_node.gain.value = this.volume / 100;
		}
	}
	worklet_msg_handler(e) {
		switch (e.data["user_cmd"]) {
			case "audio_process":
				if (!this.has_audio || this.state != "playing") {
					break;
				}
				g_player_process.postMessage(e.data); // transfer to player
				break;
			default:
				console.log("message from worklet: ", e.data);
				break;
		}
	}
	play_control(command, arg) {
		switch(command) {
			case "start":
				if (this.state == "ready") {
					if (this.has_audio) {
						this.state = "playing";
						this.control_btn.setAttribute("value", "pause");
					}
				}
				break;
			case "suspend":
				if (this.state == "playing") {
					if (this.has_audio) {
						this.audio_ctx.suspend();
						this.state = "suspend";
						this.control_btn.setAttribute("value", "play");
					}
				}
				break;
			case "resume":
				if (this.state == "suspend") {
					if (this.has_audio) {
						this.audio_ctx.resume();
						this.state = "playing";
						this.control_btn.setAttribute("value", "pause");
					}
				}
				break;
			case "stop":
				if (this.has_audio) {
					this.audio_ctx.close();
					this.control_btn.disabled = true;
					this.audio_ctx = null;
				}
				break;
			default:
				console.log("unknown command: ", command);
				break;
		}
	}
	play_toggle() {
		if (this.state == "playing") {
			this.play_control("suspend", 0);
		} else if (this.state == "ready") {
			this.play_control("start", 0);
		} else if (this.state == "suspend") {
			this.play_control("resume", 0);
		}
	}
}
