--
-- Obsypnik
-- author: Burner
-- 

Obsypnik = {};

function Obsypnik.prerequisitesPresent(specializations)
    return SpecializationUtil.hasSpecialization(Sprayer, specializations);
end;

function Obsypnik:load(xmlFile)
	self.mountAdditionalElement = SpecializationUtil.callSpecializationsFunction("mountAdditionalElement");
	self.objectInRange = Obsypnik.objectInRange;
	self.groundParticleSystem = {};
	local psName = "vehicle.groundParticleSystem";
	Utils.loadParticleSystem(xmlFile, self.groundParticleSystem, psName, self.components, false, nil, self.baseDirectory);
	self.additionalElementMounted = true;
	self.additionalElement1 = Utils.indexToObject(self.components, getXMLString(xmlFile, "vehicle.additionalElement1#index"));
	self.additionalElement2 = Utils.indexToObject(self.components, getXMLString(xmlFile, "vehicle.additionalElement2#index"));
	
	self.speedRotatingParts = {};
	local i=0;
	while true do
		local baseName = string.format("vehicle.speedRotatingParts.speedRotatingPart(%d)", i);
		local index = getXMLString(xmlFile, baseName.. "#index");
		if index == nil then
			break;
		end;
		local node = Utils.indexToObject(self.components, index);
		if node ~= nil then
			local entry = {};
			entry.node = node;
			entry.rotationSpeedScale = getXMLFloat(xmlFile, baseName.."#rotationSpeedScale");
			if entry.rotationSpeedScale == nil then
				entry.rotationSpeedScale = 1.0/Utils.getNoNil(getXMLFloat(xmlFile, baseName.."#radius"), 1);
			end;
			entry.foldMinLimit = Utils.getNoNil(getXMLFloat(xmlFile, baseName .. "#foldMinLimit"), 0);
			entry.foldMaxLimit = Utils.getNoNil(getXMLFloat(xmlFile, baseName .. "#foldMaxLimit"), 1);
			table.insert(self.speedRotatingParts, entry);
		end;
		i = i+1;
	end;
	self:setFillLevel(self.capacity, Fillable.FILLTYPE_FERTILIZER);
	self.draw = Utils.overwrittenFunction(self.draw, Obsypnik.draw);
end;

function Obsypnik:readStream(streamId, connection)
	self:mountAdditionalElement(streamReadBool(streamId), true);
end;

function Obsypnik:writeStream(streamId, connection)
	streamWriteBool(streamId, self.additionalElementMounted);
end;

function Obsypnik:loadFromAttributesAndNodes(xmlFile, key, resetVehicles)	
	if not resetVehicles then
		local mounted = Utils.getNoNil(getXMLBool(xmlFile, key .. "#additionalElementMounted"), self.additionalElementMounted);
		self:mountAdditionalElement(mounted);
	end; 
    return BaseMission.VEHICLE_LOAD_OK;
end;

function Obsypnik:getSaveAttributesAndNodes(nodeIdent)
	local attributes = 'additionalElementMounted="' .. tostring(self.additionalElementMounted) ..'"';
	return attributes, nil;
end;

function Obsypnik:delete()
	Utils.deleteParticleSystem(self.groundParticleSystem);
end;

function Obsypnik:mouseEvent(posX, posY, isDown, isUp, button)
end;

function Obsypnik:keyEvent(unicode, sym, modifier, isDown)
end;

