package routes
import (
"embed"
"html/template"
"log"
"math"
"net/http"
"slices"
"sunshine.industries/some-automoderation/rooms"
)
type brickState struct {
ColorClass template.CSS
TemplateType string
}
type personData struct {
Name string
IsSpeaker bool
IsMark bool
IsRaised bool
Raised rooms.HandGesture
Mark rooms.HandGesture
Index int
}
// data to be passed to "roomPeople" template
type roomTableData struct {
*rooms.Room
currentPerson rooms.PersonId
}
func (room *roomTableData) Persons() []personData {
total := room.Total()
persons := make([]personData, 0, total)
currentPersonIndex := slices.Index(room.Paricipants, room.currentPerson)
for i, pId := range room.Paricipants {
personData := personDataFromRoom(room, pId)
// to have index 0 for 'current person'
personData.Index = (i - currentPersonIndex + total) % total
persons = append(persons, personData)
}
return persons
}
func (r *roomTableData) Total() int {
return len(r.Paricipants)
}
func (r *roomTableData) Tangens() float64 {
total := r.Total()
if total == 2 {
return 1
}
if total == 1 {
return 500
}
return math.Tan(math.Pi / float64(r.Total())) // Math.tan(Math.PI/m);
}
type arrowData struct {
IsVisible bool
Height, Width int
Radius int
StartX, StartY int
EndX, EndY int
LargeArcFlag int
Angle1X, Angle1Y int
Angle2X, Angle2Y int
}
// arrow data - to draw SVG from current speaker to next speaker
func (r *roomTableData) ArrowData() arrowData {
// TODO figure out size to be around the people
// and this is somewhat a win
height, width := 150.0, 150.0
centerX, centerY := height/2, width/2
total := r.Total()
// speakerIndex := slices.Index(r.Paricipants, r.CurrentSpeaker)
currentPersonIndex := slices.Index(r.Paricipants, r.currentPerson)
nextSpeakerIndex, found, countedFromIndex := r.NextSpeakerIndex()
if !found {
return arrowData{}
}
startSector := countedFromIndex + total - currentPersonIndex
endSector := nextSpeakerIndex + total - currentPersonIndex
if endSector < startSector {
endSector += total
}
radius := 50.0
startAngle := 90 + float64(startSector)*(360.0/float64(total))
endAngle := 90 + float64(endSector)*(360.0/float64(total))
// if need to draw full circle
if startSector == endSector {
startAngle += 3 // a bit forward
endAngle += 357 // ~ a bit backward (almost full circle forward)
}
startAngleRad := startAngle * (math.Pi / float64(180))
endAngleRad := endAngle * (math.Pi / float64(180))
// endAngle is radius angle, so perpendicular gives direction of teh arrow
x1 := centerX + radius*math.Cos(startAngleRad)
y1 := centerY + radius*math.Sin(startAngleRad)
x2 := centerX + radius*math.Cos(endAngleRad)
y2 := centerY + radius*math.Sin(endAngleRad)
arrowAngleOffset := math.Pi / 4 // 45 degrees
arrowPointDirection := endAngleRad - math.Pi/2
arrowheadLen := 10.0
arrowMinusAngle := arrowPointDirection - arrowAngleOffset
arrowPlusAngle := arrowPointDirection + arrowAngleOffset
arrowMinusEndX := x2 + arrowheadLen*math.Cos(arrowMinusAngle)
arrowMinusEndY := y2 + arrowheadLen*math.Sin(arrowMinusAngle)
arrowPlusEndX := x2 + arrowheadLen*math.Cos(arrowPlusAngle)
arrowPlusEndY := y2 + arrowheadLen*math.Sin(arrowPlusAngle)
// indicates that the shorter of the two possible arcs should be used.
largeArcFlag := 0
//
if endAngleRad-startAngleRad > (math.Pi) {
// specifies that the longer arc should be chosen.
largeArcFlag = 1
}
return arrowData{
IsVisible: true,
Height: int(height),
Width: int(width),
Radius: int(radius),
StartX: int(x1),
StartY: int(y1),
EndX: int(x2),
EndY: int(y2),
LargeArcFlag: largeArcFlag,
Angle1X: int(arrowMinusEndX),
Angle1Y: int(arrowMinusEndY),
Angle2X: int(arrowPlusEndX),
Angle2Y: int(arrowPlusEndY),
}
}
func personDataFromRoom(room *roomTableData, pId rooms.PersonId) personData {
person, exists := room.AllKnownPeople[pId]
if !exists || !slices.Contains(room.Paricipants, pId) {
return personData{}
}
hand, handExists := room.ParticipantHands[pId]
var mark rooms.HandGesture
var markExists bool
for gesture := rooms.ChangeTopic; gesture <= rooms.Meta; gesture++ {
if room.Marks[gesture] == pId {
markExists = true
mark = gesture
}
}
isSpeaker := room.CurrentSpeaker == pId
return personData{
Name: person.Name,
IsSpeaker: isSpeaker,
IsRaised: handExists,
Raised: hand,
IsMark: markExists,
Mark: mark,
}
}
func (pData personData) BricksForPerson() []brickState {
var result = make([]brickState, 5)
for gesture := rooms.ChangeTopic; gesture <= rooms.Meta; gesture++ {
// for index := rooms.Meta; index >= rooms.ChangeTopic; index-- {
// log.Printf(">>>>> iteraging for %d", gesture)
// this results in iteration 4,3,2,1,0,255 wow
templateType := "inactiveBrick"
switch {
case pData.IsRaised && pData.IsMark && gesture == pData.Raised:
templateType = "markAndRaisedBrick"
case pData.IsMark && gesture == pData.Mark:
templateType = "markBrick"
case pData.IsSpeaker && gesture == pData.Raised:
templateType = "speakerBrick"
case pData.IsRaised && gesture == pData.Raised:
templateType = "raisedBrick"
}
result[gesture] = brickState{
ColorClass: gesture.GetGestureInfo().Color,
TemplateType: templateType,
}
}
slices.Reverse(result)
return result
}
func roomTemplatesPreview(
templateFs *embed.FS,
) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
type SingleBrickData struct {
ColorClass template.CSS
Name string
Gesture rooms.HandGesture
}
testPersonData := personData{
Name: "John Doe",
IsRaised: true,
Raised: rooms.Expand,
IsMark: true,
Mark: rooms.ProbingQ,
}
var person1 = rooms.Person{
Id: rooms.PersonId(100),
Name: "test person name 1",
}
var person2 = rooms.Person{
Id: rooms.PersonId(200),
Name: "test person name 2",
}
var person3 = rooms.Person{
Id: rooms.PersonId(300),
Name: "test person name 3",
}
var person4 = rooms.Person{
Id: rooms.PersonId(400),
Name: "test person name 4",
}
aRoom := rooms.Room{
Name: "test",
CurrentSpeaker: person3.Id,
AllKnownPeople: map[rooms.PersonId]rooms.Person{
person1.Id: person1,
person2.Id: person2,
person3.Id: person3,
person4.Id: person4,
},
Paricipants: []rooms.PersonId{
person1.Id,
person2.Id,
person3.Id,
person4.Id,
},
ParticipantHands: map[rooms.PersonId]rooms.HandGesture{
person3.Id: rooms.ClarifyingQ,
person2.Id: rooms.Meta,
person4.Id: rooms.ChangeTopic,
},
Marks: map[rooms.HandGesture]rooms.PersonId{
rooms.Expand: person1.Id,
rooms.ChangeTopic: person4.Id,
},
}
contentData := struct {
DefaultColor template.CSS
Gestures []rooms.HandGesture
ABrick brickState
TestPerson personData
ARoom *roomTableData
}{
DefaultColor: "--expand-color",
ABrick: brickState{
ColorClass: "--expand-color",
TemplateType: "raisedBrick",
},
Gestures: rooms.GesturesHighToLow[:],
TestPerson: testPersonData,
ARoom: &roomTableData{
Room: &aRoom,
currentPerson: aRoom.Paricipants[0],
},
}
pageData := pageData{
Header: headerData{Title: "look at the room templates"},
Content: contentData,
}
baseFile := "templates/base.gohtml"
tmpl := template.Must(template.New("").ParseFS(templateFs, baseFile,
"templates/tableTemplates.gohtml",
"templates/tableTemplatesPreview.gohtml",
))
err := tmpl.ExecuteTemplate(w, "full-page", pageData)
if err != nil {
log.Printf("yoyo, error %s", err)
}
}
}