// This file is generated by DispatcherBase_h.template.

// Copyright 2016 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef {{"_".join(config.protocol.namespace)}}_DispatcherBase_h
#define {{"_".join(config.protocol.namespace)}}_DispatcherBase_h

//#include "Forward.h"
//#include "ErrorSupport.h"
//#include "Values.h"

{% for namespace in config.protocol.namespace %}
namespace {{namespace}} {
{% endfor %}

class WeakPtr;

class {{config.lib.export_macro}} DispatchResponse {
public:
    enum Status {
        kSuccess = 0,
        kError = 1,
        kFallThrough = 2,
    };

    // For historical reasons, these error codes correspond to commonly used
    // XMLRPC codes (e.g. see METHOD_NOT_FOUND in
    // https://github.com/python/cpython/blob/master/Lib/xmlrpc/client.py).
    enum ErrorCode {
        kParseError = -32700,
        kInvalidRequest = -32600,
        kMethodNotFound = -32601,
        kInvalidParams = -32602,
        kInternalError = -32603,
        kServerError = -32000,
    };

    Status status() const { return m_status; }
    const String& errorMessage() const { return m_errorMessage; }
    ErrorCode errorCode() const { return m_errorCode; }
    bool isSuccess() const { return m_status == kSuccess; }

    static DispatchResponse OK();
    static DispatchResponse Error(const String&);
    static DispatchResponse InternalError();
    static DispatchResponse InvalidParams(const String&);
    static DispatchResponse FallThrough();

private:
    Status m_status;
    String m_errorMessage;
    ErrorCode m_errorCode;
};

class {{config.lib.export_macro}} DispatcherBase {
    PROTOCOL_DISALLOW_COPY(DispatcherBase);
public:
    static const char kInvalidParamsString[];
    class {{config.lib.export_macro}} WeakPtr {
    public:
        explicit WeakPtr(DispatcherBase*);
        ~WeakPtr();
        DispatcherBase* get() { return m_dispatcher; }
        void dispose() { m_dispatcher = nullptr; }

    private:
        DispatcherBase* m_dispatcher;
    };

    class {{config.lib.export_macro}} Callback {
    public:
        Callback(std::unique_ptr<WeakPtr> backendImpl, int callId, const String& method, const ProtocolMessage& message);
        virtual ~Callback();
        void dispose();

    protected:
        void sendIfActive(std::unique_ptr<protocol::DictionaryValue> partialMessage, const DispatchResponse& response);
        void fallThroughIfActive();

    private:
        std::unique_ptr<WeakPtr> m_backendImpl;
        int m_callId;
        String m_method;
        ProtocolMessage m_message;
    };

    explicit DispatcherBase(FrontendChannel*);
    virtual ~DispatcherBase();

    virtual bool canDispatch(const String& method) = 0;
    virtual void dispatch(int callId, const String& method, const ProtocolMessage& rawMessage, std::unique_ptr<protocol::DictionaryValue> messageObject) = 0;
    FrontendChannel* channel() { return m_frontendChannel; }

    void sendResponse(int callId, const DispatchResponse&, std::unique_ptr<protocol::DictionaryValue> result);
    void sendResponse(int callId, const DispatchResponse&);

    void reportProtocolError(int callId, DispatchResponse::ErrorCode, const String& errorMessage, ErrorSupport* errors);
    void clearFrontend();

    std::unique_ptr<WeakPtr> weakPtr();

private:
    FrontendChannel* m_frontendChannel;
    std::unordered_set<WeakPtr*> m_weakPtrs;
};

class {{config.lib.export_macro}} UberDispatcher {
    PROTOCOL_DISALLOW_COPY(UberDispatcher);
public:
    explicit UberDispatcher(FrontendChannel*);
    void registerBackend(const String& name, std::unique_ptr<protocol::DispatcherBase>);
    void setupRedirects(const std::unordered_map<String, String>&);
    bool parseCommand(Value* message, int* callId, String* method);
    bool canDispatch(const String& method);
    void dispatch(int callId, const String& method, std::unique_ptr<Value> message, const ProtocolMessage& rawMessage);
    FrontendChannel* channel() { return m_frontendChannel; }
    virtual ~UberDispatcher();

private:
    protocol::DispatcherBase* findDispatcher(const String& method);
    FrontendChannel* m_frontendChannel;
    std::unordered_map<String, String> m_redirects;
    std::unordered_map<String, std::unique_ptr<protocol::DispatcherBase>> m_dispatchers;
};

class InternalResponse : public Serializable {
    PROTOCOL_DISALLOW_COPY(InternalResponse);
public:
    static std::unique_ptr<InternalResponse> createResponse(int callId, std::unique_ptr<Serializable> params);
    static std::unique_ptr<InternalResponse> createNotification(const String& notification, std::unique_ptr<Serializable> params = nullptr);

    String serializeToJSON() override;
    std::vector<uint8_t> serializeToBinary() override;

    ~InternalResponse() override {}

private:
    InternalResponse(int callId, const String& notification, std::unique_ptr<Serializable> params);

    int m_callId;
    String m_notification;
    std::unique_ptr<Serializable> m_params;
};

class InternalRawNotification : public Serializable {
public:
    static std::unique_ptr<InternalRawNotification> fromJSON(String notification)
    {
        return std::unique_ptr<InternalRawNotification>(new InternalRawNotification(std::move(notification)));
    }

    static std::unique_ptr<InternalRawNotification> fromBinary(std::vector<uint8_t> notification)
    {
        return std::unique_ptr<InternalRawNotification>(new InternalRawNotification(std::move(notification)));
    }

    ~InternalRawNotification() override {}

    String serializeToJSON() override
    {
        return std::move(m_jsonNotification);
    }

    std::vector<uint8_t> serializeToBinary() override
    {
        return std::move(m_binaryNotification);
    }

private:
  explicit InternalRawNotification(String notification)
    : m_jsonNotification(std::move(notification)) { }
  explicit InternalRawNotification(std::vector<uint8_t> notification)
    : m_binaryNotification(std::move(notification)) { }

  String m_jsonNotification;
  std::vector<uint8_t> m_binaryNotification;
};

{% for namespace in config.protocol.namespace %}
} // namespace {{namespace}}
{% endfor %}

#endif // !defined({{"_".join(config.protocol.namespace)}}_DispatcherBase_h)
