/*
	I am slowly but surely getting tired of this explanations
	and will therefore narrow them down to the interesting parts.
	Which in this case is propably only the hit() method, responsible 
	for spawning smaller asteroids and items if one of them is hit.
	The children are actually handled like missiles in rectangle most of
	the time, so if something is unclear, I refer to my rants over there
	(include/rectangle.h). If something is unclear or you wish to complain
	about anything, write an email to fillius@2d-rp.de. Thanks ;-)
	Well, on to line 137 and the hit method ;-);
*/
namespace rectangle_battle
{
	class asteroid:public rectangle_battle::collision_mgr::collision_obj
	{
		protected:
		kos_gfx::pvr::texture_fragment img[3];
		kos_gfx::pvr::texture_fragment atk_item_tex, barrier_item_tex;
		
		int size;
		kos_gfx::math::vector2d<> start_pos;
		double rot, rot_speed;
		
		std::list<asteroid*> children;
		int number_of_children;
		rectangle_battle::collision_mgr::element target_elem, missile_elem;
		
		kos_gfx::sound::sfx::handle explosion_sfx;
		
		rectangle_battle::item *asteroid_item;
		
		public:
		asteroid()
		{
			explosion_sfx=0;
			asteroid_item=NULL;
			
			target_elem=rectangle_battle::collision_mgr::targets.end();
			missile_elem=rectangle_battle::collision_mgr::missiles.end();
		};
		
		asteroid(kos_gfx::pvr::texture_fragment img_small,kos_gfx::pvr::texture_fragment img_normal,kos_gfx::pvr::texture_fragment img_big,kos_gfx::pvr::texture_fragment item_atk,kos_gfx::pvr::texture_fragment item_bar,
		double pos_x, double pos_y, double speed_x, double speed_y,int sz=2,double rotation_speed=-0.001)
		{
			explosion_sfx=0;
			asteroid_item=NULL;
			
			target_elem=rectangle_battle::collision_mgr::targets.end();
			missile_elem=rectangle_battle::collision_mgr::missiles.end();
			create(img_big,img_normal,img_small,item_atk,item_bar,pos_x,pos_y,speed_x,speed_y,sz,rotation_speed);
		};
		
		void create(kos_gfx::pvr::texture_fragment img_small,kos_gfx::pvr::texture_fragment img_normal,kos_gfx::pvr::texture_fragment img_big,kos_gfx::pvr::texture_fragment item_atk,kos_gfx::pvr::texture_fragment item_bar,
		double pos_x, double pos_y, double speed_x, double speed_y,int sz=2,double rotation_speed=-0.001)
		{
			unregister();
			
			img[0]=img_small;
			img[1]=img_normal;
			img[2]=img_big;
			atk_item_tex=item_atk;
			barrier_item_tex=item_bar;
			
			start_pos=kos_gfx::math::vector2d<>(pos_x,pos_y);
			velocity=kos_gfx::math::vector2d<>(speed_x,speed_y);
			size=sz;
			size=size>2?2:size<0?0:size;
			w=img[size].w;
			h=img[size].h;
			rot=0;
			rot_speed=rotation_speed;
			number_of_children=0;
			
			target_elem=rectangle_battle::collision_mgr::register_target(this);
			missile_elem=rectangle_battle::collision_mgr::register_missile(this);
			
			revive();
		};
		
		void revive()
		{
			if(number_of_children!=0)
				return;
				
			if(asteroid_item!=NULL)
			{
				delete asteroid_item;
				asteroid_item=NULL;
			}
			
			dead=false;
			dying=false;
			position=start_pos;
			
			dmg=(size+1)*2;
		};
		
		~asteroid()
		{
			free_children();
			if(asteroid_item!=NULL)
			{
				delete asteroid_item;
			};
			
			unregister();
		};
		
		void free_children()
		{
			for(std::list<asteroid*>::iterator it=children.begin();it!=children.end();++it)
			{
				asteroid *tmp=(*it);
				it=children.erase(it);
				delete tmp;
				--it;
				--number_of_children;
			};
		};
		
