package net.phatcode.rel;

import net.phatcode.rel.math.Utils;
import net.phatcode.rel.math.Vector2D;

public class Turret
{
	 
	protected class BulletInfo
	{
		Vector2D gravity = new Vector2D();		 	// This makes the bullets sway to a direction
		Vector2D target = new Vector2D();			// Default bullet target
		float angle = 0; 							
		float speed = 5; 
		float acceleration = 0; 					// for accelerated bullets
		int stopCounter = 0;						// ticks when bullets should stop
		int goCounter = -1;							// ticks(relative to stopCounter) when bullets move again after stopping 
		boolean aim = false;						// changes direction to target after stopping
		boolean seekPlayer = false;					// seeks the player after stopping
		Animator animator = new Animator(19,3); 	
		Behavior behavior = new BehaviorAccelerated(); 			// default behavior
		Behavior nextBehavior = new BehaviorLinear(); 		// behavior after stopping
		int aabbSize = 1;									// collision box size
			
	}
	
	public boolean active = false;
	public Vector2D position = new Vector2D();		// center position of the turret
	public float angle = 3.141592653589793f / 2;							// start angle
	public float minAngle = 0;						// angle values to clamp or
	public float maxAngle = 3.141592653589793f * 2;	//     wrap the angle
	public float angleDelta = 0;					// speed of rotation 
	public int   angleDirection = 1;				// -1 or 1 (direction of rotation)
	public int 	 numBullets = 1; 					// bullets per shot
	public float xRadius = 0;						// radius of the shots from the
	public float yRadius = 0;						//     center
	public float speedDelta = 0;					// speed factor of each bullet from center to the sides
	public float sectorLength = 0;					// arc length of the shots (numBullets within the sector)				
	public boolean seekPlayer = true;				// whether turret targets the player
	public boolean symmetrical = true;				// speedDelta behavior : true = center to sides; false = side to other side 
	
	public int waveOffset = 0;						// even bullets = numBullets + waveOffset; odd jusst numbullets
	private int tempWaveOffset = 0;					// variable to save waveOffset
	
	private int shotsPerWave = 1;					// number of shots each wave fires
	
	private int delayPerSpawn = 4; 					// delay before firing each shot * numBullets
	private int delayPerWave = 4; 					// delay before each wave fires
	
	private int spawnDelay = 1;						// internal shot counter
	private int waveDelay = 0;						// internal wave counter
	
	private int	waveCounter = 0;			 		// internal variable to check if all shots in a wave are done 
	
	protected TurretBehavior rotateBehavior = new TurretRotateBehaviorDefault();
	protected TurretBehavior fireBehavior = new TurretFireBehaviorSpread();
	
	private BulletInfo bulletInfo = new BulletInfo();
	
	
	public Turret()
	{
		
		active = false;
		
	}
	
	
	public void update( BulletFactory bulletFactory, Vector2D playerShipPosition )
	{
		
		
		if( (--waveDelay) < 0 )
		{	
			if( (--spawnDelay) < 0 )
			{
				if( seekPlayer )
				{
					angle = Vector2D.angleBetween(position, playerShipPosition);
				}
				
				spawnDelay = delayPerSpawn; 
				fireBehavior.update( this, bulletFactory );
				
				
				waveOffset = tempWaveOffset * ( waveCounter & 1 );
						
				if( (++waveCounter) >= shotsPerWave) 
				{
					waveCounter = 0;
					waveDelay = delayPerWave;
					if( !seekPlayer )
					{
						rotateBehavior.update(this);
					}
				}
				
			}
		}
			
	}
	
