// Copyright (c) 2012-2014 The CEF Python authors. All rights reserved.
// License: New BSD License.
// Website: http://code.google.com/p/cefpython/

#pragma once
#include "include/cef_app.h"
#include "include/cef_print_handler.h"

#if defined(OS_LINUX)
#include "print_handler_gtk.h"
#endif

#include <map>

// CefPythonApp class is instantiated in subprocess and in
// cefpython.pyx for the browser process, so the code is shared.
// Using printf() in CefRenderProcessHandler won't work, use
// the DebugLog() function instead, it will write the message
// to the "debug.log" file.

class CefPythonApp :
        public CefApp,
        public CefBrowserProcessHandler,
        public CefRenderProcessHandler {
 protected:
  std::map<int, CefRefPtr<CefDictionaryValue> > javascriptBindings_;
  std::string commandLineString_;
  CefRefPtr<CefPrintHandler> print_handler_;

 public:
  CefPythonApp();

  void OnBeforeCommandLineProcessing(
      const CefString& process_type,
      CefRefPtr<CefCommandLine> command_line) override;

  void OnRegisterCustomSchemes(
      CefRefPtr<CefSchemeRegistrar> registrar) override;

  CefRefPtr<CefResourceBundleHandler> GetResourceBundleHandler()
        override;

  CefRefPtr<CefBrowserProcessHandler> GetBrowserProcessHandler()
        override;

  CefRefPtr<CefRenderProcessHandler> GetRenderProcessHandler()
        override;

  // ---------------------------------------------------------------------------
  // CefBrowserProcessHandler
  // ---------------------------------------------------------------------------

  void OnContextInitialized() override;

  void OnBeforeChildProcessLaunch(
      CefRefPtr<CefCommandLine> command_line) override;

  void OnRenderProcessThreadCreated(
      CefRefPtr<CefListValue> extra_info) override;

  CefRefPtr<CefPrintHandler> GetPrintHandler() override;

  void OnScheduleMessagePumpWork(int64 delay_ms) override;


  // ---------------------------------------------------------------------------
  // CefRenderProcessHandler
  // ---------------------------------------------------------------------------

  void OnRenderThreadCreated(CefRefPtr<CefListValue> extra_info)
        override;

  void OnWebKitInitialized()
        override;

  void OnBrowserCreated(CefRefPtr<CefBrowser> browser)
        override;

  void OnBrowserDestroyed(CefRefPtr<CefBrowser> browser)
        override;

  bool OnBeforeNavigation(CefRefPtr<CefBrowser> browser,
                                  CefRefPtr<CefFrame> frame,
                                  CefRefPtr<CefRequest> request,
                                  cef_navigation_type_t navigation_type,
                                  bool is_redirect)
        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,
                                        CefProcessId source_process,
                                        CefRefPtr<CefProcessMessage> message)
        override;

  // ---------------------------------------------------------------------------
  // Javascript bindings
  // ---------------------------------------------------------------------------

  void SetJavascriptBindings(CefRefPtr<CefBrowser> browser,
                                    CefRefPtr<CefDictionaryValue> data);
  CefRefPtr<CefDictionaryValue> GetJavascriptBindings(
                                    CefRefPtr<CefBrowser> browser);

  void RemoveJavascriptBindings(CefRefPtr<CefBrowser> browser);

  bool BindedFunctionExists(CefRefPtr<CefBrowser> browser,
                                    const CefString& funcName);

  void DoJavascriptBindingsForBrowser(CefRefPtr<CefBrowser> browser);

  void DoJavascriptBindingsForFrame(CefRefPtr<CefBrowser> browser,
                                    CefRefPtr<CefFrame> frame,
                                    CefRefPtr<CefV8Context> context);

private:
  IMPLEMENT_REFCOUNTING(CefPythonApp);
};
