package server
import (
"fmt"
"html/template"
"log"
"net/http"
"github.com/ray1729/puzzle-solver/anagram"
"github.com/ray1729/puzzle-solver/grep"
)
func New(assetsPath string, grepDB grep.DB, anagramDB anagram.DB) http.Handler {
mux := http.NewServeMux()
mux.Handle("/assets/", http.StripPrefix("/assets/", http.FileServer(http.Dir(assetsPath))))
mux.HandleFunc("/", getHomePage)
mux.HandleFunc("/search", getResults(grepDB, anagramDB))
return withRequestLogger(mux)
}
func withRequestLogger(h http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
log.Printf("%s %s %s", r.Method, r.URL.Path, r.URL.Query())
h.ServeHTTP(w, r)
})
}
func getResults(grepDB grep.DB, anagramDB anagram.DB) func(w http.ResponseWriter, r *http.Request) {
return func(w http.ResponseWriter, r *http.Request) {
if err := r.ParseForm(); err != nil {
log.Printf("error parsing form: %v", err)
http.Error(w, "error parsing form", http.StatusBadRequest)
return
}
mode := r.Form.Get("mode")
pattern := r.Form.Get("pattern")
templateParams := struct {
Preamble string
Results []string
}{}
switch mode {
case "match":
templateParams.Results = grepDB.FindMatches(pattern)
if len(templateParams.Results) > 0 {
templateParams.Preamble = fmt.Sprintf("Matches for %q:", pattern)
} else {
templateParams.Preamble = fmt.Sprintf("Found no matches for %q", pattern)
}
case "anagrams":
templateParams.Results = anagramDB.FindAnagrams(pattern)
if len(templateParams.Results) > 0 {
templateParams.Preamble = fmt.Sprintf("Anagrams of %q:", pattern)
} else {
templateParams.Preamble = fmt.Sprintf("Found no anagrams of %q", pattern)
}
case "clear":
// pass
default:
log.Printf("invalid mode: %s", mode)
http.Error(w, "invalid mode", http.StatusBadRequest)
return
}
renderTemplate(w, results, templateParams)
}
}
func getHomePage(w http.ResponseWriter, r *http.Request) {
renderTemplate(w, home, nil)
}
func renderTemplate(w http.ResponseWriter, t *template.Template, params any) {
err := t.Execute(w, params)
if err != nil {
log.Printf("Error rendering template %s: %v", t.Name(), err)
http.Error(w, "Internal server error", http.StatusInternalServerError)
}
}