package at.gv.egiz.simpleSigning;

import java.io.IOException;
import java.io.OutputStream;
import java.net.MalformedURLException;
import java.net.URL;

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

import org.apache.commons.codec.binary.Base64;
import org.apache.commons.fileupload.FileItemIterator;
import org.apache.commons.fileupload.FileItemStream;
import org.apache.commons.fileupload.servlet.ServletFileUpload;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import at.gv.egiz.simpleSigning.cfg.Configuration;
import at.gv.egiz.simpleSigning.helper.PDFHelper;
import at.gv.egiz.simpleSigning.helper.SessionHelper;
import at.gv.egiz.simpleSigning.helper.SessionHelper.Type;

public class StartSignature extends HttpServlet {

	private static final Logger logger = LoggerFactory
			.getLogger(StartSignature.class);

	/**
	 * 
	 */
	private static final long serialVersionUID = -2069326194649859734L;

	private static final String PARAM_PDF_URL = "PDFURL";
	private static final String PARAM_CONNECTOR = "CONNECTOR";
	private static final String PARAM_EVENTID = "EVENTID";
	private static final String PARAM_TYPE = "TYPE";
	private static final String PARAM_TARGETURL = "TARGETURL";
	private static final String PARAM_RESIZE = "RESIZE";
	private static final String PARAM_LOCALE = "LOCALE";

	private static final String PARAM_QRCODE = "QRCODE";
	private static final String PARAM_NEW = "NEW";
	private static final String PARAM_NEW_V = "1";
	
	private static final String PARAM_SIG_POS_X = "SIG_POS_X";
	private static final String PARAM_SIG_POS_Y = "SIG_POS_Y";
	private static final String PARAM_SIG_POS_P = "SIG_POS_P";
	private static final String PARAM_SIG_POS_W = "SIG_POS_W";
	private static final String PARAM_SIG_POS_F = "SIG_POS_F";

	public StartSignature() {
		super();
	}

	private void doSession(HttpServletRequest req, HttpServletResponse resp)
			throws ServletException, IOException {
		String nV = req.getParameter(PARAM_NEW);
		if (nV != null && nV.equals(PARAM_NEW_V)) {
			SessionHelper.killSession(req);
		}
	}

	@Override
	protected void doGet(HttpServletRequest req, HttpServletResponse resp)
			throws ServletException, IOException {
		this.doSession(req, resp);
		this.doProcess(req, resp);
	}

	@Override
	protected void doPost(HttpServletRequest req, HttpServletResponse resp)
			throws ServletException, IOException {

		this.doSession(req, resp);

		byte[] uploadForm = null;

		boolean isMultipart = ServletFileUpload.isMultipartContent(req);

		if (isMultipart) {
			try {
				ServletFileUpload upload = new ServletFileUpload();
				FileItemIterator iter = upload.getItemIterator(req);
				while (iter.hasNext()) {
					FileItemStream fileItem = iter.next();
					if ("pdf-file".equals(fileItem.getFieldName())) {
						uploadForm = IOUtils.toByteArray(fileItem.openStream());
						if (uploadForm.length > 5) {
							SessionHelper.setDocument(req, uploadForm);
						} else {
							logger.info("No Document uploaded");
						}
					} else if ("txtContent".equals(fileItem.getFieldName())) {
						String txtContent = IOUtils.toString(fileItem
								.openStream());
						uploadForm = PDFHelper.createPDFDocument(txtContent);
						SessionHelper.setDocument(req, uploadForm);
					} else if ("connector".equals(fileItem.getFieldName())) {
						String connector = IOUtils.toString(fileItem
								.openStream());
						SessionHelper.setConnector(req, connector);
					}
				}
			} catch (Throwable e) {
				logger.error("Failed to get upload PDF File:", e);
			}
		}
		/*
		 * try { Part pdfFile = req.getPart("pdf-file"); if(pdfFile != null) {
		 * uploadForm = IOUtils.toByteArray(pdfFile.getInputStream());
		 * SessionHelper.setDocument(req, uploadForm); } } catch(Throwable e) {
		 * logger.error("Failed to get upload PDF File:", e); }
		 */

		String txtContent = req.getParameter("txtContent");

		if (txtContent != null) {
			uploadForm = PDFHelper.createPDFDocument(txtContent);
			SessionHelper.setDocument(req, uploadForm);
		}

		String connector = req.getParameter("connector");

		if (connector != null) {
			SessionHelper.setConnector(req, connector);
		}

		this.doProcess(req, resp);
	}

