Function.prototype.bindAsEventListener = function(object) {
  var __method = this;
  return function(event) {
    return __method.call(object, event || window.event);
  }
}

//----Sprites-------

var birdl = new Array();
birdl[0] = new Image();
birdl[0].src = 'rooster0l.png';
birdl[1] = new Image();
birdl[1].src = 'rooster2l.png';

var birdr = new Array();
birdr[0] = new Image();
birdr[0].src = 'rooster0r.png';
birdr[1] = new Image();
birdr[1].src = 'rooster2r.png';

var birdhit = new Array();
birdhit[0] = new Image();
birdhit[0].src = 'birdhit0.png';


var birdl_1 = new Array();
birdl_1[0] = new Image();
birdl_1[0].src = 'rooster0l_1.png';
birdl_1[1] = new Image();
birdl_1[1].src = 'rooster2l_1.png';

var birdr_1 = new Array();
birdr_1[0] = new Image();
birdr_1[0].src = 'rooster0r_1.png';
birdr_1[1] = new Image();
birdr_1[1].src = 'rooster2r_1.png';

var birdhit_1 = new Array();
birdhit_1[0] = new Image();
birdhit_1[0].src = 'birdhit1.png';


var feather = new Array();
feather[0] = new Image();
feather[0].src = 'feather0.png';
feather[1] = new Image();
feather[1].src = 'feather1.png';
feather[2] = new Image();
feather[2].src = 'feather2.png';
feather[3] = new Image();
feather[3].src = 'feather3.png';

var gunSparcles = new Array();
gunSparcles[0] = new Image();
gunSparcles[0].src = 'boom-gun.png';

var bzSparcles = new Array();
bzSparcles[0] = new Image();
bzSparcles[0].src = 'boom.png';

var sgSparcles = new Array();
sgSparcles[0] = new Image();
sgSparcles[0].src = 'boom-sg.png';

var bloodDrop = new Image();
bloodDrop.src = 'blood.png';

var bonus = new Array();
bonus[0] = new Image();
bonus[0].src = 'bonus.png';

var bonush = new Array();
bonush[0] = new Image();
bonush[0].src = 'bonushit.png';

var bonusMessages = new Array();
bonusMessages[0] = new Image();
bonusMessages[0].src = 'bonus10sec.png';
bonusMessages[1] = new Image();
bonusMessages[1].src = 'bonus100pts.png';
bonusMessages[2] = new Image();
bonusMessages[2].src = 'bonussg.png';
bonusMessages[3] = new Image();
bonusMessages[3].src = 'bonusbz.png';
bonusMessages[4] = new Image();
bonusMessages[4].src = 'bonustatata.png';
bonusMessages[5] = new Image();
bonusMessages[5].src = 'bonusflue.png';

function rand(x) {
	return Math.round(Math.random() * x);
}

function Sprite(ctx, pos, imgs) {
	this.ctx = ctx;
	this.pos = pos;
	this.imgs = imgs;
	this.cimg = 0;
	this.period = 1;
	this.cp = 0;
}

Sprite.prototype.update = function() {
	if (this.cp == 0) {
		this.cimg ++;
		if (this.cimg >= this.imgs.length) this.cimg = 0;
		this.cp = this.period;
	}
	
	this.cp--;
}

Sprite.prototype.draw = function() {
	var img = this.imgs[this.cimg];
	this.ctx.drawImage(img, this.pos.x, this.pos.y);
}

Sprite.prototype.canRemove = function() {
	return false;
}

OnceSprite.prototype = new Sprite;
OnceSprite.prototype.constructor = OnceSprite;
function OnceSprite(ctx, pos, imgs) {
	Sprite.prototype.constructor.call(this, ctx, pos, imgs);
}

OnceSprite.prototype.update = function() {
	if (this.cp == 0) {
		if (this.cimg < this.imgs.length) this.cimg ++;
		this.cp = this.period;
	}
	this.cp--;
}

OnceSprite.prototype.draw = function() {
	if (this.cimg < this.imgs.length)
		Sprite.prototype.draw.call(this);
}

OnceSprite.prototype.canRemove = function() {
	return (this.cimg >= this.imgs.length);
}

