/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package org.etsi.saref.server.resources;

import java.io.IOException;
import java.io.StringWriter;
import java.net.URI;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.Request;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.UriInfo;
import javax.ws.rs.core.Variant;
import org.apache.jena.rdf.model.Model;
import org.apache.jena.rdfconnection.RDFConnection;
import org.apache.jena.rdfconnection.RDFConnectionFactory;
import org.etsi.saref.server.Utils;
import org.etsi.saref.server.entities.MediaTypeExt;
import org.etsi.saref.server.entities.Version;
import org.etsi.saref.server.entities.VersionManager;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 *
 * @author maxime.lefrancois
 */
@Path("/{onto: core|saref4[a-z][a-z][a-z][a-z]}")
public class OntologyResource {

    private static final Logger LOG = LoggerFactory.getLogger(OntologyResource.class);

    private @PathParam("onto")
    String onto;

    private @Context
    Request request;

    private @Context
    UriInfo uriInfo;

    @GET
    public Response getBestChoice() throws IOException {
        return getBestChoice(-1, -1, -1);
    }

    @GET
    @Path("/v{major: [1-9][0-9]*}")
    public Response getBestChoice(@PathParam("major") int major) {
        return getBestChoice(major, -1, -1);
    }

    @GET
    @Path("/v{major: [1-9][0-9]*}.{minor: [1-9][0-9]*}")
    public Response getBestChoice(
            @PathParam("major") int major,
            @PathParam("minor") int minor) {
        return getBestChoice(major, minor, -1);
    }

    @GET
    @Path("/v{major: [1-9][0-9]*}.{minor: [1-9][0-9]*}.{patch: [1-9][0-9]*}")
    public Response getBestChoice(
            @PathParam("major") int major,
            @PathParam("minor") int minor,
            @PathParam("patch") int patch) {
        return getBestChoice2(major, minor, patch, onto);
    }

    @GET
    @Path("/v{major: [1-9][0-9]*}.{minor: [1-9][0-9]*}.{patch: [1-9][0-9]*}/{onto2: core|saref4[a-z][a-z][a-z][a-z]}")
    public Response getBestChoice2(
            @PathParam("major") int major,
            @PathParam("minor") int minor,
            @PathParam("patch") int patch,
            @PathParam("onto2") String onto2) {
        if (!onto2.equals(onto)) {
            return Response.status(Response.Status.NOT_FOUND).build();
        }
        Variant variant = request.selectVariant(Utils.VARIANTS);
        if (variant == null) {
            return Response.notAcceptable(Utils.VARIANTS).build();
        }
        String ext = ((MediaTypeExt) variant.getMediaType()).getExt();
        Version v = new Version();
        v.major = major;
        v.minor = minor;
        v.patch = patch;
        v = VersionManager.getBestChoice(onto, v);
        if (v == null) {
            return Response.status(Response.Status.NOT_FOUND).build();
        }
        String redirect = String.format("%s/v%s.%s.%s/%s.%s", onto, v.major, v.minor, v.patch, onto, ext);
        return Response.status(Response.Status.SEE_OTHER).location(URI.create(redirect)).build();
    }

    @GET
    @Path("/v{major: [1-9][0-9]*}.{minor: [1-9][0-9]*}.{patch: [1-9][0-9]*}/{onto2: core|saref4[a-z][a-z][a-z][a-z]}.{ext: [a-z0-9]+}")
    public Response get(
            @PathParam("major") int major,
            @PathParam("minor") int minor,
            @PathParam("patch") int patch,
            @PathParam("onto2") String onto2,
            @PathParam("ext") String ext) {
        if (!onto2.equals(onto)) {
            return Response.status(Response.Status.NOT_FOUND).build();
        }
        MediaTypeExt mt = Utils.EXTENSIONS.get(ext);
        if (mt == null) {
            return Response.status(Response.Status.NOT_FOUND).build();
        }
        LOG.debug("get core " + ext);
        Version v = new Version();
        v.onto = onto;
        v.major = major;
        v.minor = minor;
        v.patch = patch;
        try (RDFConnection conn = RDFConnectionFactory.connect(Utils.DS)) {
            Model model = conn.fetch(v.getUri());
            if (model == null) {
                return Response.status(Response.Status.NOT_FOUND).build();
            }
            model.setNsPrefixes(Utils.PM);
            if(onto.startsWith("saref4")) {
                String prefix = String.format("s4%s", onto.substring(6));
                String ns = String.format("%s%s/", Utils.NS, onto, "/");
                model.setNsPrefix(prefix, ns);
            }
            StringWriter sw = new StringWriter();
            if (mt.isRDF()) {
                model.write(sw, mt.getLang());
            } else {
                sw.append("<pre>html for " + uriInfo.getPath() + "</pre>");
            }
            return Response.ok(sw.toString()).type(mt).build();
        } catch (Exception ex) {
            LOG.warn("ex", ex);
        }
        return Response.status(Response.Status.NOT_FOUND).build();
    }

    

    /**
     * Assumes the local name is two or more characters and does not start with v0 - v9
     * 
     * @param localName
     * @return 
     */
    @GET
    @Path("/{localName: [a-zA-Z][^/0-9][^/]*}")
    public Response getTermBestChoice(@PathParam("localName") String localName) {
        Variant variant = request.selectVariant(Utils.VARIANTS);
        if (variant == null) {
            return Response.notAcceptable(Utils.VARIANTS).build();
        }
        String ext = ((MediaTypeExt) variant.getMediaType()).getExt();
        String redirect = String.format("%s/%s.%s", onto, localName, ext);
        return Response.status(Response.Status.FOUND).location(URI.create(redirect)).build();
    }

    @GET
    @Path("/{localName: [a-zA-Z][^/0-9][^/]*}.{ext: [a-z0-9]+}")
    public Response getTerm(
            @PathParam("localName") String localName,
            @PathParam("ext") String ext) {
        MediaTypeExt mt = Utils.EXTENSIONS.get(ext);
        if (mt == null) {
            return Response.status(Response.Status.NOT_FOUND).build();
        }
        LOG.debug("get term " + ext);
        try (RDFConnection conn = RDFConnectionFactory.connect(Utils.DS)) {
            String uri = String.format("%s%s/%s", Utils.NS, onto, localName);
            Model model = conn.fetch(uri);
            if (model == null) {
                return Response.status(Response.Status.NOT_FOUND).build();
            }
            model.setNsPrefixes(Utils.PM);
            if(onto.startsWith("saref4")) {
                String prefix = String.format("s4%s", onto.substring(6));
                String ns = String.format("%s%s/", Utils.NS, onto, "/");
                model.setNsPrefix(prefix, ns);
            }
            StringWriter sw = new StringWriter();
            if (mt.isRDF()) {
                model.write(sw, mt.getLang());
            } else {
                sw.append("<pre>html for " + uriInfo.getPath() + "</pre>");
            }
            return Response.ok(sw.toString()).type(mt).build();
        } catch (Exception ex) {
            LOG.warn("ex", ex);
        }
        return Response.status(Response.Status.NOT_FOUND).build();
    }

    
}
