-- by "Marhu" 
-- v 2.0
-- Date: 29.04.2013
-- ZuchtAnlagePlace (Zuchtstation Objekt)

	
ZuchtAnlagePlace = {};
ZuchtAnlagePlace_mt = Class(ZuchtAnlagePlace, Placeable);
InitObjectClass(ZuchtAnlagePlace, "ZuchtAnlagePlace");

function ZuchtAnlagePlace:new(isServer, isClient, customMt)
    local self = Placeable:new(isServer, isClient, ZuchtAnlagePlace_mt);
    registerObjectClassName(self, "ZuchtAnlagePlace");
	
	return self;
end;

function ZuchtAnlagePlace:delete()
    if self.PlayerTrigger then
		removeTrigger(self.PlayerTrigger);
		self.PlayerTrigger = nil;
	end;
	if self.FillTriggerId then
		removeTrigger(self.FillTriggerId);
	end;
	unregisterObjectClassName(self);
    ZuchtAnlagePlace:superClass().delete(self);
end;

function ZuchtAnlagePlace:deleteFinal()
    ZuchtAnlagePlace:superClass().deleteFinal(self);
end;

function ZuchtAnlagePlace:load(xmlFilename, x,y,z, rx,ry,rz, moveMode, initRandom)
    if not ZuchtAnlagePlace:superClass().load(self, xmlFilename, x,y,z, rx,ry,rz, moveMode, initRandom) then
        return false;
    end;
	
	if not moveMode then
		local xmlFile = loadXMLFile("TempXML", xmlFilename);
		
		local Typ = getXMLString(xmlFile, "placeable.Typ#value");
		if Typ ~= "cow" and Typ ~= "sheep" and Typ ~= "chicken" then
			return false;
		else
			self.Typ = Typ;
			self.Animal = g_currentMission.husbandries[Typ];
		end;
		
		local PlayerTriggerIndex = getXMLString(xmlFile, "placeable.PlayerTrigger#index");
		if PlayerTriggerIndex then
			local PlayerTrigger = Utils.indexToObject(self.nodeId, PlayerTriggerIndex);
			if PlayerTrigger then
				self.PlayerTrigger = PlayerTrigger;
				addTrigger(self.PlayerTrigger, "PlayerTriggerCallback", self);
			end;
		end;

		local FillTriggerIndex = getXMLString(xmlFile, "placeable.FillTrigger#index");
		if FillTriggerIndex then
			local FillTrigger = Utils.indexToObject(self.nodeId, FillTriggerIndex);
			if FillTrigger then
				self.FillTriggerId = FillTrigger;
				self.FillTrigger = TipTrigger:new(self.isServer, self.isClient);
				self.FillTrigger.priceMultipliers = {};
				self.FillTrigger.acceptedFillTypes = {};
				self.FillTrigger:load(FillTrigger,self);
				self.FillTrigger:register(true);
				removeTrigger(FillTrigger);
				addTrigger(FillTrigger, "FillTriggerCallback", self);
			end;
		end;
		
		local ChildrenGroupIndex = getXMLString(xmlFile, "placeable.Children#index");
		if ChildrenGroupIndex then
			local ChildrenGroup = Utils.indexToObject(self.nodeId, ChildrenGroupIndex);
			if ChildrenGroup then
				self.Children = {};
				local numChildren = getNumOfChildren(ChildrenGroup);
				for i = 1, numChildren do
					self.Children[i] = {};
					if self.Typ == "chicken" then
						self.Children[i].vis1 = getChildAt(getChildAt(ChildrenGroup, i-1),0);
						self.Children[i].vis2 = getChildAt(getChildAt(ChildrenGroup, i-1),1);
					else
						self.Children[i].vis = getChildAt(ChildrenGroup, i-1);
					end;
					self.Children[i].has = false;
					self.Children[i].t = -1;
				end;
			end;
		end;
		
		local BalesGroupIndex = getXMLString(xmlFile, "placeable.Bales#index");
		if BalesGroupIndex then
			local BalesGroup = Utils.indexToObject(self.nodeId, BalesGroupIndex);
			if BalesGroup then
				self.Bales = BalesGroup;
			end
		end;
		self.ScaleMin = Utils.getNoNil(getXMLFloat(xmlFile, "placeable.ScaleMin#value"),  0.6);
		self.ScaleMax = Utils.getNoNil(getXMLFloat(xmlFile, "placeable.ScaleMax#value"),  1.5);
		self.Wachtum =  Utils.getNoNil(getXMLFloat(xmlFile, "placeable.Wachtum#value"),  4320); -- 3 days in min
		self.Verbrauch = Utils.getNoNil(getXMLFloat(xmlFile, "placeable.Verbrauch#value"),  80); -- Pro Day
		self.capacity = Utils.getNoNil(getXMLFloat(xmlFile, "placeable.Capacity#value"),  2000);
		
		delete(xmlFile);
				
		self.updateMs = 0;
		self.updateMin = 0;
		self.FillLevelMilk = 0;
		self.FillLevelStraw = 0;
		self.nextChildren = 0;
		
		self.resetFillLevelIfNeeded = self.resetFillLevelIfNeeded;
		self.allowFillType = ZuchtAnlagePlace.allowFillType;
		self.setFillLevel = ZuchtAnlagePlace.setFillLevel;
        self.getFillLevel = ZuchtAnlagePlace.getFillLevel;
		self.addChildren = ZuchtAnlagePlace.addChildren;
		self.setBaleVis = ZuchtAnlagePlace.setBaleVis;
		self.updateTrailerTipping = ZuchtAnlagePlace.updateTrailerTipping;
		self.getTipInfoForTrailer = ZuchtAnlagePlace.getTipInfoForTrailer;
		
		self.AddDirtyFlag = self:getNextDirtyFlag();
		
	end;
  
	return true;
