/*
 * asapweb.js - pure JavaScript ASAP for web browsers
 *
 * Copyright (C) 2009-2025  Piotr Fusik
 *
 * This file is part of ASAP (Another Slight Atari Player),
 * see http://asap.sourceforge.net
 *
 * ASAP is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License as published
 * by the Free Software Foundation; either version 2 of the License,
 * or (at your option) any later version.
 *
 * ASAP is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty
 * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 * See the GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with ASAP; if not, write to the Free Software Foundation, Inc.,
 * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 */

import { ASAP, ASAPSampleFormat } from "./asap.js";

class ASAPFileBag
{
	files;

	constructor(files)
	{
		this.files = files;
	}

	load(filename, buffer, length)
	{
		if (!this.files.hasOwnProperty(filename))
			return -1;
		const source = this.files[filename];
		if (length > source.length)
			length = source.length;
		buffer.set(source);
		return length;
	}
}

export const asapWeb = {
	stop()
	{
		if (this.processor) {
			this.processor.disconnect();
			delete this.processor;
		}
	},

	playContent(filename, content, song)
	{
		const asap = new ASAP();
		try {
			if (content instanceof Uint8Array)
				asap.load(filename, content, content.length);
			else {
				const loader = new ASAPFileBag(content);
				content = content[filename];
				asap.loadWithExtraFiles(filename, content, content.length, loader);
			}
			const info = asap.getInfo();
			if (song === undefined)
				song = info.getDefaultSong();
			asap.playSong(song, -1);
		}
		catch (e) {
			alert(e.message);
			return;
		}

		this.stop();
		const length = 4096;
		const channels = asap.getInfo().getChannels();
		const buffer = new Uint8Array(length * channels);

		const AudioContext = window.AudioContext || window.webkitAudioContext;
		if (this.context)
			this.context.close();
		this.context = new AudioContext({ sampleRate : ASAP.SAMPLE_RATE });
		if (typeof(this.onUpdate) == "function")
			this.context.onstatechange = this.onUpdate;
		this.processor = this.context.createScriptProcessor(length, 0, channels);
		this.processor.onaudioprocess = e => {
			asap.generate(buffer, length * channels, ASAPSampleFormat.U8);
			for (let c = 0; c < channels; c++) {
				const output = e.outputBuffer.getChannelData(c);
				for (let i = 0; i < length; i++)
					output[i] = (buffer[i * channels + c] - 128) / 128;
			}
			if (typeof(this.onUpdate) == "function")
				this.onUpdate();
		};
		this.processor.connect(this.context.destination);
		this.asap = asap;
		if (typeof(this.onUpdate) == "function")
			this.onUpdate();
	},

	togglePause()
	{
		if (this.context) {
			switch (this.context.state) {
			case "running":
				this.context.suspend();
				return true;
			case "suspended":
				this.context.resume();
				return false;
			default:
				break;
			}
		}
		return null;
	},

	isPaused()
	{
		if (this.context) {
			switch (this.context.state) {
			case "running":
				return false;
			case "suspended":
				return true;
			default:
				break;
			}
		}
		return null;
	},

	playUrl(url, song)
	{
		const request = new XMLHttpRequest();
		request.open("GET", url, true);
		request.responseType = "arraybuffer";
		request.onload = e => {
			if (request.status == 200 || request.status == 0)
				this.playContent(url, new Uint8Array(request.response), song);
		};
		request.send();
	},

	playFile(file)
	{
		const reader = new FileReader();
		reader.onload = e => this.playContent(file.name, new Uint8Array(e.target.result));
		reader.readAsArrayBuffer(file);
	},

	seek(position)
	{
		if (!this.context)
			return;
		this.context.suspend();
		this.asap.seek(position);
		this.context.resume();
	}
};
