--
-- John Deere 8350 grain drill
--
-- author  Mythos
-- date  06/08/2012
-- www.ARM-team.gr
-- Copyright (C) ARM Team, All Rights Reserved.

JD8350 = {};

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

--________________________________________________________________________________________________________________________________________________________
function JD8350:load(xmlFile)

	-- Functions
	self.MPCode = SpecializationUtil.callSpecializationsFunction("MPCode");
	self.getTriggerDistance = SpecializationUtil.callSpecializationsFunction("getTriggerDistance");
	self.findTriggers = SpecializationUtil.callSpecializationsFunction("findTriggers");
	self.setFertLevel = JD8350.setFertLevel;
	
	-- Animations
	self.frontLidAnim = getXMLString(xmlFile, "vehicle.frontLid#animationName");
	self.backLidAnim = getXMLString(xmlFile, "vehicle.backLid#animationName");
	self.rightAtt = getXMLString(xmlFile, "vehicle.rightAttacher#animationName");
	self.leftAtt = getXMLString(xmlFile, "vehicle.leftAttacher#animationName");
	self.disksAnim = getXMLString(xmlFile, "vehicle.disksAnim#animationName");
	
	-- Indexs
	self.fertPlanes = {};
	local node = Utils.indexToObject(self.components, getXMLString(xmlFile, "vehicle.fertPlane#index"));
	if node ~= nil then
		local defaultX, defaultY, defaultZ = getTranslation(node);
		local defaultRX, defaultRY, defaultRZ = getRotation(node);
		setVisibility(node, false);
		local animCurve = AnimCurve:new(linearInterpolatorTransRotScale);
		local keyI = 0;
		while true do
			local animKey = string.format("vehicle.fertPlane.key(%d)", keyI);
			local keyTime = getXMLFloat(xmlFile, animKey.."#time");
			local x,y,z = Utils.getVectorFromString(getXMLString(xmlFile, animKey.."#translation"));
			if y == nil then
				y = getXMLFloat(xmlFile, animKey.."#y");
			end;
			local rx,ry,rz = Utils.getVectorFromString(getXMLString(xmlFile, animKey.."#rotation"));
			local sx,sy,sz = Utils.getVectorFromString(getXMLString(xmlFile, animKey.."#scale"));
			if keyTime == nil then
				break;
			end;
			local x = Utils.getNoNil(x, defaultX);
			local y = Utils.getNoNil(y, defaultY);
			local z = Utils.getNoNil(z, defaultZ);
			local rx = Utils.getNoNil(rx, defaultRX);
			local ry = Utils.getNoNil(ry, defaultRY);
			local rz = Utils.getNoNil(rz, defaultRZ);
			local sx = Utils.getNoNil(sx, 1);
			local sy = Utils.getNoNil(sy, 1);
			local sz = Utils.getNoNil(sz, 1);
			animCurve:addKeyframe({x=x, y=y, z=z, rx=rx, ry=ry, rz=rz, sx=sx, sy=sy, sz=sz, time = keyTime});
			keyI = keyI +1;
		end;
		table.insert(self.fertPlanes, {node=node, animCurve = animCurve});
	end;
	
	-- Overlays
	self.fertLevel = {};
	self.fertLevel.xPos = Utils.getNoNil(getXMLFloat(xmlFile,  "vehicle.fertLevel#posX"), 0.7343);
	self.fertLevel.yPos = Utils.getNoNil(getXMLFloat(xmlFile,  "vehicle.fertLevel#posY"), 0.0148);
	self.fertLevel.hudBarHeight = 0.117592;
	self.fertLevel.overlay = Overlay:new("hudESLOverlay", Utils.getFilename("fertLevel_hud.png", self.baseDirectory), self.fertLevel.xPos, self.fertLevel.yPos, 0.0203125, 0.26574);
	self.fertLevel.overlayBg = Overlay:new("hudESLBackground", Utils.getFilename("fertLevel_bg.png", self.baseDirectory), self.fertLevel.xPos, self.fertLevel.yPos, 0.0203125, 0.26574);
	self.fertLevel.overlayBar = Overlay:new("hudESLbar", Utils.getFilename("fertLevel_bar.png", self.baseDirectory), self.fertLevel.xPos + 0.00208333, self.fertLevel.yPos + 0.0268, 0.0166666, 0.117592);

	-- Booleans etc
	self.lid1 = false;
	self.lid2 = false;
	self.fanimEnded = true;
	self.banimEnded = true;
	self.applyingFertilizer = false;
	self.allowFillWithFert = false;
	self.foundIt = false;

	self.allowFillFromTrigger = false;
	self.fertFillingActivated = false;
	self.alarm2 = false;
	self.fertFillLevel = 0;
	self.fertUsagePerSqm = Utils.getNoNil(getXMLFloat(xmlFile, "vehicle.fertUsagePerSqm"), 0.022);
	self.fertCapacity = Utils.getNoNil(getXMLFloat(xmlFile, "vehicle.capacity"), 830.0);
	
	self.rA = false;
	self.lA = false;
	self.lowerDisks = false;
	
	self.triggerPoints = {};
	self.triggerPoints1 = {};
		
	self.seeds = {};
	self.tipes = {};
	
	local fillTipes = getXMLString(xmlFile, "vehicle.seedFruitTypes#seedFruitTypes");
    if fillTipes ~= nil then
        self.tipes = Utils.splitString(" ", fillTipes);
    end;

	for i,v in pairs(FruitUtil.fruitTypes) do
		for k,m in pairs(self.tipes) do
			if m == v.name and v.allowsSeeding then
				table.insert(self.seeds, v.index);
				break;
			end;
		end;
	end;
	
	self.ct = 2000;
	
