package com.henrypump.poc;

import java.io.*;
import java.net.InetSocketAddress;
import java.util.HashMap;
import java.util.Map;

import com.sun.net.httpserver.HttpExchange;
import com.sun.net.httpserver.HttpHandler;
import com.sun.net.httpserver.HttpServer;
import org.json.simple.JSONObject;


/**
 * Created by patrickjmcd on 2/28/17.
 */


public class WebServer{
    private POC attachedPOC;
    private int port;

    WebServer(int port, POC attachedPOC) throws Exception {
        this.attachedPOC = attachedPOC;
        this.port = port;
        HttpServer server = HttpServer.create(new InetSocketAddress(port), 0);
        server.createContext("/command", new CommandHandler());
        server.createContext("/update", new UpdateHandler());
        server.createContext("/shake", new HandshakeHandler());
        server.createContext("/mode", new ModeHandler());
        server.setExecutor(null); // creates a default executor
        server.start();
    }

    public static Map<String, String> queryToMap(String query){
        Map<String, String> result = new HashMap<String, String>();
        for (String param : query.split("&")) {
            String pair[] = param.split("=");
            if (pair.length>1) {
                result.put(pair[0], pair[1]);
            }else{
                result.put(pair[0], "");
            }
        }
        return result;
    }

    class CommandHandler implements HttpHandler {
        @Override
        public void handle(HttpExchange t) throws IOException {
            JSONObject respJSON = new JSONObject();
            Map<String, String> params = queryToMap(t.getRequestURI().getQuery());
            String action = "";
            String user = "";
            for(Map.Entry<String, String> param_map : params.entrySet()){
                String key = param_map.getKey();
                String param = param_map.getValue();

                switch (key) {
                    case "cmd":
                        action = param;
                        break;
                    case "user":
                        user = param;
                        break;
                    default:
                        respJSON.put(key, "not implemented");

                }
            }
            if ((user.length() > 0) && (action.length() > 0)) {
                switch (action) {
                    case "start":
                        attachedPOC.thisWell.start(user);
                        respJSON.put("startCommand", "true");
                        respJSON.put("status", attachedPOC.thisWell.getRunStatusString());
                        break;
                    case "stop":
                        attachedPOC.thisWell.stop(user);
                        respJSON.put("stopCommand", "true");
                        respJSON.put("status", attachedPOC.thisWell.getRunStatusString());
                        break;
                    default:
                        respJSON.put(action, "not implemented");
                        break;
                }
            } else {
                respJSON.put("bad request", "cmd and user parameters required");
            }
            String response = respJSON.toJSONString();
            t.sendResponseHeaders(200, response.getBytes().length);
            OutputStream os = t.getResponseBody();
            os.write(response.getBytes());
            os.close();
        }
    }


    class UpdateHandler implements HttpHandler {
        @Override
        public void handle(HttpExchange t) throws IOException {
            JSONObject respJSON = new JSONObject();
            Map<String, String> params = queryToMap(t.getRequestURI().getQuery());

            for(Map.Entry<String, String> param_map : params.entrySet()){
                String key = param_map.getKey();
                String param = param_map.getValue();
                double newSP;
                if (key.equals("wellconfig")) {
                    attachedPOC.thisWell.getWellSetup();
                    respJSON.put("configUpdated", "true");
                    continue;
                } else if (key.equals("setpoint")) {
                    newSP = attachedPOC.thisWell.db.getSetpoint(param);
                    if (newSP == Double.MIN_VALUE) {
                        respJSON.put("no entry", key);
                        continue;
                    }

                    switch (param) {
                        case "fluidOilRatio":
                            attachedPOC.thisWell.setFluidOilRatio(newSP);
                            respJSON.put(param, attachedPOC.thisWell.getFluidOilRatio());
                            break;

                        case "fluidWaterRatio":
                            attachedPOC.thisWell.setFluidWaterRatio(newSP);
                            respJSON.put(param, attachedPOC.thisWell.getFluidWaterRatio());
                            break;

                        case "fluidGasRatio":
                            attachedPOC.thisWell.setFluidGasRatio(newSP);
                            respJSON.put(param, attachedPOC.thisWell.getFluidGasRatio());
                            break;

                        case "pumpOffFillPercentSetpoint":
                            attachedPOC.thisWell.setPumpOffFillPercentSetpoint(newSP);
                            respJSON.put(param, attachedPOC.thisWell.getPumpOffFillPercentSetpoint());
                            break;

                        case "pumpOffStrokesSetpoint":
                            attachedPOC.thisWell.setPumpOffStrokesSetpoint((int) newSP);
                            respJSON.put(param, attachedPOC.thisWell.getPumpOffStrokesSetpoint());
                            break;

                        case "pumpOffDowntimeMinutesSetpoint":
                            attachedPOC.thisWell.setPumpOffDowntimeMinutesSetpoint((long) newSP);
                            respJSON.put(param, attachedPOC.thisWell.getPumpOffDowntimeMinutesSetpoint());
                            break;

                        case "timerOffMinutesSetpoint":
                            attachedPOC.thisWell.setTimerOffMinutesSetpoint((long) newSP);
                            respJSON.put(param, attachedPOC.thisWell.getTimerOffMinutesSetpoint());
                            break;

                        case "timerRunMinutesSetpoint":
                            attachedPOC.thisWell.setTimerRunMinutesSetpoint((long) newSP);
                            respJSON.put(param, attachedPOC.thisWell.getTimerRunMinutesSetpoint());
                            break;

                        default:
                            respJSON.put(param, "not implemented");
                            break;

                    }
                }

            }
            String response = respJSON.toJSONString();
            t.sendResponseHeaders(200, response.getBytes().length);
            OutputStream os = t.getResponseBody();
            os.write(response.getBytes());
            os.close();
        }
    }

    class HandshakeHandler implements HttpHandler {
        @Override
        public void handle(HttpExchange t) throws IOException {
            JSONObject respJSON = new JSONObject();
            respJSON.put("shake", "shook");
            String response = respJSON.toJSONString();
            t.sendResponseHeaders(200, response.getBytes().length);
            OutputStream os = t.getResponseBody();
            os.write(response.getBytes());
            os.close();
        }
    }

    class ModeHandler implements HttpHandler {
        @Override
        public void handle(HttpExchange t) throws IOException {
            JSONObject respJSON = new JSONObject();
            Map<String, String> params = queryToMap(t.getRequestURI().getQuery());
            String action = "";
            String user = "";
            for(Map.Entry<String, String> param_map : params.entrySet()){
                String key = param_map.getKey();
                String param = param_map.getValue();

                switch (key) {
                    case "mode":
                        action = param;
                        break;
                    case "user":
                        user = param;
                        break;
                    default:
                        respJSON.put(key, "not implemented");

                }
            }
            if ((user.length() > 0) && (action.length() > 0)) {
                switch (action) {
                    case "manual":
                        attachedPOC.thisWell.setRunModeString("MANUAL");
                        break;
                    case "poc":
                        attachedPOC.thisWell.setRunModeString("POC");
                        break;
                    case "timer":
                        attachedPOC.thisWell.setRunModeString("TIMER");
                        break;
                    default:
                        respJSON.put(action, "not implemented");
                        break;
                }
                respJSON.put("runMode", attachedPOC.thisWell.getRunModeString());
            } else {
                respJSON.put("bad request", "cmd and user parameters required");
            }
            String response = respJSON.toJSONString();
            t.sendResponseHeaders(200, response.getBytes().length);
            OutputStream os = t.getResponseBody();
            os.write(response.getBytes());
            os.close();
        }
    }
}
