package org.gcube.data.analysis.nlphub;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.HttpURLConnection;
import java.net.URL;
import java.nio.charset.StandardCharsets;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.gcube.data.analysis.nlphub.legacy.JsonManager;
import org.gcube.data.analysis.nlphub.legacy.NlpHubException;
import org.gcube.data.analysis.nlphub.mapper.DefaultMapper;
import org.gcube.data.analysis.nlphub.mapper.JsonMapper;
import org.gcube.data.analysis.nlphub.session.SessionUtils;
import org.gcube.data.analysis.nlphub.shared.Constants;
import org.gcube.data.analysis.nlphub.workspace.WorkspaceManager;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * Servlet implementation class NlpMapper
 */
@WebServlet("/nlphub-mapper-servlet")
public class NLPMapper extends HttpServlet {
	private static final long serialVersionUID = 1L;
	private static final Logger logger = LoggerFactory.getLogger(NLPUploader.class);

	/**
	 * @see HttpServlet#HttpServlet()
	 */
	public NLPMapper() {
		super();
	}

	/**
	 * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse
	 *      response)
	 */
	protected void doGet(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		doWork(request, response);
	}

	/**
	 * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse
	 *      response)
	 */
	protected void doPost(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		doWork(request, response);
	}

	private void doWork(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		logger.debug("NLPMapper");
		SessionUtils sessionUtils=new SessionUtils();
		String token = sessionUtils.getToken(request);
		WorkspaceManager ws = new WorkspaceManager();

		response.setContentType("application/json");

		response.setCharacterEncoding("utf-8");
		String documentLink = request.getParameter("plink"); // link to text
																// file
																// (workspace)
		String toBeMap = request.getParameter("tobemap");
		String[] tokens;
		if (toBeMap.indexOf("|") > 0)
			tokens = toBeMap.split("\\|");
		else {
			tokens = new String[1];
			tokens[0] = toBeMap;
		}

		String annotations = request.getParameter("annotations");
		String language = request.getParameter("lang");
		PrintWriter writer = response.getWriter();

		try {
			String text = getDocument(documentLink);
			text = text.replaceAll("\n", "\\\\n");

			text = text.replaceAll("\r", "\\\\r");
			text = text.replaceAll("\t", "\\\\t");
			text = text.replaceAll("\"", "\\\\\"");

			String out = "{";
			out += "\"text\":\"" + text + "\",";
			out += "\"annotations\":\"" + annotations + "\",";
			out += "\"language\":\"" + language + "\",";
			out += "\"result\": [";

			for (int i = 0; i < tokens.length; i++) {
				String tk = tokens[i];
				String[] t = tk.split(":::");
				if (t[1].equals(Constants.ERROR_ID)) {
					logger.error("Algorithm " + t[0] + " in error. Bypass...");
					continue;
				}
				try {
					String json = ((JsonMapper) (getMapper(t[0]).newInstance())).getJson(t[0], t[1]);
					out += json;
					if (i < tokens.length - 1)
						out += ",";
				} catch (Exception e) {
					logger.error(e.getLocalizedMessage());
				}
			}
			out += "]}";

			String resultLink = saveResult(out, token, ws);
			String outResult = "{";
			outResult += "\"link\":\"" + resultLink + "\",";
			outResult += "\"output\":" + out;
			outResult += "}";
			writer.append(outResult);

		} catch (Exception e) {
			logger.error(e.getLocalizedMessage(),e);
			writer.println(new JsonManager().getErrorJsonResponse(e.getLocalizedMessage()));
		}

		// response.getWriter().write(json);
	}

	private Class<DefaultMapper> getMapper(String algId) throws Exception {
		return DefaultMapper.class;
		// return
		// Class.forName("org.gcube.data.analynlphub.mapper.DefaultMapper");
	}

	private String getDocument(String plink) throws Exception {
		HttpURLConnection connection = (HttpURLConnection) new URL(plink).openConnection();
		connection.setRequestMethod("GET");
		BufferedReader reader = new BufferedReader(new InputStreamReader(connection.getInputStream()));
		char[] readBuffer = new char[1024];
		int byteRead = 0;
		String content = "";
		while (byteRead > -1) {
			byteRead = reader.read(readBuffer, 0, 1024);
			if (byteRead > 0) {
				String bString = new String(readBuffer, 0, byteRead);
				content += bString;
			}
		}
		return content;
	}

	private String saveResult(String jsonResult, String token, WorkspaceManager ws) throws NlpHubException {
		long now = System.currentTimeMillis();
		String fileName = "result-nlp-" + now + ".json";
		ws.deleteFile(fileName);

		byte[] byteContent = jsonResult.getBytes(StandardCharsets.UTF_8);
		if (!ws.uploadFile(byteContent, fileName, Constants.DEFAULT_DESCRIPTION)) {
			throw new NlpHubException("Error writing file: " + fileName + " on workspace (token: " + token + ")", null);
		}

		String link = ws.getPublicLink(fileName);

		logger.info("Output json [" + fileName + "] created in " + (System.currentTimeMillis() - now) + " millisec.");
		return link;
	}

}