end;

function ZuchtAnlagePlace:readStream(streamId, connection)
	
	ZuchtAnlagePlace:superClass().readStream(self, streamId, connection);
	
	self.FillLevelMilk = streamReadFloat32(streamId);
	self.FillLevelStraw = streamReadFloat32(streamId);
	self.updateMin = streamReadFloat32(streamId);
	
	for i = 1, table.getn(self.Children) do
		self.Children[i].has = streamReadBool(streamId);
		self.Children[i].t = streamReadFloat32(streamId);
		if self.Children[i].has then
			if self.Typ == "chicken" then
				if self.Children[i].t <= self.Wachtum/3 then
					setVisibility(self.Children[i].vis1,false);
					setVisibility(self.Children[i].vis2,true);
				else
					setVisibility(self.Children[i].vis1,true);
					setVisibility(self.Children[i].vis2,false);
				end;
			else
				setScale(self.Children[i].vis,self.ScaleMin,self.ScaleMin,self.ScaleMin);
				setVisibility(self.Children[i].vis,true);
			end;
		end;
	end;
	
end;

function ZuchtAnlagePlace:writeStream(streamId, connection)
	
	ZuchtAnlagePlace:superClass().writeStream(self, streamId, connection);
	
	streamWriteFloat32(streamId, self.FillLevelMilk);
	streamWriteFloat32(streamId, self.FillLevelStraw);
	streamWriteFloat32(streamId, self.updateMin);
	
	for i = 1, table.getn(self.Children) do
		streamWriteBool(streamId, self.Children[i].has);
		streamWriteFloat32(streamId, self.Children[i].t);
	end
    
end;

