#pragma once

#include <set>

#include "CEF/HumanApp.h"

class HumanAppRenderer
    : public HumanApp
    , public CefRenderProcessHandler {
public:
    class Delegate : public virtual CefBaseRefCounted {
    public:
        virtual void OnWebKitInitialized(CefRefPtr<HumanAppRenderer> app) {}

        virtual void OnBrowserCreated(CefRefPtr<HumanAppRenderer> app,
            CefRefPtr<CefBrowser> browser,
            CefRefPtr<CefDictionaryValue> extra_info) {}

        virtual void OnBrowserDestroyed(CefRefPtr<HumanAppRenderer> app,
            CefRefPtr<CefBrowser> browser) {}

        virtual CefRefPtr<CefLoadHandler> GetLoadHandler(
            CefRefPtr<HumanAppRenderer> app) {
            return nullptr;
        }

        virtual void OnContextCreated(CefRefPtr<HumanAppRenderer> app,
            CefRefPtr<CefBrowser> browser,
            CefRefPtr<CefFrame> frame,
            CefRefPtr<CefV8Context> context) {}

        virtual void OnContextReleased(CefRefPtr<HumanAppRenderer> app,
            CefRefPtr<CefBrowser> browser,
            CefRefPtr<CefFrame> frame,
            CefRefPtr<CefV8Context> context) {}

        virtual void OnUncaughtException(CefRefPtr<HumanAppRenderer> app,
            CefRefPtr<CefBrowser> browser,
            CefRefPtr<CefFrame> frame,
            CefRefPtr<CefV8Context> context,
            CefRefPtr<CefV8Exception> exception,
            CefRefPtr<CefV8StackTrace> stackTrace) {}

        virtual void OnFocusedNodeChanged(CefRefPtr<HumanAppRenderer> app,
            CefRefPtr<CefBrowser> browser,
            CefRefPtr<CefFrame> frame,
            CefRefPtr<CefDOMNode> node) {}

        virtual bool OnProcessMessageReceived(
            CefRefPtr<HumanAppRenderer> app,
            CefRefPtr<CefBrowser> browser,
            CefRefPtr<CefFrame> frame,
            CefProcessId source_process,
            CefRefPtr<CefProcessMessage> message) {
            return false;
        }
    };

    using DelegateSet = std::set<CefRefPtr<Delegate>>;


    HumanAppRenderer();

private:
    static void CreateDelegates(DelegateSet& delegates);

    // CefApp methods.
    CefRefPtr<CefRenderProcessHandler> GetRenderProcessHandler() override {
        return this;
    }

    // CefRenderProcessHandler methods.
    void OnWebKitInitialized() override;
    void OnBrowserCreated(CefRefPtr<CefBrowser> browser,
        CefRefPtr<CefDictionaryValue> extra_info) override;
    void OnBrowserDestroyed(CefRefPtr<CefBrowser> browser) override;
    CefRefPtr<CefLoadHandler> GetLoadHandler() override;
    void OnContextCreated(CefRefPtr<CefBrowser> browser,
        CefRefPtr<CefFrame> frame,
        CefRefPtr<CefV8Context> context) override;
    void OnContextReleased(CefRefPtr<CefBrowser> browser,
        CefRefPtr<CefFrame> frame,
        CefRefPtr<CefV8Context> context) override;
    void OnUncaughtException(CefRefPtr<CefBrowser> browser,
        CefRefPtr<CefFrame> frame,
        CefRefPtr<CefV8Context> context,
        CefRefPtr<CefV8Exception> exception,
        CefRefPtr<CefV8StackTrace> stackTrace) override;
    void OnFocusedNodeChanged(CefRefPtr<CefBrowser> browser,
        CefRefPtr<CefFrame> frame,
        CefRefPtr<CefDOMNode> node) override;
    bool OnProcessMessageReceived(CefRefPtr<CefBrowser> browser,
        CefRefPtr<CefFrame> frame,
        CefProcessId source_process,
        CefRefPtr<CefProcessMessage> message) override;

private:
    DelegateSet delegates_;

    IMPLEMENT_REFCOUNTING(HumanAppRenderer);
    DISALLOW_COPY_AND_ASSIGN(HumanAppRenderer);
};