const ProgressBar=require('progress');

const assetSpecs=[
	{ name: 'fruit',      filename: 'apple32.png',            type: 'image' },
	{ name: 'superFruit', filename: 'peach-rainbow-anim.png', type: 'image' },
	{ name: 'decayFruit', filename: 'peach-decay-anim.png',   type: 'image' },
	{ name: 'wall',       filename: 'wall32.png',             type: 'image' },
	{ name: 'flammable',  filename: 'oil32.png',              type: 'image' },
	{ name: 'hole',       filename: 'hole-ts.png',            type: 'image' },
	{ name: 'fire',       filename: 'fire-anim.png',          type: 'image' },
	{ name: 'snake',      filename: 'snake.json',             type: 'json'  },
	{ name: 'levelList',  filename: 'levelList.json',         type: 'json'  },
	{ name: 'config',     filename: 'config.json',            type: 'json'  },
	{ name: 'metaConfig', filename: 'metaConfig.json',        type: 'json'  }
];

const tasks=[
	{ from: 'hole',       type: 'tileset',   steps: 3, tiles: ['base', 'ul', 'dr', 'dl', 'ur', 'l', 'r', 'd', 'u'] },
	{ from: 'fire',       type: 'animation', steps: 6 },
	{ from: 'superFruit', type: 'animation', steps: 5 },
	{ from: 'decayFruit', type: 'animation', steps: 5 }
];

const cvs=document.createElement('canvas');
cvs.width=400;
cvs.height=50;
cvs.classList.add('progressBar');
cvs.classList.add('hiddenBottom');

const bar=new ProgressBar(assetSpecs.length*2+tasks.reduce((a, t) => a+t.steps, 0));
bar.addUpdateListener(() => bar.draw(cvs));
bar.draw(cvs);

document.body.appendChild(cvs);
setTimeout(() => cvs.classList.remove('hiddenBottom'), 0);

bar.addReadyListener(() => {
	cvs.classList.add('hiddenBottom');
	setTimeout(() => document.body.removeChild(cvs), 1000);
});

//XXX purposefully slow down asset loading
const sleep=(ms=500) => new Promise(ok => setTimeout(ok, ms*Math.random()));

const loadAsset=async (asset) => {
	const response=await fetch('assets/'+asset.filename);
	await sleep();
	bar.update();
	let result;
	switch(asset.type) {
		case 'json':
			result=await response.json();
			break;

		case 'image':
			result=await createImageBitmap(await response.blob());
			break;
	}
	await sleep();
	bar.update();
	return [asset.name, result];
};

let assets=Object.create(null);
let ready=false;
let readyListeners=[];

(async () => {
	let arr=await Promise
		.all(
			assetSpecs.map(a => loadAsset(a))
		);

	arr.forEach(([name, value]) => {
		assets[name]=value;
	});

	for(let task of tasks) {
		const source=assets[task.from];
		switch(task.type) {
			case 'tileset': {
				let asset=assets[task.from]=Object.create(null);
				for(let tId in task.tiles) {
					const tName=task.tiles[tId];
					asset[tName]=await createImageBitmap(source, 0, source.width*tId, source.width, source.width);
					if(tId%(task.tiles.length/task.steps)==0) {
						await sleep(100);
						bar.update();
					}
				}
				break;
			}

			case 'animation': {
				let anim=assets[task.from]=[];
				let frameCount=source.height/source.width;
				for(let i=0; i<frameCount; i++) {
					anim[i]=await createImageBitmap(source, 0, source.width*i, source.width, source.width);
					if(i%(frameCount/task.steps)==0) {
						await sleep(100);
						bar.update();
					}
				}
				break;
			}
		}
	}

	ready=true;
	readyListeners.forEach(fn => fn.bind(fn)());
	readyListeners=null;
})();

const onReady=(fn) => {
	if(ready) fn.bind(fn)();
	else readyListeners.push(fn);
};

const get=(name) => {
	let asset=assets[name];
	if(!asset) throw new Error("Unknown asset: "+name);
	return asset;
};

return {
	onReady, get
};

