package org.gcube.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.apache.log4j.Logger;
import org.gcube.nlphub.workspace.WorkspaceManager;
import org.gcube.nlphub.mapper.JsonMapper;
import org.gcube.nlphub.legacy.Constants;
import org.gcube.nlphub.legacy.JsonManager;
import org.gcube.nlphub.legacy.NlpHubException;
import org.gcube.nlphub.mapper.DefaultMapper;

/**
 * Servlet implementation class NlpMapper
 */
@WebServlet("/nlphub-mapper-servlet")
public class NLPMapper extends HttpServlet {
	private static final long serialVersionUID = 1L;
	private Logger logger = Logger.getLogger(NLPMapper.class.getSimpleName());
	private String token; //= "df2cc5f5-63ee-48c1-b2a6-1210030c57b8-843339462";
	private boolean devMode = true;
	
	/**
	 * @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 {
		response.setContentType("application/json");
		
		response.setCharacterEncoding("utf-8");
		token = Constants.getToken(request, devMode);
		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 token = tokens[i];
				String[] t = token.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);
			String outResult = "{";
			outResult += "\"link\":\"" + resultLink + "\",";
			outResult += "\"output\":" + out;
			outResult += "}";
			writer.append(outResult);
			
		} catch (Exception x) {
			logger.error(x.getLocalizedMessage());
			writer.println(new JsonManager().getErrorJsonResponse(x.getLocalizedMessage()));
		}

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

	private Class getMapper(String algId) throws Exception {
		return Class.forName("org.gcube.nlphub.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) throws NlpHubException {
		WorkspaceManager ws = new WorkspaceManager();
		long now = System.currentTimeMillis();
		String fileName = "result-nlp-" + now + ".json";
		ws.deleteFile(fileName, token);
		
		byte[] byteContent = jsonResult.getBytes(StandardCharsets.UTF_8);
		if (!ws.uploadFile(byteContent, fileName, Constants.DEFAULT_DESCRIPTION, token)) {
			throw new NlpHubException("Error writing file: " + fileName + " on workspace (token: " + token + ")", null);	
		}

		String link = ws.getPublicLink(fileName, token);
		
		logger.info("Output json [" + fileName + "] created in " + (System.currentTimeMillis() - now) + " millisec.");
		return link;
	}

}
