Files
farmcal/cmd/server/calendar.go

172 lines
3.9 KiB
Go

package main
import (
"fmt"
"sort"
"strings"
)
func buildTasksForDay(plans []Plan, stepMap map[int64][]CropStep, month, day int) []Task {
var tasks []Task
for _, p := range plans {
tasks = append(tasks, expandPlanDayTasks(p, stepMap[p.CropID], month, day)...)
}
sortTasks(tasks)
return tasks
}
func buildCalendar(plans []Plan, stepMap map[int64][]CropStep, startMonth, startDay, daysPerMonth, spanMonths int) []CalendarMonth {
tasksByKey := make(map[string][]Task)
for _, p := range plans {
for m := 1; m <= 12; m++ {
for d := 1; d <= daysPerMonth; d++ {
dayTasks := expandPlanDayTasks(p, stepMap[p.CropID], m, d)
if len(dayTasks) > 0 {
key := fmt.Sprintf("%d-%d", m, d)
tasksByKey[key] = append(tasksByKey[key], dayTasks...)
}
}
}
}
for k := range tasksByKey {
sortTasks(tasksByKey[k])
}
var out []CalendarMonth
for offset := 0; offset < spanMonths; offset++ {
month := wrapMonth(startMonth + offset)
yearOffset := (startMonth - 1 + offset) / 12
label := monthNames[month-1]
if yearOffset > 0 {
label = fmt.Sprintf("%s (+%d Jahr)", label, yearOffset)
}
fromDay := 1
if offset == 0 {
fromDay = startDay
}
var days []CalendarDay
for d := fromDay; d <= daysPerMonth; d++ {
key := fmt.Sprintf("%d-%d", month, d)
items := append([]Task(nil), tasksByKey[key]...)
days = append(days, CalendarDay{Day: d, Tasks: items})
}
out = append(out, CalendarMonth{
Offset: offset,
Month: month,
Label: label,
YearOffset: yearOffset,
Days: days,
})
}
return out
}
func expandPlanDayTasks(p Plan, steps []CropStep, month, day int) []Task {
field := p.TargetName
if strings.TrimSpace(field) == "" {
field = "Unbekanntes Feld"
}
var out []Task
baseHarvest := p.HarvestMonth
if p.StartMonth == month && p.StartDay == day {
out = append(out, Task{
Type: "Aussaat",
Field: field,
Message: withOptionalNote(fmt.Sprintf("Aussaat %s", p.CropName), p.Notes),
SortOrder: 10,
})
}
harvestMonths := []int{baseHarvest}
if p.RegrowEnabled {
maxExtra := p.RegrowCycles
if maxExtra == 0 {
maxExtra = 24
}
for i := 1; i <= maxExtra; i++ {
harvestMonths = append(harvestMonths, wrapMonth(baseHarvest+(i*p.HarvestDistance())))
}
}
harvestMonths = uniqueMonths(harvestMonths)
for _, hm := range harvestMonths {
if hm == month && p.HarvestDay == day {
out = append(out, Task{
Type: "Ernte",
Field: field,
Message: withOptionalNote(fmt.Sprintf("Ernte %s", p.CropName), p.Notes),
SortOrder: 20,
})
}
}
for _, s := range steps {
switch s.Phase {
case "pre":
taskMonth := wrapMonth(p.StartMonth - s.MonthOffset)
if taskMonth == month && p.StartDay == day {
out = append(out, Task{
Type: "Vorbereitung",
Field: field,
Message: s.Title,
SortOrder: 5,
})
}
case "post":
for _, hm := range harvestMonths {
taskMonth := wrapMonth(hm + s.MonthOffset)
if taskMonth == month && p.HarvestDay == day {
out = append(out, Task{
Type: "Nachbereitung",
Field: field,
Message: s.Title,
SortOrder: 30,
})
}
}
}
}
return out
}
func (p Plan) HarvestDistance() int {
if p.GrowMonths <= 0 {
return 1
}
return p.GrowMonths
}
func withOptionalNote(base, note string) string {
n := strings.TrimSpace(note)
if n == "" {
return base
}
return fmt.Sprintf("%s (Notiz: %s)", base, n)
}
func sortTasks(tasks []Task) {
sort.Slice(tasks, func(i, j int) bool {
if tasks[i].SortOrder == tasks[j].SortOrder {
if tasks[i].Field == tasks[j].Field {
return tasks[i].Message < tasks[j].Message
}
return tasks[i].Field < tasks[j].Field
}
return tasks[i].SortOrder < tasks[j].SortOrder
})
}
func uniqueMonths(values []int) []int {
seen := make(map[int]bool)
var out []int
for _, v := range values {
if !seen[v] {
seen[v] = true
out = append(out, v)
}
}
return out
}