--author: igor29381
--v3.3
--date: 15.01.17

ShowCargoUnits = {};

function ShowCargoUnits.prerequisitesPresent(specializations)
    return SpecializationUtil.hasSpecialization(Fillable, specializations);
end;

function ShowCargoUnits:load(savegame)
	self.setUnitFillLevel = Utils.appendedFunction(self.setUnitFillLevel, ShowCargoUnits.updateCargoUnits);
	self.dumpOnPallet = ShowCargoUnits.dumpOnPallet;
	self.enableDumpOnPallet = ShowCargoUnits.enableDumpOnPallet;
	if hasXMLProperty(self.xmlFile, "vehicle.CargoUnits") then
		self.cargoUnits = {};
		local c = 0;
		while true do
			local baseString = string.format("vehicle.CargoUnits.cargoUnit(%d)",c);
			local index = getXMLString(self.xmlFile, baseString.."#index");
			local fillTypes = getXMLString(self.xmlFile, baseString.."#fillTypes");
			local defaultCargoUnit = Utils.getNoNil(getXMLBool(self.xmlFile, baseString.."#defaultCargoUnit"), false);
			if index == nil or fillTypes == nil then break; end;
			fillTypes = Utils.splitString(" ", fillTypes);
			local units = {};
			units.index = Utils.indexToObject(self.components, index);
			units.count = getNumOfChildren(units.index);
			if defaultCargoUnit then
				self.defaultCargoUnit = units;
			end;
			for i=1, #fillTypes do
				local fillType = FillUtil.fillTypeNameToInt[fillTypes[i]];
				if fillType then
					self.cargoUnits[fillType] = units;
				end;
			end;
			c = c + 1;
		end;
		if self.defaultCargoUnit then
			for fillType,_ in pairs(self.fillUnits[1].fillTypes) do
				if not self.cargoUnits[fillType] then
					self.cargoUnits[fillType] = self.defaultCargoUnit;
				end;
			end;
		end;
	end;
	local hasMeasurementNodes = false;
	for i=1, #self.fillUnits do
		if self.fillUnits[i].measurementNodes then
			hasMeasurementNodes = true;
			break;
		end;
	end;
	if hasMeasurementNodes and hasXMLProperty(self.xmlFile, "vehicle.liquidColors") then
		self.liquidColors = {};
		local c = 0;
		while true do
			local baseString = string.format("vehicle.liquidColors.color(%d)", c);
			local rgb = getXMLString(self.xmlFile, baseString.."#rgb");
			local fillTypes = getXMLString(self.xmlFile, baseString.."#fillTypes");
			if rgb == nil or fillTypes == nil then break; end;
			fillTypes = Utils.splitString(" ", fillTypes);
			for i=1, #fillTypes do
				local fillType = FillUtil.fillTypeNameToInt[fillTypes[i]];
				if fillType then
					self.liquidColors[fillType] = {Utils.getVectorFromString(rgb)};
				end;
			end;
			c = c + 1;
		end;
	end;
	if hasXMLProperty(self.xmlFile, "vehicle.rotationParts") then
		self.rotationParts = {};
		local c = 0;
		while true do
			local baseString = string.format("vehicle.rotationParts.part(%d)", c);
			local index = getXMLString(self.xmlFile, baseString.."#index");
			if index == nil then break; end;
			local id = Utils.indexToObject(self.components, index);
			if id and id > 0 then
				local rotDirections = getXMLString(self.xmlFile, baseString.."#rotDirections");
				rotDirections = {Utils.getVectorFromString(rotDirections)};
				local speed = Utils.getNoNil(getXMLFloat(self.xmlFile, baseString.."#speed"), 0);
				local rotateIfMotorStarted = Utils.getNoNil(getXMLBool(self.xmlFile, baseString.."#rotateIfMotorStarted"), false);
				table.insert(self.rotationParts, {id=id, rotDirections=rotDirections, speed=speed, rotateIfMotorStarted=rotateIfMotorStarted});
			end;
			c = c + 1;
		end;
	end;
	self.palletLoadMode = false;
	if not SpecializationUtil.hasSpecialization(Cover, self.specializations) then
		self.isCoverOpen = true;
	end;
	local palletReferencePointIndex = getXMLString(self.xmlFile, "vehicle.CargoUnits#palletReferencePointIndex");
	if palletReferencePointIndex then
		self.palletReferencePoint = Utils.indexToObject(self.components, palletReferencePointIndex);
	end;
	local palletLoadInputButton = Utils.getNoNil(getXMLString(self.xmlFile, "vehicle.CargoUnits#palletLoadInputButton"), "IMPLEMENT_EXTRA4");
	self.palletLoadInputButton = InputBinding[palletLoadInputButton];
	local dumpOnPalletInputButton = Utils.getNoNil(getXMLString(self.xmlFile, "vehicle.CargoUnits#dumpOnPalletInputButton"), "TOGGLE_TIPSTATE");
	self.dumpOnPalletInputButton = InputBinding[dumpOnPalletInputButton];
end;