MovingSprite.prototype = new Sprite;
MovingSprite.prototype.constructor = MovingSprite;
function MovingSprite(ctx, pos, speed, imgs, bounds) {
	if (pos) this.posr = {x: pos.x, y: pos.y};
	this.speed = speed;
	Sprite.prototype.constructor.call(this, ctx, pos, imgs);
	
	this.resistance = {x: 1, y: 1};
	this.g = 2;
	this.bounds = bounds;
}

MovingSprite.prototype.update = function() {
	this.posr.x += this.speed.x;
	this.posr.y += this.speed.y;
	this.speed.x *= this.resistance.x;
	this.speed.y += this.g;
	this.speed.y *= this.resistance.y;
	
	this.pos.x = Math.round(this.posr.x);
	this.pos.y = Math.round(this.posr.y);
	
	Sprite.prototype.update.call(this);
}

MovingSprite.prototype.canRemove = function() {
	return (this.pos.x < this.bounds.x) ||
		(this.pos.y < this.bounds.y) ||
		(this.pos.x > (this.bounds.x + this.bounds.width)) ||
		(this.pos.y > (this.bounds.y + this.bounds.height));
}

Feather.prototype = new MovingSprite;
Feather.prototype.constructor = Feather;
function Feather(ctx, pos, bounds) {
	var sinx = Math.random() / 2;
	var cosx = Math.sqrt(1 - sinx*sinx);
	if (Math.random() > 0.5) sinx = -sinx;
	if (Math.random() > 0.5) cosx = -cosx;
	var vs = Math.random() * (rand(5) + 10);
	var speed = {x: cosx * vs, y: sinx * vs};
	var bounds2 = {x: bounds.x - 15, y: bounds.y - 15, width: bounds.width + 15, height: bounds.height + 15};
	MovingSprite.prototype.constructor.call(this, ctx, {x: pos.x - 7, y: pos.y - 7}, speed, [feather[rand(3)]], bounds2);
		
	this.resistance.x = 0.5;
	this.resistance.y = 0.5;
}

BloodDrop.prototype = new MovingSprite;
BloodDrop.prototype.constructor = BloodDrop;
function BloodDrop(ctx, pos, bounds) {
	var sinx = Math.random();
	var cosx = Math.sqrt(1 - sinx*sinx);
	if (Math.random() > 0.5) cosx = -cosx;
	var vs = Math.random() * (rand(5) + 10);
	var speed = {x: cosx * vs, y: sinx * vs};
	var bounds2 = {x: bounds.x - 9, y: bounds.y - 9, width: bounds.width + 9, height: bounds.height + 9};
	MovingSprite.prototype.constructor.call(this, ctx, {x: pos.x - 4, y: pos.y - 4}, speed, [bloodDrop], bounds2);
		
	this.resistance.x = 0.8;
	this.resistance.y = 0.8;
}

Bird.prototype = new MovingSprite;
Bird.prototype.constructor = Bird;
function Bird(ctx, pos, dir, bounds) {
	var speed = {x: (dir == 1) ? - (Math.random()*4.5 + 2.5) : (Math.random()*4.5 + 2.5), y: 0};
	
	//var dim = rand(10);
	//this.width = 30 + dim;
	//this.height = 30 + dim;
	
	this.width = 40;
	this.height = 40;
	
	var pos2 = {x: pos.x, y: pos.y};
	var bounds2 = {x: bounds.x - this.width, y: bounds.y - this.height, width: bounds.width + this.width, height: bounds.height + this.height};
	
	if (pos2.x < bounds2.x) pos2.x = (bounds2.x + 5);
	if (pos2.x > (bounds2.x + bounds2.width)) pos2.x = (bounds2.x + bounds2.width - 5);
	if (pos2.y < bounds2.y) pos2.y = (bounds2.y + 5);
	if (pos2.y > (bounds2.y + bounds2.height)) pos2.y = (bounds2.y + bounds2.height - 5);
	
	
	if (rand(1) == 0) {
		var birdl_imgs = birdl;
		var birdr_imgs = birdr;
		var birdh_imgs = birdhit;
	} else {
		var birdl_imgs = birdl_1;
		var birdr_imgs = birdr_1;
		var birdh_imgs = birdhit_1;
	}
	MovingSprite.prototype.constructor.call(this, ctx, pos2, speed, (dir == 1) ? birdl_imgs : birdr_imgs, bounds2);
	this.imgs_hit = birdh_imgs;
	
	
	
	this.isBird = true;
	this._hit = false;
	
	this.period = 10;
};

