let MaxAnimationFrames = 16;

let SpriteNames = [];

let AnimationNames = [];
let AnimationMaxFrames = [];
let AnimationFilePaths = [];
let AnimationFrames = [];

let CurrentGraphicRect = [];
let CurrentAnimation = [];
let CurrentAnimationFrame = [];
let CurrentFilePath = [];


function CreateAnimation(spritename, animname, frames) {
	assert(frames>0, "Must have at least one frame. Animation ID: " ~ animname);
	assert(frames%1==0, "Frame number must be an integer. Animation ID: " ~ animname);
	assert(animname != "nil", "cannot have animation named "\""nil"\");
	assert(frames<=MaxAnimationFrames, "You have exceeded the maximum number of frames allowed in a single animation.");
	AnimationNames = AnimationNames ~ [[spritename, animname]];
	AnimationMaxFrames = AnimationMaxFrames ~ [frames];
	AnimationFilePaths = AnimationFilePaths ~ [emptyFilePaths(MaxAnimationFrames)];
	AnimationFrames = AnimationFrames ~ [emptyFrames(MaxAnimationFrames)];
	
	if(!spriteNameExists(spritename)){
		SpriteNames = SpriteNames ~ [spritename];
		CurrentGraphicRect = CurrentGraphicRect ~ [[0, 0, 0, 0]];
		CurrentAnimation = CurrentAnimation ~ ["nil"];
		CurrentAnimationFrame = CurrentAnimationFrame ~ [0];
		CurrentFilePath = CurrentFilePath ~ ["nil"];
	}
}

function SetAnimationFrame(spritename, animname, framenumber, imagefilepath, frameduration, left, top, right, bottom){
	let indx = getAnimationIndex(spritename, animname);
	assert(framenumber>=0 && framenumber%1==0 && framenumber<=AnimationMaxFrames[indx] - 1, ToString(framenumber) ~ " is not a valid animation frame for animation: " ~ animname);
	assert(frameduration>0 && frameduration%1==0, ToString(frameduration) ~ " is not a valid animation frame duration for animation: " ~ animname);
	AnimationFilePaths = Array2DSetValue(AnimationFilePaths, indx, framenumber, imagefilepath);
	AnimationFrames = Array2DSetValue(AnimationFrames, indx, framenumber, [frameduration, left, top, right, bottom]);
}

task Animate(spritename, animname, looping){
	let animindx = getAnimationIndex(spritename, animname);
	let spriteindx = getSpriteIndex(spritename);
	let Frames = AnimationFrames[animindx];
	
	CurrentAnimation[spriteindx] = animname;
	
	while(CurrentAnimation[spriteindx] == animname){
		CurrentAnimationFrame[spriteindx] = 0;
		ascent(i in 0..AnimationMaxFrames[animindx]){
			assert(Frames[i][0]>=0, "You did not define all animation frames in animation: " ~ animname);
			CurrentGraphicRect[spriteindx] = [Frames[i][1], Frames[i][2], Frames[i][3], Frames[i][4]];
			CurrentFilePath[spriteindx] = AnimationFilePaths[animindx][i];
			loop(Frames[i][0]){
				yield ;
				if(CurrentAnimation[spriteindx] != animname){
					CurrentAnimationFrame[spriteindx] = 0;
					return ;
				}
			}
			CurrentAnimationFrame[spriteindx] = CurrentAnimationFrame[spriteindx] + 1;
		}
		if(!looping){
			CurrentAnimation[spriteindx] = "nil";
		}
	}
}

function DrawAnimatedSprite(spritename, x, y){
	let indx = getSpriteIndex(spritename);
	SetTexture(CurrentFilePath[indx]);
	SetGraphicRect(CurrentGraphicRect[indx][0], CurrentGraphicRect[indx][1], CurrentGraphicRect[indx][2], CurrentGraphicRect[indx][3]);
	DrawGraphic(x, y);
}

function spriteNameExists(spritename){
	ascent(i in 0..length(SpriteNames)){
		if(spritename == SpriteNames[i]){
			return true;
		}
	}
	return false;
}
	
function Array2DSetValue(a,x,y,v){
	let t = a[x];
	t[y] = v;
	a[x] = t;
	return a;
}

function emptyFrames(num){
	assert(num>0, "MaxAnimationFrames must be greater than 0.");
	assert(num%1==0, "MaxAnimationFrames must be an integer.");
	let array = [];
	loop(num){
		array = array ~ [[-1, 0, 0, 0, 0]];
	}
	return array;
}

function emptyFilePaths(num){
	assert(num>0, "MaxAnimationFrames must be greater than 0.");
	assert(num%1==0, "MaxAnimationFrames must be an integer.");
	let array = [];
	loop(num){
		array = array ~ ["nil"]
	}
	return array;
}

function getSpriteIndex(spritename){
	ascent(i in 0..length(SpriteNames)){
		if(spritename == SpriteNames[i]){
			return i;
		}
	}
	assert(false, "Sprite with name of " ~ spritename ~ " cannot be found.");
}

function getAnimationIndex(spritename, animname){
	ascent(i in 0..length(AnimationNames)){
		if([spritename, animname] == AnimationNames[i]){
			return i;
		}
	}
	assert(false, "Animation with sprite name of " ~ spritename ~ " and animation name of " ~ animname ~ " cannot be found");
}