function ShowCargoUnits:delete()
end;

function ShowCargoUnits:readStream(streamId, connection)
end;

function ShowCargoUnits:writeStream(streamId, connection)
end;

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

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

function ShowCargoUnits:update(dt)
	if self:getIsActive() and self:getIsActiveForInput() and self.cargoUnits and self ~= g_currentMission.trailerInTipRange then
		if InputBinding.hasEvent(self.dumpOnPalletInputButton) then
			if self:enableDumpOnPallet() then
				self.palletLoadMode = false;
				if g_server then
					self:dumpOnPallet();
					g_server:broadcastEvent(CargoUnitsEvent:new(false, true, self));
				else
					g_client:getServerConnection():sendEvent(CargoUnitsEvent:new(false, true, self));
				end;
			end;
		end;
		if InputBinding.hasEvent(self.palletLoadInputButton) then
			self.palletLoadMode = not self.palletLoadMode;
			if g_server then
				g_server:broadcastEvent(CargoUnitsEvent:new(self.palletLoadMode, false, self));
			else
				g_client:getServerConnection():sendEvent(CargoUnitsEvent:new(self.palletLoadMode, false, self));
			end;
		end;
	end;
	if g_server and self.isCoverOpen and self.palletLoadMode then
		local x,_,z = getWorldTranslation(self.palletReferencePoint);
		if g_currentMission.itemsToSave then
			for index,item in pairs(g_currentMission.itemsToSave) do
				local pallet = item.item;
				if pallet:isa(FillablePallet) and pallet.fillType then
					local fillType = self.fillUnits[1].currentFillType;
					if (fillType ~= 0 and pallet.fillType == fillType) or (fillType == 0 and self.cargoUnits[pallet.fillType]) then
						local fillLevel = self:getFillLevel(pallet.fillType);
						local fpx, _, fpz = getWorldTranslation(pallet.nodeId);
						local distance = Utils.vector2Length(fpx-x, fpz-z);
						if distance < 1.5 then
							if pallet.fillLevel <= self:getCapacity(pallet.fillType) + 1 - fillLevel then
								self:setFillLevel(fillLevel + pallet.fillLevel, pallet.fillType);
								pallet:delete();
								g_currentMission:addSharedMoney(-50, "wagePayment");
								g_currentMission:addMoneyChange(-50, FSBaseMission.MONEY_TYPE_SINGLE, true, g_i18n:getText("finance_wagePayment"));
							else
								self.palletLoadMode = false;
								g_server:broadcastEvent(CargoUnitsEvent:new(false, false, self));
							end;
						end;
					end;
				end;
			end;
		end;
	end;
	if self.rotationParts then
		local rootAttacherVehicle = self:getRootAttacherVehicle();
		local motorStarted = rootAttacherVehicle and rootAttacherVehicle.motor and rootAttacherVehicle:getIsMotorStarted();
		for i=1, #self.rotationParts do
			local part = self.rotationParts[i];
			if not part.rotateIfMotorStarted or (part.rotateIfMotorStarted and motorStarted) then
				local rx,ry,rz = getRotation(part.id);
				local rot1 = rx + dt*part.speed*part.rotDirections[1];
				local rot2 = ry + dt*part.speed*part.rotDirections[2];
				local rot3 = rz + dt*part.speed*part.rotDirections[3];
				setRotation(part.id, rot1, rot2, rot3);
			end;
		end;
	end;
end;

function ShowCargoUnits:updateTick(dt)
end;

function ShowCargoUnits:draw()
	if self.cargoUnits then
		if self.palletLoadMode then
			g_currentMission:addHelpButtonText(g_i18n:getText("palletLoadModeOff"), self.palletLoadInputButton);
		else
			g_currentMission:addHelpButtonText(g_i18n:getText("palletLoadModeOn"), self.palletLoadInputButton);
		end;
		if self:enableDumpOnPallet() and self ~= g_currentMission.trailerInTipRange then
			g_currentMission:addHelpButtonText(g_i18n:getText("dumpOnPallet"), self.dumpOnPalletInputButton);
		end;
	end;
end;

function ShowCargoUnits:dumpOnPallet()
	local x,y,z = getWorldTranslation(self.palletReferencePoint);
	local _,ry,_ = getWorldRotation(self.palletReferencePoint);
	if g_currentMission.itemsToSave then
		for index,item in pairs(g_currentMission.itemsToSave) do
			local pallet = item.item;
			if pallet:isa(FillablePallet) then
				local fpx, _, fpz = getWorldTranslation(pallet.nodeId);
				local distance = Utils.vector2Length(fpx-x, fpz-z);
				if distance < 1.5 then
					g_currentMission:showBlinkingWarning(g_i18n:getText("otherPallet"), 2000);
					return;
				end;
			end;
		end;
	end;
	local currentFillType = self.fillUnits[1].currentFillType;
	local fillLevel = self:getFillLevel(currentFillType);
	local pallet = FillablePallet:new(self.isServer, self.isClient);
	pallet.fillablePalletValueScale = 1;
	pallet:load(Kavkaz.PalletBase[currentFillType], x,y+0.5,z, 0,ry,0);
	pallet:register();
	pallet.fillType = currentFillType;
	local delta = math.min(2000, fillLevel);
	pallet:setFillLevel(delta, true);
	pallet.sendI3dFilename = true;
	fillLevel = fillLevel - delta;
	self:setFillLevel(fillLevel, currentFillType);
	self:resetFillLevelIfNeeded(currentFillType);
	if fillLevel <= 0.99 then
		self:setFillLevel(0, 0);
		self:resetFillLevelIfNeeded(0);
	end;
	g_currentMission:addSharedMoney(-50, "wagePayment");
	g_currentMission:addMoneyChange(-50, FSBaseMission.MONEY_TYPE_SINGLE, true, g_i18n:getText("finance_wagePayment"));
