1package webui
  2
  3import (
  4	"ewdetect/comms"
  5	"ewdetect/config"
  6	"ewdetect/stations"
  7	"ewdetect/utils"
  8	"fmt"
  9	"slices"
 10	"time"
 11
 12	sm "github.com/flopp/go-staticmaps"
 13	"github.com/fogleman/gg"
 14	"github.com/gofiber/fiber/v3"
 15	"github.com/golang/geo/s2"
 16	"github.com/rs/zerolog/log"
 17
 18	"github.com/go-echarts/go-echarts/v2/charts"
 19	"github.com/go-echarts/go-echarts/v2/opts"
 20	"github.com/go-echarts/go-echarts/v2/types"
 21)
 22
 23// generate random data for line chart
 24func generateTimeSeries(connection, key string) []string {
 25	head := (*comms.Connections[connection].Heads)[key]
 26	headLoops := (*comms.Connections[connection].HeadLoops)[key]
 27	items := make([]string, 0)
 28	sampleRate := float64((*stations.Stations[connection])[key].SampleRate)
 29	var startTime time.Time
 30	for i := range config.BufferSize {
 31		startTime = (*comms.Connections[connection].StartTime)
 32		startTime = startTime.Add(time.Duration(1e9 * float64(i) / sampleRate))
 33		startTime = startTime.Add(time.Duration(1e9 * float64((headLoops-1)*config.BufferSize) / sampleRate))
 34		if i <= head {
 35			startTime = startTime.Add(time.Duration(1e9 * float64(config.BufferSize) / sampleRate))
 36		}
 37		items = append(items, startTime.Format("2006-01-02T15:04:05.000"))
 38	}
 39	return items
 40}
 41
 42func generateLineItems(connection, key string) []opts.LineData {
 43	items := make([]opts.LineData, 0)
 44	//fmt.Println(comms.Buffers["MHGZ"])
 45	for _, b := range *(*comms.Connections[connection].Buffers)[key] {
 46		curr_b := b
 47
 48		if _, ok := stations.Stations[connection]; ok {
 49			if (*stations.Stations[connection])[key].Calibrated {
 50				curr_b = curr_b - (*stations.Stations[connection])[key].DC
 51				curr_b = curr_b * 1024 / (*stations.Stations[connection])[key].NoiseFloor
 52			}
 53		}
 54		items = append(items, opts.LineData{Value: b})
 55	}
 56	return items
 57}
 58
 59func chart(c fiber.Ctx) error {
 60	log.Debug().Msg("Generating chart view")
 61	c.Type(".html")
 62	count := 0
 63	for connection := range comms.Connections {
 64		for _ = range *comms.Connections[connection].Buffers {
 65			count++
 66		}
 67	}
 68	if config.Debug {
 69		log.Debug().Msg("Generating debug station map")
 70		ctx := sm.NewContext()
 71		ctx.SetSize(config.DebugResolution, config.DebugResolution)
 72		for connection := range comms.Connections {
 73			if _, ok := stations.Stations[connection]; ok {
 74				for key := range *comms.Connections[connection].Buffers {
 75					ctx.AddObject(
 76						sm.NewMarker(
 77							s2.LatLngFromDegrees((*stations.Stations[connection])[key].Lat, (*stations.Stations[connection])[key].Lon),
 78							utils.ColorFromHash(connection),
 79							16.0,
 80						),
 81					)
 82				}
 83			} else {
 84				log.Warn().Str("connection", connection).Msg("Missing station metadata")
 85			}
 86		}
 87		ctx.OverrideAttribution(fmt.Sprintf("%s - EWDetect - Louis \"OnTake\" Dalibard - 2025.", ctx.Attribution()))
 88
 89		img, err := ctx.Render()
 90		if err != nil {
 91			log.Fatal().Err(err).Msg("Failed to render debug map")
 92		}
 93
 94		if err := gg.SavePNG("debug/station-map/stations.png", img); err != nil {
 95			log.Fatal().Err(err).Msg("Failed to save debug map")
 96		}
 97	}
 98	c.WriteString(fmt.Sprintf("<h1> Tracking %d stations</h1>", count))
 99	for connection := range comms.Connections {
100		for key := range *comms.Connections[connection].Buffers {
101			if slices.Contains(config.WebUITrackedStations, key) {
102				// create a new line instance
103				line := charts.NewLine()
104				// set some global options like Title/Legend/ToolTip or anything else
105				line.SetGlobalOptions(
106					charts.WithInitializationOpts(opts.Initialization{Theme: types.ThemeWesteros}),
107					charts.WithTitleOpts(opts.Title{
108						Title:    fmt.Sprintf("%s (%s)", (*stations.Stations[connection])[key].Name, key),
109						Subtitle: fmt.Sprintf("%0.4f, %0.4f", (*stations.Stations[connection])[key].Lat, (*stations.Stations[connection])[key].Lon),
110					}))
111
112				// Put data into instance
113				line.SetXAxis(generateTimeSeries(connection, key))
114				line.AddSeries(key, generateLineItems(connection, key))
115				line.SetSeriesOptions(charts.WithLineChartOpts(opts.LineChart{Smooth: opts.Bool(false)}))
116				line.Render(c)
117			}
118		}
119	}
120	return nil
121}
122
123func Init() {
124	log.Info().Msg("Initializing WebUI")
125	// Initialize a new Fiber app
126	app := fiber.New()
127
128	// Define a route for the GET method on the root path '/'
129	app.Get("/", chart)
130
131	// Start the server on port 3000
132	log.Info().Msg("Starting WebUI server on port 3000")
133	if err := app.Listen(":3000"); err != nil {
134		log.Fatal().Err(err).Msg("Failed to start WebUI server")
135	}
136}