	public void setPattern( BulletPattern bulletPattern )
	{
		
		
		setBulletParameters(  
				bulletPattern.bulletInfo.gravity,
				bulletPattern.bulletInfo.target,
				bulletPattern.bulletInfo.angle, 
				bulletPattern.bulletInfo.speed, 
				bulletPattern.bulletInfo.acceleration, 
				bulletPattern.bulletInfo.stopCounter,
				bulletPattern.bulletInfo.goCounter,
				bulletPattern.bulletInfo.aim,
				bulletPattern.bulletInfo.seekPlayer,
				bulletPattern.bulletInfo.animator, 
				bulletPattern.bulletInfo.behavior, 
				bulletPattern.bulletInfo.nextBehavior, 
				bulletPattern.bulletInfo.aabbSize );
		
		this.numBullets = bulletPattern.waveInfo.numBullets; 
		this.xRadius = bulletPattern.waveInfo.xRadius;
		this.yRadius = bulletPattern.waveInfo.yRadius;
		this.speedDelta = bulletPattern.waveInfo.speedDelta;
		this.sectorLength = bulletPattern.waveInfo.sectorLength;
		this.symmetrical = bulletPattern.waveInfo.symmetrical;	
		   
		this.shotsPerWave = bulletPattern.waveInfo.shotsPerWave;
		this.delayPerSpawn = bulletPattern.waveInfo.delayPerSpawn; 
		this.delayPerWave = bulletPattern.waveInfo.delayPerWave; 
		this.waveOffset = bulletPattern.waveInfo.waveOffset; 
		this.tempWaveOffset = bulletPattern.waveInfo.waveOffset; 
		
			
	}
	
	public void setBehaviorInfo( float angle,
							   	 float minAngle,
							   	 float maxAngle,
							   	 float angleDelta,
							   	 int angleDirection,
							   	 boolean seekPlayer,
							   	 TurretBehavior rotateBehavior,
							   	 TurretBehavior fireBehavior )
	{
	
		angle = Utils.wrap( angle, minAngle, maxAngle );
		
		this.angle = angle;
		this.minAngle = minAngle;
		this.maxAngle = maxAngle;
		this.angleDelta = angleDelta;
		this.angleDirection = angleDirection;
		this.seekPlayer = seekPlayer;
		this.rotateBehavior = rotateBehavior;
		this.fireBehavior = fireBehavior;
		
	
	}

	public void setParameters( Vector2D position,
							   float angle,
							   float minAngle,
							   float maxAngle,
							   float angleDelta,
							   int angleDirection,
							   int numBullets, 
							   float xRadius,
							   float yRadius,
							   float speedDelta,
							   float sectorLength,
							   boolean seekPlayer,
							   boolean symmetrical,
							   int shotsPerWave,
							   int delayPerSpawn, 
							   int delayPerWave, 
							   int waveOffset, 
							   TurretBehavior rotateBehavior,
							   TurretBehavior fireBehavior )
	{
		
		angle = Utils.wrap( angle, minAngle, maxAngle );
		
		this.position.set(position);
		this.angle = angle;
		this.minAngle = minAngle;
		this.maxAngle = maxAngle;
		this.angleDelta = angleDelta;
		this.angleDirection = angleDirection;
		
		this.numBullets = numBullets; 
		this.xRadius = xRadius;
		this.yRadius = yRadius;
		this.speedDelta = speedDelta;
		this.sectorLength = sectorLength;
		this.seekPlayer = seekPlayer;	
		this.symmetrical = symmetrical;	
		   
		this.rotateBehavior = rotateBehavior;
		this.fireBehavior = fireBehavior;
		
		this.shotsPerWave = shotsPerWave;
		this.delayPerSpawn = delayPerSpawn; 
		this.delayPerWave = delayPerWave; 
		this.waveOffset = waveOffset; 
		this.tempWaveOffset = waveOffset; 
			
	}
	
	public void setBulletParameters(  Vector2D gravity,
						   			  Vector2D target,
						   			  float angle, 
						   			  float speed, 
						   			  float acceleration, 
						   			  int stopCounter,
						   			  int goCounter,
						   			  boolean aim,
						   			  boolean seekPlayer,
						   			  Animator animator, 
						   			  Behavior behavior, 
						   			  Behavior nextBehavior, 
						   			  int aabbSize )
	{
		
		bulletInfo.gravity.set( gravity );
		bulletInfo.target.set( target );
		bulletInfo.angle = angle;
		bulletInfo.speed = speed;
		bulletInfo.acceleration = acceleration;
		bulletInfo.stopCounter = stopCounter;
		bulletInfo.goCounter = goCounter;
		bulletInfo.aim = aim;
		bulletInfo.seekPlayer = seekPlayer;
		bulletInfo.animator = animator;
		bulletInfo.behavior = behavior;
		bulletInfo.nextBehavior = nextBehavior;
		bulletInfo.aabbSize = aabbSize;
		
	}
	
	
	
