package net.floodlightcontroller.debugcounter.web;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

import net.floodlightcontroller.debugcounter.IDebugCounterService.DebugCounterInfo;

import org.restlet.resource.Get;
import org.restlet.resource.Post;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * Return the debug counter data for the get rest-api call
 *
 * URI must be in one of the following forms:
 * "http://{controller-hostname}:8080/wm/core/debugcounter/{param}/json
 *
 *  where {param} must be one of (no quotes):
 *       "all"                  returns value/info on all active counters.
 *       "{moduleName}"         returns value/info on all active counters for the specified module.
 *       "{moduleCounterName}"  returns value/info for specific counter if it is enabled.
 *
 * @author Saurav
 */
public class DebugCounterResource extends DebugCounterResourceBase {
    protected static Logger logger =
            LoggerFactory.getLogger(DebugCounterResource.class);

    /**
     * The output JSON model that contains the counter information
     */
    public static class DebugCounterInfoOutput {
        public Map<String, DebugCounterInfo> counterMap;
        public String error;

        DebugCounterInfoOutput() {
            counterMap = new HashMap<String, DebugCounterInfo>();
            error = null;
        }
        public Map<String, DebugCounterInfo> getCounterMap() {
            return counterMap;
        }

        public String getError() {
            return error;
        }

    }

    public enum Option {
        ALL, ONE_MODULE, ONE_MODULE_COUNTER, ERROR_BAD_MODULE_NAME, ERROR_BAD_PARAM,
        ERROR_BAD_MODULE_COUNTER_NAME
    }

    public static class CounterPost {
        public Boolean reset;
        public Boolean enable;

        public Boolean getReset() {
            return reset;
        }
        public void setReset(Boolean reset) {
            this.reset = reset;
        }
        public Boolean getEnable() {
            return enable;
        }
        public void setEnable(Boolean enable) {
            this.enable = enable;
        }
    }
    
    public static class ResetOutput {
        String error = null;

        public String getError() {
            return error;
        }
        public void setError(String error) {
            this.error = error;
        }
    }
    
    @Post
    public ResetOutput postHandler(CounterPost postData) {
        ResetOutput output = new ResetOutput();
        
        String param = (String)getRequestAttributes().get("param");
        if (postData.getReset() != null && postData.getReset()) {
            Option choice = Option.ERROR_BAD_PARAM;

            if (param == null) {
                param = "all";
                choice = Option.ALL;
            } else if (param.equals("all")) {
                choice = Option.ALL;
            } else if (param.contains("-")) {
                // differentiate between disabled and non-existing counters
                boolean isRegistered = debugCounter.containsMCName(param);
                if (isRegistered) {
                    choice = Option.ONE_MODULE_COUNTER;
                } else {
                    choice = Option.ERROR_BAD_MODULE_COUNTER_NAME;
                }
            } else {
                boolean isRegistered = debugCounter.containsModName(param);
                if (isRegistered) {
                    choice = Option.ONE_MODULE;
                } else {
                    choice = Option.ERROR_BAD_MODULE_NAME;
                }
            }

            switch (choice) {
                case ALL:
                    debugCounter.resetAllCounters();
                    break;
                case ONE_MODULE:
                    debugCounter.resetAllModuleCounters(param);
                    break;
                case ONE_MODULE_COUNTER:
                    debugCounter.resetCounter(param);
                    break;
                case ERROR_BAD_MODULE_NAME:
                    output.error = "Module name has no corresponding registered counters";
                    break;
                case ERROR_BAD_MODULE_COUNTER_NAME:
                    output.error = "Counter not registered";
                    break;
                case ERROR_BAD_PARAM:
                    output.error = "Bad param";
            }
        }

        if (output.getError() != null) return output;
        
        if (postData.getEnable() != null) {
            if (!param.contains("-")) {
                output.error = "Specified moduleCounterName is not of type " +
                        "<moduleName>-<counterName>.";
                return output;
            }

            if (postData.getEnable()) {
                debugCounter.enableCtrOnDemand(param);
            } else {
                debugCounter.disableCtrOnDemand(param);
            }
        }

        return output;
    }

    @Get
    public DebugCounterInfoOutput handleCounterInfoQuery() {
        DebugCounterInfoOutput output = new DebugCounterInfoOutput();
        Option choice = Option.ERROR_BAD_PARAM;

        String param = (String)getRequestAttributes().get("param");
        if (param == null) {
            param = "all";
            choice = Option.ALL;
        } else if (param.equals("all")) {
            choice = Option.ALL;
        } else if (param.contains("-")) {
            // differentiate between disabled and non-existing counters
            boolean isRegistered = debugCounter.containsMCName(param);
            if (isRegistered) {
                choice = Option.ONE_MODULE_COUNTER;
            } else {
                choice = Option.ERROR_BAD_MODULE_COUNTER_NAME;
            }
        } else {
            boolean isRegistered = debugCounter.containsModName(param);
            if (isRegistered) {
                choice = Option.ONE_MODULE;
            } else {
                choice = Option.ERROR_BAD_MODULE_NAME;
            }
        }

        switch (choice) {
            case ALL:
                poplulateAllCounters(debugCounter.getAllCounterValues(), output);
                break;
            case ONE_MODULE:
                populateModuleCounters(debugCounter.getModuleCounterValues(param), output);
                break;
            case ONE_MODULE_COUNTER:
                populateSingleCounter(debugCounter.getCounterValue(param), output);
                break;
            case ERROR_BAD_MODULE_NAME:
                output.error = "Module name has no corresponding registered counters";
                break;
            case ERROR_BAD_MODULE_COUNTER_NAME:
                output.error = "Counter not registered";
                break;
            case ERROR_BAD_PARAM:
                output.error = "Bad param";
        }

        return output;
    }

    private void populateSingleCounter(DebugCounterInfo debugCounterInfo,
                                       DebugCounterInfoOutput output) {
        if (debugCounterInfo != null)
            output.counterMap.put(debugCounterInfo.getCounterInfo().
                                  getModuleCounterName(),
                                  debugCounterInfo);
    }

    private void populateModuleCounters(List<DebugCounterInfo> moduleCounterValues,
                                        DebugCounterInfoOutput output) {
        for (DebugCounterInfo dci : moduleCounterValues) {
            populateSingleCounter(dci, output);
        }
    }

    private void poplulateAllCounters(List<DebugCounterInfo> allCounterValues,
                                      DebugCounterInfoOutput output) {
        for (DebugCounterInfo dci : allCounterValues) {
            populateSingleCounter(dci, output);
        }
    }



}

@@ -484,33 +484,24 @@
 /wm/
-core/debug
 counter
+s
 /%7Bparam%7D
 /jso
@@ -500,13 +500,9 @@
 ram%7D
-/json
+%22
 %0A *%0A

update comment on correct URL for debug counters