--
-- VariableBody
-- This is a specialization for trailers, which have a extra bodywork for loading chaff/grass?
--
--
-- @author:		fruktor (wwww.modding-society.de)
-- @version:	v2.0
-- @date:		03/01/17
-- @history:	v0.1 - inital implementation
--				v2.0 - edit to FS17 by igor29381
-- Copyright (C)
--

VariableBody = {};

function VariableBody.prerequisitesPresent(specializations)
    return SpecializationUtil.hasSpecialization(Trailer, specializations) and
		SpecializationUtil.hasSpecialization(Fillable, specializations)
end;

function VariableBody:load(savegame)
	self.changeVariableBody = SpecializationUtil.callSpecializationsFunction("changeVariableBody");
	local bulk2Category = FillUtil.registerFillTypeCategory("bulk2");
	local fillTypes = {FillUtil.FILLTYPE_POTATO, FillUtil.FILLTYPE_SUGARBEET, FillUtil.FILLTYPE_MANURE, FillUtil.FILLTYPE_CHAFF, FillUtil.FILLTYPE_SILAGE, FillUtil.FILLTYPE_WOODCHIPS};
	for i=1, #fillTypes do
		FillUtil.addFillTypeToCategory(bulk2Category, fillTypes[i]);
	end;
	self.varBody = {};
	local activeIdx = getXMLInt(self.xmlFile, "vehicle.variableBody#activeIdx");
	if activeIdx ~= nil then
		self.varBody.activeIdx = activeIdx;
	else
		self.varBody.activeIdx = 1;
	end;
	local activeIdx = getXMLInt(self.xmlFile, "vehicle.variableBody#activeSubIdx");
	if activeIdx ~= nil then
		self.varBody.activeSubIdx = activeSubIdx;
	else
		self.varBody.activeSubIdx = 1;
	end;
	self.varBody.nodes = {};
	local i=0;
	local j=0;
	while true do
		local path = string.format("vehicle.variableBody.node(%d)", i);
		local name = getXMLString(self.xmlFile, path .. "#name");
		if name == nil then
			break;
		end;
		local capacity = getXMLInt(self.xmlFile, path .. "#capacity");
		local fillTypeCategory = getXMLString(self.xmlFile, path .. "#fillTypeCategories");
		if fillTypeCategory then
			fillTypeCategory = FillUtil.fillTypeCategoryNameToInt[fillTypeCategory];
		end;
		local fillTypes = FillUtil.categoryToFillTypes[fillTypeCategory];
		--####
		local parts = {};
		j=0;
		local k=1;
		local str = getXMLString(self.xmlFile, string.format("vehicle.variableBody.node(%d).part(%d)#index%d", i, j, k));
		while str ~= nil do
			local subparts = {};
			local allowFill = getXMLInt(self.xmlFile, string.format("vehicle.variableBody.node(%d).part(%d)#allowFill", i, j));
			if allowFill ~= nil then
				subparts.allowFill = allowFill;
			else
				subparts.allowFill = 1;
			end;
			subparts.objects = {};
			while str ~= nil do
				local tmpIdx = Utils.indexToObject(self.components, str)
				k=k+1;
				table.insert(subparts.objects, tmpIdx);
				str = getXMLString(self.xmlFile, string.format("vehicle.variableBody.node(%d).part(%d)#index%d", i, j, k));
			end;
			subparts.subPartCount = k-1;
			if subparts ~= nil then
				table.insert(parts, subparts);
			else
				break;
			end;
			j=j+1;
			k=1;
			str = getXMLString(self.xmlFile, string.format("vehicle.variableBody.node(%d).part(%d)#index%d", i, j, k));
		end;
		if j == 0 then
			local subparts = {};
			subparts.objects = nil;
			subparts.allowFill = 1;
			subparts.subPartCount = 0;
			table.insert(parts, subparts);
		end;
		local entry={};
		entry.name = name;
		entry.capacity = capacity;
		entry.index = index;
		entry.parts = parts;
		entry.partCount = j;
		entry.fillTypes = fillTypes;
		table.insert(self.varBody.nodes, entry);
		i=i+1;
	end;
	for i=1, #self.fillVolumes do
		local fillVolume = self.fillVolumes[i];
		fillVolume.volume = createFillPlaneShape(fillVolume.baseNode, "fillPlane", self.varBody.nodes[i].capacity, fillVolume.maxDelta, fillVolume.maxSurfaceAngle, math.rad(35), fillVolume.maxSubDivEdgeLength, fillVolume.allSidePlanes);
		setVisibility(fillVolume.volume, false);
		link(fillVolume.baseNode, fillVolume.volume);
	end;
	if self.varBody.activeIdx > i then
		self.varBody.activeIdx = i;
	end;
	self.varBody.nodeCount=table.getn(self.varBody.nodes);
	if savegame then
		local idx = Utils.getNoNil(getXMLInt(savegame.xmlFile, savegame.key.."#varBody.activeIdx"),1);
		if idx > table.getn(self.varBody.nodes) then
			idx = 1;
		end;
		local idx2 = Utils.getNoNil(getXMLInt(savegame.xmlFile, savegame.key.."#varBody.activeSubIdx"),1);
		if idx2 > table.getn(self.varBody.nodes[idx].parts) then
			idx2 = 1;
		end;
		self:changeVariableBody(idx, idx2, true);
		local fillLevel = getXMLFloat(savegame.xmlFile, savegame.key.."#fillLevels");
		local currentFillType = getXMLString(savegame.xmlFile, savegame.key.."#fillTypes");
		currentFillType = FillUtil.fillTypeNameToInt[currentFillType];
		if fillLevel ~= nil and currentFillType ~= nil then
			self:setFillLevel(fillLevel, currentFillType);
			self:resetFillLevelIfNeeded(currentFillType);
		end;
	end;
