function Fleet(owner,planet)
{
	this.id = Fleet.SEQUENCE++;
	this.owner = owner;
	this.ships = [0,0,0,0];
	this.transports = 0;
	
	this.planet = planet;
	
	this.inTransit = false;
	this.destination = null;
	//this.course = [];
	//this.position = [];

	this.courseLength = 0;
	this.courseProgress = 0;
}

Fleet.SEQUENCE = 1;

Fleet.ListByPlanet = function(planet)
{
	var list = [];
	for (var a=0; a<Universe.Players.length; a++)
	{
		var player = Universe.Players[a];
		for (var b=0; b<player.Fleets.length; b++)
		{
			var fleet = player.Fleets[b];
			
			if (fleet.planet == planet && !fleet.inTransit && !fleet.IsEmpty())
			{
				list.push(fleet);
			}
		}
	}
	return list;
}

Fleet.GetByPlanetAndOwner = function(planet,player)
{
	var list = [];
	for (var b=0; b<player.Fleets.length; b++)
	{
		var fleet = player.Fleets[b];
		
		if (fleet.planet == planet && !fleet.inTransit)
		{
			return fleet;
		}
	}
	return null;
}

Fleet.GetByID = function(id)
{
	for (var a=0; a<Universe.Players.length; a++)
	{
		var player = Universe.Players[a];
		for (var b=0; b<player.Fleets.length; b++)
		{
			var fleet = player.Fleets[b];
			
			alert(fleet.id + ", " + id);
			if (fleet.id == id)
			{
				return fleet;
			}
		}
	}
	
	return null;
}



// Given an array of ship counts as strings or floats, return an array of integers (rounded down in the case of float values)
Fleet.Normalize = function(ships)
{
	for (var a=0; a<ships.length; a++)
	{
		if (isNaN(ships[a]))
		{
			ships[a] = Util.ForceInt(ships[a]);
		}
		else
		{
			ships[a] = Math.floor(ships[a]);
		}
	}
	
	return ships;
}

Fleet.prototype.toJSON = function()
{
	return {id:this.id
			,owner:this.owner.race
			,ships:Fleet.Normalize(this.ships)
			,transports:this.transports
			,planet:this.planet.name
			,destination:(this.destination ? this.destination.name : null)
			,inTransit:this.inTransit
			,courseLength:this.courseLength
			,courseProgress:this.courseProgress
			};
}

// returns true if the specified player has sufficient scanning tech to see this fleet
Fleet.prototype.IsVisibleTo = function(player)
{
	if (player.shipLevel >= 3										// Mark IV tech can see everything
		|| (!this.InTransit && this.planet.IsInRange(player))		// near one of the player's planets
		|| (this.destination && this.destination.owner == player) // headed to one of the player's planets
	
		|| (this.InTransit && this.planet.IsInRange(player))		// punt on intransit
	)
	{
		// Mark IV tech can see everything
		return true
	}
	
	// todo - ships in transit
	return false;
}

Fleet.prototype.SetShips = function(ships)
{
	for (var a=0; a<this.ships.length; a++)
	{
		this.ships[a] = Util.ForceInt(ships[a]);
	}
}

Fleet.prototype.GetShipFirepower = function()
{
	var power = 0;
	for (var a=0; a<this.ships.length; a++)
	{
		power += this.ships[a] * Ship.Firepower[a];
	}
	return power;
}

Fleet.prototype.GetTotalFirepower = function()
{
	var power = this.GetShipFirepower();

	if (this.planet.owner == this.owner && this.planet.bases >= 1)
	{
		// factor in base firepower too
		power += this.planet.bases * Ship.Firepower[this.owner.shipLevel] * 10;
	}
		
	return power;
}

Fleet.prototype.Fire = function()
{
	return this.GetTotalFirepower() * (1.2 - Math.random()*0.6);
}

Fleet.prototype.TakeDamages = function(power)
{
	var type = 0;
	
	while (type < this.ships.length)
	{
		while ( power > Ship.Armor[type] && this.ships[type] >= 1 )
		{
			power -= Ship.Armor[type];
			this.ships[type]--;
		}
		type++;		
	}
	
	if (this.planet.owner == this.owner && this.planet.bases >= 1 && power > 0 )
	{
		while ( this.planet.bases >= 1 && power > Ship.Armor[this.owner.shipLevel] )
		{
			power -= Ship.Armor[this.owner.shipLevel];
			this.planet.bases--;
		}
	}
	
}

Fleet.prototype.Fight = function(enemyFleet)
{
	var us = this.Fire();
	var them = enemyFleet.Fire();
	
	var report = new Report(this.owner.name + " vs. " + enemyFleet.owner.name + " @ " + this.planet.name);
	report.reportType = Report.ReportTypes.Combat;
	report.planet = this.planet;
	
	report.appendLine("both fleets engaged:");
	report.appendLine(this.ToString() + " vs. " + enemyFleet.ToString());
	report.appendLine("");
	
	this.TakeDamages(them);
	enemyFleet.TakeDamages(us);


	if (this.IsEmpty() && enemyFleet.IsEmpty())
	{
		report.appendLine("both fleets were completely destroyed.");
	}
	else if (this.IsEmpty())
	{
		report.appendLine("{0}: fleet destroyed completely.", this.owner.name);
		report.appendLine("{0}: fleet survived: {1}", enemyFleet.owner.name, enemyFleet.ToString());
	}
	else if (enemyFleet.IsEmpty())
	{
		report.appendLine("{0}: fleet destroyed completely.", enemyFleet.owner.name);
		report.appendLine("{0}: fleet survived: {1}", this.owner.name, this.ToString());
	}
	else
	{
		report.appendLine("both fleets survived:");
		report.appendLine(this.ToString() + " vs. " + enemyFleet.ToString());
	}
	
	//alert(report.toString());
	
	report.fleet = this;
	this.owner.Reports.push(report);
	
	report.fleet = enemyFleet;
	enemyFleet.owner.Reports.push(report);
}