		void unregister()
		{
			if(target_elem!=rectangle_battle::collision_mgr::targets.end())
				rectangle_battle::collision_mgr::unregister_target(target_elem);
			if(missile_elem!=rectangle_battle::collision_mgr::missiles.end())
				rectangle_battle::collision_mgr::unregister_missile(missile_elem);
				
			target_elem=rectangle_battle::collision_mgr::targets.end();
			missile_elem=rectangle_battle::collision_mgr::missiles.end();
		};
		
		void set_sound(kos_gfx::sound::sfx::handle exp_sfx)
		{
			explosion_sfx=exp_sfx;
		};
		
		//The first thing you might notice is the fact that this method is
		//declared virtual. This is because there exists a derived class
		//for the asteroids in one player mode(falling_asteroid), which
		//explodes slightly differnt and spawns way more items. I could and
		//should have implemented this via some parameter, however i am a
		//lazy bastard and this was a quick solution, i beg your forgiveness.
		//Hmm, now that i look at it again i fear i realize there is not too
		//much to explain here eighter, if damage is dealt to an asteroid
		//it explodes into two smaller one whose velocity is calculated as
		//seen below, exept if it is the smallest possible asteroid(size==0),
		//in which case it simply disappears. Furthermore an item is spawned
		//with a propabilty of 5%, and this is eighter barrier(70%) or attack(30%).
		//sorry, those explanations of mine seem to get increasingly boring
		//and bad, which is why i will not  continue them in any partricular
		//order. If you have read this far you should have a basic idea of the
		//structure and control flow of this program(if it can be called structured
		//at all), so everything else should be more or less self-evident.
		//I will add some more comments where i deem them appropiate, however
		//i thank you for reading this far. I really appreciate your interest
		//and am very grateful for you actually looking at this code. I hope my
		//weird, slightly dramatic style of commenting did not shock you too much
		//and you still consider me a partially sane member of society.
		//One last time I will offer you a token of gratitude:
		//GMKBP-H4R7X-GWCG3-CRXJB-HFMDJ
		//Thank you.
		virtual void hit(collision_obj *other)
		{
			//special item case ;-);
			if(other->damage()<0)
				return;
				
			if(size>0)
			{
				//only play sound when the explosion is visible on screen ;-);
				if(explosion_sfx!=0 && position.x+w>0 && position.x<kos_gfx::pvr::SCREEN_WIDTH
				&& position.y+h>0 && position.y<kos_gfx::pvr::SCREEN_HEIGHT)
					kos_gfx::sound::sfx::play(explosion_sfx);
				
				double stren_fact=other->damage()/dmg;
				kos_gfx::math::vector2d<> other_vel=other->vel();
				children.push_back(new asteroid(img[0],img[1],img[2],atk_item_tex,barrier_item_tex,position.x,position.y,-0.1*velocity.x+0.5*stren_fact*other_vel.x,-0.1*velocity.y+other_vel.y,size-1,-0.002));
				children.push_back(new asteroid(img[0],img[1],img[2],atk_item_tex,barrier_item_tex,position.x+img[size].w+1,position.y,1.1*velocity.x+0.5*stren_fact*other_vel.x,1.1*velocity.y+other_vel.y,size-1,-0.002));
				number_of_children+=2;
				
				if(rand()%20==1 && asteroid_item==NULL)
				{
					rectangle_battle::ITEM_TYPE type=rand()%100<30?rectangle_battle::ATTACK:rectangle_battle::BARRIER;
					asteroid_item=new rectangle_battle::item(type==rectangle_battle::ATTACK?atk_item_tex:barrier_item_tex,kos_gfx::math::vector2d<>(position.x,position.y),kos_gfx::math::vector2d<>(0,0),type);
				};
			}
			else
				dead=true;
			
			dying=true;
		};
		
