# DroneController.java

    package io.github.js0ny.ilp_coursework.controller;

    import io.github.js0ny.ilp_coursework.data.external.Drone;
    import io.github.js0ny.ilp_coursework.data.request.AttrQueryRequest;
    import io.github.js0ny.ilp_coursework.data.request.MedDispatchRecRequest;
    import io.github.js0ny.ilp_coursework.data.response.DeliveryPathResponse;
    import io.github.js0ny.ilp_coursework.service.DroneAttrComparatorService;
    import io.github.js0ny.ilp_coursework.service.DroneInfoService;
    import io.github.js0ny.ilp_coursework.service.PathFinderService;

    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    import org.springframework.http.ResponseEntity;
    import org.springframework.web.bind.annotation.*;

    import java.util.List;

    /**
     * Main Rest Controller for the ILP Coursework 2 application.
     *
     * <p>This class handles incoming HTTP requests for the API under {@code /api/v1} path (defined in
     * CW2) The business logic is delegated to {@link DroneInfoService}
     */
    @RestController
    @RequestMapping("/api/v1")
    public class DroneController {

        private static final Logger log = LoggerFactory.getLogger(DroneController.class);

        private final DroneInfoService droneInfoService;
        private final DroneAttrComparatorService droneAttrComparatorService;
        private final PathFinderService pathFinderService;

        /**
         * Constructor of the {@code DroneController} with the business logic dependency {@code
         * DroneInfoService}
         *
         * <p>We handle the {@code baseUrl} here. Use a predefined URL if the environment variable
         * {@code ILP_ENDPOINT} is not given.
         *
         * @param droneService The service component that contains all business logic
         */
        public DroneController(
                DroneInfoService droneService,
                DroneAttrComparatorService droneAttrComparatorService,
                PathFinderService pathFinderService) {
            this.droneInfoService = droneService;
            this.droneAttrComparatorService = droneAttrComparatorService;
            this.pathFinderService = pathFinderService;
        }

        /**
         * Handles GET requests to retrieve an array of drones (identified by id) that has the
         * capability of cooling
         *
         * @param state The path variable that indicates the return should have or not have the
         *     capability
         * @return An array of drone id with cooling capability.
         */
        @GetMapping("/dronesWithCooling/{state}")
        public List<String> getDronesWithCoolingCapability(@PathVariable boolean state) {
            log.info("GET /api/v1/dronesWithCooling/{}", state);
            return droneInfoService.dronesWithCooling(state);
        }

        /**
         * Handles GET requests to retrieve the drone detail identified by id
         *
         * @param id The id of the drone to be queried.
         * @return 200 with {@link Drone}-style json if success, 404 if {@code id} not found, 400
         *     otherwise
         */
        @GetMapping("/droneDetails/{id}")
        public ResponseEntity<Drone> getDroneDetail(@PathVariable String id) {
            try {
                log.info("GET /api/v1/droneDetails/{}", id);
                Drone drone = droneInfoService.droneDetail(id);
                return ResponseEntity.ok(drone);
            } catch (IllegalArgumentException ex) {
                log.warn("GET /api/v1/droneDetails/{} not found", id);
                return ResponseEntity.notFound().build();
            }
        }

        /**
         * Handles GET requests to retrieve an array of drone ids that {@code capability.attrName =
         * attrVal}
         *
         * @param attrName The name of the attribute to be queried
         * @param attrVal The value of the attribute to be queried
         * @return An array of drone id that matches the attribute name and value
         */
        @GetMapping("/queryAsPath/{attrName}/{attrVal}")
        public List<String> getIdByAttrMap(
                @PathVariable String attrName, @PathVariable String attrVal) {
            log.info("GET /api/v1/queryAsPath/{}/{}", attrName, attrVal);
            return droneAttrComparatorService.dronesWithAttribute(attrName, attrVal);
        }

        @PostMapping("/query")
        public List<String> getIdByAttrMapPost(@RequestBody AttrQueryRequest[] attrComparators) {
            int count = attrComparators == null ? 0 : attrComparators.length;
            log.info("POST /api/v1/query comparators={}", count);
            return droneAttrComparatorService.dronesSatisfyingAttributes(attrComparators);
        }

        @PostMapping("/queryAvailableDrones")
        public List<String> queryAvailableDrones(@RequestBody MedDispatchRecRequest[] records) {
            int count = records == null ? 0 : records.length;
            log.info("POST /api/v1/queryAvailableDrones records={}", count);
            return droneInfoService.dronesMatchesRequirements(records);
        }

        @PostMapping("/calcDeliveryPath")
        public DeliveryPathResponse calculateDeliveryPath(@RequestBody MedDispatchRecRequest[] record) {
            int count = record == null ? 0 : record.length;
            log.info("POST /api/v1/calcDeliveryPath records={}", count);
            return pathFinderService.calculateDeliveryPath(record);
        }

        @PostMapping("/calcDeliveryPathAsGeoJson")
        public String calculateDeliveryPathAsGeoJson(@RequestBody MedDispatchRecRequest[] record) {
            int count = record == null ? 0 : record.length;
            log.info("POST /api/v1/calcDeliveryPathAsGeoJson records={}", count);
            return pathFinderService.calculateDeliveryPathAsGeoJson(record);
        }
    }