end;

function VariableBody:readStream(streamId, connection)
	local state = streamReadInt8(streamId);
	local state2 = streamReadInt8(streamId);
	self:changeVariableBody(state, state2, true);
	local fillLevel = streamReadFloat32(streamId);
	local currentFillType = self.fillUnits[1].currentFillType;
	if fillLevel > 0 and currentFillType > 0 then
		self:setFillLevel(fillLevel, currentFillType);
		self:resetFillLevelIfNeeded(currentFillType);
	end;
end;

function VariableBody:writeStream(streamId, connection)
	streamWriteInt8(streamId, self.varBody.activeIdx);
	streamWriteInt8(streamId, self.varBody.activeSubIdx);
	streamWriteFloat32(streamId, self.fillUnits[1].fillLevel);
end;

function VariableBody:delete()
end;

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

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

function VariableBody:update(dt)
	if self.varTip ~= nil then
		if self.varTip.activeTrailerIdx ~= self.varTip.trailerNr then
			return;
		end;
	end;
	if self:getIsActive() then
		if self:getIsActiveForInput() then
			if self.tipState == Trailer.TIPSTATE_CLOSED then
				local nodes = self.varBody.nodes;
				if self.fillUnits[1].fillLevel == 0 then
					if InputBinding.hasEvent(InputBinding.VARIABLEBODY_change) then
						local idx = self.varBody.activeIdx + 1;
						if idx > self.varBody.nodeCount then
							idx = 1
						end;
						local idx2 = self.varBody.activeSubIdx;
						if idx2 > nodes[idx].partCount then
							idx2 = 1;
						end
						self:changeVariableBody(idx, idx2);
					end;
				end;
				if string.match("roof", nodes[self.varBody.activeIdx].name) then
					if InputBinding.hasEvent(InputBinding.VARIABLEBODY_changePart) then
						local idx = self.varBody.activeSubIdx + 1;
						if idx > nodes[self.varBody.activeIdx].partCount then
							idx = 1
						end;
						self:changeVariableBody(self.varBody.activeIdx, idx);
					end;
				end;
			end;
		end;
	end;
end;

function VariableBody:updateTick(dt)
end;

function VariableBody:draw()
	if self.varTip ~= nil then
		if self.varTip.activeTrailerIdx ~= self.varTip.trailerNr then
			return;
		end;
	end;
	if self:getIsActive() and self:getIsActiveForInput() then
		if self.tipState == Trailer.TIPSTATE_CLOSED then
			if self.fillUnits[1].fillLevel == 0 then
				if self.varBody.nodeCount> 1 then
					g_currentMission:addHelpButtonText(string.format(g_i18n:getText("VARIABLEBODY_display"), self.varBody.activeIdx, self.varBody.nodeCount),
					InputBinding.VARIABLEBODY_change);
				end;
			end;
			if string.match("roof", self.varBody.nodes[self.varBody.activeIdx].name) then
				g_currentMission:addHelpButtonText(g_i18n:getText("VARIABLEBODY_displayPart"), InputBinding.VARIABLEBODY_changePart );
			end;
		end;
	end;
