dofile("Scripts/Init/consts.lua");

hold_fire = false;
hold_move = false;
loaded2unit = false;

group_exchange_timeout = 50;

function SetFiringBehaviour(beh)
	hold_fire = (beh == unit.HoldFire);
end
function SetMovingBehaviour(beh)
	hold_move = (beh == unit.StandStill);
end
function OnLoad()
	loaded2unit = true;
end
function OnUnload()
	loaded2unit = false;
end

function BasicInit()
--	log("BasicInit");
	loaded2unit = object.IsFlag(object.FlagCargo);
	AIparts = utils.CreateSubsystems();
	if type(Fire) == "function" then
		AIparts:AddPeriodic("Fire", fire_timeout, Fire, object.RandomInt(fire_timeout));
	end
	if type(Move) == "function" then
		AIparts:AddPeriodic("Move", move_timeout, Move, object.RandomInt(move_timeout));
	end
	if type(MicroAI) == "function" then
		AIparts:AddPeriodic("MicroAI", mai_timeout, MicroAI, object.RandomInt(mai_timeout));
	end
--	if not object.IsHumanControlled() then
		if type(MicroAIOrderer) == "function" then
			AIparts:AddPeriodic("MicroAIOrderer", mai_orderer_timeout, MicroAIOrderer,
				object.RandomInt(mai_orderer_timeout));
		end
--	end
	if type(CheckState) == "function" then
		AIparts:AddPeriodic("CheckState", check_state_timeout, CheckState,
			object.RandomInt(check_state_timeout));
	end
	if type(EventMan) == "function" then
		AIparts:AddPeriodic("EventMan", eventman_timeout, EventMan,
			object.RandomInt(eventman_timeout));
	end
end

-- Weapons
w = {
	[1] = {
		index = 0,
		direct,
		ballistic,
		zenith,
		Drange,
		Brange,
		Zrange,
		range_max,
		Bdeadzone,
		Zdeadzone,
		last_target
	},
	[2] = {
		index = 1,
		direct,
		ballistic,
		zenith,
		Drange,
		Brange,
		Zrange,
		range_max,
		Ddeadzone,
		Bdeadzone,
		Zdeadzone,
		last_target
	},
}

for i,v in pairs(w) do
	local gun = object.desc.Armament.Guns[v.index];
	if gun then
		v.direct = gun.CanFireDirect;
		v.ballistic = gun.CanFireBallistic;
		v.zenith = gun.CanFireZenith;
		v.Drange = gun.DirectMaxRadius;
		v.Brange = gun.BallisticMaxRadius;
		v.Ddeadzone = gun.DirectDeadZone;
		v.Bdeadzone = gun.BallisticDeadZone;
		if v.Drange > v.Brange then
			v.range_max = v.Drange;
		else
			v.range_max = v.Brange;
		end
	else
		w[i] = nil;
	end
end

-- units in view area
if w[1] then
	scan_range = w[1].range_max * 2;
else
--	ScreenError("Unit \"" .. object.GetDescName() .. "\" has no PRIMARY weapon!");
end

micro_ai =
{
	scan_range = object.desc.AlarmRange,
	Init = function(self)
		self.enemies = {};
		self.allies = {};
		self.move_target = nil;
		self.fire_target = nil;
		self.move_value = nil;
		self.fire_value = nil;
		if loaded2unit then
			self.check_move = false;
			self.check_fire = false;
		else
			self.check_move = not hold_move;
			self.check_fire = not hold_fire and not unit.IsHumanAttack();
		end
	end,
	CheckAlly = function(self, target)
		local object_class = object.GetObjectClass(target);
		local value = self.allies[object_class] or 0;
		self.allies[object_class] = value + 1;
	end,
	CheckEnemy = function(self, target)
		local target_class = object.GetObjectClass(target);
		local value = self.enemies[target_class] or 0;
		self.enemies[target_class] = value + 1;
		if self.check_move then self:CheckMove(target, target_class) end;
		if self.check_fire then self:CheckFire(target, target_class) end;
	end,
	CheckMove = function()
		-- do nothing
	end,
	CheckFire = function(self, target, target_class)
		local target_type = object.GetTargetType(target);
		local target_priority = object.desc.Armament.TargetPriorities[target_type];
		if target_priority <= 0 then return end;
	
		local target_distance = unit.GetTargetDistance(target);
		if target_distance > object.desc.AlarmRange then return end;

		local target_id = object.GetObjectId(target);
		local prev_target = 1;
		if target_id == self.prev_target then prev_target = 0.5 end;
		local value = target_priority * object.GetTargetCost(target) / target_distance;

		if value > (self.fire_value or 0) then
			self.fire_target = target;
			self.fire_value = value;
		end
	end,
	CheckIdle = function()
		-- do nothing
	end,
	DoMove = function()
		-- do nothing
	end,
	DoFire = function(self)
		if not self.fire_target then return end;
		unit.AttackObject(self.fire_target);
		self.prev_target = object.GetObjectId(self.fire_target);
		self.fire_target = nil;
	end,
	Run = function(self)
		self:Init();
		for _,target in pairs(unit.GetAllyList(0, self.scan_range)) do self:CheckAlly(target) end;
		for _,target in pairs(unit.GetEnemyList(0, self.scan_range)) do self:CheckEnemy(target) end;
		if self.check_move then self:DoMove() end;
		if self.check_fire then self:DoFire() end;
		self:CheckIdle();
	end,
}

enemy_soldiers = 0;
enemy_cannons = 0;
enemy_tanks = 0;
allied_soldiers = 0;
allied_cannons = 0;
allied_tanks = 0;

-- target value multipliers for different unit types
--(must be >0 [and <=2])
-- lesser multiplier causes better chance to be a target
-- for firing soldier:
soldier_for_soldier = 1;
tank_for_soldier = 0.8;
gun_for_soldier = 1;
truck_for_soldier = 1;
plane_for_soldier = 1;
-- for firing tank:
soldier_for_tank = 1;
tank_for_tank = 0.7;
gun_for_tank = 0.5;
truck_for_tank = 1;
plane_for_tank = 1;
-- for firing gun:
soldier_for_gun = 1;
tank_for_gun = 1;
gun_for_gun = 1;
truck_for_gun = 1;
plane_for_gun = 1;
