package uk.ac.ebi.quickgo.annotation.service.http;

import uk.ac.ebi.quickgo.annotation.model.Annotation;
import uk.ac.ebi.quickgo.annotation.service.converter.GPADAnnotationConverter;
import uk.ac.ebi.quickgo.rest.search.results.QueryResult;

import java.io.IOException;
import java.io.OutputStream;
import java.nio.charset.Charset;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Stream;
import org.slf4j.Logger;
import org.springframework.http.HttpInputMessage;
import org.springframework.http.HttpOutputMessage;
import org.springframework.http.MediaType;
import org.springframework.http.converter.AbstractHttpMessageConverter;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.http.converter.HttpMessageNotWritableException;

import static org.slf4j.LoggerFactory.getLogger;

/**
 * GPAD message converter that writes a stream of {@link QueryResult} containing {@link Annotation} instances,
 * to a response's output stream.
 *
 * Created 19/01/17
 * @author Edd
 */
public class GPADHttpMessageConverter extends AbstractHttpMessageConverter<Stream<QueryResult<Annotation>>> {
    public static final String SUB_TYPE = "gpad";
    private static final MediaType MEDIA_TYPE = new MediaType("text", SUB_TYPE, Charset.forName("utf-8"));
    private static final Logger GPAD_LOGGER = getLogger(GPADHttpMessageConverter.class);
    private final GPADAnnotationConverter converter;

    public GPADHttpMessageConverter(GPADAnnotationConverter converter) {
        super(MEDIA_TYPE);
        this.converter = converter;
    }

    @Override
    protected boolean supports(Class<?> aClass) {
        return true;
    }

    @Override
    protected Stream<QueryResult<Annotation>> readInternal(
            Class<? extends Stream<QueryResult<Annotation>>> aClass,
            HttpInputMessage httpInputMessage)
            throws IOException, HttpMessageNotReadableException {
        return null;
    }

    @Override
    protected void writeInternal(
            Stream<QueryResult<Annotation>> annotationStream,
            HttpOutputMessage httpOutputMessage)
            throws IOException, HttpMessageNotWritableException {
        OutputStream out = httpOutputMessage.getBody();

        writeAnnotations(out, annotationStream);
    }

    private void writeAnnotations(OutputStream out, Stream<QueryResult<Annotation>> annotationStream) {
        AtomicInteger counter = new AtomicInteger(0);
        annotationStream.forEach(annotationResult -> {
            if (counter.get() == 0) {
                writeHeaderLines(out, converter.getHeaderLines(annotationResult));
            }
            annotationResult.getResults().forEach(annotation -> {
                try {
                    out.write((converter.convert(annotation) + "\n").getBytes());
                    counter.getAndIncrement();
                } catch (IOException e) {
                    GPAD_LOGGER.error("Could not write annotation in GPAD format: " + annotation, e);
                }
                // flush occasionally
                // todo: currently flushing every 20, to see effects. Future, flush every 10000 or so, or forget it?
                if (counter.get() % 20 == 0) {
                    try {
                        out.flush();
                    } catch (IOException e) {
                        GPAD_LOGGER.error("Could not flush stream", e);
                    }
                }
            });
        });
        GPAD_LOGGER.info("Written " + counter.get() + " GPAD annotations");
    }

    private void writeHeaderLines(OutputStream out, List<String> headerLines) {
        headerLines.forEach(headerLine -> {
            try {
                out.write((headerLine + "\n").getBytes());
            } catch (IOException e) {
                GPAD_LOGGER.error("Could not write header line: " + headerLine, e);
            }
        });
    }
}

@@ -85,13 +85,17 @@
 ion.
-model
+converter
 .Ann
@@ -97,24 +97,30 @@
 r.Annotation
+ToGPAD
 ;%0Aimport uk.
@@ -149,30 +149,14 @@
 ion.
-service.converter.GPAD
+model.
 Anno
@@ -161,25 +161,16 @@
 notation
-Converter
 ;%0Aimport
@@ -1424,20 +1424,16 @@
 e final 
-GPAD
 Annotati
@@ -1430,33 +1430,30 @@
 l Annotation
-Converter
+ToGPAD
  converter;%0A
@@ -1489,20 +1489,16 @@
 nverter(
-GPAD
 Annotati
@@ -1499,25 +1499,22 @@
 notation
-Converter
+ToGPAD
  convert
@@ -2520,143 +2520,8 @@
 %3E %7B%0A
-            if (counter.get() == 0) %7B%0A                writeHeaderLines(out, converter.getHeaderLines(annotationResult));%0A            %7D%0A
     
@@ -2645,23 +2645,21 @@
 nverter.
-convert
+apply
 (annotat

Replace GPADAnnotationConverter with AnnotationToGPAD.