
#include "ball_list.hh"
#include "bonus_list.hh"

void						ball_list_collide (struct s_ball_list* ball_list, struct s_pad* pad, t_blockGroup& groups, struct s_bonus_list* bonus_list)
{
	struct s_ball*			ball;
	t_block::iterator		block;
	t_blockGroup::iterator	group;
	char					coll;
	char					flag;
	unsigned int			i;
	unsigned int			j;

	for (i = 0; i < BALL_COUNT_ITEM; ++i)
		if (ball_list->state[i] == BALL_STATE_ALIVE)
		{
			ball = &ball_list->list[i];
			flag = 0;

			// collide with blocks
			for (group = groups.begin (); group != groups.end (); ++group)
				for (block = group->blocks.begin (); block != group->blocks.end (); ++block)
				{
					if (block->alive && (coll = ball_collide (ball, block->curOrigin.x, block->curOrigin.y, block->curOrigin.x, block->curOrigin.y, group->x1, group->x2, group->y1, group->y2)))
					{
						if (group->lives <= 0)
						{
							CHD_PlayStart (ball_list->sound[BALL_SOUND_BLOCK_UNBREAKABLE], 0);
							particle_create (bonus_list->particle, &ball_list->list[i].coord, particle_color_white, particle_define_block_hit, 0);
						}
						else if (!(ball->state & BALL_STATE_ONESHOT) && ++block->hits < group->lives)
						{
							CHD_PlayStart (ball_list->sound[BALL_SOUND_BLOCK_HIT], 0);
							particle_create (bonus_list->particle, &ball_list->list[i].coord, particle_color_green, particle_define_block_hit, 0);
						}
						else
						{
							if (ball->state & BALL_STATE_TRAVERSE)
								coll = 0;

							if (VTX_KEY_PRESSED ('b') || rand () % BALL_RAND_LOOT == 0)
								bonus_list_insert (bonus_list, block->curOrigin.x, block->curOrigin.y);

							CHD_PlayStart (ball_list->sound[BALL_SOUND_BLOCK_DESTROY], 0);
							particle_create (bonus_list->particle, &ball_list->list[i].coord, particle_color_fire, particle_define_block_destroy, 0);

							block->alive = 0;
						}

						flag |= coll;
					}
				}

			if (flag & (COLLIDE_BOTTOM | COLLIDE_TOP))
				mobile_bounce (&ball->mobile, MOBILE_BOUNCE_HORZ);

			if (flag & (COLLIDE_LEFT | COLLIDE_RIGHT))
				mobile_bounce (&ball->mobile, MOBILE_BOUNCE_VERT);

			// collide with walls
			if ((ball->mobile.x - BALL_SIZE_RADIUS < ball_list->x1 && mobile_speed_x (&ball->mobile) < 0) ||
			    (ball->mobile.x + BALL_SIZE_RADIUS > ball_list->x2 && mobile_speed_x (&ball->mobile) > 0))
			{
				CHD_PlayStart (ball_list->sound[BALL_SOUND_WALL], 0);
				mobile_bounce (&ball->mobile, MOBILE_BOUNCE_VERT);
			}

			if (ball->mobile.y + BALL_SIZE_RADIUS > ball_list->y2 && mobile_speed_y (&ball->mobile) > 0)
			{
				CHD_PlayStart (ball_list->sound[BALL_SOUND_WALL], 0);
				mobile_bounce (&ball->mobile, MOBILE_BOUNCE_HORZ);
			}

			if (ball->mobile.y < ball_list->y1 - BALL_DIST_INACTIVE)
			{
				ball_list->state[i] = BALL_STATE_INACTIVE;

				for (j = 0; j < BALL_COUNT_ITEM && ball_list->state[j] == BALL_STATE_INACTIVE; )
					++j;

				ball_list->empty = (j == BALL_COUNT_ITEM);
			}

			// collide with pad
			if ((coll = ball_collide (ball, pad->coord.px, pad->coord.py, pad->x, pad->coord.py, -pad->length - PAD_SIZE_RADIUS, pad->length + PAD_SIZE_RADIUS, -PAD_SIZE_RADIUS, PAD_SIZE_RADIUS)))
			{
				CHD_PlayStart (ball_list->sound[BALL_SOUND_PAD], 0);

				if (coll & (COLLIDE_BOTTOM | COLLIDE_TOP))
					mobile_bounce (&ball->mobile, MOBILE_BOUNCE_HORZ);

				if (coll & (COLLIDE_LEFT | COLLIDE_RIGHT))
					mobile_bounce (&ball->mobile, MOBILE_BOUNCE_VERT);

				mobile_compose (&ball->mobile, COORD_PI / 2, pad_release (pad));
				mobile_deviate (&ball->mobile, 0, (ball->mobile.x - pad->coord.px) / pad->length * ball->mobile.speed * BALL_ANGLE_DEVIATE);

				if (ball->mobile.speed > BALL_SPEED_MIN)
					ball->mobile.speed *= BALL_FACTOR_SLOW;
				else
					ball->mobile.speed = BALL_SPEED_MIN;
			}
		}
}