end;

--________________________________________________________________________________________________________________________________________________________
function JD8350:delete()
end;

--________________________________________________________________________________________________________________________________________________________
function JD8350:mouseEvent(posX, posY, isDown, isUp, button)
end;

--________________________________________________________________________________________________________________________________________________________
function JD8350:keyEvent(unicode, sym, modifier, isDown)
end;

--________________________________________________________________________________________________________________________________________________________
function JD8350:update(dt)
	
	if self:getIsHired() then
		self.fertOnLeave = true;
	else
		self.fertOnLeave = false;
	end;
	
	if (self:getIsActiveForInput() and self:getIsActive()) or self:getIsHired() then
		
		if self.fanimEnded and self.banimEnded then
			if not self.lid2 then
				if InputBinding.hasEvent(InputBinding.LID1) then
					self:MPCode(1, not self.lid1);
				end;
			end;
			if not self.lid1 then
				if InputBinding.hasEvent(InputBinding.LID2) then
					self:MPCode(2, not self.lid2);
				end;
			end;
		end;
		
		if self.fertFillLevel >0 then
			if InputBinding.hasEvent(InputBinding.APPLY_FERT) then
				self.applyingFertilizer = not self.applyingFertilizer;
			end;
		end;

		if self.allowFillFromTrigger and self.fertFillLevel < self.fertCapacity then
			if InputBinding.hasEvent(InputBinding.ACTIVATE_OBJECT) then
				if self.allowFillWithFert then
					self.fertFillingActivated = not self.fertFillingActivated;
				else
					self.alarm2 = true;
				end;
			end;
		end;
		
		if InputBinding.hasEvent(InputBinding.LOWER_IMPLEMENT) then
			self:MPCode(9, not self.lowerDisks);
		end;
		
		if InputBinding.hasEvent(InputBinding.JD8350_RA) then
			self:MPCode(10, not self.rA);
		end;
		
		if InputBinding.hasEvent(InputBinding.JD8350_LA) then
			self:MPCode(11, not self.lA);
		end;

		if self.applyingFertilizer and self.lowerDisks then
			self:MPCode(3);
		end;
		
		if self.fertFillingActivated then
			self:MPCode(4, self.allowFillWithFert, dt);
		end;
		
		if self.foundIt then
			self.allowFillFromTrigger = true;
		else
			self.allowFillFromTrigger = false;
			self.fertFillingActivated = false;
		end;
		
		self:MPCode(8);
		self:MPCode(5);
		
		if self.alarm2 then
			self.ct = self.ct - dt;
			if self.ct <0 then
				self.alarm2 = false;
				self.ct = 2000;
			end;
		end;

		if table.getn(self.triggerPoints) >0 then
			for i,v in pairs(self.triggerPoints) do
				self:getTriggerDistance(v);
				self.triggerPoints1[i] = self.myDistance1;
			end;
		end;
		
		for i,v in pairs(self.triggerPoints1) do
			if v <=7 then
				self.foundIt = true;
				break;
			else
				self.foundIt = false;
			end;
		end;
		
	end;
	
