RollerMission = {};
RollerMission.NAME = "rollerMission";
RollerMission.UI_SETTINGS = true;
RollerMission.MAX_NUM_INSTANCE = 4;
RollerMission.DEFAULT_NUM_INSTANCE = 3;
RollerMission.BALANCE = {false,0};
RollerMission.RANDOM = false;

source(AdditionalContracts.modDir.. "missions/rollerMission/RollerChangeSettingsEvent.lua");
source(AdditionalContracts.modDir.. "missions/rollerMission/RollerLoadSettingsEvent.lua");

RollerMission.uiData = {
	settings = {
		rollerMission_minMax = RollerMission.DEFAULT_NUM_INSTANCE;
	};
	controls = {
		{ typName="rollerMission", name="rollerMission_minMax", autoBind=true, min=0, max=RollerMission.MAX_NUM_INSTANCE, step=1, unit="/ ".. tostring(RollerMission.MAX_NUM_INSTANCE), nillable=false };
	};
};

RollerMission.data = {	
	ownTable = {FIELD_SIZE_BIGLARGE=30, classOverlay="tractor", typOverlay="roller"}; --big large multiple vehicles, 4x Mod Maps... / success factor for pf dlc
	reward = {dismiss=0, min=2500, PER_HA=1500};
	jobTypName = g_i18n:getText("contract_field_roller_title");	
};

RollerMission.metadata = {
	interface = "FS25 ...", --new
	title = "Rolling Contracts",
	notes = "Dieser Mod generiert Walzen Aufträge.",
	author = "(by HappyLooser)",
	build = 8,
	datum = "30.05.2022",
	update = "13.02.2026",
	debugPrint = false, 
	discord = "HappyLooser Modding",
	info = " Link Freigabe,Änderungen,Kopien oder Code Benutzung ist ohne meine Zustimmung nicht erlaubt",
	"##Orginal Link Freigabe:"
};

local function debugPrint(text, ...)
	if RollerMission.metadata.debugPrint then
		Logging.info(text,...);
	end;
end;

local RollerMission_mt = Class(RollerMission, AbstractFieldMission);
InitObjectClass(RollerMission, "RollerMission");

function RollerMission.registerXMLPaths(schema, key)
	RollerMission:superClass().registerXMLPaths(schema, key);
	schema:register(XMLValueType.INT, key .. "#rewardPerHa", "Reward per ha");
end;

function RollerMission.registerSavegameXMLPaths(schema, key)
	RollerMission:superClass().registerSavegameXMLPaths(schema, key)
	schema:register(XMLValueType.INT, key .. "#targetRollerLevel", "Target roller level")
end

function RollerMission.new(isServer, isClient, customMt)
	local title = g_i18n:getText("contract_field_roller_title"); 
	local description = g_i18n:getText("contract_field_roller_description");
	local self = AbstractFieldMission.new(isServer, isClient, title, description, customMt or RollerMission_mt);
	self.workAreaTypes = {
		[WorkAreaType.ROLLER] = true;
	};	
	self.targetRollerLevel = nil;
	return self;
end;

function RollerMission:init(field, targetRollerLevel)
	self.targetRollerLevel = targetRollerLevel;
	self:setMinReward();
	return RollerMission:superClass().init(self, field);
end;

function RollerMission:createModifier()	
	local mapId, firstChannel, numChannels = g_currentMission.fieldGroundSystem:getDensityMapData(FieldDensityMap.GROUND_TYPE);
	local levelState = FieldGroundType.getValueByType(FieldGroundType.ROLLER_LINES);
	self.completionModifier = DensityMapModifier.new(mapId, firstChannel, numChannels, g_terrainNode);
	self.completionFilter = DensityMapFilter.new(self.completionModifier);
	self.completionFilter:setValueCompareParams(DensityValueCompareType.EQUAL, levelState);	
end;

function RollerMission:getFieldFinishTask()
	self.field:getFieldState().rollerLevel = 1;	
	local fieldState = self.field:getFieldState();
	debugPrint("f%s, growth %d, spray %s, sprayType %s, plow %s, lime %s, weed %s, roller %s, /getFieldFinishTask",
			self.field.farmland.name, fieldState.growthState, fieldState.sprayLevel, fieldState.sprayType, fieldState.plowLevel, fieldState.limeLevel, fieldState.weedState, fieldState.rollerLevel)
		
	return RollerMission:superClass().getFieldFinishTask(self);
end;

function RollerMission:getCompletion()	
	return self:getFieldCompletion() / g_additionalContractTypes:getSuccessFactor();
	--if g_modIsLoaded.FS25_precisionFarming then
	--	return self:getFieldCompletion() / RollerMission.data.ownTable.SUCCESS_FACTOR;
	--end;
	--return RollerMission:superClass().getCompletion(self);	
end;