void				ball_list_define (struct s_ball_list* ball_list, struct s_particle* particle, struct s_surface* surface, GLUquadricObj* quadric, float x1, float x2, float y1, float y2)
{
	unsigned int	i;

	for (i = 0; i < BALL_COUNT_ITEM; ++i)
		ball_list->state[i] = BALL_STATE_INACTIVE;

	CHD_LoadSound ("data/sounds/ball_block_destroy.wav", FMOD_DEFAULT, &ball_list->sound[BALL_SOUND_BLOCK_DESTROY]);
	CHD_LoadSound ("data/sounds/ball_block_hit.wav", FMOD_DEFAULT, &ball_list->sound[BALL_SOUND_BLOCK_HIT]);
	CHD_LoadSound ("data/sounds/ball_block_unbreakable.wav", FMOD_DEFAULT, &ball_list->sound[BALL_SOUND_BLOCK_UNBREAKABLE]);
	CHD_LoadSound ("data/sounds/ball_pad.wav", FMOD_DEFAULT, &ball_list->sound[BALL_SOUND_PAD]);
	CHD_LoadSound ("data/sounds/ball_wall.wav", FMOD_DEFAULT, &ball_list->sound[BALL_SOUND_WALL]);

	surface_load (surface, "data/ball_heavy.png", &ball_list->texture[BALL_TYPE_HEAVY]);
	surface_load (surface, "data/ball_light.png", &ball_list->texture[BALL_TYPE_LIGHT]);
	surface_load (surface, "data/ball_normal.png", &ball_list->texture[BALL_TYPE_NORMAL]);

	ball_list->empty = true;
	ball_list->particle = particle;
	ball_list->quadric = quadric;
	ball_list->x1 = x1;
	ball_list->x2 = x2;
	ball_list->y1 = y1;
	ball_list->y2 = y2;
}

void				ball_list_draw (struct s_ball_list* ball_list)
{
	unsigned int	i;

	for (i = 0; i < BALL_COUNT_ITEM; ++i)
		if (ball_list->state[i] == BALL_STATE_ALIVE)
			ball_draw (&ball_list->list[i]);
}

void				ball_list_insert (struct s_ball_list* ball_list, float x, float y)
{
	struct s_coord	coord;
	unsigned int	i;
	unsigned int	s;

	coord_set_pos (&coord, x, y, 0);
	coord_set_rot (&coord, 0, 0, 0);

	for (i = 0; i < BALL_COUNT_ITEM; ++i)
		if (ball_list->state[i] == BALL_STATE_INACTIVE)
		{
			for (s = 0; s < BALL_COUNT_ITEM; ++s)
				if (ball_list->state[s] == BALL_STATE_ALIVE)
				{
					coord_set_pos (&coord, ball_list->list[s].coord.px, ball_list->list[s].coord.py, 0);

					break;
				}

			particle_create (ball_list->particle, &coord, particle_color_purple, particle_define_ball_create, 0);

			ball_define (&ball_list->list[i], coord.px, coord.py, BALL_WEIGHT_NORMAL, ball_list->texture[BALL_TYPE_NORMAL], ball_list->quadric);
			ball_list->state[i] = BALL_STATE_ALIVE;

			break;
		}

	ball_list->empty = false;
}

void				ball_list_loop (struct s_ball_list* ball_list)
{
	unsigned int	i;

	for (i = 0; i < BALL_COUNT_ITEM; ++i)
		if (ball_list->state[i] == BALL_STATE_ALIVE)
			ball_loop (&ball_list->list[i], ball_list->particle);
}

void				ball_list_move (struct s_ball_list* ball_list)
{
	unsigned int	i;

	for (i = 0; i < BALL_COUNT_ITEM; ++i)
		if (ball_list->state[i] == BALL_STATE_ALIVE)
			ball_move (&ball_list->list[i]);
}

void				ball_list_state (struct s_ball_list* ball_list, char flag)
{
	unsigned int	i;

	for (i = 0; i < BALL_COUNT_ITEM; ++i)
		if (ball_list->state[i] == BALL_STATE_ALIVE)
			ball_list->list[i].state |= flag;
}

void				ball_list_type (struct s_ball_list* ball_list, enum e_ball_type type)
{
	unsigned int	i;

	for (i = 0; i < BALL_COUNT_ITEM; ++i)
		if (ball_list->state[i] == BALL_STATE_ALIVE)
			switch (type)
			{
				case BALL_TYPE_HEAVY:
					ball_type (&ball_list->list[i], BALL_WEIGHT_HEAVY, ball_list->texture[BALL_TYPE_HEAVY]);
				break;

				case BALL_TYPE_LIGHT:
					ball_type (&ball_list->list[i], BALL_WEIGHT_LIGHT, ball_list->texture[BALL_TYPE_LIGHT]);
				break;

				case BALL_TYPE_NORMAL:
					ball_type (&ball_list->list[i], BALL_WEIGHT_NORMAL, ball_list->texture[BALL_TYPE_NORMAL]);
				break;
			}
}