end;

--________________________________________________________________________________________________________________________________________________________
function JD8350:updateTick(dt)
	if self:getIsActive() then
		self.isSelected = true;
	end;
end;

--________________________________________________________________________________________________________________________________________________________
function JD8350:onAttach(attacherVehicle)
	self:findTriggers(getRootNode(), "SprayerFillTrigger.onCreate", "MapFruitTrigger.MapFruitTriggerOnCreate");
end;

--________________________________________________________________________________________________________________________________________________________
function JD8350:onDetach()
	for i=1, table.getn(self.triggerPoints) do
		table.remove(self.triggerPoints);
		table.remove(self.triggerPoints1);
	end;
	self.applyingFertilizer = false;
	self.fertFillingActivated = false;
end;

--________________________________________________________________________________________________________________________________________________________
function JD8350:onLeave()
	if self.deactivateOnLeave then
		JD8350.onDeactivate(self);
	end;
end;

--________________________________________________________________________________________________________________________________________________________
function JD8350:onDeactivate()
    self.applyingFertilizer = false;
	self.fertFillingActivated = false;
end;

--________________________________________________________________________________________________________________________________________________________
function JD8350:MPCode(mode, state, dtime, noEventSend)
	JD8350Event.sendEvent(self, mode, state, dtime, noEventSend);

--______________________________________________________________________________
if mode == 1 then
--_________________________________ LID1 ________________________________________
	if state then
		self:playAnimation(self.frontLidAnim, 1, nil, true);
		self.lid1 = true;
	else
		self:playAnimation(self.frontLidAnim, -1, nil, true);
		self.lid1 = false;
		self.isSowingMachineFilling = false;
	end;
--______________________________________________________________________________
elseif mode == 2 then
--_________________________________ LID2 ________________________________________
	if state then
		self:playAnimation(self.backLidAnim, 1, nil, true);
		self.lid2 = true;
	else
		self:playAnimation(self.backLidAnim, -1, nil, true);
		self.lid2 = false;
		self.allowFillWithFert = false;
		self.fertFillingActivated = false;
	end;
--______________________________________________________________________________
elseif mode == 3 then
--_________________________________ FERT ________________________________________
if self.movingDirection > 0 then
	if self.fertFillLevel > 0 then
		local sprayAreas = {};
		local area = 0;
		local x,y,z = getWorldTranslation(self.cuttingAreas[1].start);
		local x1,y1,z1 = getWorldTranslation(self.cuttingAreas[1].width);
		local x2,y2,z2 = getWorldTranslation(self.cuttingAreas[1].height);
		table.insert(sprayAreas, {x,z,x1,z1,x2,z2});
		if (table.getn(sprayAreas) > 0) then
			local area = SprayArea.runLocallys(sprayAreas)
			if area > 0 then
				if g_server ~= nil then
					g_server:broadcastEvent(SprayArea:new(sprayAreas));
				else
					g_client:getServerConnection():sendEvent(SprayArea:new(sprayAreas));
				end;
			
				local pixelToSqm = g_currentMission:getTerrainDetailPixelsToSqm();
				local sqm = area*pixelToSqm;
				local usage = sqm*self.fertUsagePerSqm/10;
				if not self:getIsHired() then
					self.fertFillLevel = self.fertFillLevel - usage;
					self:setFertLevel();
				else
					local fillTypeDesc = Fillable.fillTypeIndexToDesc[Fillable.FILLTYPE_SEEDS]
					if fillTypeDesc ~= nil then
						local price = usage*fillTypeDesc.pricePerLiter;
						g_currentMission.missionStats.expensesTotal = g_currentMission.missionStats.expensesTotal + price;
						g_currentMission.missionStats.expensesSession = g_currentMission.missionStats.expensesSession + price;
						g_currentMission.missionStats.money = g_currentMission.missionStats.money - price;
					end;
				end;
			end;
		end;
	else
		self.applyingFertilizer = false;
		self.fertFillLevel = 0;
		self:setFertLevel();
	end;
