package uk.gov.register.resources;

import com.codahale.metrics.annotation.Timed;
import com.fasterxml.jackson.databind.JsonNode;
import com.google.common.base.Throwables;
import com.google.common.collect.Iterables;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import uk.gov.register.core.*;
import uk.gov.register.exceptions.ItemValidationException;
import uk.gov.register.exceptions.LoadException;
import uk.gov.register.exceptions.RSFParseException;
import uk.gov.register.serialization.RSFFormatter;
import uk.gov.register.serialization.RegisterResult;
import uk.gov.register.serialization.RegisterSerialisationFormat;
import uk.gov.register.service.RegisterSerialisationFormatService;
import uk.gov.register.util.ObjectReconstructor;
import uk.gov.register.views.representations.ExtraMediaType;

import javax.annotation.security.PermitAll;
import javax.inject.Inject;
import javax.servlet.http.HttpServletRequest;
import javax.ws.rs.Consumes;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import java.io.InputStream;
import java.time.Instant;
import java.util.concurrent.atomic.AtomicInteger;

@Path("/")
public class DataUpload {
    private final Logger logger = LoggerFactory.getLogger(this.getClass());

    private final ObjectReconstructor objectReconstructor;
    private final RegisterSerialisationFormatService rsfService;
    private final RegisterContext registerContext;
    private final RSFFormatter rsfFormatter;

    @Inject
    public DataUpload(ObjectReconstructor objectReconstructor, RegisterSerialisationFormatService rsfService, RegisterContext registerContext) {
        this.objectReconstructor = objectReconstructor;
        this.rsfService = rsfService;
        this.registerContext = registerContext;
        this.rsfFormatter = new RSFFormatter();
    }

    @Context
    HttpServletRequest httpServletRequest;

    @POST
    @PermitAll
    @Path("/load")
    @Timed
    public void load(String payload) {
        try {
            Iterable<JsonNode> objects = objectReconstructor.reconstructWithCanonicalization(payload.split("\n"));
            mintItems(objects);
        } catch (Throwable t) {
            logger.error(Throwables.getStackTraceAsString(t));
            throw new LoadException(t.getMessage(), t);
        }
    }

    @POST
    @PermitAll
    @Consumes(ExtraMediaType.APPLICATION_RSF)
    @Produces(MediaType.APPLICATION_JSON)
    @Path("/load-rsf")
    @Timed
    public Response loadRsf(InputStream inputStream) throws RSFParseException {
        RegisterSerialisationFormat rsf = rsfService.readFrom(inputStream, rsfFormatter);
        rsfService.process(rsf);
        return Response.status(Response.Status.OK).entity(RegisterResult.createSuccessResult()).build();
    }

    private void mintItems(Iterable<JsonNode> objects) {
        registerContext.transactionalRegisterOperation(register -> {
            AtomicInteger currentEntryNumber = new AtomicInteger(register.getTotalEntries());
            Iterables.transform(objects, Item::new).forEach(item -> mintItem(register, currentEntryNumber, item));
        });
    }

    private void mintItem(Register register, AtomicInteger currentEntryNumber, Item item) {
        register.addItem(item);
        String key = item.getValue(this.registerContext.getRegisterId().value())
                .orElseThrow(() -> new ItemValidationException("Item did not contain key field", item.getContent()));

        register.appendEntry(new Entry(currentEntryNumber.incrementAndGet(), item.getSha256hex(), Instant.now(), key, EntryType.user));
    }
}

@@ -1280,144 +1280,8 @@
 d %7B%0A
-    private final Logger logger = LoggerFactory.getLogger(this.getClass());%0A%0A    private final ObjectReconstructor objectReconstructor;%0A
     
@@ -1345,59 +1345,8 @@
 ce;%0A
-    private final RegisterContext registerContext;%0A
     
@@ -1425,49 +1425,8 @@
 oad(
-ObjectReconstructor objectReconstructor, 
 Regi
@@ -1470,1995 +1470,614 @@
 vice
-, RegisterContext registerContext) %7B%0A        this.objectReconstructor = objectReconstructor;%0A        this.rsfService = rsfService;%0A        this.registerContext = registerContext;%0A        this.rsfFormatter = new RSFFormatter();%0A    %7D%0A%0A    @Context%0A    HttpServletRequest httpServletRequest;%0A%0A    @POST%0A    @PermitAll%0A    @Path(%22/load%22)%0A    @Timed%0A    public void load(String payload) %7B%0A        try %7B%0A            Iterable%3CJsonNode%3E objects = objectReconstructor.reconstructWithCanonicalization(payload.split(%22%5Cn%22));%0A            mintItems(objects);%0A        %7D catch (Throwable t) %7B%0A            logger.error(Throwables.getStackTraceAsString(t));%0A            throw new LoadException(t.getMessage(), t);%0A        %7D%0A    %7D%0A%0A    @POST%0A    @PermitAll%0A    @Consumes(ExtraMediaType.APPLICATION_RSF)%0A    @Produces(MediaType.APPLICATION_JSON)%0A    @Path(%22/load-rsf%22)%0A    @Timed%0A    public Response loadRsf(InputStream inputStream) throws RSFParseException %7B%0A        RegisterSerialisationFormat rsf = rsfService.readFrom(inputStream, rsfFormatter);%0A        rsfService.process(rsf);%0A        return Response.status(Response.Status.OK).entity(RegisterResult.createSuccessResult()).build();%0A    %7D%0A%0A    private void mintItems(Iterable%3CJsonNode%3E objects) %7B%0A        registerContext.transactionalRegisterOperation(register -%3E %7B%0A            AtomicInteger currentEntryNumber = new AtomicInteger(register.getTotalEntries());%0A            Iterables.transform(objects, Item::new).forEach(item -%3E mintItem(register, currentEntryNumber, item));%0A        %7D);%0A    %7D%0A%0A    private void mintItem(Register register, AtomicInteger currentEntryNumber, Item item) %7B%0A        register.addItem(item);%0A        String key = item.getValue(this.registerContext.getRegisterId().value())%0A                .orElseThrow(() -%3E new ItemValidationException(%22Item did not contain key field%22, item.getContent()));%0A%0A        register.appendEntry(new Entry(currentEntryNumber.incrementAndGet(), item.getSha256hex(), Instant.now(), key, EntryType.user)
+) %7B%0A        this.rsfService = rsfService;%0A        this.rsfFormatter = new RSFFormatter();%0A    %7D%0A%0A    @Context%0A    HttpServletRequest httpServletRequest;%0A%0A    @POST%0A    @PermitAll%0A    @Consumes(ExtraMediaType.APPLICATION_RSF)%0A    @Produces(MediaType.APPLICATION_JSON)%0A    @Path(%22/load-rsf%22)%0A    @Timed%0A    public Response loadRsf(InputStream inputStream) throws RSFParseException %7B%0A        RegisterSerialisationFormat rsf = rsfService.readFrom(inputStream, rsfFormatter);%0A        rsfService.process(rsf);%0A        return Response.status(Response.Status.OK).entity(RegisterResult.createSuccessResult()).build(
 );%0A 

Remove load endpoint