package com.r11.tools.controller;

import com.google.gson.Gson;
import com.google.gson.JsonObject;
import com.r11.tools.controller.internal.GlobalControllerManifest;
import com.r11.tools.controller.internal.HandlerType;
import com.r11.tools.controller.internal.RestController;
import com.r11.tools.controller.internal.ScopedControllerManifest;
import com.r11.tools.xml.Saxon;
import com.r11.tools.xml.Xalan;
import com.r11.tools.xml.XmlEngine;
import org.apache.logging.log4j.Logger;
import spark.Request;
import spark.Response;

@GlobalControllerManifest
public class XsltController implements RestController {

    private final Gson gson;
    private final Logger logger;

    private final XmlEngine saxon;
    private final XmlEngine xalan;

    public XsltController(Gson gson, Logger logger, XmlEngine saxon, XmlEngine xalan) {
        this.gson = gson;
        this.logger = logger;
        this.saxon = saxon;
        this.xalan = xalan;
    }

    @ScopedControllerManifest(method = HandlerType.POST, path = "/xslt")
    public void transform(Request request, Response response) {
        String body = request.body();

        JsonObject requestJson;
        try {
            requestJson = this.gson.fromJson(body, JsonObject.class);
        } catch (Exception e) {
            JsonObject responseJson = new JsonObject();
            responseJson.addProperty("result", e.getMessage());
            responseJson.addProperty("processor", "N/A");
            responseJson.addProperty("status", "ERR");
            responseJson.addProperty("time", "N/A");

            response.status(400);
            response.body(this.gson.toJson(responseJson));
            return;
        }

        String data = requestJson.get("data").getAsString();
        String query = requestJson.get("process").getAsString();
        String processor = requestJson.get("processor").getAsString();
        String version = requestJson.get("version").getAsString();

        if (processor == null) {
            response.body("saxon, xalan");
            return;
        }
        JsonObject responseJson = new JsonObject();
        switch (processor) {
            case "saxon":
                processWithSaxon(response, data, query, version, responseJson);
                return;

            case "xalan":
                processWithXalan(response, data, query, responseJson);
                return;

            default:
                response.body("saxon, xalan");
        }
    }

    private void processWithXalan(Response response, String data, String query, JsonObject responseJson) {
        long duration;
        long timeStart;
        String tmp;
        timeStart = System.currentTimeMillis();
        try {
            tmp = xalan.processXSLT(data, query);

            response.status(200);

            responseJson.addProperty("result", tmp);
            responseJson.addProperty("status", "OK");
        } catch (Exception ex) {
            this.logger.error("Error on processing XSLT using Xalan. " + ex);

            response.status(400);

            responseJson.addProperty("result", ex.getMessage());
            responseJson.addProperty("status", "ERR");
        }

        duration = System.currentTimeMillis() - timeStart;
        this.logger.info("Request (XSLT, Xalan) processed in " + duration + " ms.");

        responseJson.addProperty("processor", xalan.getVersion());
        responseJson.addProperty("time", duration);

        response.body(this.gson.toJson(responseJson));
    }

    private void processWithSaxon(Response response, String data, String query, String version, JsonObject responseJson) {
        long duration;
        String tmp;
        long timeStart;
        timeStart = System.currentTimeMillis();
        try {
            tmp = saxon.processXSLT(data, query);

            response.status(200);

            responseJson.addProperty("result", tmp);
            responseJson.addProperty("status", "OK");
        } catch (Exception ex) {
            this.logger.error("Error on processing XSLT using Saxon. " + ex);

            response.status(400);

            responseJson.addProperty("result", ex.getMessage());
            responseJson.addProperty("status", "ERR");
        }

        duration = System.currentTimeMillis() - timeStart;
        this.logger.info("Request (XSLT, Saxon) processed in " + duration + " ms.");

        responseJson.addProperty("processor", "Saxon " + saxon.getVersion() + " " + version);
        responseJson.addProperty("time", duration);

        response.body(this.gson.toJson(responseJson));
    }
}