end;
--______________________________________________________________________________
elseif mode == 4 then
--_________________________________ FILL FERT ____________________________________
	if state then
		if self.fertFillLevel < self.fertCapacity then
			local delta = self.fillLitersPerSecond*dtime*0.001;
			self.fertFillLevel = self.fertFillLevel + delta;
			self:setFertLevel();
			local fillTypeDesc = Fillable.fillTypeIndexToDesc[Fillable.FILLTYPE_SEEDS]
			if fillTypeDesc ~= nil then
				local price = delta*fillTypeDesc.pricePerLiter;
				g_currentMission.missionStats.expensesTotal = g_currentMission.missionStats.expensesTotal + price;
				g_currentMission.missionStats.expensesSession = g_currentMission.missionStats.expensesSession + price;
				g_currentMission.missionStats.money = g_currentMission.missionStats.money - price;
			end;
		else
			self.fertFillLevel = self.fertCapacity;
			self:setFertLevel();
			self.fertFillingActivated = false;
		end;
	end;
--______________________________________________________________________________
elseif mode == 5 then
--_________________________________ FERT LID CONF ______________________________
	if self.activeAnimations[self.backLidAnim] ~= nil then
		self.banimEnded = false;
		self.animTime = self:getRealAnimationTime(self.backLidAnim);
		if self.animTime > 900 and self.lid2 then
			self.allowFillWithFert = true;
		end;
	else
		self.banimEnded = true;
	end;
--______________________________________________________________________________
elseif mode == 8 then
--_________________________________ SEED LID CONF ______________________________
	if self.activeAnimations[self.frontLidAnim] ~= nil then
		self.fanimEnded = false;
	else
		self.fanimEnded = true;
	end;
--______________________________________________________________________________
elseif mode == 9 then
--_________________________________ DISKS ANIMATION ____________________________
	if state then
		self:playAnimation(self.disksAnim, 1, nil, true);
		self.lowerDisks = true;
	else
		self:playAnimation(self.disksAnim, -1, nil, true);
		self.lowerDisks = false;
	end;
--______________________________________________________________________________
elseif mode == 10 then
--_________________________________ RIGHT ATTACHER ______________________________
	if state then
		self:playAnimation(self.rightAtt, 1, nil, true);
		self.rA = true;
	else
		self:playAnimation(self.rightAtt, -1, nil, true);
		self.rA = false;
	end;
--______________________________________________________________________________
elseif mode == 11 then
--_________________________________   LEFT ATTACHER   ______________________________
	if state then
		self:playAnimation(self.leftAtt, 1, nil, true);
		self.lA = true;
	else
		self:playAnimation(self.leftAtt, -1, nil, true);
		self.lA = false;
	end;
end;
end;