Bird.prototype.update = function () {
	MovingSprite.prototype.update.call(this);
	if (!this._hit) this.speed.y = 0;
}

Bird.prototype.hit = function () {
	this._hit = true;
	this.resistance.y = 0.99;
	this.resistance.x = 1;
	this.g = 0.8;
	this.imgs = this.imgs_hit;
	this.cimg = 0;
}

/* Bird.prototype.draw = function() {
	var img = this.imgs[this.cimg];
	this.ctx.drawImage(img, this.pos.x, this.pos.y, this.width, this.height);
} */

Bird.prototype.getHitArea = function () {
	return {x: this.pos.x, y: this.pos.y, width: this.width, height: this.height};
}

Bonus.prototype = new MovingSprite;
Bonus.prototype.constructor = Bonus;
function Bonus(ctx, pos, bounds) {
	var speed = {x: 0, y: 30};
	
	this.width = 50;
	this.height = 50;
	
	var bounds2 = {x: bounds.x - this.width, y: bounds.y - this.height, width: bounds.width + this.width, height: bounds.height + this.height};
	MovingSprite.prototype.constructor.call(this, ctx, pos, speed, bonus, bounds2);
	this.imgs_hit = bonush;
	
	this.isBonus = true;
	
	this.resistance.y = 0.5;
	this.g = 0.8;
	
	this.bonus = rand(5);
};

Bonus.prototype.hit = function () {
	this.resistance.y = 0.99;
	this.imgs = this.imgs_hit;
	this.cimg = 0;
}

Bonus.prototype.getParachute = function () {
	return {x: this.pos.x, y: this.pos.y, width: this.width, height: 20};
}

Bonus.prototype.getBox = function () {
	return {x: this.pos.x + 10, y: this.pos.y + 25, width: 30, height: 25};
}

BonusMessage.prototype = new MovingSprite;
BonusMessage.prototype.constructor = BonusMessage;
function BonusMessage(ctx, bounds, tip) {
	var speed = {x: 0, y: -2};
	
	var img = bonusMessages[tip];
	this.width = img.width;
	this.height = img.height;
	
	var pos = {x: Math.round((bounds.width - this.width) / 2), y: Math.round((bounds.height - this.height) / 2)}
	var bounds2 = {x: bounds.x - this.width, y: bounds.y - this.height, width: bounds.width + this.width, height: bounds.height + this.height};
	MovingSprite.prototype.constructor.call(this, ctx, pos, speed, [img], bounds2);
	
	this.resistance.y = 1;
	this.g = 0.0;
};

//----Weapons-----

function dist(p1, p2) {
	var s1 = p1.x - p2.x;
	var s2 = p1.y - p2.y;
	return Math.sqrt(s1 * s1 + s2 * s2);
}

function intersect(rect, circle) {
	var ok = (circle.x < (rect.x + rect.width + circle.radius)) && (circle.x > (rect.x - circle.radius)) &&
		(circle.y < (rect.y + rect.height)) && (circle.y > rect.y);
	ok = ok || ((circle.x < (rect.x + rect.width)) && (circle.x > rect.x) &&
		(circle.y < (rect.y + rect.height + circle.radius)) && (circle.y > (rect.y - circle.radius)));
	ok = ok || (dist({x: rect.x, y: rect.y}, {x: circle.x, y: circle.y}) < circle.radius);
	ok = ok || (dist({x: rect.x + rect.width, y: rect.y}, {x: circle.x, y: circle.y}) < circle.radius);
	ok = ok || (dist({x: rect.x + rect.width, y: rect.y + rect.height}, {x: circle.x, y: circle.y}) < circle.radius);
	ok = ok || (dist({x: rect.x, y: rect.y + rect.height}, {x: circle.x, y: circle.y}) < circle.radius);
	return ok;
}

function Weapon(ctx, rnd, radius, imgs_fire, destroy, min_f, cp) {
	this.rnd = rnd;
	this.ci = rnd;
	this.radius = radius;
	this.imgs_fire = imgs_fire;
	this.ctx = ctx;
	this.destroy = destroy;
	this.min_f = min_f;
	this.cp = cp;
	
	this.unlimited = (rnd == 0);
}

