import java.awt.*;
import java.io.*;


public class SpaceShip
{
private int WIDTH;  // width of the toroidal canvas
private int HEIGHT; // height of the toroidal canvas

private V3x1  PIXELS[]; // a local copy of never changing coordinates of every pixel
public  V3x1  pixels[]; // these pixels are for the world to look at
public  Color pcolor[]; // the color of every pixel
private V3x1  DebrisV[];
private V3x1  DebrisP[];
    
private V3x1   Velocity;    // velocity
private double Acceleration;// acceleration
private double Theta;       // orientation angle
private V3x1   Position;    // position vector
private double Omega;       // angular velocity
private double Alpha;       // angular acceleration;
private V3x1   Orientation; // orientation vector
public  int    num;         // number of pixels in the image
public  M3x3   R;           // rotational matrix;

    
private static Color dark_red  = new Color(255, 0, 0);
private static Color dark_blue = new Color(0, 0, 255);
private static Color dark_green= new Color(0, 128, 0);
private static Color green     = new Color(0, 255, 0);
private static Color dark_gray = new Color(96, 64, 64);
private static Color gray      = new Color(128, 128, 128);
private static Color lite_gray = new Color(196, 196, 196);
private static Color colors[] = null;
    
private int    radius;
public  static double Scale = 2;// the pixel resolution of an object
public  int dead;
private int reassamble_count;
    
public SpaceShip(String bitmap, int width, int height, int W_, int H_, int R_, int C_)
    {
	if(colors==null)
	    {
		colors = new Color[17];
		colors[0]  = new Color(0xb8, 0x00, 0x00);
		colors[1]  = new Color(0xd8, 0x00, 0x00);
		colors[2]  = new Color(0xfc, 0x00, 0x00);
		colors[3]  = new Color(0xfc, 0x4c, 0x4c);
		colors[4]  = new Color(0xb4, 0x00, 0xb4);
		colors[5]  = new Color(0xfc, 0xfc, 0x00);
		colors[6]  = new Color(0x98, 0x60, 0x00);
		colors[7]  = new Color(0xd8, 0xbc, 0x00);
		colors[8]  = new Color(0xf4, 0x38, 0xfc);
		colors[9]  = new Color(0xf4, 0x74, 0xfc);
		colors[10] = new Color(0x70, 0x00, 0x70);
		colors[11] = new Color(0x94, 0x00, 0x94);
		colors[12] = new Color(0x98, 0x00, 0x00);
		colors[13] = new Color(0xfc, 0x78, 0x78);
		colors[14] = new Color(0x74, 0x00, 0x00);
		colors[15] = new Color(0xfc, 0x24, 0x24);
		colors[16] = new Color(0xd8, 0x00, 0xd8);
	    }
	
	radius = R_;
	WIDTH  = W_;
	HEIGHT = H_;
	StringBuffer TEMP_STR = new StringBuffer(bitmap);
	int pos=0;
	num=0;
	for(int i=0; i<height; i++)
	    {
		for(int j=0; j<width; j++)
		    {
			try
			    {
				if(TEMP_STR.charAt(pos)!='.')
				    num++;
			    }
			catch(StringIndexOutOfBoundsException e)
			    {
				System.out.println("error: bitmap string parameter to short, fix the HTML file");
				break;
			    }
			pos++;
		    }
	    }
	PIXELS = new V3x1[num];
	pixels = new V3x1[num];
	pcolor = new Color[num];
	pos = 0;
	num = 0;
	
	for(int i=0; i<height; i++)
	    {
		for(int j=0; j<width; j++)
		    {
			try
			    {
				if(TEMP_STR.charAt(pos)!='.')
				    {
					PIXELS[num]=new V3x1(j-(int)(width/2), i-(int)(height/2));
					if(C_==0)
					    {
						if(TEMP_STR.charAt(pos)=='x')
						    pcolor[num]=green;
						else if(TEMP_STR.charAt(pos)=='b')
						    pcolor[num]=dark_blue;
						else if(TEMP_STR.charAt(pos)=='r')
						    pcolor[num]=dark_red;
						else if(TEMP_STR.charAt(pos)=='d')
						    pcolor[num]=dark_green;
						else if(TEMP_STR.charAt(pos)=='g')
						    pcolor[num]=dark_gray;
						else if(TEMP_STR.charAt(pos)=='y')
						    pcolor[num]=gray;
						else if(TEMP_STR.charAt(pos)=='l')
						    pcolor[num]=lite_gray;
						else if(TEMP_STR.charAt(pos)=='o')
						    pcolor[num]=Color.orange;
						else
						    pcolor[num]=Color.black;
					    }
					else
					    {
						pcolor[num]=colors[TEMP_STR.charAt(pos)-'`'];
					    }
					num++;
				    }
			    }		    
			catch(StringIndexOutOfBoundsException e)
			    {
				System.out.println("error: bitmap string parameter to short, fix the HTML file");
				break;
			    }
			pos++;
		    }
	    }
	Orientation  = new V3x1(0,-1);      // orientation vector pointing straight down (up in the canvas coordinates)
	Position     = new V3x1((int)(WIDTH/2), (int)(HEIGHT/2)); 
	Acceleration = 1;                   // acceleration
	Velocity     = new V3x1(0, 0);      // velocity vector
	Omega = 0;                          // angular velocity
	Alpha = Math.PI/90;                 // angular acceleration
	Theta = 0;                          // orientation angle
	dead = 0;
    }

    
public SpaceShip(SpaceShip UFO, String bitmap, int width, int height, int W_, int H_, int R_, int C_)
    {
	radius = R_;
	WIDTH  = W_;
	HEIGHT = H_;
	StringBuffer TEMP_STR = new StringBuffer(bitmap);
	int pos=0;
	num=0;
	for(int i=0; i<height; i++)
	    {
		for(int j=0; j<width; j++)
		    {
			try
			    {
				if(TEMP_STR.charAt(pos)!='.')
				    num++;
			    }
			catch(StringIndexOutOfBoundsException e)
			    {
				System.out.println("error: bitmap string parameter to short, fix the HTML file");
				break;
			    }
			pos++;
		    }
	    }
	PIXELS = new V3x1[num];
	pixels = new V3x1[num];
	pcolor = new Color[num];
	pos = 0;
	num = 0;
	
	for(int i=0; i<height; i++)
	    {
		for(int j=0; j<width; j++)
		    {
			try
			    {
				if(TEMP_STR.charAt(pos)!='.')
				    {
					PIXELS[num]=new V3x1(j-(int)(width/2), i-(int)(height/2));
					if(C_==0)
					    {
						if(TEMP_STR.charAt(pos)=='x')
						    pcolor[num]=green;
						else if(TEMP_STR.charAt(pos)=='b')
						    pcolor[num]=dark_blue;
						else if(TEMP_STR.charAt(pos)=='r')
						    pcolor[num]=dark_red;
						else if(TEMP_STR.charAt(pos)=='d')
						    pcolor[num]=dark_green;
						else if(TEMP_STR.charAt(pos)=='g')
						    pcolor[num]=dark_gray;
						else if(TEMP_STR.charAt(pos)=='y')
						    pcolor[num]=gray;
						else if(TEMP_STR.charAt(pos)=='l')
						    pcolor[num]=lite_gray;
						else if(TEMP_STR.charAt(pos)=='o')
						    pcolor[num]=Color.orange;
						else
						    pcolor[num]=Color.black;
					    }
					else
					    {
						pcolor[num]=colors[TEMP_STR.charAt(pos)-'`'];
					    }
					num++;
				    }
			    }
			catch(StringIndexOutOfBoundsException e)
			    {
				System.out.println("error: bitmap string parameter to short, fix the HTML file");
				break;
			    }
			pos++;
		    }
	    }
	Orientation  = new V3x1(UFO.Orientation);// orientation vector must be copied from the parent ship
	Position     = new V3x1(UFO.Position);
	V3x1 TEMP    = new V3x1(Orientation, (double)(UFO.radius*SpaceShip.Scale*2));
	Position.add(TEMP);
	Acceleration = UFO.Acceleration*20;
	Velocity     = new V3x1(UFO.Velocity);
	Omega = 0;
	Alpha = 0;
	Theta = UFO.Theta;
	dead = 0;
    }

public void reset(String bitmap, int width, int height, int W_, int H_, int R_, int C_)
    {
	int NUM = num;
	radius = R_;
	WIDTH  = W_;
	HEIGHT = H_;
	StringBuffer TEMP_STR = new StringBuffer(bitmap);
	int pos=0;
	num=0;
	for(int i=0; i<height; i++)
	    {
		for(int j=0; j<width; j++)
		    {
			try
			    {
				if(TEMP_STR.charAt(pos)!='.')
				    num++;
			    }
			catch(StringIndexOutOfBoundsException e)
			    {
				System.out.println("error: bitmap string parameter to short, fix the HTML file");
				break;
			    }
			pos++;
		    }
	    }
	PIXELS = new V3x1[num];
	pixels = new V3x1[num];
	pcolor = new Color[num];
	pos = 0;
	num = 0;
	
	for(int i=0; i<height; i++)
	    {
		for(int j=0; j<width; j++)
		    {
			try
			    {
				if(TEMP_STR.charAt(pos)!='.')
				    {
					PIXELS[num]=new V3x1(j-(int)(width/2), i-(int)(height/2));
					if(C_==0)
					    {
						if(TEMP_STR.charAt(pos)=='x')
						    pcolor[num]=green;
						else if(TEMP_STR.charAt(pos)=='b')
						    pcolor[num]=dark_blue;
						else if(TEMP_STR.charAt(pos)=='r')
						    pcolor[num]=dark_red;
						else if(TEMP_STR.charAt(pos)=='d')
						    pcolor[num]=dark_green;
						else if(TEMP_STR.charAt(pos)=='g')
						    pcolor[num]=dark_gray;
						else if(TEMP_STR.charAt(pos)=='y')
						    pcolor[num]=gray;
						else if(TEMP_STR.charAt(pos)=='l')
						    pcolor[num]=lite_gray;
						else if(TEMP_STR.charAt(pos)=='o')
						    pcolor[num]=Color.orange;
						else
						    pcolor[num]=Color.black;
					    }
					else
					    {
						pcolor[num]=colors[TEMP_STR.charAt(pos)-'`'];
					    }
					num++;
				    }
			    }
			catch(StringIndexOutOfBoundsException e)
			    {
				System.out.println("error: bitmap string parameter to short, fix the HTML file");
				break;
			    }
			pos++;
		    }
	    }
	if(dead != 0)
	    {
		if(num>NUM)
		    {
			V3x1 DebrisV_TEMP[] = new V3x1[num];
			V3x1 DebrisP_TEMP[] = new V3x1[num];
			for(int i=0; i<NUM; i++)
			    {
				DebrisV_TEMP[i] = DebrisV[i];
				DebrisP_TEMP[i] = DebrisP[i];
			    }
			for(int i=NUM; i<num; i++)
			    {
				DebrisV_TEMP[i] = DebrisV[i%NUM];
				DebrisP_TEMP[i] = DebrisP[i%NUM];
			    }
			DebrisV = null;
			DebrisP = null;
			DebrisV = DebrisV_TEMP;
			DebrisP = DebrisP_TEMP;
		    }
	    }
    }
    
public void accelerate()
    { 
	if(dead == 0)
	    {
		V3x1 temp = new V3x1(Orientation, Acceleration);
		Velocity.add(temp); // allways accelerate in the direction of orientation vector times 1(m/s**2)
		temp = null;
	    }
    }

public void deaccelerate()
    {
	if(dead == 0)
	    {
		V3x1 temp = new V3x1(Orientation, -Acceleration);
		Velocity.add(temp); // allways deaccelerate in the direction of orientation vector times 1(m/s**2)
		temp = null;
	    }
    }
    

public void rotate_ccw()
    {
	if(dead == 0)
	    Omega = Omega - Alpha; // speedup counter clockwise rotation
    }
    

public void rotate_cw()
    {
	if(dead == 0)
	    Omega = Omega + Alpha; // speedup clockwise rotation
    }

    
public boolean collision(SpaceShip ship)
    {
	if(dead==0 && ship.dead==0)
	    {
		double x1=Position.V[0];
		double y1=Position.V[1];
		double x2=ship.Position.V[0];
		double y2=ship.Position.V[1];
		int D1 = (radius + ship.radius)*(int)(SpaceShip.Scale);
		int D2 = 0;
		try
		    {
			D2 = (int)(Math.sqrt(Math.pow(x1-x2, 2)+Math.pow(y1-y2, 2)));
		    }
		catch (ArithmeticException e)
		    {
		    }
		if(D2<D1)
		    {
			return true;
		    }
	    }
	return false;
    }

public void explode()
    {
	if(dead==0)
	    {
		dead = 1;
		DebrisV = new V3x1[num];
		DebrisP = new V3x1[num];
		for(int i=0; i<num; i++)
		    {
			DebrisV[i] = new V3x1(0,0);
			double angle = Math.PI*2*Math.random();
			M3x3 R = new M3x3(angle);
			V3x1 Ortion = new V3x1(R, new V3x1(0, -1));
			V3x1 temp = new V3x1(Ortion, Acceleration);
			DebrisV[i].add(temp);
			temp = null;
			DebrisP[i] = new V3x1(PIXELS[i]);
		    }
	    }
    }


public void reassemble()
    {
	if(dead==1)
	    {
		dead = 2;
		reassamble_count = 25;
		for(int i=0; i<num; i++)
		    {
/*		    
			if(SpaceShip.Scale*DebrisP[i].V[0]+Position.V[0]>WIDTH)
			    DebrisP[i].V[0]=((SpaceShip.Scale*DebrisP[i].V[0]+Position.V[0])%WIDTH-Position.V[0])/SpaceShip.Scale;
			if(SpaceShip.Scale*DebrisP[i].V[0]+Position.V[0]<0)
			    DebrisP[i].V[0]=((SpaceShip.Scale*DebrisP[i].V[0]+Position.V[0])%WIDTH+Position.V[0])/SpaceShip.Scale;
			if(SpaceShip.Scale*DebrisP[i].V[1]+Position.V[1]>HEIGHT)
			    DebrisP[i].V[1]=((SpaceShip.Scale*DebrisP[i].V[1]+Position.V[1])%HEIGHT-Position.V[1])/SpaceShip.Scale;
			if(SpaceShip.Scale*DebrisP[i].V[1]+Position.V[1]<0)
			    DebrisP[i].V[1]=((SpaceShip.Scale*DebrisP[i].V[1]+Position.V[1])%HEIGHT+Position.V[1])/SpaceShip.Scale;
*/
			DebrisV[i]=new V3x1(PIXELS[i], DebrisP[i], '-');
			DebrisV[i].mult(0.04);
		    }
	    }
    }

public void move()
    {
	if(dead==0)
	    {
		Theta = Theta + Omega;
		R = new M3x3(Theta);
		Orientation = null;
		Orientation = new V3x1(R, new V3x1(0, -1));
		Position.add(Velocity);
		if(Position.V[0]>WIDTH)
		    Position.V[0]-=WIDTH;
		else if(Position.V[0]<0)
		    Position.V[0]+=WIDTH;
		if(Position.V[1]>HEIGHT)
		    Position.V[1]-=HEIGHT;
		else if(Position.V[1]<0)
		    Position.V[1]+=HEIGHT;
		M3x3 T = new M3x3(Position.V[0], Position.V[1], 't');
		M3x3 M = new M3x3(T, R);
		for(int i=0; i<num; i++)
		    {
			pixels[i] = null;
			V3x1 scaled = new V3x1(PIXELS[i], SpaceShip.Scale);
			pixels[i] = new V3x1(M, scaled);// i prefer to scale this way because it takes less multiplications
			scaled = null;
			
			if(pixels[i].V[0]>WIDTH)
			    pixels[i].V[0]-=WIDTH;
			else if(pixels[i].V[0]<0)
			    pixels[i].V[0]+=WIDTH;
			
			if(pixels[i].V[1]>HEIGHT)
			    pixels[i].V[1]-=HEIGHT;
			else if(pixels[i].V[1]<0)
			    pixels[i].V[1]+=HEIGHT;
		    }
	    }
	else if(dead==1)
	    {		
		Theta = Theta + Omega;
		R = new M3x3(Theta);
		Orientation = null;
		Orientation = new V3x1(R, new V3x1(0, -1));
		Position.add(Velocity);
		if(Position.V[0]>WIDTH)
		    Position.V[0]-=WIDTH;
		else if(Position.V[0]<0)
		    Position.V[0]+=WIDTH;
		if(Position.V[1]>HEIGHT)
		    Position.V[1]-=HEIGHT;
		else if(Position.V[1]<0)
		    Position.V[1]+=HEIGHT;
		M3x3 T = new M3x3(Position.V[0], Position.V[1], 't');
		M3x3 M = new M3x3(T, R);

		for(int i=0; i<num; i++)
		    {
			DebrisP[i].add(DebrisV[i]);
			pixels[i] = null;
			V3x1 scaled = new V3x1(DebrisP[i], SpaceShip.Scale);
			pixels[i] = new V3x1(M, scaled);// i prefer to scale this way because it takes less multiplications
			scaled = null;
			
			if(pixels[i].V[0]>WIDTH)
			    pixels[i].V[0]=pixels[i].V[0]%WIDTH;
			else if(pixels[i].V[0]<0)
			    pixels[i].V[0]=pixels[i].V[0]%WIDTH+WIDTH;
			
			if(pixels[i].V[1]>HEIGHT)
			    pixels[i].V[1]=pixels[i].V[1]%HEIGHT;
			else if(pixels[i].V[1]<0)
			    pixels[i].V[1]=pixels[i].V[1]%HEIGHT+HEIGHT;
		    }
	    }
	else if(dead==2)
	    {
		Theta = Theta + Omega;
		R = new M3x3(Theta);
		Orientation = null;
		Orientation = new V3x1(R, new V3x1(0, -1));
		Position.add(Velocity);
		if(Position.V[0]>WIDTH)
		    Position.V[0]-=WIDTH;
		else if(Position.V[0]<0)
		    Position.V[0]+=WIDTH;
		if(Position.V[1]>HEIGHT)
		    Position.V[1]-=HEIGHT;
		else if(Position.V[1]<0)
		    Position.V[1]+=HEIGHT;
		M3x3 T = new M3x3(Position.V[0], Position.V[1], 't');
		M3x3 M = new M3x3(T, R);
		
		for(int i=0; i<num; i++)
		    {
			DebrisP[i].add(DebrisV[i]);
			pixels[i] = null;
			V3x1 scaled = new V3x1(DebrisP[i], SpaceShip.Scale);
			pixels[i] = new V3x1(M, scaled);// i prefer to scale this way because it takes less multiplications
			scaled = null;
			
			if(pixels[i].V[0]>WIDTH)
			    pixels[i].V[0]=pixels[i].V[0]%WIDTH;
			else if(pixels[i].V[0]<0)
			    pixels[i].V[0]=pixels[i].V[0]%WIDTH+WIDTH;
			
			if(pixels[i].V[1]>HEIGHT)
			    pixels[i].V[1]=pixels[i].V[1]%HEIGHT;
			else if(pixels[i].V[1]<0)
			    pixels[i].V[1]=pixels[i].V[1]%HEIGHT+HEIGHT;
		    }
		reassamble_count--;
		if(reassamble_count<1)
		    dead = 0;
	    }
    }
    
public void dump()
    {
	System.out.print("number of PIXELS in bitmap: ");
	System.out.println(num);
	Position.dump();
    }
}

