interface CharacterMoveInfo {
	x:number;
	y:number;
	dx:number;
	dy:number;
	f:number;
	t:number;
}
interface CharacterMovedEventArgs {
	nextMove?: string;
}
class Character extends Sprite {
	moving:bool;
	moveInfo:CharacterMoveInfo;
	nextMove:string;
	moved:Trigger;
	charaSeq: number;
	charaCol: number;
	animeCnt: number;
	movePixel: number;
	moveTime: number;
	animation: bool;
	angleSeq: any;//{[key:Angle]: number; };
	currentAngle:Angle;

	constructor(width:number, height:number, image:HTMLImageElement, wait?:number) {
		super(width, height, image);

		this.moving = false;
		if (! wait)
			wait = 200;

		this.startTimer(wait);
		this.animeCnt = 2;
		this.charaSeq = 0;
		this.charaCol = 1;
		this.movePixel = 64;
		this.moveTime = 300;
		this.animation = true;
	}

	moveLeft(stackNext?:bool) {
		if (this.move(-this.movePixel, 0, this.moveTime)) {
			this.angle(Angle.left);
			return true;
		}
		if (stackNext && this.moveInfo.t*2 >= this.moveInfo.f)
			this.nextMove = "Left";
		return false;
	}

	moveRight(stackNext?:bool) {
		if (this.move(this.movePixel, 0, this.moveTime)) {
			this.angle(Angle.right);
			return true;
		}
		if (stackNext && this.moveInfo.t*2 >= this.moveInfo.f)
			this.nextMove = "Right";
		return false;
	}

	moveUp(stackNext?:bool) {
		if (this.move(0, -this.movePixel, this.moveTime)) {
			this.angle(Angle.up);
			return true;
		}
		if (stackNext && this.moveInfo.t*2 >= this.moveInfo.f)
			this.nextMove = "Up";
		return false;
	}

	moveDown(stackNext?:bool) {
		if (this.move(0, 64, this.moveTime)) {
			this.angle(Angle.down);
			return true;
		}
		if (stackNext && this.moveInfo.t*2 >= this.moveInfo.f)
			this.nextMove = "Down";
		return false;
	}

	move(x:number, y:number, f:number) {
		if (this.moving)
			return false;
		this.moving = true;
		this.moveInfo = {
			x: this.x,
			y: this.y,
			dx: this.x + x,
			dy: this.y + y,
			f: f,
			t: 0
		}

		this.start();

		return true;
	}

	update(t:number) {
		if (this.moving) {
			this.moveInfo.t += t;
			if (this.moveInfo.t < this.moveInfo.f) {
				this.moveTo(
					this.moveInfo.x + Math.round((this.moveInfo.dx - this.moveInfo.x) / this.moveInfo.f * this.moveInfo.t),
					this.moveInfo.y + Math.round((this.moveInfo.dy - this.moveInfo.y) / this.moveInfo.f * this.moveInfo.t)
				);
			} else {
				this.moveTo(this.moveInfo.dx, this.moveInfo.dy);
				this.endMove();
			}
		}
	}

	endMove() {
		this.moving = false;
		this.stop();
		var e:CharacterMovedEventArgs = {}
		if (this.nextMove) {
			e.nextMove = this.nextMove;
			delete this.nextMove;
		}
		if (this.moved)
			this.moved.fire(e);
		if (e.nextMove) {
			this["move"+e.nextMove]();
		}
	}

	angle(angle:Angle) {
		this.currentAngle = angle;
		var rowP = Math.floor(this.charaSeq / this.charaCol) * 4;

		switch (angle) {
		case Angle.up:
			rowP += (this.angleSeq ? this.angleSeq[Angle.up] : 3);
		break;
		case Angle.down:
			rowP += (this.angleSeq ? this.angleSeq[Angle.down] : 0);
		break;
		case Angle.left:
			rowP += (this.angleSeq ? this.angleSeq[Angle.left] : 1);
		break;
		case Angle.right:
			rowP += (this.angleSeq ? this.angleSeq[Angle.right] : 2);
		break;
		}

		var f = this.animeCnt * (this.charaSeq % this.charaCol) + this.charaCol * this.animeCnt * rowP;
		this.frame = [];
		if (this.animeCnt % 2 == 1) {
			for (var i=0; i<this.animeCnt; i++)
				this.frame.push(i+f);
			for (var i=this.animeCnt-2; i>0; i--)
				this.frame.push(i+f);
		} else {
			for (var i=0; i<this.animeCnt; i++)
				this.frame.push(i+f);
		}
	}

	interval() {
		if (this.animation) {
			this.fno = (this.fno+1) % this.frame.length;
			this.updated();
		}
	}
}