Base =
{
	Atreides = { AConyard, ABarracks1, ABarracks2, AHeavyFactory, ALightFactory1, ALightFactory2, AOutpost, ARepairPad, AStarport, AResearch, ARefinery1, ARefinery2, ARefinery3, ARefinery4, APalace, AHighTech, ASilo1, ASilo2, ASilo3, ASilo4, ASilo5, ASilo6, ASilo7, ASilo8, ASilo9, ASilo10, ASilo11, ASilo12, ASilo13, ASilo14, ASilo15, ASilo16, ASilo17, ASilo18, ASilo19, ASilo20, ASilo21, ASilo22, ASilo23, ASilo24, AGunt1, AGunt2, AGunt3, AGunt4, AGunt5, AGunt6, ARoct1, ARoct2, ARoct3, ARoct4, ARoct5, ARoct6 },
	Harkonnen = { HConyard, HBarracks1, HBarracks2, HHeavyFactory, HLightFactory1, HLightFactory2, HOutpost, HRepairPad, HStarport, HResearch, HRefinery1, HRefinery2, HRefinery3, HRefinery4, HPalace, HHighTech, HSilo1, HSilo2, HSilo3, HSilo4, HSilo5, HSilo6, HSilo7, HSilo8, HSilo9, HSilo10, HSilo11, HSilo12, HSilo13, HSilo14, HSilo15, HSilo16, HSilo17, HSilo18, HSilo19, HSilo20, HGunt1, HGunt2, HGunt3, HGunt4, HGunt5, HGunt6, HRoct1, HRoct2, HRoct3, HRoct4 },
	Ordos = { OConyard, OBarracks1, OBarracks2, OHeavyFactory, OLightFactory1, OLightFactory2, OOutpost, ORepairPad, OStarport, OResearch, ORefinery1, ORefinery2, ORefinery3, ORefinery4, OPalace, OHighTech, OSilo1, OSilo2, OSilo3, OSilo4, OSilo5, OSilo6, OSilo7, OSilo8, OSilo9, OSilo10, OSilo11, OSilo12, OSilo13, OSilo14, OSilo15, OSilo16, OSilo17, OSilo18, OSilo19, OSilo20, OSilo21, OGunt1, OGunt2, OGunt3, OGunt4, OGunt5, ORoct1, ORoct2, ORoct3 },
	Smugglers = { SBarracks, SLightFactory, SOutpost, SStarport, SRefinery1, SRefinery2, SPower1, SPower2, SPower3, SPower4, SPower5, SSilo1, SSilo2, SSilo3, SSilo4, SSilo5, SGunt1, SGunt2, SGunt3 }
}

IdlingUnits =
{
	Atreides = { },
	Harkonnen = { },
	Ordos = { },
	Smugglers = { }
}

AttackGroupSize =
{
	easy = 6,
	normal = 8,
	hard = 10
}

AttackDelays =
{
	easy = { DateTime.Seconds(4), DateTime.Seconds(7) },
	normal = { DateTime.Seconds(2), DateTime.Seconds(5) },
	hard = { DateTime.Seconds(1), DateTime.Seconds(3) }
}

AttackLocations = {
	Atreides = { HConyard.Location, OConyard.Location },
	Harkonnen = { AConyard.Location, OConyard.Location },
	Ordos = { AConyard.Location, HConyard.Location },
	Smugglers = { HConyard.Location, OConyard.Location }
}

AtreidesBarrackses = { ABarracks1, ABarracks2 }
HarkonnenBarrackses = { HBarracks1, HBarracks2 }
OrdosBarrackses = { OBarracks1, OBarracks2 }
SmugglerBarracks = { SBarracks }

AtreidesLightFactories = { ALightFactory1, ALightFactory2 }
HarkonnenLightFactories = { HLightFactory1, HLightFactory2 }
OrdosLightFactories = { OLightFactory1, OLightFactory2 }
SmugglerLightFactory = { SLightFactory }