function Obsypnik:update(dt)
	if self:getIsActive() then
		self.isTurnedOn = self:isLowered(false);
		self.fillLevel = self.capacity;
		Utils.setEmittingState(self.groundParticleSystem, (self.isTurnedOn and self.lastSpeed*3600 > 5));
		if self:isLowered(false) then
			for k,v in pairs(self.speedRotatingParts) do
				rotate(v.node, v.rotationSpeedScale * self.lastSpeedReal * self.movingDirection * dt, 0, 0);
			end;
		end;
	end;
	if self:objectInRange(self.additionalElement1) then
		if InputBinding.hasEvent(InputBinding.Obsypnik_MountAdditionalElement) then
			self:mountAdditionalElement(not self.additionalElementMounted);
		end;
		if self.additionalElementMounted then
			g_currentMission:addHelpButtonText(g_i18n:getText("Obsypnik_MountAdditionalElement"), InputBinding.Obsypnik_MountAdditionalElement);
		else
			g_currentMission:addHelpButtonText(g_i18n:getText("Obsypnik_UnmountAdditionalElement"), InputBinding.Obsypnik_MountAdditionalElement);
		end;
	end;
	if self.additionalElement1 ~= nil then
		setVisibility(self.additionalElement1, self.additionalElementMounted);
	end;
	if self.additionalElement2 ~= nil then
		setVisibility(self.additionalElement2, not self.additionalElementMounted);
	end;
end;

function Obsypnik:draw()
	Attachable.draw(self)
end;

function Obsypnik:onDetach()
	Utils.setEmittingState(self.groundParticleSystem, false);
end;

function Obsypnik:onLeave()
end;

function Obsypnik:onDeactivate()
	Utils.setEmittingState(self.groundParticleSystem, false);
end;

function Obsypnik:objectInRange(object)
	if g_currentMission.player ~= nil and object ~= nil then
		local nearestDistance = 2;
		local vx, vy, vz = getWorldTranslation(g_currentMission.player.rootNode);
		local px, py, pz = getWorldTranslation(object); 
		local distance = Utils.vector3Length(px-vx, py-vy, pz-vz);	
		if distance < nearestDistance then
			return true;
		else
			return false;
		end;
	else
		return false;
	end;
end;

function Obsypnik:mountAdditionalElement(additionalElementState, noEventSend)
	MountAdditionalElementEvent.sendEvent(self, additionalElementState, noEventSend)
	self.additionalElementMounted = additionalElementState;
end;

-- events
MountAdditionalElementEvent = {};
MountAdditionalElementEvent_mt = Class(MountAdditionalElementEvent, Event);

InitEventClass(MountAdditionalElementEvent, "MountAdditionalElementEvent");

function MountAdditionalElementEvent:emptyNew()
    local self = Event:new(MountAdditionalElementEvent_mt);
    self.className="MountAdditionalElementEvent";
    return self;
end;

function MountAdditionalElementEvent:new(vehicle, additionalElementState)
    local self = MountAdditionalElementEvent:emptyNew()
    self.vehicle = vehicle;
	self.additionalElementState = additionalElementState;
    return self;
end;

function MountAdditionalElementEvent:readStream(streamId, connection)
    local id = streamReadInt32(streamId);
	self.additionalElementState = streamReadBool(streamId);
    self.vehicle = networkGetObject(id);
    self:run(connection);
end;

function MountAdditionalElementEvent:writeStream(streamId, connection)
    streamWriteInt32(streamId, networkGetObjectId(self.vehicle));
	streamWriteBool(streamId, self.additionalElementState);
end;

function MountAdditionalElementEvent:run(connection)   
	self.vehicle:mountAdditionalElement(self.additionalElementState, true);
    if not connection:getIsServer() then
        g_server:broadcastEvent(MountAdditionalElementEvent:new(self.vehicle, self.additionalElementState), nil, connection, self.vehicle);
    end;
end;

function MountAdditionalElementEvent.sendEvent(vehicle, additionalElementState, noEventSend)
	if noEventSend == nil or noEventSend == false then
		if g_server ~= nil then
			g_server:broadcastEvent(MountAdditionalElementEvent:new(vehicle, additionalElementState), nil, nil, vehicle);
		else
			g_client:getServerConnection():sendEvent(MountAdditionalElementEvent:new(vehicle, additionalElementState));
		end;
	end;
end;