package lemming.lemma;

import com.fasterxml.jackson.core.JsonEncoding;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.MapperFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import lemming.data.EntityManagerListener;
import org.hibernate.ScrollMode;
import org.hibernate.ScrollableResults;
import org.hibernate.Session;
import org.hibernate.StatelessSession;
import org.hibernate.query.Query;

import javax.annotation.security.RolesAllowed;
import javax.persistence.EntityManager;
import javax.persistence.EntityTransaction;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.WebApplicationException;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.StreamingOutput;
import java.io.IOException;
import java.io.OutputStream;
import java.util.List;

/**
 * A resource for lemma data.
 */
@Path("lemmas")
@RolesAllowed({"STUDENT","USER","ADMIN"})
public class LemmaResource {
    /**
     * Returns a chunked JSON response.
     *
     * @return A JSON response.
     */
    @GET
    @Produces(MediaType.APPLICATION_JSON)
    public Response get() {
        EntityManager entityManager1 = EntityManagerListener.createEntityManager();
        EntityTransaction transaction = null;

        try {
            StatelessSession session = entityManager1.unwrap(Session.class).getSessionFactory().openStatelessSession();
            transaction = session.beginTransaction();
            Query query = session.createQuery("SELECT l.id FROM Lemma l ORDER BY l.name");
            query.setReadOnly(true).setCacheable(false).setFetchSize(Integer.MIN_VALUE);
            ScrollableResults results = query.scroll(ScrollMode.FORWARD_ONLY);
            StreamingOutput streamingOutput = new StreamingOutput() {
                @Override
                public void write(OutputStream outputStream) throws IOException, WebApplicationException {
                    JsonGenerator jsonGenerator = new ObjectMapper().configure(MapperFeature.USE_ANNOTATIONS, true)
                            .getFactory().createGenerator(outputStream, JsonEncoding.UTF8);
                    jsonGenerator.writeStartArray();
                    EntityManager entityManager2 = EntityManagerListener.createEntityManager();

                    while (results.next()) {
                        List<Lemma> lemmaList = entityManager2
                                .createQuery("SELECT l FROM Lemma l WHERE l.replacement IS NULL AND id = :id",
                                        Lemma.class)
                                .setParameter("id", results.getInteger(0)).getResultList();

                        if (!lemmaList.isEmpty()) {
                            jsonGenerator.writeObject(lemmaList.get(0));
                            jsonGenerator.flush();
                        }
                    }

                    jsonGenerator.writeEndArray();
                    jsonGenerator.flush();
                    jsonGenerator.close();
                    entityManager2.close();
                    results.close();
                    session.getTransaction().commit();
                }
            };

            return Response.ok(streamingOutput).type(MediaType.APPLICATION_JSON)
                    .header("Content-Disposition", "attachment; filename=\"lemmata.json\"").build();
        } catch (RuntimeException e) {
            e.printStackTrace();

            if (transaction != null && transaction.isActive()) {
                transaction.rollback();
            }

            throw e;
        } finally {
            entityManager1.close();
        }
    }
}

@@ -859,16 +859,44 @@
 Stream;%0A
+import java.util.ArrayList;%0A
 import j
@@ -2352,54 +2352,244 @@
 ();%0A
-%0A                    while (results.next()) %7B%0A
+                    List%3CInteger%3E idList = new ArrayList%3CInteger%3E(1000);%0A%0A                    while (results.next()) %7B%0A                        idList.add(results.getInteger(0));%0A%0A                        if (idList.size() == 1000) %7B%0A    
     
@@ -2679,16 +2679,20 @@
         
+    
 .createQ
@@ -2755,18 +2755,11 @@
 AND 
-id = :id%22,
+%22 +
 %0A   
@@ -2794,16 +2794,52 @@
         
+     %22id IN (:ids) ORDER BY l.name%22,
  Lemma.c
@@ -2844,16 +2844,20 @@
 .class)%0A
+    
         
@@ -2901,32 +2901,751 @@
 (%22id
+s
 %22, 
-results.getInteger(0)
+idList).getResultList();%0A%0A                            for (Lemma lemma : lemmaList) %7B%0A                                jsonGenerator.writeObject(lemma);%0A                                jsonGenerator.flush();%0A                            %7D%0A%0A                            idList.clear();%0A                            entityManager2.clear();%0A                        %7D%0A                    %7D%0A%0A                    if (!idList.isEmpty()) %7B%0A                        List%3CLemma%3E lemmaList = entityManager2%0A                                .createQuery(%22SELECT l FROM Lemma l WHERE l.replacement IS NULL AND %22 +%0A                                        %22id IN (:ids) ORDER BY l.name%22, Lemma.class)%0A                                .setParameter(%22ids%22, idList
 ).ge
@@ -3688,32 +3688,36 @@
     
-if (!lemmaList.isEmpty()
+for (Lemma lemma : lemmaList
 ) %7B%0A
@@ -3779,19 +3779,8 @@
 emma
-List.get(0)
 );%0A 

Enhance performance of LemmaResource by reducing database queries.