import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.node.ObjectNode; import com.google.api.client.googleapis.auth.oauth2.GoogleIdToken; import com.google.api.client.googleapis.auth.oauth2.GoogleIdTokenVerifier; import com.google.api.client.http.HttpTransport; import com.google.api.client.http.javanet.NetHttpTransport; import com.google.api.client.json.JsonFactory; import com.google.api.client.json.jackson2.JacksonFactory; import com.sun.net.httpserver.HttpExchange; import com.sun.net.httpserver.HttpHandler; import com.sun.net.httpserver.HttpServer; import java.io.File; import java.io.IOException; import java.io.OutputStream; import java.net.InetSocketAddress; import java.net.URL; import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; import java.security.GeneralSecurityException; import java.sql.SQLException; import java.time.LocalDate; import java.time.LocalDateTime; import java.time.format.DateTimeFormatter; import java.time.temporal.ChronoUnit; import java.util.*; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.Future; public class Server { private static final ExecutorService executorService = Executors.newFixedThreadPool(1); public static void main(String[] args) throws IOException, SQLException { // Start HTTP server DatabaseUtil.initializeDatabase(); HttpServer server = HttpServer.create(new InetSocketAddress(8000), 0); server.createContext("/", new FrontendHandler()); server.createContext("/submit", new FrontendHandler()); server.createContext("/admin/start-scraper", new FrontendHandler()); server.createContext("/admin/last-update-time", new FrontendHandler()); server.createContext("/admin/current-options-count", new FrontendHandler()); server.createContext("/admin/changed-options-count", new FrontendHandler()); server.createContext("/account/login", new AccountHandler()); server.createContext("/account/register", new AccountHandler()); server.createContext("/account/delete-account", new AccountHandler()); server.createContext("/account/session", new AccountHandler()); server.createContext("/save-favorite", new SaveFavoriteHandler()); server.createContext("/get-saved-trips", new GetSavedTripsHandler()); server.createContext("/remove-from-saved", new RemoveFromSavedTripsHandler()); server.start(); System.out.println("Server started on port 8000"); LocalDateTime lastUpdateTime = getLastUpdateTime(); LocalDateTime now = LocalDateTime.now(); if (ChronoUnit.MONTHS.between(lastUpdateTime, now) >= 3) { System.out.println("Automatic Update"); Future future = executorService.submit(new Scraper()); Server.updateLastUpdateTime(); executorService.submit(() -> { try { future.get(); } catch (Exception e) { e.printStackTrace(); } }); } } static class RemoveFromSavedTripsHandler implements HttpHandler { @Override public void handle(HttpExchange exchange) throws IOException { if (exchange.getRequestMethod().equalsIgnoreCase("POST")) { String requestBody = new String(exchange.getRequestBody().readAllBytes()); ObjectMapper mapper = new ObjectMapper(); Map requestData = mapper.readValue(requestBody, Map.class); String userEmail = (String) requestData.get("userEmail"); int optionId = (int) requestData.get("optionId"); int userId; try { userId = DatabaseUtil.getUserIdByEmail(userEmail); boolean removed = DatabaseUtil.removeFavoriteOption(userId, optionId); if (removed) { sendResponse(exchange, 200, "{\"success\": true}"); } else { sendResponse(exchange, 500, "{\"success\": false, \"message\": \"Failed to remove option\"}"); } } catch (SQLException e) { e.printStackTrace(); sendResponse(exchange, 500, "{\"message\": \"Failed to retrieve user ID.\"}"); } } else { sendResponse(exchange, 405, "{\"message\": \"Method not allowed.\"}"); } } } static class SaveFavoriteHandler implements HttpHandler { @Override public void handle(HttpExchange exchange) throws IOException { if (exchange.getRequestMethod().equalsIgnoreCase("POST")) { String requestBody = new String(exchange.getRequestBody().readAllBytes()); ObjectMapper mapper = new ObjectMapper(); Map requestData = mapper.readValue(requestBody, Map.class); String optionId = requestData.get("optionId"); String userEmail = requestData.get("user"); int userId; try { userId = DatabaseUtil.getUserIdByEmail(userEmail); } catch (SQLException e) { e.printStackTrace(); sendResponse(exchange, 500, "{\"message\": \"Failed to retrieve user ID.\"}"); return; } try { if (DatabaseUtil.saveFavoriteOption(userId, Integer.parseInt(optionId))) { sendResponse(exchange, 200, "{\"message\": \"Favorite saved successfully!\"}"); } else { sendResponse(exchange, 500, "{\"message\": \"Failed to save favorite.\"}"); } } catch (SQLException e) { e.printStackTrace(); sendResponse(exchange, 500, "{\"message\": \"Failed to save favorite.\"}"); } } else { sendResponse(exchange, 405, "{\"message\": \"Method not allowed.\"}"); } } } static class GetSavedTripsHandler implements HttpHandler { @Override public void handle(HttpExchange exchange) throws IOException { if (exchange.getRequestMethod().equalsIgnoreCase("POST")) { String requestBody = new String(exchange.getRequestBody().readAllBytes()); ObjectMapper mapper = new ObjectMapper(); Map requestData = mapper.readValue(requestBody, Map.class); String userEmail = requestData.get("userEmail"); int userId; try { userId = DatabaseUtil.getUserIdByEmail(userEmail); } catch (SQLException e) { e.printStackTrace(); sendResponse(exchange, 500, "{\"message\": \"Failed to retrieve user ID.\"}"); return; } List