		void update_children()
		{
			for(std::list<asteroid*>::iterator it=children.begin();it!=children.end();++it)
			{
				if((*it)->dead)
				{
					asteroid *tmp=(*it);
					it=children.erase(it);
					delete tmp;
					--it;
					--number_of_children;
				}
				else
					(*it)->update();
			};
		};
		
		void update()
		{
			if(asteroid_item!=NULL)
				asteroid_item->update();
				
			if(dying || dead)
			{
				if(dying)
				{
					update_children();
					if(number_of_children<=0)
						dead=true;
				};
				return;
			};
			
			position+=velocity;
			rot+=rot_speed;
			
			//declare the asteroid dead if it will never be seen again ;-);
			if((position.x+img[size].w<0 && velocity.x<0) ||
			(position.y+img[size].h<0 && velocity.y<0) ||
			(position.x>kos_gfx::pvr::SCREEN_WIDTH && velocity.x>0) ||
			(position.y>kos_gfx::pvr::SCREEN_HEIGHT && velocity.y>0))
				dead=true;
			
			double sign=rot_speed>0?1:-1;
			rot=rot*sign>2*kos_gfx::math::PI?rot-sign*2*kos_gfx::math::PI:rot;
		};
		
		void draw_children()
		{
			for(std::list<asteroid*>::iterator it=children.begin();it!=children.end();++it)
				(*it)->draw();
		};
		
		void draw()
		{
			if(dying)
				draw_children();
			else
				if(!dead)
					kos_gfx::pvr::draw(img[size],position.x,position.y,img[size].w,img[size].h,rot);
			
			if(asteroid_item!=NULL)
				asteroid_item->draw();
		};
	};
	
	//this one explodes slightly different ;-)
	class falling_asteroid:public asteroid
	{
		public:
		falling_asteroid():asteroid()
		{
		};
		
		falling_asteroid(kos_gfx::pvr::texture_fragment img_small,kos_gfx::pvr::texture_fragment img_normal,kos_gfx::pvr::texture_fragment img_big,kos_gfx::pvr::texture_fragment item_atk,kos_gfx::pvr::texture_fragment item_bar,
		double pos_x, double pos_y, double speed_x, double speed_y,int sz=2,double rotation_speed=-0.001):
		asteroid(img_small,img_normal,img_big,item_atk,item_bar,pos_x,pos_y,speed_x,speed_y,sz,rotation_speed)
		{
		};
		
		void hit(collision_obj *other)
		{
			//special item case ;-);
			if(other->damage()<0)
				return;
				
			if(size>0)
			{
				//only play sound when the explosion is visible on screen ;-);
				if(explosion_sfx!=0 && position.x+w>0 && position.x<kos_gfx::pvr::SCREEN_WIDTH
				&& position.y+h>0 && position.y<kos_gfx::pvr::SCREEN_HEIGHT)
					kos_gfx::sound::sfx::play(explosion_sfx);
				
				double stren_fact=other->damage()/dmg;
				kos_gfx::math::vector2d<> other_vel=other->vel();
				children.push_back(new falling_asteroid(img[0],img[1],img[2],atk_item_tex,barrier_item_tex,position.x,position.y,-2,velocity.y+0.5*stren_fact*other_vel.y,size-1,-0.002));
				children.push_back(new falling_asteroid(img[0],img[1],img[2],atk_item_tex,barrier_item_tex,position.x+img[size].w+1,position.y,2,velocity.y+0.5*stren_fact*other_vel.y,size-1,-0.002));
				number_of_children+=2;

				if(rand()%20<8 && asteroid_item==NULL)
				{
					rectangle_battle::ITEM_TYPE type=rand()%100<30?rectangle_battle::ATTACK:rectangle_battle::BARRIER;
					asteroid_item=new rectangle_battle::item(type==rectangle_battle::ATTACK?atk_item_tex:barrier_item_tex,kos_gfx::math::vector2d<>(position.x,position.y),kos_gfx::math::vector2d<>(0,2),type);
				};
			}
			else
				dead=true;
			
			dying=true;
		};
	};
	
};
