### Persefone.jl - a model of agricultural landscapes and ecosystems in Europe.
###
### This file contains code for the fields that farmers manage.
###

mutable struct FarmPlot{T} <: ModelAgent
    const id::Int64
    pixels::Vector{Tuple{Int64, Int64}}
    cropstate :: T
end

croptype(f::FarmPlot{T}) where {T} = croptype(f.cropstate)
cropname(f::FarmPlot{T}) where {T} = cropname(croptype(f))
cropheight(f::FarmPlot{T}) where {T} = cropheight(f.cropstate)
cropcover(f::FarmPlot{T}) where {T} = cropcover(f.cropstate)
cropyield(f::FarmPlot{T}) where {T} = cropyield(f.cropstate)

"""
    stepagent!(farmplot, model)

Update a farm plot by one day.
"""
function stepagent!(farmplot::FarmPlot{T}, model::SimulationModel) where T
    stepagent!(farmplot.cropstate, model)
end

"""
    sow!(farmplot, model, cropname)

Sow the specified crop on the farmplot.
"""
function sow!(farmplot::FarmPlot, model::SimulationModel, cropname::String)
    #XXX test if the crop is sowable?
    createevent!(model, farmplot.pixels, sowing)
    sow!(farmplot.cropstate, model, cropname)
end

"""
    harvest!(farmplot, model)

Harvest the crop of this farmplot.
"""
function harvest!(farmplot::FarmPlot{T}, model::SimulationModel) where T
    createevent!(model, farmplot.pixels, harvesting)
    harvest!(farmplot.cropstate, model)  # TODO: multiply with area to return units of `g`
end

## UTILITY FUNCTIONS

"""
    averagefieldsize(model)

Calculate the average field size in hectares for the model landscape.
"""
function averagefieldsize(model::SimulationModel)
    conversionfactor = 100 #our pixels are currently 10x10m, so 100 pixels per hectare
    sizes::Vector{Float64} = []
    for fp in model.farmplots
        push!(sizes, size(fp.pixels)[1]/conversionfactor)
    end
    round(sum(sizes)/size(sizes)[1], digits=2)
end

"""
    croptype(model, position)

Return the crop at this position, or nothing if there is no crop here (utility wrapper).
"""
function croptype(pos::Tuple{Int64,Int64}, model::SimulationModel)
    ismissing(model.landscape[pos...].fieldid) ? nothing :
              croptype(model.farmplots[model.landscape[pos...].fieldid])
end

"""
    cropname(model, position)

Return the name of the crop at this position, or an empty string if there is no crop here
(utility wrapper).
"""
function cropname(pos::Tuple{Int64,Int64}, model::SimulationModel)
    field = model.landscape[pos...].fieldid
    ismissing(field) ? "" : cropname(model.farmplots[field])
end

"""
    cropheight(model, position)

Return the height of the crop at this position, or nothing if there is no crop here
(utility wrapper).
"""
function cropheight(pos::Tuple{Int64,Int64}, model::SimulationModel)
    ismissing(model.landscape[pos...].fieldid) ? 0.0cm :  # TODO: 0.0cm correct here?
              cropheight(model.farmplots[model.landscape[pos...].fieldid])
end

"""
    cropcover(model, position)

Return the crop cover of the crop at this position, or nothing if
there is no crop here (utility wrapper).
"""
function cropcover(pos::Tuple{Int64,Int64}, model::SimulationModel)
    ismissing(model.landscape[pos...].fieldid) ? 0.0 :  # TODO: 0.0 correct here?
              cropcover(model.farmplots[model.landscape[pos...].fieldid])
end