mudMask = {	};
local mudMask_mt = Class(mudMask);

function mudMask.new(mission, isServer, customMt)
	local self = setmetatable({}, customMt or mudMask_mt);
	self.mission = g_currentMission;
	self.isServer = g_currentMission:getIsServer();
	self.handle = nil;
	self.layerName = "";
	self.createSave = false;
	return self;
end

function mudMask:delete()
	g_messageCenter:unsubscribeAll(self);
end;

function mudMask:onTerrainLoad(terrainRootNode, typeIndex)
	if self.isServer then
		typeIndex = typeIndex+1;
		self.layerName = mudMask.type[typeIndex];
		local xmlPath = self.mission.missionInfo.mapXMLFilename;
		local isBaseMap = false;
		if string.find(xmlPath, "$data") then isBaseMap =  true; end;
		local infoLayerDir = Utils.getDirectory(xmlPath) .. "data/";
		local mapXML;
		if not isBaseMap then mapXML = loadXMLFile("tempMapXML", self.mission.missionInfo.baseDirectory..xmlPath, "map"); end;
		if mapXML ~= nil and mapXML == 0 then mapXML = nil; end;
		local customDir = false;
		local customInfoLayerDir;
		if mapXML ~= nil then customInfoLayerDir = getXMLString(mapXML, "map.mudSystem#dataDir"); end;
		if customInfoLayerDir ~= nil then
			customDir = true;
			infoLayerDir = customInfoLayerDir;
			if string.sub(infoLayerDir,string.len(infoLayerDir)) ~= "/" then infoLayerDir = infoLayerDir.."/"; end;
		end;
		local infoLayerFilename = infoLayerDir .. "infoLayer_"..self.layerName.."Mask.grle";
		local hasinfoLayer = false;
		if fileExists(self.mission.missionInfo.baseDirectory .. infoLayerFilename) then 
			self.handle = getInfoLayerFromTerrain(terrainRootNode, self.layerName.."Mask");
			hasinfoLayer = true;
		elseif customDir then
			Logging.warning("Mud System Mask : Could not locate infoLayer '".. self.mission.missionInfo.baseDirectory .. infoLayerFilename .."'");
		end;
		if not hasinfoLayer or self.handle == nil or self.handle == 0 then
			if mapXML ~= nil then delete(mapXML); end;
			return hasinfoLayer;
		end;
		if g_currentMission.resetMudApplication ~= nil then
			Logging.warning("'"..self.layerName.."Mask' Reset, this will cause a 'callback' warning; no issue will arise, please ignore");
		end;
		self.type = typeIndex;
		self.densityHeight = 0;
		self.applicationAmount = 0.1; 
		if typeIndex > 1 then 
			self.applicationAmount = 0.5; 
		end;
		if mapXML ~= nil then
			self.applicationAmount = Utils.getNoNil(getXMLFloat(mapXML, "map.mudSystem#"..self.layerName.."InfoLayerHeight"), self.applicationAmount);
			self.applicationAmount = MathUtil.clamp(self.applicationAmount, 0.1, typeIndex*0.5);
			delete(mapXML);
		end;
		self.resetAmount = -100.0;
		self:resetDensityHeight();
		return hasinfoLayer;
	end;
end;

function mudMask:startApplication(delta)
	self.densityHeight = delta;
	local updater = g_densityMapHeightManager.terrainDetailHeightUpdater;
	local filltypeIndex = FillType.MUD;
	local interval = 5;
	if self.type > 1 then filltypeIndex = FillType.DIRT; end;
	local heightTypeIndex = g_densityMapHeightManager:getDensityMapHeightTypeIndexByFillTypeIndex(filltypeIndex);
	if heightTypeIndex == nil then Logging.error("Mud System Mask Error: Mud or Dirt could not be created"); return; end;
	local heightLimit = self.densityHeight+0.01;
	local limitToMaxAngle = false;
	local useCollisionMap = false;
	local firstChannel = 0;
	local blockId = 1;
	if self.densityHeight < 0 then blockId = 0; end;
	applyDensityMapHeightUpdate(updater, heightTypeIndex, self.densityHeight , heightLimit, limitToMaxAngle, useCollisionMap, self.handle, firstChannel, blockId, "onApplicationFinished", self, interval);
end;

function mudMask:resetDensityHeight()
	self:startApplication(self.resetAmount);
end;

function mudMask:onApplicationFinished()
	if self.densityHeight < 0 then
		self:startApplication(self.applicationAmount);
	else
		self.createSave = true;
		if self.type < 2 then 
			g_mudMask:onTerrainLoad(g_currentMission.terrainRootNode,1);
			--[[print("CALLED AFTER FINISH");]]
		end;
	end;
end;

mudMaskUpdater = {};

function mudMaskUpdater:loadMapFinished()
	g_mudMask = mudMask.new(g_currentMission,g_currentMission:getIsServer());
	if g_currentMission.setMudApplication ~= nil then
		local hasinfoLayer = g_mudMask:onTerrainLoad(g_currentMission.terrainRootNode,0); --mud
		if (hasinfoLayer ~= nil and not hasinfoLayer) then
			g_mudMask:onTerrainLoad(g_currentMission.terrainRootNode,1); --dirt
			--[[print("CALLED AT MAP LOAD"];]]
		end;
	end;
end;


function mudMaskUpdater:saveSettings(savegame)
	if g_mudMask.createSave then
		local savegameFolderPath = g_currentMission.missionInfo.savegameDirectory;
		if savegameFolderPath == nil then
			savegameFolderPath = ('%ssavegame%d'):format(getUserProfileAppPath(), g_currentMission.missionInfo.savegameIndex);
		end;
		local xmlFileName = savegameFolderPath.."/mudSystemMask.xml";
		local xmlFile = createXMLFile("mudSystemMask", xmlFileName, "mudSystemMask");
		setXMLString(xmlFile, "mudSystemMask.infoLayer#howToReset", "simply delete this file to reset mud and dirt InfoLayer");
		saveXMLFile(xmlFile);
		delete(xmlFile);
	end;
end;

function mudMaskUpdater:loadMap(savegame)
	local hasSaveGame = false;
	local savegameFolderPath = g_currentMission.missionInfo.savegameDirectory;
	if savegameFolderPath == nil then
		savegameFolderPath = ('%ssavegame%d'):format(getUserProfileAppPath(), g_currentMission.missionInfo.savegameIndex);
	else
		hasSaveGame = true;
	end;

	local xmlFileName = savegameFolderPath.."/mudSystemMask.xml";
	if not fileExists(xmlFileName) then
		g_currentMission.setMudApplication = true;
		xmlFileName = savegameFolderPath.."/densityMapHeight.xml";
		if hasSaveGame or fileExists(xmlFileName) then
			g_currentMission.resetMudApplication = true;
		end;
	end;
end;

mudMask.type = {"mud","dirt"};
FSBaseMission.saveSavegame = Utils.appendedFunction(FSBaseMission.saveSavegame, mudMaskUpdater.saveSettings);
FSBaseMission.loadMapFinished = Utils.appendedFunction(FSBaseMission.loadMapFinished, mudMaskUpdater.loadMapFinished);

addModEventListener(mudMaskUpdater);