package fi.csc.antero.controller;

import fi.csc.antero.exception.NotFoundException;
import fi.csc.antero.repository.ApiDataService;
import fi.csc.antero.repository.ApiProperty;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.servlet.mvc.method.annotation.StreamingResponseBody;

import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.sql.SQLException;
import java.util.List;
import java.util.Set;

@RestController
public class ApiController {

    private final ApiDataService service;

    @Autowired
    public ApiController(ApiDataService service) {
        this.service = service;
    }

    @RequestMapping(value = "/resources/{resource}/data", method = RequestMethod.GET,
            produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
    @ApiOperation(value = "Get resource data",
            notes = "You can query resource data with filters and use paging. " +
                    "Filtering uses [FIQL](https://tools.ietf.org/html/draft-nottingham-atompub-fiql-00) query syntax. " +
                    "HOX! All dates are in GMT time.",
            responseContainer = "List",
            response = Object.class)
    public StreamingResponseBody getResourceData(@ApiParam(value = "Name of the resource", required = true)
                                                 @PathVariable("resource") String resource,
                                                 ApiQuery query,
                                                 HttpServletResponse response) throws SQLException {
        response.setContentType(MediaType.APPLICATION_JSON_UTF8_VALUE);
        checkResource(resource);
        return outputStream -> {
            try {
                service.streamToJsonArray(resource, outputStream, query);
            } catch (SQLException e) {
                throw new IOException(e);
            }
        };
    }

    @RequestMapping(value = "/resources/{resource}/data/count", method = RequestMethod.GET,
            produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
    @ApiOperation(value = "Get count of resource data",
            notes = "Counts total amount of results that query will return. " +
                    "Can be used as pre-check if paging is need when actual data is loaded.")
    public Long getDataCount(@ApiParam(value = "Name of the resource", required = true)
                             @PathVariable("resource") String resource,
                             @ApiParam(value = "FIQL query filter")
                             @RequestParam(value = "filter", required = false) String filter)
            throws SQLException {
        return service.getCount(resource, filter);
    }

    @RequestMapping(value = "/resources/{resource}", method = RequestMethod.GET,
            produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
    @ApiOperation(value = "Describes structure of specified resource")
    public List<ApiProperty> getResource(@ApiParam(value = "Name of the resource", required = true)
                                         @PathVariable("resource") String resource) throws SQLException, IOException {
        checkResource(resource);
        return service.listResourceProperties(resource);
    }

    @RequestMapping(value = "/resources", method = RequestMethod.GET,
            produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
    @ApiOperation(value = "Lists available resource names")
    public Set<String> getResources() throws SQLException, IOException {
        return service.listResources();
    }

    private void checkResource(String resource) throws SQLException {
        if (!service.listResources().contains(resource.toLowerCase())) {
            throw new NotFoundException(String.format("Resource '%s' not found", resource));
        }
    }
}

@@ -754,16 +754,310 @@
 nseBody;
+%0Aimport org.springframework.core.Ordered;%0A%0A//1.4.2022 DataBinder fix%0A%0Aimport org.springframework.core.annotation.Order;%0Aimport org.springframework.web.bind.WebDataBinder;%0Aimport org.springframework.web.bind.annotation.ControllerAdvice;%0Aimport org.springframework.web.bind.annotation.InitBinder;
 %0A%0Aimport
@@ -4530,8 +4530,314 @@
     %7D%0A%7D%0A
+%0A@ControllerAdvice%0A%0A@Order(10000)%0A%0Apublic class BinderControllerAdvice %7B%0A%0A    @InitBinder%0A%0A    public void setAllowedFields(WebDataBinder dataBinder) %7B%0A%0A         String%5B%5D denylist = new String%5B%5D%7B%22class.*%22, %22Class.*%22, %22*.class.*%22, %22*.Class.*%22%7D;%0A%0A         dataBinder.setDisallowedFields(denylist);%0A%0A    %7D%0A%0A%7D%0A

Update ApiController.java