package com.outbrain.ob1k.crud.service;

import com.google.common.base.Preconditions;
import com.google.gson.JsonObject;
import com.outbrain.ob1k.Request;
import com.outbrain.ob1k.Response;
import com.outbrain.ob1k.concurrent.ComposableFuture;
import com.outbrain.ob1k.crud.dao.ICrudAsyncDao;
import kotlin.ranges.IntRange;

import java.util.Optional;

public class CrudService implements ICrudService {
  private final EndpointUtils endpointUtils = new EndpointUtils();
  private final ICrudAsyncDao<JsonObject> dao;

  public CrudService(ICrudAsyncDao<JsonObject> dao) {
    this.dao = Preconditions.checkNotNull(dao);
  }

  @Override
  public ComposableFuture<Response> list(String sort, String range, String filter) {
    IntRange rng = endpointUtils.range(Optional.ofNullable(range).orElse("[0,100000]"));
    return dao.list(rng,
            endpointUtils.sort(Optional.ofNullable(sort).orElse("[\"id\",\"ASC\"]")),
            endpointUtils.asJson(Optional.ofNullable(filter).orElse("{}"))).
            map(new EntitiesOfJsonToResponse(rng));
  }

  @Override
  public ComposableFuture<Response> get(String id) {
    return dao.read(id).map(new AnyToResponseFunc());
  }

  @Override
  public ComposableFuture<Response> create(Request request) {
    return dao.create(endpointUtils.asJson(request.getRequestBody()).getAsJsonObject()).map(new AnyToResponseFunc());
  }

  @Override
  public ComposableFuture<Response> update(Request request) {
    return dao.update(request.getPathParam("id"), endpointUtils.asJson(request.getRequestBody()).getAsJsonObject()).map(new AnyToResponseFunc());
  }

  @Override
  public ComposableFuture<Response> delete(String id) {
    return dao.delete(id).map(new EmptyResponseFunc());
  }

  @Override
  public String resourceName() {
    return dao.resourceName();
  }
}

@@ -79,16 +79,126 @@
 itions;%0A
+import com.google.common.collect.Lists;%0Aimport com.google.gson.JsonArray;%0Aimport com.google.gson.JsonElement;%0A
 import c
@@ -224,16 +224,16 @@
 Object;%0A
-
 import c
@@ -396,16 +396,82 @@
 yncDao;%0A
+import com.outbrain.ob1k.crud.model.Entities;%0Aimport kotlin.Pair;%0A
 import k
@@ -490,24 +490,47 @@
 .IntRange;%0A%0A
+import java.util.List;%0A
 import java.
@@ -543,16 +543,38 @@
 ptional;
+%0Aimport java.util.Set;
 %0A%0Apublic
@@ -1034,40 +1034,131 @@
     
-return dao.list(rng,%0A           
+JsonObject filterJson = endpointUtils.asJson(Optional.ofNullable(filter).orElse(%22%7B%7D%22));%0A    Pair%3CString, String%3E sortPair =
  end
@@ -1230,99 +1230,227 @@
 %5D%22))
-,
+;
 %0A    
-        endpointUtils.asJson(Optional.ofNullable(filter).orElse(%22%7B%7D%22))).%0A            
+JsonArray ids = ids(filterJson);%0A    ComposableFuture%3CEntities%3CJsonObject%3E%3E entities = ids == null ?%0A            dao.list(rng, sortPair, filterJson) :%0A            dao.list(fromJsonArray(ids));%0A    return entities.
 map(
@@ -2206,24 +2206,24 @@
 rceName() %7B%0A
-
     return d
@@ -2244,11 +2244,665 @@
 e();%0A  %7D
+%0A%0A  private JsonArray ids(JsonObject jo) %7B%0A    Set%3CString%3E keySet = jo.keySet();%0A    if (keySet.size() != 1) %7B%0A      return null;%0A    %7D%0A    String key = keySet.iterator().next();%0A    if (!key.replace(%22%5C%22%22, %22%22).equals(%22id%22)) %7B%0A      return null;%0A    %7D%0A    JsonElement value = jo.get(key);%0A    return value.isJsonArray() ? value.getAsJsonArray() : null;%0A  %7D%0A%0A  private List%3CString%3E fromJsonArray(JsonArray jr) %7B%0A    List%3CString%3E lst = Lists.newArrayListWithExpectedSize(jr.size());%0A    for (int i = 0; i %3C jr.size(); ++i) %7B%0A      String value = jr.get(i).getAsJsonPrimitive().getAsString();%0A      lst.add(value.replace(%22%5C%22%22, %22%22));%0A    %7D%0A    return lst;%0A  %7D
 %0A%7D%0A

support filter by ids