package com.r11.tools.controller;

import com.google.gson.Gson;
import com.google.gson.JsonObject;
import com.r11.tools.controller.internal.*;
import com.r11.tools.xml.XmlEngine;
import org.apache.logging.log4j.Logger;
import spark.Request;
import spark.Response;

@GlobalControllerManifest
public class XPathController implements RestController {

    private final Gson gson;
    private final Logger logger;

    private final XmlEngine saxon;
    private final XmlEngine xalan;

    public XPathController(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 = "/xpath")
    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);
                break;
            case "xalan":
                processWithXalan(response, data, query, responseJson);
                break;
            default:
                response.body("saxon, xalan");
        }
    }

    private void processWithXalan(Response response, String data, String query, JsonObject responseJson) {
        long timeStart;
        long duration;
        response.header("processor", xalan.getVersion());
        timeStart = System.currentTimeMillis();

        try {
            XPathQueryResult xPathQueryResult = xalan.processXPath(data, query, "");

            response.status(200);

            responseJson.addProperty("result", xPathQueryResult.getData().trim());
            responseJson.addProperty("status", "OK");
            responseJson.addProperty("type", xPathQueryResult.getType());
        } catch (Exception ex) {
            this.logger.error("Error on processing XPath using Xalan. " + ex);

            response.status(400);

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

        duration = System.currentTimeMillis() - timeStart;
        this.logger.info("Request (XPath, 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 timeStart;
        String tmp;
        long duration;
        response.header("processor", "Saxon " + saxon.getVersion() + " " + version + " over s9api");
        timeStart = System.currentTimeMillis();

        try {
            tmp = saxon.processXPath(data, query, version).getData().trim();

            response.status(200);

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

            response.status(400);

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

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

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

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