--________________________________________________________________________________________________________________________________________________________
function JD8350:draw()

	if self.fanimEnded and self.banimEnded then
		if not self.lid2 then
			g_currentMission:addHelpButtonText(string.format(g_i18n:getText("Lid1"), self.typeDesc), InputBinding.LID1);
		end;
		if not self.lid1 then
			g_currentMission:addHelpButtonText(string.format(g_i18n:getText("Lid2"), self.typeDesc), InputBinding.LID2);
		end;
	end;
	
	if self.lowerDisks then
		g_currentMission:addHelpButtonText(string.format(g_i18n:getText("DISKS_UP"), self.typeDesc), InputBinding.LOWER_IMPLEMENT);
	else
		g_currentMission:addHelpButtonText(string.format(g_i18n:getText("DISKS_DOWN"), self.typeDesc), InputBinding.LOWER_IMPLEMENT);
	end;
	
	g_currentMission:addHelpButtonText(string.format(g_i18n:getText("RIGHT_ATT"), self.typeDesc), InputBinding.JD8350_RA);
	g_currentMission:addHelpButtonText(string.format(g_i18n:getText("LEFT_ATT"), self.typeDesc), InputBinding.JD8350_LA);
	
	if self.fertFillLevel >0 then
		if self.applyingFertilizer then
			g_currentMission:addHelpButtonText(string.format(g_i18n:getText("Stop fertilizer"), self.typeDesc), InputBinding.APPLY_FERT);
		else
			g_currentMission:addHelpButtonText(string.format(g_i18n:getText("Apply fertilizer"), self.typeDesc), InputBinding.APPLY_FERT);
		end;
	end;
	
	if self.foundIt and self.fertFillLevel < self.fertCapacity then
		if self.fertFillingActivated then
			g_currentMission:addHelpButtonText(string.format("Stop Filling Fertilizer", self.typeDesc), InputBinding.ACTIVATE_OBJECT);
		else
			g_currentMission:addHelpButtonText(string.format("Fill Fertilizer", self.typeDesc), InputBinding.ACTIVATE_OBJECT);
		end;
	end;
	
	if self.alarm2 then
		g_currentMission:addWarning("Open the fertilizer lid first!", 0.07+0.022);
	end;
	
	self.fertLevel.overlayBg:render();
	
	local percentage = self.fertFillLevel*100/self.fertCapacity;
	self.fertLevel.overlayBar.height = self.fertLevel.hudBarHeight * math.min(1, percentage/101);	
    setOverlayUVs(self.fertLevel.overlayBar.overlayId, 0, 0.05, 0, math.min(1, percentage/101), 1, 0.05, 1, math.min(1, percentage/101));
	self.fertLevel.overlayBar:render();
	
	self.fertLevel.overlay:render();
	
	if self.fertFillLevel == self.fertCapacity then
		setTextBold(true);
		setTextColor(0, 0, 0, 1);
		setTextAlignment(RenderText.ALIGN_CENTER);
		renderText(self.fertLevel.xPos + 0.007, self.fertLevel.yPos + 0.09, 0.02, "F");
		renderText(self.fertLevel.xPos + 0.0075, self.fertLevel.yPos + 0.07, 0.017, "U");
		renderText(self.fertLevel.xPos + 0.007, self.fertLevel.yPos + 0.05, 0.02, "L");
		renderText(self.fertLevel.xPos + 0.007, self.fertLevel.yPos + 0.03, 0.02, "L");
	end;
	
end;

--________________________________________________________________________________________________________________________________________________________
function JD8350:setFertLevel()
	local t = self.fertFillLevel/self.fertCapacity;
	for _, node in ipairs(self.fertPlanes) 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, self.fertFillLevel > 0);
	end;
end;

--________________________________________________________________________________________________________________________________________________________
function JD8350:getTriggerDistance(nodeId)

	local sx, sy, sz = getWorldTranslation(self.rootNode);
	local nx, ny, nz = getWorldTranslation(nodeId);
	local distance = Utils.vector3Length(sx-nx, sy-ny, sz-nz);
	self.myDistance1 = distance;

end;

--________________________________________________________________________________________________________________________________________________________
function JD8350:findTriggers(nodeId, name, name1)
	local getAttr = getUserAttribute(nodeId, "onCreate");
	if getAttr == name then
		if getUserAttribute(nodeId, "sprayType") == "fertilizer" then
			table.insert(self.triggerPoints, nodeId);
		end;
	elseif getAttr == name1 then
		if getUserAttribute(nodeId, "fruitType") == "fertilizer" then
			table.insert(self.triggerPoints, nodeId);
		end;
	end;
	
	for i=0, getNumOfChildren(nodeId)-1 do
		self:findTriggers(getChildAt(nodeId, i), name, name1);
	end;

