/*
 *  Copyright (C) 2019,2020 Stichting Akvo (Akvo Foundation)
 *
 *  This file is part of Akvo FLOW.
 *
 *  Akvo FLOW is free software: you can redistribute it and modify it under the terms of
 *  the GNU Affero General Public License (AGPL) as published by the Free Software Foundation,
 *  either version 3 of the License or any later version.
 *
 *  Akvo FLOW is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
 *  without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 *  See the GNU Affero General Public License included below for more details.
 *
 *  The full license text can also be seen at <http://www.gnu.org/licenses/agpl.html>.
 */

package org.akvo.flow.api.app;

import com.gallatinsystems.framework.dao.BaseDAO;
import com.gallatinsystems.framework.rest.AbstractRestApiServlet;
import com.gallatinsystems.framework.rest.RestRequest;
import com.gallatinsystems.framework.rest.RestResponse;
import com.gallatinsystems.surveyal.domain.SurveyedLocale;
import org.akvo.flow.util.FlowJsonObjectWriter;
import org.waterforpeople.mapping.app.web.dto.SurveyedLocaleDto;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.util.List;
import java.util.logging.Logger;


/**
 * JSON service for returning the list of assigned data point records for a specific device and surveyId
 */
@SuppressWarnings("serial")
public class DataPointServlet extends AbstractRestApiServlet {
    private static final Logger log = Logger.getLogger(DataPointServlet.class.getName());

    public static final int LIMIT_DATAPOINTS_30 = 30;

    public DataPointServlet() {
        setMode(JSON_MODE);
    }

    @Override
    protected RestRequest convertRequest() throws Exception {
        HttpServletRequest req = getRequest();
        RestRequest restRequest = new DataPointRequest();
        restRequest.populateFromHttpRequest(req);
        return restRequest;
    }

    /**
     * calls the surveyedLocaleDao to get the list of surveyedLocales for a certain surveyGroupId
     * passed in via the request, or the total number of available surveyedLocales if the
     * checkAvailable flag is set.
     */
    @Override
    protected RestResponse handleRequest(RestRequest req) throws Exception {
        DataPointRequest dpReq = (DataPointRequest) req;
        DataPointResponse res = new DataPointResponse();
        if (dpReq.getSurveyId() == null) {
            res.setCode(String.valueOf(HttpServletResponse.SC_FORBIDDEN));
            res.setMessage("Invalid Survey");
            return res;
        }

        DataPointUtil dpu = new DataPointUtil();
        List<SurveyedLocale> dpList;
        try {
            dpList = dpu.getAssignedDataPoints(dpReq.getAndroidId(), dpReq.getSurveyId(), dpReq.getCursor(), LIMIT_DATAPOINTS_30);
        } catch(Exception e) {
            res.setCode(String.valueOf(HttpServletResponse.SC_NOT_FOUND));
            res.setMessage(e.getMessage());
            return res;
        }

        res = convertToResponse(dpList, dpReq.getSurveyId());
        String cursor = BaseDAO.getCursor(dpList);
        if (cursor == null && dpList.size() > 0) {
            cursor = dpList.size() + "";
        }
        res.setCursor(cursor);

        return res;
    }




    /**
     * converts the domain objects to dtos and then installs them in a DataPointResponse object
     */
    private DataPointResponse convertToResponse(List<SurveyedLocale> slList, Long surveyId) {
        DataPointResponse resp = new DataPointResponse();
        if (slList == null) {
            resp.setCode(String.valueOf(HttpServletResponse.SC_INTERNAL_SERVER_ERROR));
            resp.setMessage("Internal Server Error");
            return resp;
        }
        // set meta data
        resp.setCode(String.valueOf(HttpServletResponse.SC_OK));
        resp.setResultCount(slList.size());

        DataPointUtil dpu = new DataPointUtil();
        List<SurveyedLocaleDto> dtoList = dpu.getSurveyedLocaleDtosList(slList, surveyId);

        resp.setDataPointData(dtoList);
        return resp;
    }


    /**
     * writes response as a JSON string
     */
    @Override
    protected void writeOkResponse(RestResponse resp) throws Exception {
        int sc;
        try {
            sc = Integer.valueOf(resp.getCode());
        } catch (NumberFormatException ignored) {
            // Status code was not properly set in the RestResponse
            sc = HttpServletResponse.SC_INTERNAL_SERVER_ERROR;
        }
        getResponse().setStatus(sc);
        if (sc == HttpServletResponse.SC_OK) {
            FlowJsonObjectWriter writer = new FlowJsonObjectWriter();
            OutputStream stream = getResponse().getOutputStream();
            writer.writeValue(stream, resp);
            PrintWriter endwriter = new PrintWriter(stream);
            endwriter.println();
        } else {
            getResponse().getWriter().println(resp.getMessage());
        }
    }
}

@@ -1135,16 +1135,50 @@
 leDto;%0A%0A
+import javax.annotation.Nullable;%0A
 import j
@@ -3279,24 +3279,90 @@
 ze() %3E 0) %7B%0A
+            int offset = getOffsetFromRequest(dpReq.getCursor());%0A
             
@@ -3370,16 +3370,17 @@
 ursor = 
+(
 dpList.s
@@ -3386,16 +3386,26 @@
 size() +
+ offset) +
  %22%22;%0A   
@@ -3470,16 +3470,411 @@
 %0A    %7D%0A%0A
+    private int getOffsetFromRequest(@Nullable String cursor) %7B%0A        if (cursor == null %7C%7C cursor.isEmpty()) %7B%0A            return 0;%0A        %7D else %7B%0A            try %7B%0A                return Integer.parseInt(cursor);%0A            %7D catch (NumberFormatException e) %7B%0A                //cursor is not a number which can happen, not an error%0A                return 0;%0A            %7D%0A        %7D%0A    %7D
 %0A%0A%0A    /

make sure to add an offset to the cursor (#3659)