--
-- Cultivator
-- Class for all Cultivators
-- 
-- @author  Stefan Geiger
-- @date  04/02/08
--
-- Copyright (C) GIANTS Software GmbH, Confidential, All Rights Reserved.

Wiesenwalze = {};

function Wiesenwalze.prerequisitesPresent(specializations)
    return true;
end;

function Wiesenwalze:load(xmlFile)
    self.groundContactReport = SpecializationUtil.callSpecializationsFunction("groundContactReport");

    self.contactReportNodes = {};
    local contactReportNodeFound = false;
    local i=0;
    while true do
        local baseName = string.format("vehicle.contactReportNodes.contactReportNode(%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.hasGroundContact = false;

            self.contactReportNodes[node] = entry;
            contactReportNodeFound = true;
        end;
        i = i+1;
    end;
    if not contactReportNodeFound then
        local entry = {};
        entry.node = self.components[1].node;
        entry.hasGroundContact = false;
        self.contactReportNodes[entry.node] = entry;
    end;

    self.groundReferenceThreshold = Utils.getNoNil(getXMLFloat(xmlFile, "vehicle.groundReferenceNode#threshold"), 10);
    self.groundReferenceNode = Utils.indexToObject(self.components, getXMLString(xmlFile, "vehicle.groundReferenceNode#index"));

    local numCuttingAreas = Utils.getNoNil(getXMLInt(xmlFile, "vehicle.cuttingAreas#count"), 0);
    for i=1, numCuttingAreas do
        local areanamei = string.format("vehicle.cuttingAreas.cuttingArea%d", i);
        self.cuttingAreas[i].foldMinLimit = Utils.getNoNil(getXMLFloat(xmlFile, areanamei .. "#foldMinLimit"), 0);
        self.cuttingAreas[i].foldMaxLimit = Utils.getNoNil(getXMLFloat(xmlFile, areanamei .. "#foldMaxLimit"), 1);
    end;


    self.groundParticleSystems = {};
    local psName = "vehicle.groundParticleSystem";
    Utils.loadParticleSystem(xmlFile, self.groundParticleSystems, psName, self.components, false, nil, self.baseDirectory)

    self.newGroundParticleSystems = {};
    local i=0;
    while true do
        local baseName = string.format("vehicle.groundParticleSystems.groundParticleSystem(%d)", i);
        if not hasXMLProperty(xmlFile, baseName) then
            break;
        end;
        local entry = {};
        entry.ps = {};
        Utils.loadParticleSystem(xmlFile, entry.ps, baseName, self.components, false, nil, self.baseDirectory);
        if table.getn(entry.ps) > 0 then
            entry.isActive = false;
            table.insert(self.newGroundParticleSystems, entry);
        end;
        i = i+1;
    end;

    self.aiTerrainDetailChannel1 = g_currentMission.ploughChannel;
    self.aiTerrainDetailChannel2 = g_currentMission.sowingChannel;

    self.maxSpeedLevel = Utils.getNoNil(getXMLInt(xmlFile, "vehicle.maxSpeedLevel#value"), 1);
    self.speedViolationMaxTime = 2500;
    self.speedViolationTimer = self.speedViolationMaxTime;
    self.cultivatorContactReportsActive = false;
    self.startActivationTimeout = 2000;
    self.startActivationTime = 0;

    self.cultivatorHasGroundContact = false;

    self.cultivatorLimitToField = false;
    self.cultivatorForceLimitToField = true;

    self.cultivatorGroundContactFlag = self.nextDirtyFlag;
    self.nextDirtyFlag = self.cultivatorGroundContactFlag*2;

    self.cuttingAreasSend = {};
	
	
	self.showPS = false;
	self.particleSystemSchaber = {};
    local i = 0;
    while true do
        local system1i = string.format("vehicle.particleSystemSchaber.system(%d)", i);
		local index1i = Utils.indexToObject(self.components, getXMLString(xmlFile, system1i .. "#index"));
		if index1i == nil then
			break;
		end; 
        Utils.loadParticleSystem(xmlFile, self.particleSystemSchaber, system1i, index1i, false, nil, self.baseDirectory)		
		i = i +1;		
    end;
    self.startIndexSpray = Utils.indexToObject(self.components, getXMLString(xmlFile, "vehicle.DuengeArea#startIndex"));
    self.widthIndexSpray = Utils.indexToObject(self.components, getXMLString(xmlFile, "vehicle.DuengeArea#widthIndex"));
    self.heightIndexSpray = Utils.indexToObject(self.components, getXMLString(xmlFile, "vehicle.DuengeArea#heightIndex"));

end;

function Wiesenwalze:delete()

    Utils.deleteParticleSystem(self.groundParticleSystems);
    Utils.deleteParticleSystem(self.particleSystemSchaber);   
    for _, entry in ipairs(self.newGroundParticleSystems) do
        Utils.deleteParticleSystem(entry.ps);
    end;
    
    Wiesenwalze.removeContactReports(self);
end;

function Wiesenwalze:readUpdateStream(streamId, timestamp, connection)
    if connection:getIsServer() then
        self.cultivatorHasGroundContact = streamReadBool(streamId);
    end;
end;

function Wiesenwalze:writeUpdateStream(streamId, connection, dirtyMask)
    if not connection:getIsServer() then
        --if bitAND(dirtyMask, self.cultivatorGroundContactFlag) ~= 0 then
        --    streamWriteBool(streamId, true);
        streamWriteBool(streamId, self.cultivatorHasGroundContact);
    end;
end;

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

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

function Wiesenwalze:update(dt)	
end;

function Wiesenwalze:updateTick(dt)
	if self.lastSpeed*3600 > 5 then
		Utils.setEmittingState(self.particleSystemSchaber, true);	
	else
		Utils.setEmittingState(self.particleSystemSchaber, false);	
	end;
				
    if self:getIsActive() then
        local hasGroundContact = false;
        if self.isServer then
            for k, v in pairs(self.contactReportNodes) do
                if v.hasGroundContact then
                    hasGroundContact = true;
                    break;
                end;
            end;

            if not hasGroundContact then
                if self.groundReferenceNode ~= nil then
                    local x,y,z = getWorldTranslation(self.groundReferenceNode);
                    local terrainHeight = getTerrainHeightAtWorldPos(g_currentMission.terrainRootNode, x, 0, z);
                    if terrainHeight+self.groundReferenceThreshold >= y then
                        hasGroundContact = true;					
                    end;
                end;
            end;

            if self.cultivatorHasGroundContact ~= hasGroundContact then
                self:raiseDirtyFlags(self.cultivatorGroundContactFlag);
            end;
            self.cultivatorHasGroundContact = hasGroundContact;
        end;
        local hasGroundContact = self.cultivatorHasGroundContact;

        local rotateRotatingParts = false;

        local foldAnimTime = self.foldAnimTime;
        if hasGroundContact or not hasGroundContact then
            rotateRotatingParts = true;
            local enableGroundParticleSystems = (self.lastSpeed*3600 > 5);
            if self.isClient then
				
		        local Sx,Sy,Sz = getWorldTranslation(self.startIndexSpray);
                local Sx1,Sy1,Sz1 = getWorldTranslation(self.widthIndexSpray);
                local Sx2,Sy2,Sz2 = getWorldTranslation(self.heightIndexSpray);
                Utils.updateSprayArea(Sx, Sz, Sx1, Sz1, Sx2, Sz2);
	
                if enableGroundParticleSystems then
                    for k, cuttingArea in pairs(self.cuttingAreas) do
                        local ps = self.newGroundParticleSystems[k];
                        if self:getIsAreaActive(cuttingArea) then
                            if ps ~= nil then
                                if not ps.isActive then
                                    ps.isActive = true;
                                    Utils.setEmittingState(ps.ps, true);
                                end;
                            end;
                        else
                            if ps ~= nil and ps.isActive then
                                ps.isActive = false;
                                Utils.setEmittingState(ps.ps, false);
                            end;
                        end;
                    end;
                else
                    for k, ps in pairs(self.newGroundParticleSystems) do
                        if ps.isActive then
                            ps.isActive = false;
                            Utils.setEmittingState(ps.ps, false);
                        end;
                    end;
                end;
            end;

            if self.startActivationTime <= self.time then
                if self.isServer then
                    local cuttingAreasSend = {};
                    for k, cuttingArea in pairs(self.cuttingAreas) do
                        if self:getIsAreaActive(cuttingArea) then
                            local x,y,z = getWorldTranslation(cuttingArea.start);
                            local x1,y1,z1 = getWorldTranslation(cuttingArea.width);
                            local x2,y2,z2 = getWorldTranslation(cuttingArea.height);
                            --Utils.updateCultivatorArea(x, z, x1, z1, x2, z2, not self.cultivatorLimitToField);
                            table.insert(cuttingAreasSend, {x,z,x1,z1,x2,z2});
                        end;
                    end;
                    if table.getn(cuttingAreasSend) > 0 then
                        local limitToField = self.cultivatorLimitToField or self.cultivatorForceLimitToField;
                        if not g_currentMission.allowClientsCreateFields then
                            local owner = self:getOwner();
                            if owner ~= nil and not owner:getIsLocal() then
                                limitToField = true;
                            end;
                        end;

                        WiesenwalzeEvent.runLocally(cuttingAreasSend, limitToField);
                        g_server:broadcastEvent(WiesenwalzeEvent:new(cuttingAreasSend, limitToField));
                    end;
                end;

                local speedLimit = 20;
                if self.maxSpeedLevel == 2 then
                    speedLimit = 30;
                elseif self.maxSpeedLevel == 3 then
                    speedLimit = 100;
                end;
                if self:doCheckSpeedLimit() and self.lastSpeed*3600 > speedLimit then
                    self.speedViolationTimer = self.speedViolationTimer - dt;
                    if self.isServer then
                        if self.speedViolationTimer < 0 then
                            if self.attacherVehicle then
                                self.attacherVehicle:detachImplementByObject(self);
                            end;
                        end;
                    end;
                else
                    self.speedViolationTimer = self.speedViolationMaxTime;
                end;
            end;
        else
            self.speedViolationTimer = self.speedViolationMaxTime;

            if self.isClient then
                for k, ps in pairs(self.newGroundParticleSystems) do
                    if ps.isActive then
                        ps.isActive = false;
                        Utils.setEmittingState(ps.ps, false);
                    end;
                end;
            end;
        end;
    end;

end;

function Wiesenwalze:draw()
    if math.abs(self.speedViolationTimer - self.speedViolationMaxTime) > 2 then
        local buttonName = InputBinding.SPEED_LEVEL1;
        if self.maxSpeedLevel == 2 then
            buttonName = InputBinding.SPEED_LEVEL2;
        elseif self.maxSpeedLevel == 3 then
            buttonName = InputBinding.SPEED_LEVEL3;
        end;
        g_currentMission:addWarning(g_i18n:getText("Dont_drive_to_fast") .. "\n" .. string.format(g_i18n:getText("Cruise_control_levelN"), tostring(self.maxSpeedLevel), InputBinding.getKeyNamesOfDigitalAction(buttonName)), 0.07+0.022, 0.019+0.029);
    end;
end;

function Wiesenwalze:onAttach(attacherVehicle)
    Wiesenwalze.onActivate(self);
    Wiesenwalze.addContactReports(self);
    self.startActivationTime = self.time + self.startActivationTimeout;		
end;

function Wiesenwalze:onDetach()
	Utils.setEmittingState(self.particleSystemSchaber, false);	
    self.cultivatorLimitToField = false;
    if self.deactivateOnDetach then
        Wiesenwalze.onDeactivate(self);
        Wiesenwalze.removeContactReports(self);
    else
        Wiesenwalze.onDeactivateSounds(self);
    end;	
end;

function Wiesenwalze:onEnter(isControlling)
    if isControlling then
        Wiesenwalze.onActivate(self);
        Wiesenwalze.addContactReports(self);
    end;
end;

function Wiesenwalze:onLeave()
    if self.deactivateOnLeave then
        Wiesenwalze.onDeactivate(self);
        Wiesenwalze.removeContactReports(self);
    else
        Wiesenwalze.onDeactivateSounds(self);
    end;
end;

function Wiesenwalze:onActivate()
end;

function Wiesenwalze:onDeactivate()
    self.speedViolationTimer = self.speedViolationMaxTime;

    Utils.setEmittingState(self.groundParticleSystems, false);
    for k, ps in pairs(self.newGroundParticleSystems) do
        if ps.isActive then
            ps.isActive = false;
            Utils.setEmittingState(ps.ps, false);
        end;
    end;

    Wiesenwalze.onDeactivateSounds(self);
end;

function Wiesenwalze:onDeactivateSounds()
end;

function Wiesenwalze:aiTurnOn()
    self.cultivatorLimitToField = true;
end;

function Wiesenwalze:aiTurnOff()
    self.cultivatorLimitToField = false;
end;

function Wiesenwalze:addContactReports()
    if not self.cultivatorContactReportsActive then
        for k, v in pairs(self.contactReportNodes) do
            addContactReport(v.node, 0.0001, "groundContactReport", self);
        end;

        self.cultivatorContactReportsActive = true;
    end;
end;

function Wiesenwalze:removeContactReports()
    if self.cultivatorContactReportsActive then
        for k, v in pairs(self.contactReportNodes) do
            removeContactReport(v.node);
            v.hasGroundContact = false;
        end;
        self.cultivatorContactReportsActive = false;
    end;
end;

function Wiesenwalze:groundContactReport(objectId, otherObjectId, isStart, normalForce, tangentialForce)

    if otherObjectId == g_currentMission.terrainRootNode then
        local entry = self.contactReportNodes[objectId];
        if entry ~= nil then
            entry.hasGroundContact = isStart or normalForce > 0 or tangentialForce > 0;
        end;
    end;

end;