function ZuchtAnlagePlace:readUpdateStream(streamId, timestamp, connection)
	ZuchtAnlagePlace:superClass().readUpdateStream(self, streamId, timestamp, connection);
	if connection:getIsServer() then
		self.FillLevelMilk = streamReadFloat32(streamId);
		self.FillLevelStraw = streamReadFloat32(streamId);
		self.updateMin = streamReadFloat32(streamId);
		
		for i = 1, table.getn(self.Children) do
			self.Children[i].has = streamReadBool(streamId);
			self.Children[i].t = streamReadFloat32(streamId);
			if self.Children[i].has then
				if self.Typ == "chicken" then
					if self.Children[i].t <= self.Wachtum/3 then
						setVisibility(self.Children[i].vis1,false);
						setVisibility(self.Children[i].vis2,true);
					else
						setVisibility(self.Children[i].vis1,true);
						setVisibility(self.Children[i].vis2,false);
					end;
				else
					setScale(self.Children[i].vis,self.ScaleMin,self.ScaleMin,self.ScaleMin);
					setVisibility(self.Children[i].vis,true);
				end;
			end;
		end;
	else
		local AddEgg = streamReadBool(streamId);
		if AddEgg and g_currentMission:getSiloAmount(Fillable.fillTypeNameToInt["egg"]) > 0 then
			self:addChildren();
		end;
	end;
	
end;

function ZuchtAnlagePlace:writeUpdateStream(streamId, connection, dirtyMask)
	ZuchtAnlagePlace:superClass().writeUpdateStream(self, streamId, connection, dirtyMask);
	if not connection:getIsServer() then
		streamWriteFloat32(streamId, self.FillLevelMilk);
		streamWriteFloat32(streamId, self.FillLevelStraw);
		streamWriteFloat32(streamId, self.updateMin);
		
		for i = 1, table.getn(self.Children) do
			streamWriteBool(streamId, self.Children[i].has);
			streamWriteFloat32(streamId, self.Children[i].t);
		end;
	else
		streamWriteBool(streamId, self.SendAddEgg);
		self.SendAddEgg = false;
	end;
	
end;

local function MinToTimeSring(minuten)

	local tt = "";
	local days = math.floor(minuten / 1440);
	local hours = math.mod(math.floor(minuten / 60), 24);
	local minute = math.mod(math.floor(minuten), 60);
	
	if days > 0 then
		tt = tostring(days).."d ";
	end;
	if hours < 10 and days > 0 then
		tt = tt.."0"..tostring(hours).."h ";
	elseif hours > 0 then
		tt = tt..tostring(hours).."h ";
	end;
	if days <= 0 then
		if minute < 10 and minute > 0 and hours > 0 then
			tt = tt.."0"..tostring(math.floor(minute)).."min";
		else
			tt = tt..tostring(math.floor(minute)).."min";
		end;
	end;
		
	return tt;
end