Weapon.prototype.getFire = function(pos) {
	var fire = new OnceSprite(this.ctx, {x: pos.x - Math.round(this.imgs_fire[0].width / 2), y: pos.y - Math.round(this.imgs_fire[0].height / 2)}, this.imgs_fire);
	fire.cp = this.cp;
	return fire;
}

Weapon.prototype.canFire = function() {
	return (this.unlimited) || (this.ci > 0);
}

Weapon.prototype.fire = function() {
	if (!this.unlimited)
		this.ci--;
}

Weapon.prototype.update = function() {
	
}

Weapon.prototype.checkHit = function(pos, rect) {
	return intersect(rect, {x: pos.x, y: pos.y, radius: this.radius});
}

Weapon.prototype.reload = function() {
	this.ci = this.rnd;
}

//----Arena------




var score = 0;
var rem_time = 60;
var terminated = true;

function Arena(canvas) {
	this.canvas = document.getElementById(canvas);
	this.ctx = this.canvas.getContext('2d');
	this.topCtx = this.canvas.getContext('2d');
	
	this.width = this.canvas.offsetWidth;
	this.height = this.canvas.offsetHeight;
	this.left = this.canvas.offsetLeft;
	this.top = this.canvas.offsetTop;
	this.bounds = {x: 0, y: 0, width: this.width, height: this.height - 50};
	
	this.sprites = new Array();
	
	this.aimpos = {x: Math.round(this.width / 2), y: Math.round(this.height / 2)};
	this.shooting = false;
	
	this.feathers = new Array();
	
	this.gun = new Weapon(this.ctx, 0, 3, gunSparcles, false, 1, 5);
	this.bazooka = new Weapon(this.ctx, 6, 60, bzSparcles, true, 1, 10);
	this.shotgun = new Weapon(this.ctx, 40, 15, sgSparcles, true, 1, 5);
	this.tatata = new Weapon(this.ctx, 200, 1, gunSparcles, false, 1, 5);
	this.tatata.rapid = true;
	
	this.weapon = this.gun;
	
	this.attachMouseEvents();
}

Arena.prototype.tryShoot = function() {
	if (this.shooting) {
		if (!this.weapon.canFire()) this.weapon = this.gun;
		if (this.weapon.canFire()) {
			this.weapon.fire();
			
			var i = 0;
			var n = this.sprites.length;
			var num = 0;
			
			this.sprites.push(this.weapon.getFire(this.aimpos));
			
			var wpn = this.weapon;
			
			while (i < n) {
				if (this.sprites[i].isBird && !this.sprites[i]._hit) {
					if (wpn.checkHit(this.aimpos, this.sprites[i].getHitArea())) {
						num++;
						var pos = {x: Math.round(this.sprites[i].pos.x + this.sprites[i].width / 2), y: Math.round(this.sprites[i].pos.y + this.sprites[i].height / 2)}
						this.addFeathers(pos, wpn.min_f);
						this.addBloodDrops(pos);
						if (!wpn.destroy) {
							this.sprites[i].hit();
						} else {
							this.sprites.splice(i, 1);
							i--;
							n--;
						}
					}
				} else if (this.sprites[i].isBonus) {
					var para = this.sprites[i].getParachute();
					var box = this.sprites[i].getBox();
					if (wpn.checkHit(this.aimpos, box)) {
						var bonus = this.sprites[i].bonus;
						switch (bonus) {
							case 0: rem_time += 5; updateTime(); break;
							case 1: score += 25; updateScore(); break;
							case 2: if (this.weapon != this.shotgun) {
										this.weapon = this.shotgun;
										this.weapon.ci = this.weapon.rnd;
									} else this.weapon.ci += this.weapon.rnd;
									break;
							case 3: if (this.weapon != this.bazooka) {
										this.weapon = this.bazooka;
										this.weapon.ci = this.weapon.rnd;
									} else this.weapon.ci += this.weapon.rnd;
									break;
							case 4: if (this.weapon != this.tatata) {
										this.weapon = this.tatata;
										this.weapon.ci = this.weapon.rnd;
									} else this.weapon.ci += this.weapon.rnd;
									break;
							case 5: for (var j = 0; j < n; j++) {
										if (this.sprites[j].isBird && !this.sprites[j]._hit) {
											this.sprites[j].hit();
											num++;
										}
									}
									break;
						}
						this.addBonusMessage(bonus);
						//no need to alter i, n, because message is added to the end
						
						this.sprites.splice(i, 1);
						i--;
						n--;
					} else if (wpn.checkHit(this.aimpos, para)) {
						this.sprites[i].hit();
					}
				}
				i++;
			}
			
			
			if (num > 0) {
				score += num * 5;
				if (num >= 5) scrore += 50;
				else if (num >= 4) score += 30;
				else if (num >= 3) score += 10;
				else if (num >= 2) score += 5;
				
				updateScore();
			}
			
		}
	}
}

