----------------------------------------------------------------------------------------------------
-- SeasonsGrowth
----------------------------------------------------------------------------------------------------
-- Purpose:  Growth main class
--
-- Copyright (c) Realismus Modding, 2018
----------------------------------------------------------------------------------------------------

SeasonsGrowth = {}

local SeasonsGrowth_mt = Class(SeasonsGrowth)

SeasonsGrowth.MAX_STATE = 99
SeasonsGrowth.CUT = 200
SeasonsGrowth.WITHERED = 300
SeasonsGrowth.FIRST_LOAD_TRANSITION = 999
SeasonsGrowth.UNKNOWN_FRUIT_COPY_SOURCE = "BARLEY"
SeasonsGrowth.MAX_ALLOWABLE_GROWTH_PERIOD = 12 * 2 -- max growth for any fruit = 2 years

SeasonsGrowth.EXCEPTIONAL_EVENT_DROUGHT = 800
SeasonsGrowth.EXCEPTIONAL_EVENT_FROST = 801
SeasonsGrowth.EXCEPTIONAL_EVENT_OPTIMAL_GROWTH = 802

SeasonsGrowth.DEFAULT_WEEDS_SCALE = 30
SeasonsGrowth.DEFAULT_WEEDS_SIZE = 6
SeasonsGrowth.DEFAULT_DAMAGE_SCALE = 100
SeasonsGrowth.DEFAULT_DAMAGE_SIZE = 10
SeasonsGrowth.DEFAULT_SCALE_DAYS = 9

SeasonsGrowth.WEEDS_SPROUT = 1
SeasonsGrowth.WEEDS_GROW = 2
SeasonsGrowth.WEEDS_REMOVE = 3
SeasonsGrowth.WEEDS_WITHER = 4

SeasonsGrowth.PLANTED_STATE = 11
SeasonsGrowth.GERMINATION_FAILED_STATE = 12

SeasonsGrowth.CROP_DAMAGE_FROST = "frost"
SeasonsGrowth.CROP_DAMAGE_DROUGHT = "drought"

function SeasonsGrowth:new(mission, environment, messageCenter,i18n, fruitTypeManager, densityMapScanner, weather, sprayTypeManager, fieldManager)
    local self = setmetatable({}, SeasonsGrowth_mt)

    self.mission = mission
    self.environment = environment
    self.messageCenter = messageCenter
    self.i18n = i18n
    self.fruitTypeManager = fruitTypeManager
    self.densityMapScanner = densityMapScanner
    self.weather = weather
    self.sprayTypeManager = sprayTypeManager

    self.fruitTypes = SeasonsGrowthFruitTypes:new(mission, messageCenter, fruitTypeManager)
    self.data = SeasonsGrowthData:new(mission, environment, weather, fruitTypeManager)
    self.pcf = SeasonsGrowthPatchyCropFailure:new(mission, self.data)

    self.manager = SeasonsGrowthManager:new(mission, environment, fruitTypeManager, densityMapScanner, weather, self.data, self.pcf)
    self.cropRotation = SeasonsCropRotation:new(mission, environment, messageCenter, fruitTypeManager, densityMapScanner, i18n, self.data, environment)
    self.npcs = SeasonsGrowthNPCMissions:new(fruitTypeManager, messageCenter, fieldManager, self.data, self.cropRotation, environment)


    SeasonsModUtil.overwrittenStaticFunction(FSDensityMapUtil, "updateSowingArea", SeasonsGrowth.inj_densityMapUtil_updateSowingArea)
    SeasonsModUtil.overwrittenStaticFunction(FSDensityMapUtil, "updateDirectSowingArea", SeasonsGrowth.inj_densityMapUtil_updateDirectSowingArea)
    SeasonsModUtil.overwrittenStaticFunction(FSDensityMapUtil, "cutFruitArea", SeasonsGrowth.inj_densityMapUtil_cutFruitArea)
    SeasonsModUtil.overwrittenStaticFunction(FSDensityMapUtil, "updateCultivatorArea", SeasonsGrowth.inj_densityMapUtil_updateCultivatorArea)

    -- These functions load growth state from XML files. As the growth system is not used we prevent them
    -- from running to save a bit of performance
    local noop = function(...) end
    SeasonsModUtil.overwrittenConstant(getfenv(0), "loadCropsGrowthStateFromFile", noop)
    SeasonsModUtil.overwrittenConstant(getfenv(0), "loadTerrainDetailUpdaterStateFromFile", noop)
    SeasonsModUtil.overwrittenConstant(getfenv(0), "saveTerrainDetailUpdaterStateToFile", noop)
    SeasonsModUtil.overwrittenConstant(getfenv(0), "saveCropsGrowthStateToFile", noop)

    return self
end

function SeasonsGrowth:delete()
    self.messageCenter:unsubscribeAll(self)

    self.data:delete()
    self.fruitTypes:delete()
    self.manager:delete()
    self.npcs:delete()
    self.cropRotation:delete()
    self.pcf:delete()
