--
-- VariableBody
-- This is the specialization for trailers, which have a extra bodywork for loading chaff/grass?
-- 
--
-- @author:		fruktor (wwww.modding-society.de)
-- @version:	v0.1
-- @date:		08/12/10
-- @history:	v0.1 - inital implementation
--
-- Copyright (C) 
-----------------------------------------------------
-- Class for extra sides of Galucho trailers
--
-- @edited by  PeterJ - euroDZN
-- @date  06/11/2012
--
-- http://eurodzn.wordpress.com/
--
-- Copyright (C) euroDZN, Confidential, All Rights Reserved.

VariableBody = {};

function VariableBody.prerequisitesPresent(specializations)
    return SpecializationUtil.hasSpecialization(Attachable, specializations);
end;

function VariableBody:load(xmlFile)
------------------------<<<<<<<<<<<<<<<>>>>>>>>>>>>>>>>------------------------
	--- has to be loaded before Fillable ---
	self.fillTypes = {};
	self.fillTypes[Fillable.FILLTYPE_UNKNOWN] = true;
  
	local fruitTypes = getXMLString(xmlFile, "vehicle.fillTypes#fruitTypes");
	if fruitTypes ~= nil then
		local types = Utils.splitString(" ", fruitTypes);
		for k,v in pairs(types) do
			local fillType = Fillable.fillTypeNameToInt[v];
			if fillType ~= nil then
				self.fillTypes[fillType] = true;
			end;
		end;
	end;
