// timetable.go package controllers import ( "bytes" "fmt" "html/template" "log" "officeHours/models" "officeHours/templating" ) // A function that takes a slice of office hours and // constructs a timetable t such that t[date][slot] is an // office hour that takes place at this time and no such cell has more than one // office hour and each officehour is in exactly one slot. // It also indicates how many slots exist per day. func (b *BaseHandler) GetTimetable(officeHours []models.OfficeHour) (map[models.Date]map[int]models.OfficeHour, []int) { var timetable = make(map[models.Date]map[int]models.OfficeHour) for _, officeHour := range officeHours { var slot int = 0 for minute := 0; minute < officeHour.Duration; minute += b.config.Date.MinuteGranularity { // find slot id _, exists := timetable[models.GetEndDate(officeHour.Date, minute, true)] if exists { _, exists := timetable[models.GetEndDate(officeHour.Date, minute, true)][slot] if exists { slot += 1 minute = 0 continue } } else { timetable[models.GetEndDate(officeHour.Date, minute, true)] = make(map[int]models.OfficeHour) } } for minute := 0; minute < officeHour.Duration; minute += b.config.Date.MinuteGranularity { // write officeHour id to timetable timetable[models.GetEndDate(officeHour.Date, minute, true)][slot] = officeHour } } slots := []int{1, 1, 1, 1, 1} for date, _ := range timetable { if slots[date.Day] < len(timetable[date]) { slots[date.Day] = len(timetable[date]) } } return timetable, slots } // A function to generate the HTML code for the table of office hours from a timetable. func (b *BaseHandler) printTimetable(timetable map[models.Date]map[int]models.OfficeHour, slots []int, deleteIcons bool) template.HTML { if len(timetable) == 0 { // no office hours to display return template.HTML("

Aktuell sind keine passenden Sprechstunden eingetragen.

") } var tableBody string for hour := b.config.Date.EarliestStartTime.Hour; hour < b.config.Date.LatestStartTime.Hour+b.config.Date.MaxDuration/60; hour += 1 { for minute := 0; minute < 60; minute += b.config.Date.MinuteGranularity { tableBody += "" if minute == 0 { tableBody += fmt.Sprintf("%d Uhr\n", hour) } else { tableBody += "\n" } for day := 0; day < 5; day += 1 { for slot := 0; slot < slots[day]; slot += 1 { current, currentExists := timetable[models.Date{Week: 0, Day: day, Hour: hour, Minute: minute}][slot] if currentExists { // This slot is taken by some office hour var continued bool = false // is this slot occupied by the same office hour the previous minute? var predecessorExists bool var predecessor models.OfficeHour if hour > 0 && minute < b.config.Date.MinuteGranularity { predecessor, predecessorExists = timetable[models.Date{Week: 0, Day: day, Hour: hour - 1, Minute: 60 - b.config.Date.MinuteGranularity}][slot] } else { predecessor, predecessorExists = timetable[models.Date{Week: 0, Day: day, Hour: hour, Minute: minute - b.config.Date.MinuteGranularity}][slot] } if predecessorExists { continued = (predecessor == current) } else { continued = false } if continued { continue } else { var celldata bytes.Buffer data := struct { OfficeHour models.OfficeHour MinuteGranularity int DeleteIcons bool }{OfficeHour: current, MinuteGranularity: b.config.Date.MinuteGranularity, DeleteIcons: deleteIcons} err := templating.WriteTemplate(&celldata, "td", data) if err != nil { err = fmt.Errorf("writing table cell failed:\n%w", err) log.Println(err.Error()) // TODO: better error wrapping up to top-level request handler } tableBody += celldata.String() } } else { if slot+1 == slots[day] { tableBody += "\n" } else { tableBody += "\n" } } } } tableBody += "\n" } } var table bytes.Buffer tableData := struct { ColspanMon int ColspanTue int ColspanWed int ColspanThu int ColspanFri int TableBody template.HTML }{ slots[0], slots[1], slots[2], slots[3], slots[4], template.HTML(tableBody), } err := templating.WriteTemplate(&table, "officeHourTable", tableData) if err != nil { err = fmt.Errorf("writing table failed:\n%w", err) log.Println(err.Error()) // TODO: better error wrapping up to top-level request handler } return template.HTML(table.String()) }