	public boolean isActive()
	{
		return active;
	}


	public void setActive(boolean active)
	{
		this.active = active;
	}


	public BulletInfo getBulletInfo()
	{
		return bulletInfo;
	}

	public Vector2D getPosition()
	{
		return position;
	}

	public float getAngle()
	{
		return angle;
	}

	public float getMinAngle()
	{
		return minAngle;
	}

	public float getMaxAngle()
	{
		return maxAngle;
	}

	public float getAngleDelta()
	{
		return angleDelta;
	}

	public int getAngleDirection()
	{
		return angleDirection;
	}

	public int getNumBullets()
	{
		return numBullets;
	}

	public float getxRadius()
	{
		return xRadius;
	}

	public float getyRadius()
	{
		return yRadius;
	}

	public float getSpeedDelta()
	{
		return speedDelta;
	}

	public float getSectorLength()
	{
		return sectorLength;
	}

	public boolean isSeekPlayer()
	{
		return seekPlayer;
	}

	public boolean isSymmetrical()
	{
		return symmetrical;
	}

	public int getWaveOffset()
	{
		return waveOffset;
	}

	public TurretBehavior getRotateBehavior()
	{
		return rotateBehavior;
	}

	public TurretBehavior getFireBehavior()
	{
		return fireBehavior;
	}

	public void setPosition(Vector2D position)
	{
		this.position = position;
	}

	public void setPosition( float x, float y )
	{
		position.set(x,y);
	}

	public void setAngle(float angle)
	{
		this.angle = angle;
	}

	public void setMinAngle(float minAngle)
	{
		this.minAngle = minAngle;
	}

	public void setMaxAngle(float maxAngle)
	{
		this.maxAngle = maxAngle;
	}

	public void setAngleDelta(float angleDelta)
	{
		this.angleDelta = angleDelta;
	}

	public void setAngleDirection(int angleDirection)
	{
		this.angleDirection = angleDirection;
	}

	public void setNumBullets(int numBullets)
	{
		this.numBullets = numBullets;
	}

	public void setxRadius(float xRadius)
	{
		this.xRadius = xRadius;
	}

	public void setyRadius(float yRadius)
	{
		this.yRadius = yRadius;
	}

	public void setSpeedDelta(float speedDelta)
	{
		this.speedDelta = speedDelta;
	}

	public void setSectorLength(float sectorLength)
	{
		this.sectorLength = sectorLength;
	}

	public void setSeekPlayer(boolean seekPlayer)
	{
		this.seekPlayer = seekPlayer;
	}

	public void setSymmetrical(boolean symmetrical)
	{
		this.symmetrical = symmetrical;
	}

	public void setWaveOffset(int waveOffset)
	{
		this.waveOffset = waveOffset;
	}

	public void setRotateBehavior(TurretBehavior rotateBehavior)
	{
		this.rotateBehavior = rotateBehavior;
	}

	public void setFireBehavior(TurretBehavior fireBehavior)
	{
		this.fireBehavior = fireBehavior;
	}

	public int getShotsPerWave()
	{
		return shotsPerWave;
	}

	public int getDelayPerSpawn()
	{
		return delayPerSpawn;
	}

	public int getDelayPerWave()
	{
		return delayPerWave;
	}

	public int getSpawnDelay()
	{
		return spawnDelay;
	}

	public int getWaveDelay()
	{
		return waveDelay;
	}

	public void setShotsPerWave(int shotsPerWave)
	{
		this.shotsPerWave = shotsPerWave;
	}

	public void setDelayPerSpawn(int delayPerSpawn)
	{
		this.delayPerSpawn = delayPerSpawn;
	}

	public void setDelayPerWave(int delayPerWave)
	{
		this.delayPerWave = delayPerWave;
	}

	public void setSpawnDelay(int spawnDelay)
	{
		this.spawnDelay = spawnDelay;
	}

	public void setWaveDelay(int waveDelay)
	{
		this.waveDelay = waveDelay;
	}
		
	public void kill()
	{
		active = false;
		spawnDelay = 1;						// internal shot counter
		waveDelay = 0;						// internal wave counter
		waveCounter = 0;			 		// internal variable to check if all shots in a wave are done 
		
	}
	
	
		
}   // end class