function ZuchtAnlagePlace:update(dt)
	
	if self.changeAllowed then
		local numChildren = 0;
		for i = 1, table.getn(self.Children) do
			if self.Children[i].has then
				numChildren =  numChildren + 1;
				if self.Typ ~= "cow" or self.FillLevelStraw > 0 then
					g_currentMission:addExtraPrintText(g_i18n:getText(self.Typ.."Children")..i.." - "..MinToTimeSring(self.Children[i].t));
				else
					g_currentMission:addExtraPrintText(g_i18n:getText(self.Typ.."Children")..i.." - "..MinToTimeSring(self.Children[i].t * 2));
				end;
			end;
		end;
		if numChildren < table.getn(self.Children) then
			if self.Typ == "chicken" then
				if g_currentMission:getSiloAmount(Fillable.fillTypeNameToInt["egg"]) > 0 then
					self:addChildren();
				end;
			else
				g_currentMission:addExtraPrintText(g_i18n:getText("next").." "..g_i18n:getText(self.Typ.."Children").." ~ "..MinToTimeSring(self.nextChildren));--.." ("..math.floor(self.Animal.totalNumAnimals * self.Animal.productivity).."%)");
			end;
		end
		if self.Typ ~= "chicken" then
			local txt = Fillable.fillTypeIndexToDesc[Fillable.FILLTYPE_MILK].nameI18N; 
			g_currentMission:addExtraPrintText(txt..": "..math.floor(self.FillLevelMilk).."l ("..math.floor(self.FillLevelMilk/(numChildren*self.Verbrauch)).."d)");
			if self.Typ == "cow" then
				txt = Fillable.fillTypeIndexToDesc[Fillable.FILLTYPE_WHEAT_WINDROW].nameI18N;
				g_currentMission:addExtraPrintText(txt..": "..math.floor(self.FillLevelStraw).."l ("..math.floor(self.FillLevelStraw/(numChildren*self.Verbrauch)).."d)");
			end;
		end;
		if not g_currentMission.controlPlayer then
			self.changeAllowed = false;
		end;
	end;
	
	self.updateMs = self.updateMs + (dt * g_currentMission.missionStats.timeScale);
	if self.updateMs >= 60000 then
		self.updateMs = self.updateMs - 60000;
		for i = 1, table.getn(self.Children) do
			if self.Children[i].has then
				if self.Typ == "chicken" then
					self.Children[i].t = self.Children[i].t - 1;
					if self.Children[i].t <= 0 then
						self.Children[i].has = false;
						setVisibility(self.Children[i].vis1,false);
						setVisibility(self.Children[i].vis2,false);
						self.Animal:addAnimals(1,0);
					elseif self.Children[i].t <= self.Wachtum/3 then
						setVisibility(self.Children[i].vis1,false);
						setVisibility(self.Children[i].vis2,true);
					end;
				else
					if self.FillLevelMilk > 0 then
						self.FillLevelMilk = math.max(0,self.FillLevelMilk - (self.Verbrauch/24/60));
						self.FillLevelStraw = math.max(0,self.FillLevelStraw - (self.Verbrauch/24/60));
						self:setBaleVis();
						if self.Typ == "sheep" or self.FillLevelStraw > 0 then
							self.Children[i].t = self.Children[i].t - 1;
						else
							self.Children[i].t = self.Children[i].t - 0.5;
						end;
						local Scale  = Utils.lerp(self.ScaleMax, self.ScaleMin, self.Children[i].t/self.Wachtum); -- range
						setScale(self.Children[i].vis,Scale,Scale,Scale);
						if self.Children[i].t <= 0 then
							self.Children[i].has = false;
							setVisibility(self.Children[i].vis,false);
							setScale(self.Children[i].vis,self.ScaleMin,self.ScaleMin,self.ScaleMin);
							self.Animal:addAnimals(1,0);
						end;
					end;
				end;
			end;
		end;
		if self.Typ ~= "chicken" and self.Animal.productivity > 0  then
			local freePlace = false;
			for i = 1, table.getn(self.Children) do
				if not self.Children[i].has then
					freePlace = true;
					break;
				end;
			end;
			if freePlace then
				self.updateMin = self.updateMin + 1;
				if self.Animal.productivity > 0 then
					self.nextChildren = math.floor((100 / (self.Animal.totalNumAnimals * self.Animal.productivity)) * (120)) - self.updateMin;
					if self.nextChildren <= 0 then
						self.updateMin = 0;			
						self:addChildren();
					end;
				end;
			end;
		end;
	end;
	
end;

function ZuchtAnlagePlace:getSaveAttributesAndNodes(nodeIdent)
	
	local attributes, nodes = ZuchtAnlagePlace:superClass().getSaveAttributesAndNodes(self, nodeIdent);
	
	local Milk = self.FillLevelMilk or 0;
	local Straw = self.FillLevelStraw or 0;
	local minute = self.updateMin or 0;
	
	attributes = attributes..' Milk="'..Milk..'" Straw="'..Straw..'" minute="'..minute..'"';
    
	local ChildrenNum = 0;
	
	for i = 1,table.getn(self.Children) do
		if self.Children[i].has then
			if ChildrenNum>0 then
				nodes = nodes.."\n";
			end;
			nodes = nodes..nodeIdent..'<Children time="'..self.Children[i].t..'" />';
			ChildrenNum = ChildrenNum+1;
		end;
	end;
	
    return attributes,nodes;
