function Planet(x,y,name)
{
	this.x = x;
	this.y = y;
	this.name = name;
	
	this.environment = Util.RandInt(Planet.Environments.length);
	this.population = 0;
	this.SetPopulationMax();
	this.factories = 0;
	this.bases = 0;
	this.waste = 0;
	this.owner = null;
	
	//this.fleet = null;
	
	this.priority = [0,0,100,0,0];	// ship,base,industry,ecology,research
	
}

Planet.Priorities = {"Ship":0,"Base":1,"Industry":2,"Ecology":3,"Research":4}
Planet.Names = ["Sol","Fierias","Cryslon","Sssla","Mentar","Paranar","Kholdan","Ursa","Meklon","Nazin","Denubius","Draconis","Zoctan","Talas","Moro","Quayal","Neptunus","Jinga","Argus","Escalon","Berel","Collassa","Whynil","Nordia","Tau","Phyco","Firma","Keeta","Arietis","Rhilus","Willow","Mu","Delphi","Stalaz","Gorra","Beta","Ceti","Omicron","Rha","Kailis","Vulcan","Centauri","Herculis","Endoria","Kulthos","Hyboria","Zhardan","Yarrow","Incedius","Paladia","Romulas","Galos","Uxmai","Thrax","Laan","Imra","Selia","Seidon","Tao","Rana","Vox","Maalor","Xudax","Helos","Crypto","Gion","Phantos","Reticuli","Maretta","Toranor","Exis","Tyr","Ajax","Obaca","Dolz","Drakka","Ryoun","Anraq","Rotan","Proxima","Mobas","Iranha","Celtsi","Dunatis","Morrig","Primodius","Nyarl","Ukko","Crius","Hyades","Kronos","Guradas","Rayden","Kakata","Misha","Xendalla","Artemis","Aurora","Proteus","Esper","Darrian","Trax","Xengara","Nitzer","Simius","Bootis","Pollus","Cygni","Aquilae","Volantis","Tauri","Klystron","Lyae","Alcor","Castor","Antares","Diphda"
				,"Procyon","Kochab","Adara","Agena","Saiph","Vega","Nihal","Algol","Schedar","Rastaban","Izar","Mirzam","Alioth","Etamin","Wesen","Nunki","Sirius","Ascella","Spica","Dubhe","Arneb","Gemma","Wolf","Canopus","Shedir","Mintaka","Phaeda","Altair","Sabik","Mizar","Enif","Furud","Polaris","Pollux","Aludra","Megrez","Regulus","Nath","Hamal","Capella","Thuban","Caph","Rigel","Gienah","Deneb","Almak","Alhena","Zosma","Acrux","Ross","Tarazed"];
Planet.Environments = ["Terran", "Jungle", "Ocean", "Arid", "Steppe", "Desert", "Minimal", "Barren", "Tundra", "Dead", "Inferno", "Toxic", "Radiated", "None"];
Planet.PopulationRanges = [[80,100],[70,100],[60,100],[40,70],[40,70],[30,60],[20,50],[20,40],[10,40],[10,40],[10,40],[10,40],[10,40],[0,0]]

Planet.ListInRange = function(player, excludePlayerOwned)
{
	var list = [];
	for (var a=0; a<Universe.Planets.length; a++)
	{
		var planet = Universe.Planets[a];
		if (planet.IsInRange(player) && (!excludePlayerOwned || planet.owner != player))
		{
			list.push(planet);
		}
	}
	
	return list;
}

Planet.GetByName = function(planetName)
{
	// .Load()ed Universes will have a hash we can look in.
	if (Universe.PlanetHash)
	{
		var planet = Universe.PlanetHash[planetName];
		if (planet)
		{
			return planet;
		}
	}
	
	for (var a=0; a<Universe.Planets.length; a++)
	{
		var planet = Universe.Planets[a];
		if (planet.name == planetName)
		{
			return planet;
		}
	}
	
	alert("planet not found: " + planetName);
}

Planet.prototype.toJSON = function()
{
	return {name:this.name
			,x:this.x
			,y:this.y
			,environment:Math.floor(this.environment)
			,population:Math.floor(this.population)
			,populationMax:this.populationMax
			,factories:Math.floor(this.factories)
			,bases:Math.floor(this.bases)
			,waste:Math.floor(this.waste)
			,priority:this.priority
			,owner:(this.owner ? this.owner.race : null)
			};
}

Planet.prototype.ToOrders = function()
{
	//this.priority[Planet.Priorities.Base] = 50;
	return this.priority;
}

Planet.prototype.SetPopulationMax = function()
{
	var min = Planet.PopulationRanges[this.environment][0];
	var max = Planet.PopulationRanges[this.environment][0];
	
	this.populationMax = Util.RandInt((max-min)/5)*5 + min;
}

Planet.prototype.GetDistance = function(planet)
{
	var dx = this.x - planet.x;
	var dy = this.y - planet.y;
	
	return Math.round(Math.sqrt(dx*dx + dy*dy));
}

