#include <allegro.h>

#include "main.h"
#include "game.h"
#include "ball.h"
#include "line.h"
#include "target.h"
#include "flipper.h"
#include "squirrel.h"

Ball *ball[BALLNUM] = {0, 0, 0, 0};

BITMAP *Ball::bmp = 0, *Ball::bmpl = 0, *Ball::bmpr = 0;

static float g = GRAVITY;

Ball::Ball(float _xp, float _yp, float _R) : Part(_xp, _yp, 0, _R) {	
	who = 0;
	out = false;
	hit = 0;	
	hit2 = 0;
	hit3 = 0;
	hit4 = 0;
	ghost = false;
	
	drx1 = -int(R);
	dry1 = -int(R);
	drx2 = int(R);
	dry2 = int(R);	
	
	xa = 0;
	ya = 0;
	num = 0;
}

void Ball::move(float d) {		
	
	if(out) return;
		
	if(num > 0) {
		xc += xa / num;
		yc += ya / num;
		num = 0;		
	}		
	xa = 0;
	ya = 0;
									
	yc = yc + g * d;
							
	xp = xp + xc * d;
	yp = yp + yc * d;	
			
	yc = yc + yc * FRICTION * d;
	xc = xc + xc * FRICTION * d;
							
	for(Line *line = Line::lines; line; line = line->nextline) {
			
		float len;	
		float nx, ny;
		float lx, ly;						
		
		bool doescol;
		
		doescol = line->ballcollision(this, &nx, &ny, &lx, &ly, &len);
		if(doescol) {
			
			float n = sqrt(nx * nx + ny * ny);
			
			float nxc, nyc;
			
			nx /= n;
			ny /= n;
			
			// adjust position, so ball can never be inside line
			// (lines themself do no collision detection, so this might happen
			// inside e.g. a flipper move)
			xp = line->xp + lx * len + nx * (R + POSADJUST);
			yp = line->yp + ly * len + ny * (R + POSADJUST);							
							
			nxc = -xc * COLLISION_LOST;
			nyc = -yc * COLLISION_LOST;
			
			float n_ = nx * nxc + ny * nyc; // (n==1) * n'
			float l_ = nx * nyc - ny * nxc; // (n==1) * l'
			
			float f_ = 0;
																		
			if(line == flipperleft1->sideup) {
				who = -1;
				if(flipperleft1->rc < 0) f_ = -flipperleft1->rc * len * HITVAL;							
			}
			if(line == flipperright1->sideup) {
				who = -1;
				if(flipperright1->rc > 0) f_ = flipperright1->rc * (line->R - len) * HITVAL;							
			}
			
			if(line == flipperleft2->sideup) {
				who = 1;
				if(flipperleft2->rc < 0) f_ = -flipperleft2->rc * len * HITVAL;							
			}
			if(line == flipperright2->sideup) {
				who = 1;
				if(flipperright2->rc > 0) f_ = flipperright2->rc * (line->R - len) * HITVAL;							
			}
			
			if(line->sound == 1) {	
				if(n_+ f_ > 100) hit = int(n_+f_);				
			}
			
			if(line->sound == 2) {	
				hit2 = int(n_);
			}
			
			if(line == bottomref) {
				f_ = BOTREFLECT;						
			}
			if(line == leftref || line == rightref) {
				f_ = REFLECT;	
			}
			
			if(who)
			for(Target *target = Target::targets; target; target = target->nexttarget) {
				if(!target->owncol) {
					target->ballcollision(this);									
				}
			}
									
			nxc = lx * -l_ + nx * (n_ + f_);
			nyc = ly * -l_ + ny * (n_ + f_);
			
			xa += nxc - xc;
			ya += nyc - yc;
			
			num = num + 1;
						
		}
	}
	
	for(Target *target = Target::targets; target; target = target->nexttarget) {
		if(target->owncol) {
			bool doescol;
			float nx, ny;				
			doescol = target->ballcollision(this, &nx, &ny);												
			if(doescol) {
				if(target == launcher) {
					xp = target->xp;
					yp = target->yp;
															
					if(who < 0) {
						xp -= 20;
						yp -= 20;
						xc -= REFLECT;
					} else {
						xp += 20;
						yp -= 20;
						xc += REFLECT;
					}
					
					hit4 = 255;
										
				} else {
					float lx, ly;
					float n = sqrt(nx * nx + ny * ny);						
			
					float nxc, nyc;
					
					nx /= n;
					ny /= n;
					
					ly = nx;
					lx = -ny;
					
					// adjust position, so ball can never be inside target					
					xp = target->xp + nx * (target->R + R + POSADJUST);
					yp = target->yp + ny * (target->R + R + POSADJUST);							
									
					nxc = -xc * COLLISION_LOST;
					nyc = -yc * COLLISION_LOST;
					
					float n_ = nx * nxc + ny * nyc; // (n==1) * n'
					float l_ = nx * nyc - ny * nxc; // (n==1) * l'
					
					float f_ = REFLECT;
					
					nxc = lx * -l_ + nx * (n_ + f_);
					nyc = ly * -l_ + ny * (n_ + f_);
					
					xa += nxc - xc;
					ya += nyc - yc;
			
					num = num + 1;
															
					hit2 = int(n_);
				}	
			}
		}
	}
						
}

void Ball::collide(Ball *other, float nx, float ny) {
	float n = sqrt(nx * nx + ny * ny);						
		
	float nxc, nyc;
	float lx, ly;
				
	nx /= n;
	ny /= n;
	
	ly = nx;
	lx = -ny;
													
	nxc = -xc * 0.5;
	nyc = -yc * 0.5;		
																					
	float n_ = nx * nxc + ny * nyc; // (n==1) * n'
	float l_ = nx * nyc - ny * nxc; // (n==1) * l'
					
	float f_ = 0;
	{
		float otx = other->xc;
		float oty = other->yc;
		
		float bla = (otx * nx + oty * ny) * 0.5;
		
		f_ = bla;
		
	}
	
	nxc = lx * -l_ + nx * (n_ + f_);
	nyc = ly * -l_ + ny * (n_ + f_);
	
	xa += nxc - xc;
	ya += nyc - yc;

	num = num + 1;
}

bool Ball::ballcollision(Ball *b, float *nx, float *ny) {
	float bx = b->xp - xp;
	float by = b->yp - yp;
	if(bx * bx + by * by <= R * R + b->R * b->R) {		
		*nx = bx;
		*ny = by;
		
		return true;				
									
	}
	return false;
}

void Ball::load() {
		
	bmp = load_bitmap("dat.dat#ball.bmp", NULL);
	bmpl = load_bitmap("dat.dat#balll.bmp", NULL);
	bmpr = load_bitmap("dat.dat#ballr.bmp", NULL);	
	
	if(!bmp || !bmpl || !bmpr) {
		allegro_message("Error loading bitmaps.\n"); exit(-1);
	}
}

void Ball::draw() {
			
	if(out) return;		
					
	old = true;
	
	xo = xp;
	yo = yp;
	
	BITMAP *b = bmp;
	if(who == 1) b = bmpr;
	if(who == -1) b = bmpl;
	
	draw_sprite(page, b, int(xo) - 6, int(yo) - 6);			
	
	rest = true;
	
}