end;

function ZuchtAnlagePlace:loadFromAttributesAndNodes(xmlFile, Key)
	if not ZuchtAnlagePlace:superClass().loadFromAttributesAndNodes(self, xmlFile, Key) then
		return false;
	end;
			
	self.FillLevelMilk = Utils.getNoNil(getXMLFloat(xmlFile, Key.."#Milk"),0);
	self.FillLevelStraw = Utils.getNoNil(getXMLFloat(xmlFile, Key.."#Straw"),0);
	self.updateMin = Utils.getNoNil(getXMLFloat(xmlFile, Key.."#minute"),0);
	
	local i=0;
	while true do
		local ChildrenKey = Key..string.format(".Children(%d)", i);
		if not hasXMLProperty(xmlFile, ChildrenKey) then
			break;
		end;
		local t = getXMLFloat(xmlFile, ChildrenKey.."#time");
		if t ~= nil then
			self.Children[i+1].has = true;
			self.Children[i+1].t = t;
			if self.Typ == "chicken" then
				if t <= self.Wachtum/3 then
					setVisibility(self.Children[i+1].vis1,false);
					setVisibility(self.Children[i+1].vis2,true);
				else
					setVisibility(self.Children[i+1].vis1,true);
					setVisibility(self.Children[i+1].vis2,false);
				end;
			else
				local Scale  = Utils.lerp(self.ScaleMax, self.ScaleMin, self.Children[i+1].t/self.Wachtum); -- range 
				setScale(self.Children[i+1].vis,Scale,Scale,Scale);
				setVisibility(self.Children[i+1].vis,true);
			end;
		end;
		i=i+1;
	end;
	
	self:setBaleVis();
	
	return true;
end;

function ZuchtAnlagePlace:updateTrailerTipping(trailer, fillDelta, fillType)
    if fillDelta < 0 then
        self:resetFillLevelIfNeeded(fillType);
        local fillLevel = self:getFillLevel(fillType);
        self:setFillLevel(fillLevel - fillDelta, fillType);
    end;
end;

function ZuchtAnlagePlace:getTipInfoForTrailer(trailer, tipReferencePointIndex)
    
	if not self:allowFillType(trailer.currentFillType) then
        return true, math.huge;
    end;
    if self:getFillLevel(trailer.currentFillType) >= self.capacity then
         return true, math.huge;
    end;
	
	local minDistance, bestPoint = self.FillTrigger:getTipDistanceFromTrailer(trailer, tipReferencePointIndex);
	local isAllowed = true;
   
    return isAllowed, minDistance, bestPoint;
end

function ZuchtAnlagePlace:resetFillLevelIfNeeded(fillType)
end;

function ZuchtAnlagePlace:allowFillType(fillType)
	if fillType == Fillable.FILLTYPE_MILK or 
	   fillType == Fillable.FILLTYPE_BARLEY_WINDROW or
	   fillType == Fillable.FILLTYPE_WHEAT_WINDROW then
		return true;
	end;
end;

function ZuchtAnlagePlace:setFillLevel(fillLevel, fillType)
	if fillType == Fillable.FILLTYPE_MILK or 
	   fillType == Fillable.FILLTYPE_BARLEY_WINDROW or
	   fillType == Fillable.FILLTYPE_WHEAT_WINDROW then
		if fillLevel > self.capacity then
			fillLevel = self.capacity;
		end;
		if fillLevel < 0 then
			fillLevel = 0;
		end;
		if fillType == Fillable.FILLTYPE_MILK or self.Typ == "sheep" then
			self.FillLevelMilk = fillLevel;
		else
			self.FillLevelStraw = fillLevel;
			self:setBaleVis();
		end;
		self:raiseDirtyFlags(self.AddDirtyFlag);
	end;
	
