### Persephone - a socio-economic-ecological model of European agricultural landscapes.
###
### This file includes the core functions for initialising and running simulations.
###

"""
    initialise(config)

Initialise the model: read in parameters, create the output data directory,
and instantiate the AgentBasedModel object.
"""
function initialise(config::String=PARAMFILE)
    # do some housekeeping
    initsettings(config)
    Random.seed!(param("core.seed"))
    setupdatadir()
    # initialise world-level properties
    landcover = GeoArrays.read(param("core.landcovermap"))
    farmfields = GeoArrays.read(param("core.farmfieldsmap"))
    space = GridSpace(size(landcover)[1:2], periodic=false)
    properties = Dict{Symbol,Any}(:age=>0,
                                  :date=>param("core.startdate"),
                                  :landcover=>landcover,
                                  :farmfields=>farmfields)
    model = AgentBasedModel(Union{Farmer,Animal,CropPlot}, space, properties=properties,
                            rng=Random.Xoshiro(param("core.seed")))
    # initialise submodels
    initfarms!(model)
    initfields!(model)
    initnature!(model)
    @info "Simulation initialised at $(Dates.now())."
    model
end

"""
    stepsimulation!(model)

Execute one update of the model.
"""
function stepsimulation!(model::AgentBasedModel)
    model.age += 1
    model.date += Day(1)
    @info "Simulating day $(model.date)."
    for a in Schedulers.ByType((Farmer,Animal,CropPlot), true)(model)
        stepagent!(getindex(model, a), model)
    end
end

"""
    finalise(model)

Wrap up the simulation. Output all remaining data and exit.
"""
function finalise(model::AgentBasedModel)
    @info "Simulation completed at $(Dates.now()),\nwrote output to $(param("core.outdir"))."
    #TODO
    genocide!(model)
end

"""
    simulate(config)

Carry out a complete simulation run.
"""
function simulate(config::String=PARAMFILE)
    model = initialise(config)
    runtime = Dates.value(param("core.enddate")-param("core.startdate"))
    step!(model, dummystep, stepsimulation!, runtime)
    finalise(model)
end