Arena.prototype.update = function() {
	var i = 0;
	var n = this.sprites.length;
	while (i < n) {
		this.sprites[i].update();
		if (this.sprites[i].canRemove()) {
			if (this.sprites[i].isBird && !this.sprites[i]._hit) {
				score--;
				updateScore();
			}
			this.sprites.splice(i, 1);
			n--;
		} else {
			i++;
		}
	}
	
	this.weapon.update();
	
	if (this.shooting) {
		if (this.weapon.rapid) {
		
		} else {
			this.shooting = false;
		}
	}
	this.tryShoot();
}

Arena.prototype.draw = function() {
	this.ctx.clearRect(0, 0, this.width, this.height);
	this.ctx.strokeRect(0, 0, this.width, this.height);
	for (var i = 0; i < this.sprites.length; i++)
		this.sprites[i].draw();
}

Arena.prototype.addBird = function (dir) {
	var pos = {x: ((dir == 1) ? this.width : -40), y: Math.round(Math.random() * (this.height - 140))};
	var sprite = new Bird(this.ctx, pos, dir, this.bounds);
	this.sprites.push(sprite);
}

Arena.prototype.addBonus = function () {
	var pos = {x: 50 + rand(350), y: -50};
	var sprite = new Bonus(this.ctx, pos, this.bounds);
	this.sprites.push(sprite);
}

Arena.prototype.addFeathers = function(pos, min) {
	if (min) var n = min;
	else n = 1;
	n += rand(2);
	for (var i = 0; i < n; i++) {
		var f = new Feather(this.ctx, pos, this.bounds);
		this.sprites.push(f);
	}
}

Arena.prototype.addBloodDrops = function(pos) {
	for (var i = 0; i < 10; i++) {
		var b = new BloodDrop(this.ctx, pos, this.bounds);
		this.sprites.push(b);
	}
}

Arena.prototype.addBonusMessage = function(tip) {
	var sprite = new BonusMessage(this.ctx, this.bounds, tip);
	this.sprites.push(sprite);
}

Arena.prototype.attachMouseEvents = function () {
	if(document.all) {
		this.canvas.attachEvent("onmousedown", this.mouseDown.bindAsEventListener(this));
		this.canvas.attachEvent("onmousemove", this.mouseMove.bindAsEventListener(this));
		this.canvas.attachEvent("onmouseup", this.mouseUp.bindAsEventListener(this));
	} else {
		this.canvas.addEventListener("mousedown", this.mouseDown.bindAsEventListener(this), false);
		this.canvas.addEventListener("mousemove", this.mouseMove.bindAsEventListener(this), false);
		this.canvas.addEventListener("mouseup", this.mouseUp.bindAsEventListener(this), false);
	}
}

Arena.prototype.mouseDown = function(event) {
	if (terminated) return;
	
	var cx = event.pageX - this.left;
	var cy = event.pageY - this.top;
	this.aimpos = {x: cx, y: cy};
	this.shooting = true;
	this.tryShoot();
	if (this.weapon.rapid) {
	
	} else {
		this.shooting = false;
	}
}

Arena.prototype.mouseMove = function(event) {
	if (this.shooting) {
		var cx = event.pageX - this.left;
		var cy = event.pageY - this.top;
		this.aimpos = {x: cx, y: cy};
	}
}

Arena.prototype.mouseUp = function(event) {
	this.shooting = false;
	return false;
}

Arena.prototype.clear = function() {
	this.sprites.length = 0;
}

//----------------

var scoreField = null;
function updateScore() {
	if (scoreField == null)
		scoreField = document.getElementById('score');
	scoreField.innerHTML = score;
}

var timeField = null;
function updateTime() {
	if (timeField == null)
		timeField = document.getElementById('time');
	timeField.innerHTML = rem_time;
}