AtreidesHeavyFactory = { AHeavyFactory }
HarkonnenHeavyFactory = { HHeavyFactory }
OrdosHeavyFactory = { OHeavyFactory }

AtreidesStarport = { AStarport }
HarkonnenStarport = { HStarport }
OrdosStarport = { OStarport }
SmugglerStarport = { SStarport }

AtreidesInfantryTypes = { "light_inf", "light_inf", "light_inf", "trooper", "trooper", "grenadier" }
AtreidesVehicleTypes = { "trike", "trike", "quad" }
AtreidesTankTypes = { "combat_tank_a", "combat_tank_a", "combat_tank_a", "missile_tank", "missile_tank", "siege_tank", "sonic_tank" }
AtreidesStarportTypes = { "trike.starport", "quad.starport", "siege_tank.starport", "missile_tank.starport", "combat_tank_a.starport" }

HarkonnenInfantryTypes = { "light_inf", "light_inf", "light_inf", "trooper", "trooper", "sardaukar" }
HarkonnenVehicleTypes = { "trike", "trike", "quad" }
HarkonnenTankTypes = { "combat_tank_h", "combat_tank_h", "combat_tank_h", "missile_tank", "missile_tank", "siege_tank", "devastator" }
HarkonnenStarportTypes = { "trike.starport", "quad.starport", "siege_tank.starport", "missile_tank.starport", "combat_tank_h.starport" }

OrdosInfantryTypes = { "light_inf", "light_inf", "light_inf", "trooper", "trooper" }
OrdosVehicleTypes = { "raider", "raider", "raider", "quad", "quad", "stealth_raider" }
OrdosTankTypes = { "combat_tank_o", "combat_tank_o", "combat_tank_o", "missile_tank", "missile_tank", "siege_tank", "deviator" }
OrdosStarportTypes = { "trike.starport", "quad.starport", "siege_tank.starport", "missile_tank.starport", "combat_tank_o.starport" }

SmugglerInfantryTypes = { "light_inf", "light_inf", "light_inf", "trooper", "trooper" }
SmugglerVehicleTypes = { "raider", "raider", "quad" }
SmugglerStarportTypes = { "trike.starport", "quad.starport", "siege_tank.starport", "missile_tank.starport", "combat_tank_s.starport" }

IsAttacking = 
{
	Atreides = false,
	Harkonnen = false,
	Ordos = false,
	Smugglers = false
}

IsDefending = 
{
	Atreides = false,
	Harkonnen = false,
	Ordos = false,
	Smugglers = false
}

HoldProduction =
{
	Atreides = false,
	Harkonnen = false,
	Ordos = false,
	Smugglers = false
}

HarvesterKilled =
{
	Atreides = false,
	Harkonnen = false,
	Ordos = false,
	Smugglers = false
}

IdleHunt = function(unit) if not unit.IsDead then Trigger.OnIdle(unit, unit.Hunt) end end