end;

function ZuchtAnlagePlace:getFillLevel(fillType)
	if fillType == Fillable.FILLTYPE_MILK then
		return  self.FillLevelMilk;
	elseif fillType == Fillable.FILLTYPE_BARLEY_WINDROW or fillType == Fillable.FILLTYPE_WHEAT_WINDROW then
		if self.Typ == "sheep" then
			return self.FillLevelMilk;
		else
			return self.FillLevelStraw;
		end;
	end;
	return 0;
end;

function ZuchtAnlagePlace:addChildren()
	for i = 1, table.getn(self.Children) do
		if not self.Children[i].has then
			self.Children[i].has = true;
			self.Children[i].t = self.Wachtum; 
			if self.Typ == "chicken" then
				if self.isServer then
					setVisibility(self.Children[i].vis1,true);
					setVisibility(self.Children[i].vis2,false);
					g_currentMission:setSiloAmount(Fillable.fillTypeNameToInt["egg"], math.max(g_currentMission:getSiloAmount(Fillable.fillTypeNameToInt["egg"])-1, 0));
				else
					self.SendAddEgg = true;
					self.Children[i].has = false;
					setVisibility(self.Children[i].vis1,false);
					setVisibility(self.Children[i].vis2,false);
				end;
			else
				setScale(self.Children[i].vis,self.ScaleMin,self.ScaleMin,self.ScaleMin);
				setVisibility(self.Children[i].vis,true);
			end;
			self:raiseDirtyFlags(self.AddDirtyFlag);
			break;
		end;
	end;
	
end;

function ZuchtAnlagePlace:setBaleVis()
	if self.Bales ~= nil then
		local num = getNumOfChildren(self.Bales);
        local numVisible = math.ceil(num * self.FillLevelStraw / self.capacity);
        for i=1,num do
            setVisibility(getChildAt(self.Bales, i-1), i <= numVisible);
        end;
    end;
end;

function ZuchtAnlagePlace:PlayerTriggerCallback(triggerId, otherId, onEnter, onLeave, onStay)
	
	if (g_currentMission.controlPlayer and g_currentMission.player and otherId == g_currentMission.player.rootNode) then
		if (onEnter) then 
            self.changeAllowed = true;
        elseif (onLeave) then
            self.changeAllowed = false;
        end;
	end;
	
end;
 
function ZuchtAnlagePlace:FillTriggerCallback(triggerId, otherId, onEnter, onLeave, onStay, otherShapeId)
	
	local vehicle = g_currentMission.nodeToVehicle[otherId];
	local trailer = g_currentMission.objectToTrailer[otherShapeId];
	
	if vehicle ~= nil and vehicle.addMilchTrailerFillTrigger ~= nil and vehicle.addMilchTrailerFillTrigger ~= nil then
		if onEnter then
			vehicle:addMilchTrailerFillTrigger({id = triggerId, Zucht = self});
		else -- onLeave
			vehicle:removeMilchTrailerFillTrigger({id = triggerId, Zucht = self});
		end;
	elseif self.FillTrigger.isEnabled and trailer ~= nil and trailer.allowTipDischarge then
		if onEnter then
            if g_currentMission.trailerTipTriggers[trailer] == nil then
                g_currentMission.trailerTipTriggers[trailer] = {};
            end;
            table.insert(g_currentMission.trailerTipTriggers[trailer], self);
		elseif onLeave then
			local triggers = g_currentMission.trailerTipTriggers[trailer];
			if triggers ~= nil then
				for i=1, table.getn(triggers) do
					if triggers[i] == self.FillTrigger then
						table.remove(triggers, i);
						if table.getn(triggers) == 0 then
							g_currentMission.trailerTipTriggers[trailer] = nil;
						end;
						break;
					end;
				end;
			end;
		end;
	end;

 end;
 
registerPlaceableType("ZuchtAnlagePlace", ZuchtAnlagePlace);