Fleet.prototype.IsEmpty = function()
{
	if (this.transports > 0)
	{
		return false;
	}
	
	for (var a=0; a<this.ships.length; a++)
	{
		if(this.ships[a] >= 1)
		{
			return false;
		}
	}
	
	return true;
}

/// Can this fleet colonize the planet it's orbiting?
Fleet.prototype.CanColonize = function()
{
	if (!this.inTransit 
		&& this.planet.populationMax > 0
		&& !this.planet.owner
		&& this.GetShipFirepower() >= Ship.ColonyFirepower)
	{
		return true;
	}
}

Fleet.prototype.GetShipCount = function()
{
	return Util.Reduce(function(sum,count){return sum + count;}, this.ships, 0);
}

// Shortcut method to split off a new fleet if necessary and send it on its way
Fleet.prototype.SendTo = function(planet, ships)
{
	ships = Fleet.Normalize(ships);
	var fleets = this.Split(ships);
	if (!fleets[0])
	{
		// whole fleet selected
		this.SetCourse(planet);
	}
	else if (!fleets[1])
	{
		// no ships selected
	}
	else
	{
		// had to split the fleet
		var newFleet = fleets[1];
		newFleet.owner = this.owner;
		newFleet.SetCourse(planet);
		this.owner.Fleets.push(newFleet);
	}
}

// Send this entire fleet to a new planet
Fleet.prototype.SetCourse = function(planet)
{
	this.destination = planet;
	var dx = this.planet.x - planet.x;
	var dy = this.planet.y - planet.y;
	
	this.courseLength =  Math.round(Math.sqrt(dx*dx + dy*dy) / (this.owner.shipLevel+1));
	this.courseProgress = 0;

}

Fleet.prototype.Colonize = function(planet)
{
	if (!this.inTransit 
		&& this.planet == planet 
		&& !this.planet.owner
		&& this.GetShipFirepower() >= Ship.ColonyFirepower)
	{
		planet.owner = this.owner;
		planet.population = 2;
		this.owner.Planets.push(planet);

		this.TakeDamages(Ship.ColonyFirepower);
		if (this.IsEmpty())
		{
			this.Delete();
		}
	}

}



// Split this fleet by specifying an array for the new composition.
// Returns an array containing 2 fleet objects, either of which may be null: [remainder,newfleet]
// case 1: new composition is [0,0,0,0]						-> [fleet, null]
// case 2: new composition == existing fleet composition	-> [null, fleet]
// case 3: new composition is smaller than existing fleet	-> [fleet, fleet]
Fleet.prototype.Split = function(ships)
{
	if (ships == [0,0,0,0])
	{
		return [this,null];
	}
	
	var wholeFleet = true;
	var empty = true;
	for (var a=0; a<ships.length; a++)
	{
		var count = Util.ForceInt(ships[a]);
		wholeFleet = (count >= this.ships[a]) ? wholeFleet : false;
		empty = (count == 0) ? empty : false;
		
	}

	//Util.AlertMulti(empty, wholeFleet);
	if (empty)
	{
		return [this,null];
	}
	if (wholeFleet)
	{
		return [null,this];
	}


	var fleet = new Fleet();
	fleet.owner = this.owner;
	fleet.planet = this.planet;
	
	for (var a=0; a<fleet.ships.length; a++)
	{
		var count = Util.GetMin( Util.ForceInt(ships[a]), this.ships[a]);
		this.ships[a] -= count;
		fleet.ships[a] = count;
	}
	
	return [this,fleet];
}

// Merge the supplied fleet into this one
Fleet.prototype.Merge = function(fleet)
{
	for (var a=0; a<fleet.ships.length; a++)
	{
		this.ships[a] += parseInt(fleet.ships[a]);
	}
	this.transports += fleet.transports;
}

Fleet.prototype.Delete = function()
{
	for (var a=this.owner.Fleets.length-1; a>=0; a--)
	{
		if (this.owner.Fleets[a] == this)
		{
			this.owner.Fleets.splice(a,1);
		}
	}

	if (this.onDelete)
	{
		this.onDelete(this);
	}
	
	if (this.planet.fleet == this)
	{
		// we're the home fleet for a planet.
		this.planet.fleet = null;
	}
	this.owner = null;
	this.planet = null;
	this.destination = null;
}

Fleet.prototype.ToString = function()
{
	return Util.Format("{0}, {1}, {2}, {3}"
		, Math.floor(this.ships[0])
		, Math.floor(this.ships[1])
		, Math.floor(this.ships[2])
		, Math.floor(this.ships[3])
		);
}