end;

function VariableBody:getSaveAttributesAndNodes(nodeIdent)
	local attributes = ' varBody.activeIdx="'..tostring(self.varBody.activeIdx)..'" varBody.activeSubIdx="'..tostring(self.varBody.activeSubIdx)..'"';
    local node = nil;
    return attributes, node;
end;

function VariableBody:changeVariableBody(state, state2, noEventSend)
	VariableBodyEvent.sendEvent(self, state, state2, noEventSend);
	for i=1, table.getn(self.varBody.nodes) do
		if self.varBody.nodes[i].partCount > 0 then
			for j=1, table.getn(self.varBody.nodes[i].parts) do
				if i ~= state or j ~= state2 then
					for k=1,table.getn(self.varBody.nodes[i].parts[j].objects) do
						setVisibility(self.varBody.nodes[i].parts[j].objects[k], false);
					end;
				end
			end;
		end;
	end;
	local stateNodes = self.varBody.nodes[state];
	if stateNodes ~= nil then
		if stateNodes.partCount > 0 then
			if stateNodes.parts[state2].subPartCount > 0 then
				for k=1,table.getn(stateNodes.parts[state2].objects) do
					setVisibility(stateNodes.parts[state2].objects[k], true);
				end;
			end;
		end;
	end;
	self.fillUnits[1].fillVolumeIndex = state;
	self.fillUnits[1].fillTypes = stateNodes.fillTypes;
	self.fillUnits[1].capacity = stateNodes.capacity;
	if self.cp and self.cp.workTools and self.cp.workTools[1] then
		self.cp.workTools[1].fillTypes = stateNodes.fillTypes;
	end;
	if stateNodes.parts[state2].allowFill == 1 then
		self.allowFillFromAir = true;
	else
		self.allowFillFromAir = false;
	end;
	self.varBody.activeIdx = state;
	self.varBody.activeSubIdx = state2;
end;


---------------------------------------------------------------------------------------

VariableBodyEvent = {};
VariableBodyEvent_mt = Class(VariableBodyEvent, Event);

InitEventClass(VariableBodyEvent, "VariableBodyEvent");

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

function VariableBodyEvent:new(vehicle, state, state2)
    local self = VariableBodyEvent:emptyNew()
    self.vehicle = vehicle;
    self.state = state;
    self.state2 = state2;
    return self;
end;

function VariableBodyEvent:readStream(streamId, connection)
    local id = streamReadInt32(streamId);
    self.state = streamReadInt8(streamId);
    self.state2 = streamReadInt8(streamId);
    self.vehicle = networkGetObject(id);
    self:run(connection);
end;

function VariableBodyEvent:writeStream(streamId, connection)
    streamWriteInt32(streamId, networkGetObjectId(self.vehicle));
    streamWriteInt8(streamId, self.state);
    streamWriteInt8(streamId, self.state2);
end;

function VariableBodyEvent:run(connection)
    self.vehicle:changeVariableBody(self.state, self.state2, true);
    if not connection:getIsServer() then
        g_server:broadcastEvent(VariableBodyEvent:new(self.vehicle, self.state, self.state2), nil, connection, self.vehicle);
    end;
end;

function VariableBodyEvent.sendEvent(vehicle, state, state2, noEventSend)
    if vehicle == nil then
        print("--------> VariableBody erRoR :/ ");
    end;
    if state ~= vehicle.varBody.activeIdx or state2 ~= vehicle.varBody.activeSubIdx then
        if noEventSend == nil or noEventSend == false then
            if g_server ~= nil then
                g_server:broadcastEvent(VariableBodyEvent:new(vehicle, state, state2), nil, nil, vehicle);
            else
                g_client:getServerConnection():sendEvent(VariableBodyEvent:new(vehicle, state, state2));
            end;
        end;
    end;
end;