function RollerMission:getVehicleVariant()	
	if self.field:getAreaHa() >= RollerMission.data.ownTable.FIELD_SIZE_BIGLARGE then return "BIGLARGE";end; --big large multiple vehicles, 4x Mod Maps
	return "GRAIN";
end;

function RollerMission:getRewardPerHa()
	return g_missionManager:getMissionTypeDataByName(RollerMission.NAME).rewardPerHa;
end;

function RollerMission:setMinReward()
	if RollerMission.data.reward.min == nil or RollerMission.data.reward.min <= 0 then return;end;
	if self.reward < RollerMission.data.reward.min then self.reward = RollerMission.data.reward.min;end;	
end;

function RollerMission:getMissionTypeName()
	return RollerMission.NAME;
end;

function RollerMission:validate(event)
	if RollerMission:superClass().validate(self, event) then
		return (self:getIsFinished() or RollerMission.isAvailableForField(self.field, self)) and true or false;
	else
		return false;
	end;
end;

function RollerMission.loadMapData(xmlFile, key, baseDirectory)
	g_missionManager:getMissionTypeDataByName(RollerMission.NAME).rewardPerHa = xmlFile:getFloat(key .. "#rewardPerHa", RollerMission.data.reward.PER_HA);
	return true;
end;

function RollerMission.tryGenerateMission(addConsole)
	if RollerMission.canRun(addConsole) then
		local field = g_fieldManager:getFieldForMission();
		if field == nil then
			if addConsole then printError("Error: No found mission field");end;
			return;
		end;
		if field.currentMission ~= nil then
			if addConsole then printError("Error: Field currentMission already");end;
			return;
		end;
		if not RollerMission.isAvailableForField(field, nil) then
			if addConsole then printError("Error: No found isAvailableForField");end;
			return;
		end;
		local rollerLevel = field:getFieldState().rollerLevel + 1
		local mission = RollerMission.new(true, g_client ~= nil);
		if mission:init(field, rollerLevel) then
			mission:setDefaultEndDate();
			return mission;
		end;
		if addConsole then printError("Error: Mission init not true");end;
		mission:delete();
	end;
	if addConsole then printError("Error: Mission type not active or disabled");end;
	return nil;
end;

function RollerMission.isAvailableForField(field, mission)
	if mission == nil then
		local fieldState = field:getFieldState();
		if not fieldState.isValid then
			return false;
		end;
		if field.grassMissionOnly then
			return false;
		end;
		--if field.groundType ~= FieldGroundType.SOWN then
		--	return false;
		--end;
		debugPrint("f%s, growth %d, spray %s, sprayType %s, plow %s, lime %s, weed %s, roller %s, /isAvailableForField",
			field.farmland.name, fieldState.growthState, fieldState.sprayLevel, fieldState.sprayType, fieldState.plowLevel, fieldState.limeLevel, fieldState.weedState, fieldState.rollerLevel)
		if fieldState.rollerLevel == nil or fieldState.rollerLevel > 0 then 
			return false;
		end;
		local fruitIndex = fieldState.fruitTypeIndex;
		if fruitIndex == FruitType.UNKNOWN then
			return false;
		end;
		local growthState = fieldState.growthState;
		local fruitDesc = g_fruitTypeManager:getFruitTypeByIndex(fruitIndex);
		if fruitDesc == nil or not fruitDesc.needsRolling then return false;end;
		if fruitDesc:getIsCatchCrop() or growthState > 1 then
			return false;
		end;
	else
		if mission:getIsReadyToStart() and not mission:getIsInProgress() then --check and cancel
			if field:getFieldState().growthState > 1 then return false;end;
		end;
	end;
	return true;
end;

function RollerMission.canRun(addConsole)
	if not RollerMission:getOnOff() then return false;end;
	if addConsole then return true;end;
	local data = g_missionManager:getMissionTypeDataByName(RollerMission.NAME);
	if data.numInstances >= data.maxNumInstances or data.numInstances >= g_additionalContractTypes.settings[RollerMission.NAME.. "_minMax"] then
		return false;
	else
		return not g_currentMission.growthSystem:getIsGrowingInProgress();
	end;
end;

function RollerMission:setMaxNumInstance(maxNumInstance)
	self.uiData.settings[RollerMission.NAME.. "_minMax"] = maxNumInstance;
	g_additionalContractTypes:replaceUISettings(RollerMission.NAME.. "_minMax", maxNumInstance);
	local data = g_missionManager:getMissionTypeDataByName(RollerMission.NAME);
	if data ~= nil then data.maxNumInstances = maxNumInstance;end;	
end;

function RollerMission:getMaxNumInstance()
	local data = g_missionManager:getMissionTypeDataByName(RollerMission.NAME);
	if data == nil then 
		return g_additionalContractTypes.settings[RollerMission.NAME.. "_minMax"];
	end;
	return data.maxNumInstances;
end;