end;

--________________________________________________________________________________________________________________________________________________________
function JD8350:loadFromAttributesAndNodes(xmlFile, key, resetVehicles)
	if not resetVehicles then
		self.lid1 = Utils.getNoNil(getXMLBool(xmlFile, key.."#lid1"),false);
		self.lid2 = Utils.getNoNil(getXMLBool(xmlFile, key.."#lid2"),false);
		self.rA = Utils.getNoNil(getXMLBool(xmlFile, key.."#rA"),false);
		self.lA = Utils.getNoNil(getXMLBool(xmlFile, key.."#lA"),false);
		self.fertFillLevel = Utils.getNoNil(getXMLFloat(xmlFile, key.."#fertFillLevel"),0.0);
		self:setFertLevel();
		self:MPCode(1, self.lid1);
		self:MPCode(2, self.lid2);
		self:MPCode(10, self.rA);
		self:MPCode(11, self.lA);
		self.allowFillWithFert = self.lid2;
	end;
	
	return BaseMission.VEHICLE_LOAD_OK;
end;

--________________________________________________________________________________________________________________________________________________________
function JD8350:getSaveAttributesAndNodes(nodeIdent)
	local attributes = 'lid1="'..tostring(self.lid1)..
	'" lid2="'..tostring(self.lid2)..
	'" rA="'..tostring(self.rA)..
	'" lA="'..tostring(self.lA)..
	'" fertFillLevel="'..tostring(self.fertFillLevel)..'"';
	
	local nodes = nil;
	
	return attributes,nodes;
end;

--________________________________________________________________________________________________________________________________________________________
function JD8350:validateAttacherJoint(implement, jointDesc, dt)
    return true;
end;

--________________________________________________________________________________________________________________________________________________________
function JD8350:readStream(streamId, connection)
	self.lid1 = streamReadBool(streamId);
	self.lid2 = streamReadBool(streamId);
	self.rA = streamReadBool(streamId);
	self.lA = streamReadBool(streamId);
	self.fertFillLevel = streamReadFloat32(streamId);
	self:MPCode(1, self.lid1, nil, true);
	self:MPCode(2, self.lid2, nil, true);
	self:MPCode(10, self.rA, nil, true);
	self:MPCode(11, self.lA, nil, true);
	self:setFertLevel();
end;

--________________________________________________________________________________________________________________________________________________________
function JD8350:writeStream(streamId, connection)
	streamWriteBool(streamId, self.lid1);
	streamWriteBool(streamId, self.lid2);
	streamWriteBool(streamId, self.rA);
	streamWriteBool(streamId, self.lA);
	streamWriteFloat32(streamId, self.fertFillLevel);
end;

--*****************************************************************
JD8350Event = {};
JD8350Event_mt = Class(JD8350Event, Event);

InitEventClass(JD8350Event, "JD8350Event");

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

function JD8350Event:new(vehicle, mode, state, dtime)
    local self = JD8350Event:emptyNew()
    self.vehicle = vehicle;
	self.mode = mode;
	self.state = state;
	self.dtime = dtime;
    return self;
end;

function JD8350Event:readStream(streamId, connection)
    local id = streamReadInt32(streamId);
	self.mode = streamReadInt32(streamId);
	self.state = streamReadBool(streamId);
	self.dtime = streamReadFloat32(streamId);
    self.vehicle = networkGetObject(id);
    self:run(connection);
end;

function JD8350Event:writeStream(streamId, connection)
    streamWriteInt32(streamId, networkGetObjectId(self.vehicle));
	streamWriteInt32(streamId, self.mode);
	streamWriteBool(streamId, self.state);
	streamWriteFloat32(streamId, self.dtime);
end;

function JD8350Event:run(connection)
	self.vehicle:MPCode(self.mode, self.state, self.dtime, true);
    if not connection:getIsServer() then
        g_server:broadcastEvent(JD8350Event:new(self.vehicle, self.mode, self.state, self.dtime), nil, connection, self.vehicle);
    end;
end;

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