	protected void doProcess(HttpServletRequest req, HttpServletResponse resp)
			throws ServletException, IOException {

		try {

			String content = req.getParameter(PARAM_PDF_URL);
			String connector = req.getParameter(PARAM_CONNECTOR);
			String eventId = req.getParameter(PARAM_EVENTID);
			String type = req.getParameter(PARAM_TYPE);
			String targetUrl = req.getParameter(PARAM_TARGETURL);
			String qrCodeData = req.getParameter(PARAM_QRCODE);
			String localeData = req.getParameter(PARAM_LOCALE);
			
			String sigPosX = req.getParameter(PARAM_SIG_POS_X);
			String sigPosY = req.getParameter(PARAM_SIG_POS_Y);
			String sigPosP = req.getParameter(PARAM_SIG_POS_P);
			String sigPosW = req.getParameter(PARAM_SIG_POS_W);
			String sigPosF = req.getParameter(PARAM_SIG_POS_F);

			// Step 1. Setup Parameters
			if (type != null) {
				// If we have a type set it
				SessionHelper.setType(req, type);

				logger.trace("[" + req.getSession().getId()
						+ "]: setting Type to: " + type);
			}

			if (qrCodeData != null) {
				// If we have a type set it
				SessionHelper.setQRCodeContent(req, qrCodeData);

				logger.trace("[" + req.getSession().getId()
						+ "]: setting QR Code Data to: " + qrCodeData);
			}
			
			if (localeData != null) {
				// If we have a type set it
				SessionHelper.setLocale(req, localeData);

				logger.trace("[" + req.getSession().getId()
						+ "]: setting Locale to: " + localeData);
			}

			if (eventId != null) {
				SessionHelper.setEventID(req, eventId);

				logger.trace("[" + req.getSession().getId()
						+ "]: setting Event Id to: " + eventId);
			}

			if (targetUrl != null) {
				SessionHelper.setTargetURL(req, targetUrl);

				logger.trace("[" + req.getSession().getId()
						+ "]: setting Target URL to: " + targetUrl);
			}

			if (connector != null && connector.length() != 0) {
				// If we have a connector set it
				SessionHelper.setConnector(req, connector);
				logger.trace("[" + req.getSession().getId()
						+ "]: setting Connector to: " + connector);
			}

			if (content != null && content.length() != 0) {
				// If we have a content set it
				SessionHelper.setContent(req, content);
				logger.trace("[" + req.getSession().getId()
						+ "]: setting Content");

				if (SessionHelper.getType(req).equals(Type.TEXT)) {
					SessionHelper.setDocument(req,
							PDFHelper.createPDFDocument(content));
				} else if (SessionHelper.getType(req).equals(Type.B64)) {
					SessionHelper
							.setDocument(req, Base64.decodeBase64(content));
				}

			}
			
			//Position Params
			if (sigPosX != null && !sigPosX.isEmpty()) {
				if(isNumeric(sigPosX, req, resp)==false)
					return;
				// If we have a type set it
				SessionHelper.setSigPosX(req, sigPosX);

				logger.trace("[" + req.getSession().getId()
						+ "]: setting SigPosX to: " + sigPosX);
			}
			if (sigPosY != null && !sigPosY.isEmpty()) {
				if(isNumeric(sigPosY, req, resp)==false)
					return;
				// If we have a type set it
				SessionHelper.setSigPosY(req, sigPosY);

				logger.trace("[" + req.getSession().getId()
						+ "]: setting SigPosY to: " + sigPosY);
			}
			if (sigPosP != null && !sigPosP.isEmpty()) {
				if(isNumeric(sigPosP, req, resp)==false)
					return;
				// If we have a type set it
				SessionHelper.setSigPosP(req, sigPosP);

				logger.trace("[" + req.getSession().getId()
						+ "]: setting SigPosP to: " + sigPosP);
			}
			if (sigPosW != null && !sigPosW.isEmpty()) {
				if(isNumeric(sigPosW, req, resp)==false)
					return;
				// If we have a type set it
				SessionHelper.setSigPosW(req, sigPosW);

				logger.trace("[" + req.getSession().getId()
						+ "]: setting SigPosW to: " + sigPosW);
			}
			if (sigPosF != null && !sigPosF.isEmpty()) {
				if(isNumeric(sigPosF, req, resp)==false)
					return;
				// If we have a type set it
				SessionHelper.setSigPosF(req, sigPosF);

				logger.trace("[" + req.getSession().getId()
						+ "]: setting SigPosF to: " + sigPosF);
			}

			if ((SessionHelper.getContent(req) == null && SessionHelper
					.getDocument(req) == null)
					|| SessionHelper.getConnector(req) == null) {

				// We need more information

				String form = FileUtils.readFileToString(FileUtils
						.toFile(PDFASJsServlet.class
								.getResource("/html/questionForm.html")));

				String input = "";
				if ((SessionHelper.getContent(req) == null && SessionHelper
						.getDocument(req) == null)) {

					if (SessionHelper.getType(req).equals(Type.PDF)) {
						input = FileUtils.readFileToString(FileUtils
								.toFile(PDFASJsServlet.class
										.getResource("/html/fileupload")));
					} else {
						input = FileUtils.readFileToString(FileUtils
								.toFile(PDFASJsServlet.class
										.getResource("/html/textinput")));
					}
				}
				form = form.replace("##REPLACE##FILEUP##", input);

				String bkusel = "";
				if (SessionHelper.getConnector(req) == null) {
					bkusel = FileUtils.readFileToString(FileUtils
							.toFile(PDFASJsServlet.class
									.getResource("/html/bkuSelektion")));

					bkusel = bkusel.replace("##REPLACE##PUBURL##",
							Configuration.getPublicUrl());

				} else {
					bkusel = FileUtils.readFileToString(FileUtils
							.toFile(PDFASJsServlet.class
									.getResource("/html/submit")));

					if (SessionHelper.getType(req) != null
							&& SessionHelper.getType(req).equals(Type.PDF)) {
						bkusel = bkusel.replace("##REPLACE##NAME##",
								"Dokument signieren");
					} else {
						bkusel = bkusel.replace("##REPLACE##NAME##",
								"Text signieren");
					}

				}
				form = form.replace("##REPLACE##BKUSEL##", bkusel);

				form = form.replace("##ACTIONURL##",
						Configuration.getPublicUrl() + "/Start;jsessionid="
								+ req.getSession().getId());

				String resize = FileUtils.readFileToString(FileUtils
						.toFile(PDFASJsServlet.class
								.getResource("/js/resize_response.js")));

				resize = resize.replace("##REPLACE##EVENTID##",
						SessionHelper.getEventID(req));
				resize = resize.replace("##REPLACE##TARGETURL##",
						SessionHelper.getTargetURL(req));

				String postman = FileUtils.readFileToString(FileUtils
						.toFile(PDFASJsServlet.class
								.getResource("/js/postman.js")));

				String script_txt = postman + resize;

				form = form.replace("##REPLACE##SCRIPT##", script_txt);

				resp.setContentType("text/html");
				OutputStream os = resp.getOutputStream();
				os.write(form.getBytes());
				os.close();
				return;
			}

			// Resize Iframe for BKU communication

			String resizeDone = req.getParameter(PARAM_RESIZE);

			if (resizeDone != null && resizeDone.equals("1")) {
				SessionHelper.setResizeDone(req);
			}

			if (!SessionHelper.getResizeDone(req)) {
				String form = FileUtils.readFileToString(FileUtils
						.toFile(PDFASJsServlet.class
								.getResource("/html/resize_form.html")));
				form = form.replace("##ACTIONURL##",
						Configuration.getPublicUrl() + "/Start;jsessionid="
								+ req.getSession().getId());

				String resize = FileUtils.readFileToString(FileUtils
						.toFile(PDFASJsServlet.class
								.getResource("/js/resizing_response.js")));

				resize = resize.replace("##REPLACE##EVENTID##",
						SessionHelper.getEventID(req));
				resize = resize.replace("##REPLACE##TARGETURL##",
						SessionHelper.getTargetURL(req));

				// Handy Signatur: style="width: 255px; height: 250px;"

				// Online BKU: width: 225px; height: 225px;

				if (SessionHelper.getConnector(req).equals("mobilebku")) {
					resize = resize.replace("##REPLACE##HEIGHT##", "255");

					resize = resize.replace("##REPLACE##WIDTH##", "250");
				} else {
					resize = resize.replace("##REPLACE##HEIGHT##", "225");

					resize = resize.replace("##REPLACE##WIDTH##", "225");
				}

				String postman = FileUtils.readFileToString(FileUtils
						.toFile(PDFASJsServlet.class
								.getResource("/js/postman.js")));

				String script_txt = postman + resize;

				form = form.replace("##REPLACE##SCRIPT##", script_txt);

				resp.setContentType("text/html");
				OutputStream os = resp.getOutputStream();
				os.write(form.getBytes());
				os.close();

				return;
			}

			// Step 4. Start Signature Process with PDF-AS

			String template = FileUtils.readFileToString(FileUtils
					.toFile(PDFASJsServlet.class
							.getResource("/html/template_start.html")));

			if (SessionHelper.getDocument(req) != null) {
				template = template.replace("##PDFURL##",
						Configuration.getPublicUrl() + "/Provide;jsessionid="
								+ req.getSession().getId());
			} else {
				if (SessionHelper.getContent(req) == null) {
					logger.error("["
							+ req.getSession().getId()
							+ "]: Failed to generate signature Data!: Document is null and Content is null");
					PDFHelper.toError(req, resp,
							"Failed to get signature Data",
							"Document is null and Content is null");
					return;
				} else {
					try {
						URL url = new URL(SessionHelper.getContent(req));
						//logger.info("[" + req.getSession().getId()
						//		+ "]: Setting PDF URL: " + url.toExternalForm());
						template = template.replace("##PDFURL##",
								url.toExternalForm());
					} catch (MalformedURLException e) {
						logger.error(
								"["
										+ req.getSession().getId()
										+ "]: Failed to generate signature Data!: Document is null and Content is not an URL: "
										+ SessionHelper.getContent(req), e);
						PDFHelper.toError(
								req,
								resp,
								"Failed to get signature Data",
								"Invalid PDF URL: "
										+ SessionHelper.getContent(req));
						return;
					}
				}
			}
			String entry = "";
			if (SessionHelper.getQRCodeContent(req) != null) {
				entry += "<input type=\"hidden\" name=\"qrcontent\" value=\""
						+ SessionHelper.getQRCodeContent(req) + "\">";
			} 
			if (SessionHelper.getLocale(req) != null) {
				entry += "<input type=\"hidden\" name=\"locale\" value=\""
						+ SessionHelper.getLocale(req) + "\">";
			}
			if (SessionHelper.getSigPosX(req) != null){
				entry += "<input type=\"hidden\" name=\"sig-pos-x\" value=\""
						+ SessionHelper.getSigPosX(req) + "\">";
			}
			if (SessionHelper.getSigPosY(req) != null){
				entry += "<input type=\"hidden\" name=\"sig-pos-y\" value=\""
						+ SessionHelper.getSigPosY(req) + "\">";
			}
			if (SessionHelper.getSigPosP(req) != null){
				entry += "<input type=\"hidden\" name=\"sig-pos-p\" value=\""
						+ SessionHelper.getSigPosP(req) + "\">";
			}
			if (SessionHelper.getSigPosW(req) != null){
				entry += "<input type=\"hidden\" name=\"sig-pos-w\" value=\""
						+ SessionHelper.getSigPosW(req) + "\">";
			}
			if (SessionHelper.getSigPosF(req) != null){
				entry += "<input type=\"hidden\" name=\"sig-pos-f\" value=\""
						+ SessionHelper.getSigPosF(req) + "\">";
			}

			template = template.replace("##ADDITIONAL##",
					entry);
			
			template = template.replace("##PDFASURL##",
					Configuration.getPDFAsLocation() + "/Sign");
			template = template.replace("##INVOKEURL##",
					Configuration.getPublicUrl() + "/Finish;jsessionid="
							+ req.getSession().getId());
			template = template.replace("##CONNECTOR##",
					SessionHelper.getConnector(req));
			template = template.replace("##INVOKETARGET##", "_self");
			template = template.replace("##INVOKEERRORURL##",
					Configuration.getPublicUrl() + "/Error;jsessionid="
							+ req.getSession().getId());

			resp.setContentType("text/html");
			OutputStream os = resp.getOutputStream();
			os.write(template.getBytes());
			os.close();

		} catch (Throwable e) {
			logger.error("[" + req.getSession().getId()
					+ "]: Something went wrong", e);
			PDFHelper
					.toError(req, resp, "Something went wrong", e.getMessage());
		}
	}
	
	private static boolean isNumeric(String nr, HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException  
	{  
	  try  
	  {  
	    Double.parseDouble(nr);  
	  }  
	  catch(NumberFormatException e)  
	  {  
		  logger.error("["
					+ req.getSession().getId()
					+ "]: Failed to generate signature Data!: Position Parameter is not numeric");
		  PDFHelper.toError(req, resp,
					"Failed to get signature Data",
					"Position Parameter is not numeric");
		  return false;
 
	  } 
	  return true;

	}
}