end

function SeasonsGrowth:load()
    self.fruitTypes:load()
    self.data:load()

    self.messageCenter:subscribe(MessageType.DAY_CHANGED, self.onDayChanged, self)
    self.messageCenter:subscribe(SeasonsMessageType.HOUR_CHANGED_FIX, self.onHourChanged, self)
    self.messageCenter:subscribe(SeasonsMessageType.PERIOD_CHANGED, self.onPeriodChanged, self)
    self.messageCenter:subscribe(SeasonsMessageType.SEASON_LENGTH_CHANGED, self.onSeasonLengthChanged, self)

    self.manager:load()
    self.pcf:load()
    self.npcs:load()
    self.cropRotation:load()

    -- Add visual sprayed ground to herbicide for preventive spraying
    self.sprayTypeManager:getSprayTypeByName("HERBICIDE").groundType = 1

    -- Turn 2-level fertilization into 3-level again
    self.mission.sprayLevelMaxValue = (2 ^ self.mission.sprayLevelNumChannels) - 1
end

function SeasonsGrowth:setDataPaths(dataPaths)
    self.fruitTypes:setDataPaths(dataPaths)
    self.data:setDataPaths(dataPaths)
end

function SeasonsGrowth:loadFromSavegame(xmlFile)
    self.data:loadFromSavegame(xmlFile)
    self.cropRotation:loadFromSavegame(xmlFile)
    self.npcs:loadFromSavegame(xmlFile)
    self.pcf:loadFromSavegame(xmlFile)
end

function SeasonsGrowth:saveToSavegame(xmlFile)
    self.cropRotation:saveToSavegame(xmlFile)
    self.npcs:saveToSavegame(xmlFile)
    self.pcf:saveToSavegame(xmlFile)
end

function SeasonsGrowth:onMissionLoaded()
    self.manager:onMissionLoaded()
    self.npcs:onMissionLoaded()
end

---Reset all growth to a state for a new game
function SeasonsGrowth:resetGrowth()
    self.manager:resetGrowth()
end

function SeasonsGrowth:onTerrainLoaded()
    self.cropRotation:onTerrainLoaded()
end

-----------------------------------
-- Events
-----------------------------------

function SeasonsGrowth:onDayChanged()
    self.manager:onDayChanged()
end

function SeasonsGrowth:onHourChanged()
    self.manager:onHourChanged()
end

function SeasonsGrowth:onPeriodChanged()
    self.manager:onPeriodChanged()
end

function SeasonsGrowth:onSeasonLengthChanged()
    self.manager:onSeasonLengthChanged()
end

function SeasonsGrowth:update(dt)
    self.manager:update(dt)
end

-----------------------------------
-- Injections
-----------------------------------

---Default the planting state to 11 (planted). In vanilla it would default to 1, which is the first growth state
function SeasonsGrowth.inj_densityMapUtil_updateSowingArea(superFunc, fruitId, startWorldX, startWorldZ, widthWorldX, widthWorldZ, heightWorldX, heightWorldZ, angle, growthState, blockedSprayTypeIndex)
    return superFunc(fruitId, startWorldX, startWorldZ, widthWorldX, widthWorldZ, heightWorldX, heightWorldZ, angle, growthState or SeasonsGrowth.PLANTED_STATE, blockedSprayTypeIndex)
end

function SeasonsGrowth.inj_densityMapUtil_updateDirectSowingArea(superFunc, fruitId, startWorldX, startWorldZ, widthWorldX, widthWorldZ, heightWorldX, heightWorldZ, angle, growthState, blockedSprayTypeIndex)
    return superFunc(fruitId, startWorldX, startWorldZ, widthWorldX, widthWorldZ, heightWorldX, heightWorldZ, angle, growthState or SeasonsGrowth.PLANTED_STATE, blockedSprayTypeIndex)
end

---Do set weeds after treshing
function SeasonsGrowth.inj_densityMapUtil_cutFruitArea(superFunc, fruitIndex, startWorldX, startWorldZ, widthWorldX, widthWorldZ, heightWorldX, heightWorldZ, destroySpray, destroySeedingWidth, useMinForageState, excludedSprayType, setsWeeds)
    return superFunc(fruitIndex, startWorldX, startWorldZ, widthWorldX, widthWorldZ, heightWorldX, heightWorldZ, destroySpray, destroySeedingWidth, useMinForageState, excludedSprayType, true)
end

function SeasonsGrowth.inj_densityMapUtil_updateCultivatorArea(superFunc, startWorldX, startWorldZ, widthWorldX, widthWorldZ, heightWorldX, heightWorldZ, createField, commonForced, angle, blockedSprayTypeIndex, setsWeeds)
    return superFunc(startWorldX, startWorldZ, widthWorldX, widthWorldZ, heightWorldX, heightWorldZ, createField, commonForced, angle, blockedSprayTypeIndex, true)
end