function RollerMission:getOnOff()
	return g_additionalContractTypes.settings[RollerMission.NAME.. "_minMax"] > 0;
end;

function RollerMission:setOnOff(state)
	
end;

function RollerMission:canBalance()
	return RollerMission.BALANCE[1];
end;

function RollerMission:getBalance()
	return RollerMission.BALANCE[2];
end;

function RollerMission:setBalance(state)
	RollerMission.BALANCE[2] = state or RollerMission.BALANCE[2] + 1;
end;

function RollerMission:canRandom()
	return RollerMission.RANDOM;
end;

function RollerMission:setRandom(state)
	RollerMission.RANDOM = state or not RollerMission.RANDOM;
end;

function RollerMission:getJobTypName()
	return self.data.jobTypName;
end;

function RollerMission:onStartMap(args)
	if not args.isDetiServer and FS25_MissionsExpanded ~= nil and FS25_MissionsExpanded.MissionsExpanded ~= nil and FS25_MissionsExpanded.MissionsExpanded.missionsMultiplier["rollerMission"] ~= nil then --replace MissionsExpanded value
		FS25_MissionsExpanded.MissionsExpanded.missionsMultiplier["rollerMission"][1] = g_additionalContractTypes.settings[RollerMission.NAME.. "_minMax"];
		local data = g_missionManager:getMissionTypeDataByName(RollerMission.NAME);
		if data ~= nil and data.maxNumInstances ~= g_additionalContractTypes.settings[RollerMission.NAME.. "_minMax"] then data.maxNumInstances = g_additionalContractTypes.settings[RollerMission.NAME.. "_minMax"];end; 
	end;
end;

function RollerMission:loadInit()	
	if RollerMission.UI_SETTINGS then		
		local isReady = false;
		for key, value in pairs(RollerMission.uiData.settings) do			
			isReady = g_additionalContractTypes:setUISettings(key, value);
			if not isReady then break;end; 
		end;
		if isReady then
			for _, control in ipairs(RollerMission.uiData.controls) do
				g_additionalContractTypes:setUIControls(control);			
			end;
		else
			for key, value in pairs(RollerMission.uiData.settings) do
				g_additionalContractTypes:delUISettings(key);				 
			end;
		end;		
	end;
	local xmlFile = Utils.getFilename("missionVehicles/rollerMissionVehicles.xml", AdditionalContracts.modDir)
	g_missionManager:addPendingMissionVehiclesFile(xmlFile, AdditionalContracts.modDir)
end;

function RollerMission:loadSettingsEvent(mission, connection, x, y, z, viewDistanceCoeff)
	if g_currentMission ~= nil and g_currentMission.missionDynamicInfo ~= nil and g_currentMission.missionDynamicInfo.isMultiplayer then
		g_client:getServerConnection():sendEvent(RollerLoadSettingsEvent.new());
	end;
end;

function RollerMission:changeSettingsEvent(settingsId, state)
	if g_currentMission ~= nil and g_currentMission.missionDynamicInfo ~= nil and g_currentMission.missionDynamicInfo.isMultiplayer then
		g_client:getServerConnection():sendEvent(RollerChangeSettingsEvent.new(settingsId, state));
	else
		self:onChangeSettings(settingsId, state);
	end;
end;

function RollerMission:onChangeSettings(settingsId, state)
	if settingsId == "rollerMission_minMax" then		
		self:setMaxNumInstance(state);		
	end;	
end;

function RollerMission:loadSettingsXML(xmlFile, prefix)
	if not xmlFile:hasProperty(prefix.. ".".. RollerMission.NAME.. ".minMax") then return;end;	
	local minMax = xmlFile:getInt(prefix.. ".".. RollerMission.NAME.. ".minMax");
	local control = g_additionalContractTypes:getUIControls(RollerMission.NAME.. "_minMax");
	if minMax > control.max then minMax = control.max;elseif minMax < control.min then minMax = control.min;end;	
	self:setMaxNumInstance(minMax);	
end;

function RollerMission:saveSettingsXML(xmlFile, prefix)	
	xmlFile:setInt(prefix.. ".".. RollerMission.NAME.. ".minMax", g_additionalContractTypes.settings[RollerMission.NAME.. "_minMax"]);
end;

function RollerMission:getClassTypOverlay(args)
	local classOverlay = "tractor";
	local typOverlay = "roller";
	if self.data.ownTable.classOverlay ~= nil then classOverlay = self.data.ownTable.classOverlay;end;
	if self.data.ownTable.typOverlay ~= nil then typOverlay = self.data.ownTable.typOverlay;end;	
	return classOverlay, typOverlay;
end;

function RollerMission:getFillTypeIndexOverlay(args)
	return nil, "fillType_field";
end;

g_additionalContractTypes:registerTyp(RollerMission, RollerMission.NAME, true, "FS25_RollerMission");
