### Persefone.jl - a model of agricultural landscapes and ecosystems in Europe.
###
### This file is responsible for managing the farm module(s).
###    

##TODO what data do we need to gather from the farm submodel?

"""
    Farmer

This is the agent type for the farm ABM. (Not yet implemented.)
"""
mutable struct Farmer <: ModelAgent
    #XXX make this into an abstract type and create subtypes for different farm submodels? (#69)
    const id::Int64
    fields::Vector{Int64} # IDs of the farmplots this farmer owns
    croprotation::Vector{String} #TODO figure this out
    totalincome::Float64
end

"""
    stepagent!(farmer, model)

Update a farmer by one day.
"""
function stepagent!(farmer::Farmer, model::SimulationModel)
    for f in farmer.fields
        field = model.farmplots[f]
        ctype = croptype(field)
        if ctype.group != "semi-natural" && isharvestable(field)
            harvest!(field, model)
            #XXX later: calculate income based on yield and annual price
            (ctype.group != "grass") && @sow("no growth")
        elseif cropname(field) == "no growth"
            #TODO if a field has been harvested, check if the next crop can be sown
        end
    end     
end

"""
    initfarms!(model)

Initialise the model with a set of farm agents.
"""
function initfarms!(model::SimulationModel)
    #XXX initially, we only have one farmer controlling all fields in the region
    farmer = Farmer(1, collect(1:length(model.farmplots)), [], 0)
    model.farmers = [farmer]
    setasides = findsetasides(farmer, model)
    for field in model.farmplots
        if isgrassland(field, model)
            @sow("permanent grassland (seeded)")
        elseif field.id in setasides
            @sow("permanent set-aside")
        else
            @sow("no growth")
        end
    end
end

"""
    findsetasides(farmer, model)

Return a vector of field IDs that this farmer should keep fallow to satisfy the configured
set-aside rules.
"""
function findsetasides(farmer::Farmer, model::SimulationModel)
    @param(farm.setaside) == 0 && return []
    croparea = @areaof(sum(f -> isgrassland(f, model) ? 0 : length(f.pixels),
                           model.farmplots[farmer.fields]))
    setasidearea = 0m²
    setasides = []
    for f in farmer.fields #XXX should be sorted smallest-largest for highest efficiency
        field = model.farmplots[f]
        isgrassland(field, model) && continue
        push!(setasides, f)
        setasidearea += @areaof(length(field.pixels))
        if setasidearea >= croparea*@param(farm.setaside)
            @debug "Farmer $(farmer.id) has set aside $(setasidearea |> ha)."
            return setasides
        end
    end
end