------------------------<<<<<<<<<<<<<<<>>>>>>>>>>>>>>>>------------------------

	self.changeVariableBody = SpecializationUtil.callSpecializationsFunction("changeVariableBody");
	
	self.varBody = {};

	local activeIdx = getXMLInt(xmlFile, "vehicle.variableBody#activeIdx");
	if activeIdx ~= nil then
		self.varBody.activeIdx = activeIdx;
	else
		self.varBody.activeIdx = 1;
	end;
	
	local activeIdx = getXMLInt(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(xmlFile, path .. "#name");
		if name == nil then
			break;
		end;
		local capacity = getXMLInt(xmlFile, path .. "#capacity");
		local fillTypes = {};
		local fruitTypes = getXMLString(xmlFile, path .. "#fruitTypes");
		if fruitTypes ~= nil then
			local types = Utils.splitString(" ", fruitTypes);
			for k,v in pairs(types) do
				local fillType = Fillable.fillTypeNameToInt[v];
				if fillType ~= nil then
					fillTypes[fillType] = true;
				else
					print("Warning: '"..self.configFileName.. "' has invalid fillType '"..v.."'.");
				end;
			end;
		end;
		local onlyTipBack = Utils.getNoNil(getXMLBool(xmlFile, path.."#onlyTipBack"), false);
		local parts = {};
		j=0;
		local k=1;
		local str = getXMLString(xmlFile, string.format("vehicle.variableBody.node(%d).part(%d)#index%d", i, j, k));	
		while str ~= nil do
			local subparts = {};
			subparts.allowFill = Utils.getNoNil(getXMLBool(xmlFile, string.format("vehicle.variableBody.node(%d).part(%d)#allowFill", i, j)), true);
			subparts.objects = {};
			while str ~= nil do 
				local tmpIdx = Utils.indexToObject(self.components, str)
				k=k+1;
				table.insert(subparts.objects, tmpIdx);
				str = getXMLString(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(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 = true;
			subparts.subPartCount = 0;
			table.insert(parts, subparts);
		end;
		local entry={};
		entry.name = name;
		entry.capacity = capacity;
		entry.onlyTipBack = onlyTipBack;
		entry.index = index; 
		entry.parts = parts;
		entry.partCount = j;
		entry.fillTypes = fillTypes;
		table.insert(self.varBody.nodes, entry);
		i=i+1;
	end;
	
	if self.varBody.activeIdx > i then
		self.varBody.activeIdx = i;
	end;
	self.varBody.nodeCount=table.getn(self.varBody.nodes);
	
	self.previousFillLevel = self.fillLevel;
	
	--self:changeVariableBody(self.varBody.activeIdx, self.varBody.activeSubIdx, true);
	
	self.operateCoverDelay = 0;
end;

function VariableBody:readStream(streamId, connection)
	local state = streamReadInt8(streamId);
	local state2 = streamReadInt8(streamId);
	self:changeVariableBody(state, state2, true);
end;

function VariableBody:writeStream(streamId, connection)
	streamWriteInt8(streamId, self.varBody.activeIdx);
	streamWriteInt8(streamId, self.varBody.activeSubIdx);
end;

function VariableBody:delete()
end;

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

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

function VariableBody:loadFromAttributesAndNodes(xmlFile, key, resetVehicles)
	if self.synchronizeFillLevel then
		local idx = Utils.getNoNil(getXMLInt(xmlFile,key.."#varBodyIdx"),1);
		if idx > table.getn(self.varBody.nodes) then
			idx = 1;
		end;
		local idx2 = Utils.getNoNil(getXMLInt(xmlFile,key.."#varBodySubIdx"),1);
		if idx2 > table.getn(self.varBody.nodes[idx].parts) then
			idx2 = 1;
		end;
		self:changeVariableBody(idx, idx2, true);
	end;
    return BaseMission.VEHICLE_LOAD_OK;
end;

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

function VariableBody:update(dt)
	if self:getIsActive() then
		if self:getIsActiveForInput() then
			if self.tipState == Trailer.TIPSTATE_CLOSED and self.capacity > 0 then
				if self.fillLevel == 0 then
					if InputBinding.hasEvent(InputBinding.IMPLEMENT_EXTRA) then
						if self.fillLevel == 0 then
							local idx = self.varBody.activeIdx + 1;
							if idx > self.varBody.nodeCount then
								idx = 1
							end;
							local idx2 = 1;
							self:changeVariableBody(idx, idx2);
						end;
					end;
				end;
				if string.match("sidesWithCover", self.varBody.nodes[self.varBody.activeIdx].name) and self.operateCoverDelay < self.time then
					if InputBinding.hasEvent(InputBinding.IMPLEMENT_EXTRA3) then
						local idx = self.varBody.activeSubIdx + 1;
						if idx > self.varBody.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)
	if self:getIsActive() then
		if self.fillLevel ~= self.previousFillLevel then
			self.operateCoverDelay = self.time + 1200;
		end;
		self.previousFillLevel = self.fillLevel;
	end;
end;

function VariableBody:draw()
	if self.tipState == Trailer.TIPSTATE_CLOSED and self.capacity > 0 then
		if self.fillLevel == 0 then
			if self.varBody.nodeCount > 1 then
				g_currentMission:addHelpButtonText(g_i18n:getText("ChangeBody"), InputBinding.IMPLEMENT_EXTRA);
			end;
		end;
		if self.operateCoverDelay < self.time then
			if string.match("sidesWithCover", self.varBody.nodes[self.varBody.activeIdx].name) then
				g_currentMission:addHelpButtonText(g_i18n:getText("GrainCover"), InputBinding.IMPLEMENT_EXTRA3);
			end;
		end;
	end;
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;
	if self.varBody.nodes[state] ~= nil then
		if self.varBody.nodes[state].partCount > 0 then
			if self.varBody.nodes[state].parts[state2].subPartCount > 0 then
				for k=1,table.getn(self.varBody.nodes[state].parts[state2].objects) do
					setVisibility(self.varBody.nodes[state].parts[state2].objects[k], true);
				end;	
			end;
		end;
	end;
	for i,j in pairs(self.fillTypes) do
		if self.varBody.nodes[state].fillTypes[i] == true then
			self.fillTypes[i] = true;
		else
			self.fillTypes[i] = false;
		end;
	end;	
	if self.varBody.nodes[state].parts[state2].allowFill then
		self.allowFillFromAir = true;
	else
		self.allowFillFromAir = false;
	end;
	self.capacity = self.varBody.nodes[state].capacity;
	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 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;