package uk.ac.ebi.quickgo.annotation.download;

import uk.ac.ebi.quickgo.annotation.download.http.GAFHttpMessageConverter;
import uk.ac.ebi.quickgo.annotation.download.http.GPADHttpMessageConverter;
import uk.ac.ebi.quickgo.common.loader.GZIPFiles;

import com.google.common.base.Preconditions;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.attribute.FileTime;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;
import javax.servlet.http.HttpServletRequest;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyEmitter;

import static java.util.Arrays.stream;

/**
 * Produce a header for downloaded files.
 *
 * Example of a header for a GAF file.
 * !gaf-version: 2.1
 * !Project_name: UniProt GO Annotation (UniProt-GOA)
 * !URL: http://www.ebi.ac.uk/GOA
 * !Contact Email: goa@ebi.ac.uk
 * !Date downloaded from the QuickGO browser: 20170123
 * !Filtering parameters selected to generate file:
 * GAnnotation?count=25&protein=Q4VCS5&select=normal&advanced=&termUse=ancestor&slimTypes=IPO%3D
 *
 * Example of a header for a GPAD file:
 * !gpa-version: 1.1
 * !Project_name: UniProt GO Annotation (UniProt-GOA)
 * !URL: http://www.ebi.ac.uk/GOA
 * !Contact Email: goa@ebi.ac.uk
 * !Date downloaded from the QuickGO browser: 20170117
 * !Filtering parameters selected to generate file:
 * GAnnotation?count=25&protein=A0A000&select=normal&advanced=&termUse=ancestor&slimTypes=IPO%3D
 *
 * @author Tony Wardell
 * Date: 25/01/2017
 * Time: 10:09
 * Created with IntelliJ IDEA.
 */
@Component
public class AnnotationDownloadFileHeader {
    private Logger logger = LoggerFactory.getLogger(AnnotationDownloadFileHeader.class);
    static final String PROJECT_NAME = "Project_name: UniProt GO Annotation (UniProt-GOA)";

    static final String URL = "URL: http://www.ebi.ac.uk/GOA";
    static final String EMAIL = "Contact Email: goa@ebi.ac.uk";
    static final String DATE = "Date downloaded from QuickGO: ";
    static final String FILTERS_INTRO = "Filtering parameters selected to generate file:";
    static final String REQUEST_LINE_INDENTATION = "   ";

    static final String GAF_VERSION = "gaf-version: 2.1";
    static final String GPAD_VERSION = "gpa-version: 1.1";
    private static final String HEADER_LINE_PREFIX = "!";
    private final Path ontologyPath;
    private List<String> savedOntologyLines;
    private FileTime previousTimeStamp;

    public AnnotationDownloadFileHeader(Path ontologyPath) {
        Preconditions.checkArgument(ontologyPath != null, "The path to the ontology file must not be null");
        this.ontologyPath = ontologyPath;
    }

    /**
     * Write the contents of the header to the ResponseBodyEmitter instance.
     * @param emitter streams the header content to the client
     * @param request holds the URI and parameter list to be added to the header information.
     * @param acceptHeader holds the response type 'GAF' or 'GPAD';
     */
    public void write(ResponseBodyEmitter emitter, HttpServletRequest request, MediaType acceptHeader) {
        send(emitter, version(acceptHeader));
        send(emitter, PROJECT_NAME);
        send(emitter, URL);
        send(emitter, EMAIL);
        send(emitter, date());
        ontology().forEach(s -> send(emitter, s));
        send(emitter, FILTERS_INTRO);
        send(emitter, request(request));
    }

    private void send(ResponseBodyEmitter emitter, String content) {
        try {
            emitter.send(HEADER_LINE_PREFIX + content + "\n", MediaType.TEXT_PLAIN);
        } catch (IOException e) {
            throw new RuntimeException("Failed to send download header", e);
        }
    }

    private String version(MediaType acceptHeader) {
        switch (acceptHeader.getSubtype()) {
            case GAFHttpMessageConverter.SUB_TYPE:
                return GAF_VERSION;
            case GPADHttpMessageConverter.SUB_TYPE:
                return GPAD_VERSION;
            default:
                throw new IllegalArgumentException("Unknown Media subtype requested: " + acceptHeader.getSubtype());
        }
    }

    private String date() {
        return DATE + LocalDateTime.now().format(DateTimeFormatter.ISO_DATE);
    }

    private String request(HttpServletRequest request) {
        return REQUEST_LINE_INDENTATION + request.getRequestURI() + "?" + parameterString(request);
    }

    private String parameterString(HttpServletRequest request) {
        return request.getParameterMap()
                .entrySet()
                .stream()
                .map(s -> String.format("%s=%s", s.getKey(), stream(s.getValue())
                        .collect(Collectors.joining(","))))
                .collect(Collectors.joining("&"));
    }

    private List<String> ontology() {
        try {
            FileTime lastModifiedTime = Files.getLastModifiedTime(ontologyPath);

            if (!lastModifiedTime.equals(previousTimeStamp)) {
                previousTimeStamp = lastModifiedTime;
                savedOntologyLines = GZIPFiles.lines(ontologyPath)
                        .skip(1)
                        .map(s -> s.substring(s.indexOf("http:")))
                        .collect(Collectors.toList());

            }
        } catch (Exception e) {
            savedOntologyLines = Collections.emptyList();
            logger.error("Failed to load the version of the ontology", e);
        }
        return savedOntologyLines;
    }
}

@@ -45,159 +45,8 @@
 d;%0A%0A
-import uk.ac.ebi.quickgo.annotation.download.http.GAFHttpMessageConverter;%0Aimport uk.ac.ebi.quickgo.annotation.download.http.GPADHttpMessageConverter;%0A
 impo
@@ -741,16 +741,193 @@
 .stream;
+%0Aimport static uk.ac.ebi.quickgo.annotation.download.http.MediaTypeFactory.GAF_SUB_TYPE;%0Aimport static uk.ac.ebi.quickgo.annotation.download.http.MediaTypeFactory.GPAD_SUB_TYPE;
 %0A%0A/**%0A *
@@ -1911,21 +1911,28 @@
 ate 
+static 
 Logger 
-logger
+LOGGER
  = L
@@ -4089,37 +4089,17 @@
 case GAF
-HttpMessageConverter.
+_
 SUB_TYPE
@@ -4161,29 +4161,9 @@
 GPAD
-HttpMessageConverter.
+_
 SUB_
@@ -4246,107 +4246,17 @@
     
-throw new IllegalArgumentException(%22Unknown Media subtype requested: %22 + acceptHeader.getSubtype())
+return %22%22
 ;%0A  
@@ -5501,14 +5501,14 @@
     
-logger
+LOGGER
 .err

Use MediaTypeFactory for media types. Fix name of logger instance.