end;

function ShowCargoUnits:enableDumpOnPallet()
	local fillType = self.fillUnits[1].currentFillType;
	if self.isCoverOpen and Kavkaz and Kavkaz.PalletBase and fillType ~= 0 and Kavkaz.PalletBase[fillType] then
		return true;
	end;
	return false;
end;

function ShowCargoUnits:updateCargoUnits()
	local fillUnit = self.fillUnits[1];
	local fillType = fillUnit.currentFillType;
	if self.cargoUnits then
		if fillType ~= 0 then
			local units = self.cargoUnits[fillType];
			local capacity = self:getCapacity(fillType);
			if units and capacity > 0 then
				local unitsToShow = math.ceil(units.count*(self:getFillLevel(fillType)/capacity));
				for i=1, units.count do
					setVisibility(getChildAt(units.index, i-1), i <= unitsToShow);
				end;
			end;
		else
			for _,units in pairs(self.cargoUnits) do
				for i=1, units.count do
					setVisibility(getChildAt(units.index, i-1), false);
				end;
			end;
		end;
	end;
	if fillUnit.currentFillPlane ~= nil then
        for _, node in ipairs(fillUnit.currentFillPlane.nodes) do
            setVisibility(node.node, false);
        end
        fillUnit.currentFillPlane = nil;
    end
    if fillUnit.fillPlanes ~= nil and fillUnit.defaultFillPlane ~= nil then
        local fillPlane;
        local t = 0;
        if fillType ~= FillUtil.FILLTYPE_UNKNOWN then
            fillPlane = fillUnit.fillPlanes[fillType];
            t = fillUnit.fillLevel/fillUnit.capacity;
        end;
        if fillPlane == nil then
            fillPlane = fillUnit.defaultFillPlane;
        end;
        for _, node in ipairs(fillPlane.nodes) do
            local x,y,z, rx,ry,rz, sx,sy,sz = node.animCurve:get(t);
            setTranslation(node.node, x, y, z);
            setRotation(node.node, rx, ry, rz);
            setScale(node.node, sx, sy, sz);
            setVisibility(node.node, fillUnit.fillLevel > 0 or node.alwaysVisible);
        end;
        fillUnit.currentFillPlane = fillPlane;
    end;
	if self.liquidColors then
		for i=1, #self.fillUnits do
			local fillUnit = self.fillUnits[i];
			if fillUnit.measurementNodes then
				for ii=1, #fillUnit.measurementNodes do
					local rgb = self.liquidColors[fillUnit.currentFillType];
					if rgb then
						setShaderParameter(fillUnit.measurementNodes[ii], "liquidColor", rgb[1], rgb[2], rgb[3], 0, false);
					end;
				end;
			end;
		end;
	end;
end;

CargoUnitsEvent = {};
CargoUnitsEvent_mt = Class(CargoUnitsEvent, Event);
InitEventClass(CargoUnitsEvent, "CargoUnitsEvent");

function CargoUnitsEvent:emptyNew()
	local self = Event:new(CargoUnitsEvent_mt);
    return self;
end;

function CargoUnitsEvent:new(palletLoadMode, dumpOnPallet, vehicle)
	local self = CargoUnitsEvent:emptyNew();
	self.palletLoadMode = palletLoadMode;
	self.dumpOnPallet = dumpOnPallet;
	self.vehicle = vehicle;
	return self;
end;

function CargoUnitsEvent:readStream(streamId, connection)
	local palletLoadMode = streamReadBool(streamId);
	local dumpOnPallet = streamReadBool(streamId);
	local id = streamReadInt32(streamId);
    local vehicle = networkGetObject(id);
	if vehicle then
		vehicle.palletLoadMode = palletLoadMode;
		if g_server then
			if dumpOnPallet then
				vehicle:dumpOnPallet();
			end;
			g_server:broadcastEvent(CargoUnitsEvent:new(vehicle.palletLoadMode, false, vehicle));
		end;
	end;
end;

function CargoUnitsEvent:writeStream(streamId, connection)
	streamWriteBool(streamId, self.palletLoadMode);
	streamWriteBool(streamId, self.dumpOnPallet);
	streamWriteInt32(streamId, networkGetObjectId(self.vehicle));
end;
