package org.minimalj.frontend.impl.nanoserver;

import java.io.IOException;
import java.io.InputStream;
import java.util.List;
import java.util.Locale;
import java.util.Locale.LanguageRange;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;

import org.minimalj.frontend.impl.json.JsonFrontend;
import org.minimalj.frontend.impl.json.JsonHandler;
import org.minimalj.util.resources.Resources;

import fi.iki.elonen.NanoHTTPD.Response.Status;
import fi.iki.elonen.NanoWSD;
import fi.iki.elonen.NanoWSD.WebSocketFrame.CloseCode;

public class MjWebSocketDaemon extends NanoWSD {
	private static final Logger logger = Logger.getLogger(MjWebSocketDaemon.class.getName());

	private JsonHandler handler = new JsonHandler();
	
	public MjWebSocketDaemon(int port, boolean secure) {
		super(port);
		if (secure) {
			try {
				// keytool.exe -keystore mjdevkeystore.jks -keyalg RSA -keysize 3072 -genkeypair -dname "cn=localhost, ou=MJ, o=Minimal-J, c=CH" -storepass mjdev1 -keypass mjdev1
				// keytool.exe -keystore mjdevkeystore.jks -storepass mjdev1 -keypass mjdev1 -export -file mj.cer
				makeSecure(makeSSLSocketFactory("/mjdevkeystore.jks", "mjdev1".toCharArray()), null);
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
	}
	
	@Override
	protected WebSocket openWebSocket(IHTTPSession handshake) {
		return new MjWebSocket(handshake);
	}
	
	private static Locale getLocale(String userLocale) {
        final List<LanguageRange> ranges = Locale.LanguageRange.parse(userLocale);
        if (ranges != null) {
        	for (LanguageRange languageRange : ranges) {
                final String localeString = languageRange.getRange();
                final Locale locale = Locale.forLanguageTag(localeString);
                return locale;
            }
        }
        return null;
	}
	
	@Override
    public Response serve(String uri, Method method, Map<String, String> headers, Map<String, String> parms,
            Map<String, String> files) {
		if (uri.equals("/")) {
			String htmlTemplate = JsonFrontend.getHtmlTemplate();
			Locale locale = getLocale(headers.get("accept-language"));
			String html = JsonFrontend.fillPlaceHolder(htmlTemplate, locale);
			return newFixedLengthResponse(Status.OK, "text/html", html);
		} else if ("/ajax_request.xml".equals(uri)) {
			String data = files.get("postData");
			String result = handler.handle(data);
			return newFixedLengthResponse(Status.OK, "text/xml", result);
		} else {
			int index = uri.lastIndexOf('.');
			if (index > -1 && index < uri.length()-1) {
				String postfix = uri.substring(index+1);
				String mimeType = Resources.getMimeType(postfix);
				if (mimeType != null) {
					InputStream inputStream = Resources.getInputStream(uri.substring(1));
					return newChunkedResponse(Status.OK, mimeType, inputStream);
				}
			}
		}
		logger.warning("Could not serve: " + uri);
		return newFixedLengthResponse(Status.NOT_FOUND, "text/html", uri + " not found");
	}

	public class MjWebSocket extends WebSocket {
		
		public MjWebSocket(IHTTPSession handshakeRequest) {
			super(handshakeRequest);
		}

		@Override
		protected void onOpen() {
			// nothing to do
		}

		@Override
		protected void onMessage(WebSocketFrame message) {
			String result = handler.handle(message.getTextPayload());
			try {
				send(result);
			} catch (IOException e) {
				logger.log(Level.SEVERE, "Send response failed", e);
			}
		}
		
		@Override
		protected void onPong(WebSocketFrame pong) {
			// nothing to do
		}

		@Override
		protected void onClose(CloseCode code, String reason, boolean initiatedByRemote) {
			logger.fine("Close " + reason + " / " + initiatedByRemote);
		}

		@Override
		protected void onException(IOException exception) {
			// nothing to do
		}
	}
	
}

@@ -841,24 +841,648 @@
  %7B%0A%09%09%09try %7B%0A
+%09%09%09%09// nanohttpd geht davon aus, dass keypass = storepass... ob das so sein darf / kann?%0A%09%09%09%09// bei storepass d%C3%BCrfte nanohttpd auch null mitgeben um die %C3%9Cberpr%C3%BCfung auszulassen...%0A%09%09%09%09%0A%09%09%09%09// note 1: to first read the property MjKeystorePassphrase and then convert it to char%5B%5D%0A%09%09%09%09// makes the whole char%5B%5D story senseless. But how to do it else? Maybe specify a filename%0A%09%09%09%09// and then read it byte by byte.%0A%09%09%09%09%0A%09%09%09%09// note 2: nanohttpd implies that keypass and storepass are the same passwords. I don't%0A%09%09%09%09// know if this is a good idea.%0A%09%09%09%09%0A%09%09%09%09// note 3: example to generate the store (todo: move to documentation)%0A
 %09%09%09%09// keyto
@@ -1742,88 +1742,309 @@
 cer%0A
+%0A
 %09%09%09%09
-makeSecure(makeSSLSocketFactory(%22/mjdevkeystore.jks%22, %22mjdev1%22.toCharArray()
+String keyAndTrustStoreClasspathPath = System.getProperty(%22MjKeystore%22); // in example '/mjdevkeystore.jks'%0A%09%09%09%09char%5B%5D passphrase = System.getProperty(%22MjKeystorePassphrase%22).toCharArray(); //  ub example 'mjdev1'%0A%09%09%09%09%0A%09%09%09%09makeSecure(makeSSLSocketFactory(keyAndTrustStoreClasspathPath, passphrase
 ), n
@@ -2111,24 +2111,25 @@
 %09%09%09%7D%0A%09%09%7D%0A%09%7D%0A
+%0A
 %09%0A%09@Override

make keystore configurable