Planet.prototype.IsInRange = function(player)
{

	var shipRange = 3 + player.shipLevel * 2;
	for (var a=0; a<player.Planets.length; a++)
	{
		if (this.GetDistance(player.Planets[a]) <= shipRange)
		{

			return true;
		}
	}
	
	return false;
}


Planet.prototype.GetWorkingFactories = function()
{
	return Util.GetMin(this.factories, this.population * this.owner.factoriesPerWorker);
}

Planet.prototype.GetProduction = function()
{
	if (!this.owner)
	{
		return 0;
	}
	
//	var workingFactories = Util.GetMin(this.factories, this.population * this.owner.factoriesPerWorker);
	//alert(this.population + ", " + this.factories + ", " + workingFactories);
	
	return Math.floor(this.population * this.owner.workerProduction + this.GetWorkingFactories() * this.owner.factoryProduction);
}

Planet.prototype.GetMaintenance = function()
{
	if (!this.owner)
	{
		return 0;
	}
	
	// TODO - ship and base maintenance
	return 0;
}

// adjust spending ratio so that Ecology at least balances waste
Planet.prototype.AdjustEcology = function()
{
	if (!this.owner)
	{
		return;
	}
	
	//var wastePerTurn = this.GetWorkingFactories() * this.owner.wastePerFactory;
	var wastePerTurn = this.GetWorkingFactories() * this.owner.wastePerFactory + this.waste;
	

	// todo - add existing waste into this	
	var minWastePercentage = Util.GetMin( Math.ceil(wastePerTurn * this.owner.wasteCleanupCost / (this.GetProduction() - this.GetMaintenance()) * 100), 100);
	

	this.priority[Planet.Priorities.Ecology] = minWastePercentage+1;
	var sum = 0;
	Util.Map(this.priority, function(val){sum += val;});
	
if (this.name == "Sol")
{
//	alert(wastePerTurn + " wasteperturn, " + this.waste + " waste, " + this.GetWorkingFactories() * this.owner.wastePerFactory);
	//alert(minWastePercentage + ", " + sum);
}
	
	for (var a=0; a<this.priority.length; a++)
	{
		if (a != Planet.Priorities.Ecology)
		{
			this.priority[a] = Math.floor(this.priority[a] * (100-minWastePercentage)/(sum-minWastePercentage));
		}
	}
}

Planet.prototype.AdjustIndustry = function()
{
	if (this.factories >= this.populationMax * 2)
	{
		this.priority[Planet.Priorities.Research] += this.priority[Planet.Priorities.Industry];
		this.priority[Planet.Priorities.Industry] = 0;
	}
}

Planet.prototype.NormalizePriorities = function()
{
	//alert(this.priority);
	
	var sum = 0;
	Util.Map(this.priority, function(val){sum += val;});
	
	/*
	for (var a=0; a<this.priority.length; a++)
	{
		sum += this.priority[a];
	}
	*/
	
	if (sum != 100)
	{
		for (var a=0; a<this.priority.length; a++)
		{
			this.priority[a] = Math.floor(this.priority[a] * 100/sum);
		}
		
//		Util.Map(this.priority, function(a){this.priority[a] *= 100/sum;});
	}
}

Planet.prototype.TransportTo = function(planet, count)
{
	if (count < this.population / 2)
	{
		var fleet = new Fleet(this.owner, this);
		fleet.transports = count;
		fleet.SetCourse(planet);
		this.owner.Fleets.push(fleet);
		
		this.population -= count;
	}
}

Planet.prototype.ResolveSpaceConflicts = function()
{
	var fleets = Fleet.ListByPlanet(this);
	if (fleets.length > 0)
	{
		// TODO - randomize order of fleets in the array
		
		// TODO - deal with other possibilites than everybody fighting everybody

		// fight eachother		
		var foundOwner = false;
		for (var a=0; a<fleets.length; a++)
		{
			foundOwner = foundOwner || (fleets[a].owner == this.owner);
			for (var b=0; b<fleets.length; b++)
			{
				if (a<b)
				{
					fleets[a].Fight(fleets[b]);
				}
				
			}
		}
		
		//alert(foundOwner + ", " + this.bases);
		// fight the planet (if it didn't have a fleet)
		if (!foundOwner && this.bases >= 1)
		{
//alert("no fleet, but bases: " + planet.name);		
			var fleet = new Fleet(this.owner, this);
			for (var b=0; b<fleets.length; b++)
			{
				if (fleets[b].owner != fleet.owner)
				{
					fleet.Fight(fleets[b]);
				}
				
			}
		}
		
		// kill off the losers
		for (var a=0; a<fleets.length; a++)
		{
			if (fleets[a].IsEmpty())
			{
				//alert(fleets[a].owner.name + ": fleet destroyed completely");
				fleets[a].Delete();
			}
		}
	}
}

