package controllers.api;

import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.node.ArrayNode;
import controllers.App;
import play.mvc.Result;
import uk.gov.openregister.domain.Record;
import uk.gov.openregister.domain.RecordVersionInfo;
import uk.gov.openregister.model.Field;

import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import java.util.stream.StreamSupport;

import static play.mvc.Results.ok;

// XXX this is a hacky hacky class to prove a point. It's subject to all sorts of
// data injection problems.
public class TurtleRepresentation implements Representation {

    public static final String TURTLE_HEADER = "@prefix field: <http://fields.openregister.org/field/>.\n" +
            "\n";
    public static final String TEXT_TURTLE = "text/turtle; charset=utf-8";

    @Override
    public Result toListOfRecords(List<Record> records, Map<String, String> representationsMap) throws Exception {
        return ok(records.stream()
                        .map(this::renderRecord)
                        .collect(Collectors.joining("\n", TURTLE_HEADER, ""))
        ).as(TEXT_TURTLE);
    }

    @Override
    public Result toRecord(Record record, List<RecordVersionInfo> history, Map<String, String> representationsMap) {
        return ok(TURTLE_HEADER + renderRecord(record)).as(TEXT_TURTLE);
    }

    private String renderRecord(Record record) {
        String entity = String.format("<http://%s.openregister.org/hash/%s>\n", App.instance.register.name(), record.getHash());
        return App.instance.register.fields().stream()
                .map(field -> String.format("  field:%s %s", field.getName(), renderValue(record, field)))
                .collect(Collectors.joining(" ;\n", entity, " .\n"));
    }

    private String renderValue(Record record, Field field) {
        JsonNode jsonNode = record.getEntry().get(field.getName());
        if (jsonNode == null) {
            return "\"\"";
        }
        switch (field.getCardinality()) {
            case ONE:
                return renderScalar(field, jsonNode);
            case MANY:
                return renderList(field, jsonNode);
            default:
                throw new IllegalStateException("Invalid Cardinality: " + field.getCardinality());
        }
    }

    private String renderScalar(Field field, JsonNode jsonNode) {
        if (field.getRegister().isPresent()) {
            String register = field.getRegister().get();
            return String.format("<http://%s.openregister.org/%s/%s>", register, register, jsonNode.asText());
        }
        return jsonNode.toString();
    }

    private String renderList(Field field, JsonNode jsonNode) {
        ArrayNode arrayNode = (ArrayNode) jsonNode;
        return StreamSupport.stream(arrayNode.spliterator(),false)
                .map(val -> renderScalar(field, val))
                .collect(Collectors.joining(", "));

    }

    public static Representation instance = new TurtleRepresentation();
}

@@ -305,16 +305,73 @@
 Field;%0A%0A
+import java.net.URI;%0Aimport java.net.URISyntaxException;%0A
 import j
@@ -2562,40 +2562,86 @@
     
-return String.format
+URI uri;%0A            try %7B%0A                uri = new URI
 (%22
-%3C
 http
-://%25s
+s%22, register + %22
 .ope
@@ -2657,15 +2657,32 @@
 .org
+%22, String.format(%22
 /%25s/%25s
-%3E
 %22, r
@@ -2689,26 +2689,16 @@
 egister,
- register,
  jsonNod
@@ -2708,16 +2708,176 @@
 sText())
+, null);%0A            %7D catch (URISyntaxException e) %7B%0A                throw new RuntimeException(e);%0A            %7D%0A            return String.format(%22%3C%25s%3E%22, uri)
 ;%0A      

fix urls with spaces