package org.dainst.chronontology.handler;

import com.fasterxml.jackson.databind.JsonNode;
import org.dainst.chronontology.handler.dispatch.Dispatcher;
import org.dainst.chronontology.handler.model.Document;
import org.dainst.chronontology.handler.model.RightsValidator;
import org.dainst.chronontology.handler.model.Results;
import spark.Request;
import spark.Response;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * @author Daniel M. de Oliveira
 */
public class SearchDocumentHandler extends DocumentHandler {

    public SearchDocumentHandler(Dispatcher dispatcher, RightsValidator rightsValidator) {
        super(dispatcher,rightsValidator);
    }

    @Override
    public Object handle(
            final Request req,
            final Response res) throws IOException {

        String queryString= req.queryString();
        Integer size= null;
        Integer offset= null;
        if (queryString!=null) {
            // TODO refactor
            Matcher sizeMatcher = Pattern.compile("([&|?]size=\\d+)").matcher(queryString);
            while (sizeMatcher.find()) {
                String s = sizeMatcher.group(1);
                size = Integer.parseInt(s.split("=")[1]);
                queryString = queryString.replace(s, "");
            }
            Matcher offsetMatcher = Pattern.compile("([&|?]offset=\\d+)").matcher(queryString);
            while (offsetMatcher.find()) {
                String s = offsetMatcher.group(1);
                offset = Integer.parseInt(s.split("=")[1]);
                queryString = queryString.replace(s, "");
            }
        }
        Results results= dispatcher.dispatchSearch(req.pathInfo(),queryString);
        removeNodes(results, indicesToRemove(req, results));


        trimUntilOffset(results,offset);
        trimToSize(results,size);
        return results;
    }

    private void trimUntilOffset(Results results, Integer offset) {
        if (offset==null) return;
        for (int i=0;i<offset;i++) {
            results.remove(i);
        }
    }

    private void trimToSize(Results results, Integer size) {
        if (size==null) return;
        for (int i=results.getAll().size()-1;i>0;i--) {
            if (i>=size) results.remove(i);
        }
    }

    private void removeNodes(Results r, List<Integer> indicesToRemove) {
        Collections.reverse(indicesToRemove); // TODO write test
        for (Integer index:indicesToRemove) {
            r.remove(index); // TODO check removal
        }
    }

    private List<Integer> indicesToRemove(Request req, Results r) {
        List<Integer> indicesToRemove = new ArrayList<Integer>();
        int i=0;
        for (final JsonNode n : r.getAll()) {

            if (!userAccessLevelSufficient(req, Document.from(n), RightsValidator.Operation.READ)) {
                indicesToRemove.add(i);
            }
            i++;
        }
        return indicesToRemove;
    }
}

@@ -920,810 +920,48 @@
     
-String queryString= req.queryString();%0A        Integer size= null;%0A        Integer offset= null;%0A        if (queryString!=null) %7B%0A            // TODO refactor%0A            Matcher sizeMatcher = Pattern.compile(%22(%5B&%7C?%5Dsize=%5C%5Cd+)%22).matcher(queryString);%0A            while (sizeMatcher.find()) %7B%0A                String s = sizeMatcher.group(1);%0A                size = Integer.parseInt(s.split(%22=%22)%5B1%5D);%0A                queryString = queryString.replace(s, %22%22);%0A            %7D%0A            Matcher offsetMatcher = Pattern.compile(%22(%5B&%7C?%5Doffset=%5C%5Cd+)%22).matcher(queryString);%0A            while (offsetMatcher.find()) %7B%0A                String s = offsetMatcher.group(1);%0A                offset = Integer.parseInt(s.split(%22=%22)%5B1%5D);%0A                queryString = queryString.replace(s, %22%22);%0A            %7D%0A        %7D
+Query q = new Query(req.queryString());%0A
 %0A   
@@ -1023,16 +1023,18 @@
 hInfo(),
+q.
 queryStr
@@ -1134,16 +1134,18 @@
 results,
+q.
 offset);
@@ -1172,16 +1172,18 @@
 results,
+q.
 size);%0A 
@@ -2278,11 +2278,784 @@
 e;%0A    %7D
+%0A%0A    private class Query %7B%0A        public String queryString=null;%0A        public Integer size= null;%0A        public Integer offset= null;%0A%0A        public Query(String qs) %7B%0A            if (qs!=null) %7B%0A                queryString = qs;%0A                size= mod(%22(%5B&%7C?%5Dsize=%5C%5Cd+)%22);%0A                offset= mod(%22(%5B&%7C?%5Doffset=%5C%5Cd+)%22);%0A            %7D%0A        %7D%0A%0A        private Integer mod(String pattern) %7B%0A            Integer nr= null;%0A            Matcher sizeMatcher = Pattern.compile(pattern).matcher(queryString);%0A            while (sizeMatcher.find()) %7B%0A                String s = sizeMatcher.group(1);%0A                nr = Integer.parseInt(s.split(%22=%22)%5B1%5D);%0A                queryString = queryString.replace(s, %22%22);%0A            %7D%0A            return nr;%0A        %7D%0A    %7D
 %0A%7D%0A

Remove code duplication by introducing method object.