Planet.prototype.ResolveGroundConflicts = function()
{
	if (!this.owner)
	{
		return;
	}
	
	var fleets = Fleet.ListByPlanet(this);
	for (var a=0; a<fleets.length; a++)
	{
		var fleet = fleets[a];
		if (fleet.owner != this.owner && fleet.transports > 0)
		{
			//alert("ground combat");
			
			var defendingFleet = Fleet.GetByPlanetAndOwner(this, this.owner);
			if (defendingFleet && !defendingFleet.IsEmpty())
			{
				//alert(fleet.owner.name + " lost " + fleet.transports + " transports.");
				fleet.transports = 0;
			}
			
			
//alert(this.owner.shipLevel + fleet.owner.shipLevel)			
			while (Math.floor(this.population) > 0 && fleet.transports > 0)
			{
			
				// weight combat rolls by tech level
				var roll = Math.floor(Math.random() * (this.owner.shipLevel + fleet.owner.shipLevel + 2));
				if (roll < this.owner.shipLevel+1)
				{
					fleet.transports--;
				}
				else
				{
					
					this.population--;
					
					
				}
				//Util.AlertMulti(fleet.transports, this.population, roll);
			}
			
			if (Math.floor(this.population) == 0)
			{
				//alert("invasion successful");
				this.population = fleet.transports;
				this.owner.RemovePlanet(this);
				this.owner = fleet.owner;
				fleet.owner.Planets.push(this);
				
				fleet.transports = 0;
			}
			else
			{
				//alert("invasion repelled " + fleet.IsEmpty());
			}

			if (fleet.IsEmpty())
			{
				fleet.Delete();
			}
		}
	}
	
}


Planet.prototype.Step = function()
{
	if (!this.owner)
	{
		return;
	}
	
	this.NormalizePriorities()
	
	var production = this.GetProduction() - this.GetMaintenance();

	// calculate waste before building new factories.  that's only fair.
	//var newWaste = 
	this.waste += this.GetWorkingFactories() * this.owner.wastePerFactory;
	
	this.factories += production * this.priority[Planet.Priorities.Industry] / 100 / this.owner.factoryCost;
	if (this.factories > this.populationMax * this.owner.factoriesPerWorker)
	{
		this.factories = this.populationMax * this.owner.factoriesPerWorker
	}
	
	
	// Waste, and how much eco needs to be spent on it...	
	var ecoProduction = production * this.priority[Planet.Priorities.Ecology] / 100;
if (this.name == "Sol")
{
//	alert(ecoProduction + " ecoProduction, ");
	//alert(minWastePercentage + ", " + sum);
}

	var wasteCost = this.waste * this.owner.wasteCleanupCost;
	if (ecoProduction > wasteCost)
	{
		this.waste = 0;
		ecoProduction -= wasteCost;
	}
	else
	{
		this.waste -= ecoProduction;
		ecoProduction = 0;
	}
	
	// Organic Growth:  10% growth when at 50% max pop.  Linearly less efficient as we move away from that #.  0% growth at 100% and 0% max pop.
	var organicGrowth = (1.005-Math.abs(this.population - this.populationMax/2 ) / (this.populationMax/2)) * 0.1 * this.population;

	this.population += organicGrowth;
	this.population += ecoProduction / this.owner.workerCost;
	if (this.population > this.populationMax)
	{
		this.population = this.populationMax;
	}

	// Fleet
	
	// TODO - keep a planetary ship surplus.  only add fully built ships to a fleet.
	
	var fleet = Fleet.GetByPlanetAndOwner(this, this.owner);
	if (!fleet)
	{
		fleet = new Fleet(this.owner, this);
		this.owner.Fleets.push(fleet);
	}	
	//fleet.ships[this.owner.shipLevel] +=  production * this.priority[Planet.Priorities.Ship] / 100 / Ship.Cost[this.owner.shipLevel];
	fleet.ships[this.owner.shipLevel] +=  this.CalculateShipsPerTurn(production);
	
	// Bases
	//this.bases +=  production * this.priority[Planet.Priorities.Base] / 100 / 100;
	this.bases +=  this.CalculateBasesPerTurn(production);
	
	// Tech
	//this.owner.research += production * this.priority[Planet.Priorities.Research] / 100;
	this.owner.research += this.CalculateResearchPerTurn(production);
	if (this.owner.research > Ship.Tech[this.owner.shipLevel] && this.owner.shipLevel < Ship.Tech.length-1)
	{
		this.owner.shipLevel++;
		this.owner.research = 0;
	}
	//alert(this.owner.research);
	
	this.AdjustEcology();
	this.AdjustIndustry();
	
	return true;
}

Planet.prototype.CalculateShipsPerTurn = function(production)
{
	if (!this.owner)
	{
		return 0;
	}
	
	return production * this.priority[Planet.Priorities.Ship] / 100 / Ship.Cost[this.owner.shipLevel];
}

Planet.prototype.CalculateBasesPerTurn = function(production)
{
	if (!this.owner)
	{
		return 0;
	}
	
	return production * this.priority[Planet.Priorities.Base] / 100 / 75;
}

Planet.prototype.CalculateResearchPerTurn = function(production)
{
	if (!this.owner)
	{
		return 0;
	}
	
	return production * this.priority[Planet.Priorities.Research] / 100;
}


