class AudioRender extends AudioWorkletProcessor {
	constructor(context, param) {
		super(context, param);
		this.queue = [];
		this.queue_1st_offset = 0;
		this.queue_length = 0;
		this.port.onmessage = this.message_handler.bind(this);
		this.req_id = 0;
	}
	message_handler(e) {
		// console.log("enter message_handler");
		switch (e.data["user_cmd"]) {
			case "audio_process_resp":
				var waves = e.data["waves"];
				this.queue.push(waves);
				// console.log(e.data["req_id"] + " resp " + this.queue_length + " => " + (this.queue_length + waves[0].length));
				this.queue_length += waves[0].length;
				// console.log("%cafter push: " + this.queue_length, "color:#0f0;");
				break;
			default:
				console.log("unknown command " + e.data["user_cmd"]);
				break;
		}
	}
	noise(output, channel="both") {
		var start = 0;
		var end = output.length;
		if (channel == "left") {
			end = 1;
		} else if (channel == "right") {
			start = 1;
		}
		for (var i = start; i < end; i++) {
			var out_ch = output[i];
			for (var j = 0; j < out_ch.length; j++) {
				out_ch[j] = Math.random() * 0.2 - 0.1;
			}
		}
	}
	process(inputs, outputs, parameters) {
		// console.log(inputs, outputs, parameters);
		var output = outputs[0];
		var channels_cnt = output.length; 
		var need_update = output[0].length;
		// console.log(this.queue_length, need_update);

		if (this.queue_length < 1024) {
			this.port.postMessage({user_cmd:"audio_process",req_id:this.req_id,length:need_update});
		}
		// console.log(this.req_id + " req");
		// this.req_id++;
		if (this.queue_length < need_update) {
			// console.log("%cfill zero", "color:#f00;");
			for (var i = 0; i < output.length; i++) {
				var out_ch = output[i];
				out_ch.fill(0); // keep mute
			}
			// this.noise(output, "right");
			// this.noise(output);
			return true;
		}
		while (true) {
			if (this.queue.length == 0) {
				console.error("inner error, no more data");
				break;
			}
			var in_data = this.queue[0];
			var in_chn_num = in_data.length;
			var in_len = in_data[0].length;
			if (in_len - this.queue_1st_offset <= need_update) {
				for (var i = 0; i < channels_cnt; i++) {
					var in_chn = in_data[i < in_chn_num ? i : 0];
					var out_ch = output[i];
					out_ch.set(in_chn.slice(this.queue_1st_offset), out_ch.length - need_update);
				}
				need_update -= in_len - this.queue_1st_offset;
				this.queue_1st_offset = 0;
				// console.log("shift");
				this.queue.shift();
			} else {
				for (var i = 0; i < channels_cnt; i++) {
					var in_chn = in_data[i < in_chn_num ? i : 0];
					var out_ch = output[i];
					out_ch.set(in_chn.slice(this.queue_1st_offset, this.queue_1st_offset + need_update), out_ch.length - need_update);
				}
				this.queue_1st_offset += need_update;
				need_update = 0;
			}
			// console.log("need_update: " + need_update);
			if (need_update <= 0) {
				this.queue_length -= output[0].length;
				// console.log("after used: " + this.queue_length);
				if (need_update != 0) {
					console.error("inner error, need_update != 0");
				}
				break;
			}
		}
		return true;
	}
}

registerProcessor('audio_render', AudioRender);

