scouting: Add support for /requests/request/data_scouting

Signed-off-by: Philipp Schrader <philipp.schrader@gmail.com>
Change-Id: I6a53ed395a187f04c889af506ce6ecacd0a75916
diff --git a/scouting/webserver/requests/requests.go b/scouting/webserver/requests/requests.go
index 44c0b60..3c21402 100644
--- a/scouting/webserver/requests/requests.go
+++ b/scouting/webserver/requests/requests.go
@@ -9,6 +9,8 @@
 	"github.com/frc971/971-Robot-Code/scouting/webserver/requests/messages/error_response"
 	"github.com/frc971/971-Robot-Code/scouting/webserver/requests/messages/request_all_matches"
 	"github.com/frc971/971-Robot-Code/scouting/webserver/requests/messages/request_all_matches_response"
+	"github.com/frc971/971-Robot-Code/scouting/webserver/requests/messages/request_data_scouting"
+	"github.com/frc971/971-Robot-Code/scouting/webserver/requests/messages/request_data_scouting_response"
 	"github.com/frc971/971-Robot-Code/scouting/webserver/requests/messages/request_matches_for_team"
 	"github.com/frc971/971-Robot-Code/scouting/webserver/requests/messages/request_matches_for_team_response"
 	"github.com/frc971/971-Robot-Code/scouting/webserver/requests/messages/submit_data_scouting"
@@ -22,6 +24,8 @@
 type RequestAllMatchesResponseT = request_all_matches_response.RequestAllMatchesResponseT
 type RequestMatchesForTeam = request_matches_for_team.RequestMatchesForTeam
 type RequestMatchesForTeamResponseT = request_matches_for_team_response.RequestMatchesForTeamResponseT
+type RequestDataScouting = request_data_scouting.RequestDataScouting
+type RequestDataScoutingResponseT = request_data_scouting_response.RequestDataScoutingResponseT
 
 // The interface we expect the database abstraction to conform to.
 // We use an interface here because it makes unit testing easier.
@@ -199,9 +203,66 @@
 	w.Write(builder.FinishedBytes())
 }
 
+// TODO(phil): Can we turn this into a generic?
+func parseRequestDataScouting(w http.ResponseWriter, buf []byte) (*RequestDataScouting, bool) {
+	success := true
+	defer func() {
+		if r := recover(); r != nil {
+			respondWithError(w, http.StatusBadRequest, fmt.Sprintf("Failed to parse SubmitDataScouting: %v", r))
+			success = false
+		}
+	}()
+	result := request_data_scouting.GetRootAsRequestDataScouting(buf, 0)
+	return result, success
+}
+
+// Handles a RequestDataScouting request.
+type requestDataScoutingHandler struct {
+	db Database
+}
+
+func (handler requestDataScoutingHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) {
+	requestBytes, err := io.ReadAll(req.Body)
+	if err != nil {
+		respondWithError(w, http.StatusBadRequest, fmt.Sprint("Failed to read request bytes:", err))
+		return
+	}
+
+	_, success := parseRequestDataScouting(w, requestBytes)
+	if !success {
+		return
+	}
+
+	stats, err := handler.db.ReturnStats()
+	if err != nil {
+		respondWithError(w, http.StatusInternalServerError, fmt.Sprint("Faled to query database: ", err))
+	}
+
+	var response RequestDataScoutingResponseT
+	for _, stat := range stats {
+		response.StatsList = append(response.StatsList, &request_data_scouting_response.StatsT{
+			Team:            stat.TeamNumber,
+			Match:           stat.MatchNumber,
+			MissedShotsAuto: stat.ShotsMissedAuto,
+			UpperGoalAuto:   stat.UpperGoalAuto,
+			LowerGoalAuto:   stat.LowerGoalAuto,
+			MissedShotsTele: stat.ShotsMissed,
+			UpperGoalTele:   stat.UpperGoalShots,
+			LowerGoalTele:   stat.LowerGoalShots,
+			DefenseRating:   stat.PlayedDefense,
+			Climbing:        stat.Climbing,
+		})
+	}
+
+	builder := flatbuffers.NewBuilder(50 * 1024)
+	builder.Finish((&response).Pack(builder))
+	w.Write(builder.FinishedBytes())
+}
+
 func HandleRequests(db Database, scoutingServer server.ScoutingServer) {
 	scoutingServer.HandleFunc("/requests", unknown)
 	scoutingServer.Handle("/requests/submit/data_scouting", submitDataScoutingHandler{db})
 	scoutingServer.Handle("/requests/request/all_matches", requestAllMatchesHandler{db})
 	scoutingServer.Handle("/requests/request/matches_for_team", requestMatchesForTeamHandler{db})
+	scoutingServer.Handle("/requests/request/data_scouting", requestDataScoutingHandler{db})
 }