#include "BaseProtocol.hpp"
#include "Requests.hpp"

namespace DebugAdapterProtocol {
    ProtocolMessage* ProtocolMessage::FromJson(nlohmann::json& j) {
        auto t = j["type"];
        ProtocolMessage* msg;
        if (t == "request") {
            msg = Request::FromJson(j);
        } else if (t == "event") {
            throw std::logic_error("Unhandled type");
            // msg = Event::FromJson(j);
        } else if (t == "response") {
            msg = Response::FromJson(j);
        } else {
            throw std::logic_error("Unknown type");
        }
        msg->type = t;
        msg->seq = j["seq"];
        return msg;
    }

    template <IsRequestArguments T, const char* S> ProtocolMessage* DefinedRequest<T, S>::FromJson(nlohmann::json& j) {
        std::string c = j["command"];
        auto o = new DefinedRequest<T, S>();
        auto a = j["arguments"];
        if (!a.empty()) {
            o->arguments = dynamic_cast<T*>(new T(a));
        }
        return o;
    }
    ProtocolMessage* Request::FromJson(nlohmann::json& j) {
        std::string c = j["command"];
        // This is the worst, we need to fix this eventually.
        if (c == "attach")
            return AttachRequest::FromJson(j);
        if (c == "breakpointLocations")
            return BreakpointLocationsRequest::FromJson(j);
        if (c == "completions")
            return CompletionsRequest::FromJson(j);
        if (c == "configurationDone")
            return ConfigurationDoneRequest ::FromJson(j);
        if (c == "continue")
            return ContinueRequest ::FromJson(j);
        if (c == "dataBreakpointInfo")
            return DataBreakpointInfoRequest ::FromJson(j);
        if (c == "disassemble")
            return DisassembleRequest ::FromJson(j);
        if (c == "disconnect")
            return DisconnectRequest ::FromJson(j);
        if (c == "evaluate")
            return EvaluateRequest ::FromJson(j);
        if (c == "exceptionInfo")
            return ExceptionInfoRequest ::FromJson(j);
        if (c == "Goto")
            return GotoRequest ::FromJson(j);
        if (c == "GotoTargets")
            return GotoTargetsRequest ::FromJson(j);
        if (c == "initialize")
            return InitializeRequest ::FromJson(j);
        if (c == "launch")
            return LaunchRequest ::FromJson(j);
        if (c == "loadedSources")
            return LoadedSourcesRequest ::FromJson(j);
        if (c == "modules")
            return ModulesRequest ::FromJson(j);
        if (c == "next")
            return NextRequest ::FromJson(j);
        if (c == "pause")
            return PauseRequest ::FromJson(j);
        if (c == "readMemory")
            return ReadMemoryRequest ::FromJson(j);
        if (c == "restart")
            return RestartRequest ::FromJson(j);
        if (c == "restartFrame")
            return RestartFrameRequest ::FromJson(j);
        if (c == "reverseContinue")
            return RestartFrameRequest ::FromJson(j);
        if (c == "scopes")
            return ScopesRequest ::FromJson(j);
        if (c == "setBreakpoints")
            return SetBreakpointsRequest ::FromJson(j);
        if (c == "setDataBreakpoints")
            return SetDataBreakpointsRequest ::FromJson(j);
        if (c == "setExceptionBreakpoints")
            return SetExceptionBreakpointsRequest ::FromJson(j);
        if (c == "setExpression")
            return SetExpressionRequest ::FromJson(j);
        if (c == "setFunctionBreakpoints")
            return SetFunctionBreakpointsRequest ::FromJson(j);
        if (c == "setInstructionBreakpoints")
            return SetInstructionBreakpointsRequest ::FromJson(j);
        if (c == "setVariable")
            return SetVariableRequest ::FromJson(j);
        if (c == "source")
            return SourceRequest ::FromJson(j);
        if (c == "stackTrace")
            return StackTraceRequest ::FromJson(j);
        if (c == "stepBack")
            return StepBackRequest ::FromJson(j);
        if (c == "stepIn")
            return StepInRequest ::FromJson(j);
        if (c == "stepInTargets")
            return StepInTargetsRequest ::FromJson(j);
        if (c == "stepOut")
            return StepOutRequest ::FromJson(j);
        if (c == "terminate")
            return TerminateRequest ::FromJson(j);
        if (c == "terminateThreads")
            return TerminateThreadsRequest ::FromJson(j);
        if (c == "threads")
            return ThreadsRequest ::FromJson(j);
        if (c == "variables")
            return VariablesRequest ::FromJson(j);
        if (c == "writeMemory")
            return WriteMemoryRequest ::FromJson(j);
        throw std::logic_error("Unknown command");
    }
}