SetupAttackGroup = function(house)
	local units = { }

	for i = 0, AttackGroupSize[Difficulty], 1 do
		if #IdlingUnits[house.Name] == 0 then
			return units
		end

		local number = Utils.RandomInteger(1, #IdlingUnits[house.Name])

		if IdlingUnits[house.Name][number] and not IdlingUnits[house.Name][number].IsDead then
			units[i] = IdlingUnits[house.Name][number]
			table.remove(IdlingUnits[house.Name], number)
		end
	end

	return units
end

SendAttack = function(house)
	if IsAttacking[house.Name] then
		return
	end
	IsAttacking[house.Name] = true
	HoldProduction[house.Name] = true

	local units = SetupAttackGroup(house)
	Utils.Do(units, function(unit)
		unit.AttackMove(Utils.Random(AttackLocations[house.Name]))
		IdleHunt(unit)
	end)

	Trigger.OnAllRemovedFromWorld(units, function()
		IsAttacking[house.Name] = false
		HoldProduction[house.Name] = false
	end)
end

ProtectHarvester = function(unit, house)
	DefendActor(unit, house)
	Trigger.OnKilled(unit, function() HarvesterKilled[house.Name] = true end)
end

DefendActor = function(unit, house)
	Trigger.OnDamaged(unit, function(self, attacker)
		if IsDefending[house.Name] then
			return
		end
		IsDefending[house.Name] = true

		if attacker and attacker.Type == "spicebloom" then
			return
		end

		local Guards = SetupAttackGroup(house)

		if #Guards <= 0 then
			IsDefending[house.Name] = false
			return
		end

		Utils.Do(Guards, function(unit)
			if not self.IsDead then
				unit.AttackMove(self.Location)
			end
			IdleHunt(unit)
		end)

		Trigger.OnAllRemovedFromWorld(Guards, function() IsDefending[house.Name] = false end)
	end)
end

InitAIUnits = function(house)
	Utils.Do(Base[house.Name], function(actor)
		DefendActor(actor, house)
		Trigger.OnDamaged(actor, function(building)
			if building.Health < building.MaxHealth * 3/4 and building.Owner.Name == house.Name then
				building.StartBuildingRepairs()
			end
		end)
	end)
end

Produce = function(house, units, factories)
	if #Utils.Where(factories, function(f) return not f.IsDead end) == 0 then
		return
	end

	if HoldProduction[house.Name] then
		Trigger.AfterDelay(DateTime.Seconds(30), function() Produce(house, units, factories) end)
		return
	end

	local delay = Utils.RandomInteger(AttackDelays[Difficulty][1], AttackDelays[Difficulty][2] + 1)
	local toBuild = { Utils.Random(units) }
	house.Build(toBuild, function(unit)
		local unitCount = 1
		if IdlingUnits[house.Name] then
			unitCount = 1 + #IdlingUnits[house.Name]
		end
		IdlingUnits[house.Name][unitCount] = unit[1]
		Trigger.AfterDelay(delay, function() Produce(house, units, factories) end)

		if unitCount >= (AttackGroupSize[Difficulty] * 2.5) then
			SendAttack(house)
		end
	end)
end

ActivateAI = function()
	InitAIUnits(atreides)
	InitAIUnits(harkonnen)
	InitAIUnits(ordos)
	InitAIUnits(smuggler)
	
	smuggler.Build(Harvester)

	Trigger.AfterDelay(DateTime.Seconds(14), function()
		Produce(atreides, AtreidesInfantryTypes, AtreidesBarrackses)
		Produce(atreides, AtreidesVehicleTypes, AtreidesLightFactories)
		Produce(atreides, AtreidesTankTypes, AtreidesHeavyFactory)
		Produce(atreides, AtreidesStarportTypes, AtreidesStarport)

		Produce(harkonnen, HarkonnenInfantryTypes, HarkonnenBarrackses)
		Produce(harkonnen, HarkonnenVehicleTypes, HarkonnenLightFactories)
		Produce(harkonnen, HarkonnenTankTypes, HarkonnenHeavyFactory)
		Produce(harkonnen, HarkonnenStarportTypes, HarkonnenStarport)

		Produce(ordos, OrdosInfantryTypes, OrdosBarrackses)
		Produce(ordos, OrdosVehicleTypes, OrdosLightFactories)
		Produce(ordos, OrdosTankTypes, OrdosHeavyFactory)
		Produce(ordos, OrdosStarportTypes, OrdosStarport)
	end)
end

ActivateSmugglerAI = function()
	Trigger.AfterDelay(0, function()
		Produce(smuggler, SmugglerInfantryTypes, SmugglerBarracks)
		Produce(smuggler, SmugglerVehicleTypes, SmugglerLightFactory)
		Produce(smuggler, SmugglerStarportTypes, SmugglerStarport)
	end)
end
