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

#include "tests/cefclient/browser/main_message_loop_multithreaded_win.h"

#include "include/base/cef_bind.h"
#include "include/base/cef_logging.h"
#include "include/cef_app.h"
#include "tests/cefclient/browser/resource.h"
#include "tests/shared/browser/util_win.h"

namespace client {

namespace {

const wchar_t kWndClass[] = L"Client_MessageWindow";
const wchar_t kTaskMessageName[] = L"Client_CustomTask";

}  // namespace

MainMessageLoopMultithreadedWin::MainMessageLoopMultithreadedWin()
    : thread_id_(base::PlatformThread::CurrentId()),
      task_message_id_(RegisterWindowMessage(kTaskMessageName)),
      dialog_hwnd_(NULL),
      message_hwnd_(NULL) {}

MainMessageLoopMultithreadedWin::~MainMessageLoopMultithreadedWin() {
  DCHECK(RunsTasksOnCurrentThread());
  DCHECK(!message_hwnd_);
  DCHECK(queued_tasks_.empty());
}

int MainMessageLoopMultithreadedWin::Run() {
  DCHECK(RunsTasksOnCurrentThread());

  HINSTANCE hInstance = ::GetModuleHandle(NULL);

  {
    base::AutoLock lock_scope(lock_);

    // Create the hidden window for message processing.
    message_hwnd_ = CreateMessageWindow(hInstance);
    CHECK(message_hwnd_);

    // Store a pointer to |this| in the window's user data.
    SetUserDataPtr(message_hwnd_, this);

    // Execute any tasks that are currently queued.
    while (!queued_tasks_.empty()) {
      PostTaskInternal(queued_tasks_.front());
      queued_tasks_.pop();
    }
  }

  HACCEL hAccelTable =
      LoadAccelerators(hInstance, MAKEINTRESOURCE(IDC_CEFCLIENT));

  MSG msg;

  // Run the application message loop.
  while (GetMessage(&msg, NULL, 0, 0)) {
    // Allow processing of dialog messages.
    if (dialog_hwnd_ && IsDialogMessage(dialog_hwnd_, &msg))
      continue;

    if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg)) {
      TranslateMessage(&msg);
      DispatchMessage(&msg);
    }
  }

  {
    base::AutoLock lock_scope(lock_);

    // Destroy the message window.
    DestroyWindow(message_hwnd_);
    message_hwnd_ = NULL;
  }

  return static_cast<int>(msg.wParam);
}

void MainMessageLoopMultithreadedWin::Quit() {
  // Execute PostQuitMessage(0) on the main thread.
  PostClosure(base::Bind(::PostQuitMessage, 0));
}

void MainMessageLoopMultithreadedWin::PostTask(CefRefPtr<CefTask> task) {
  base::AutoLock lock_scope(lock_);
  PostTaskInternal(task);
}

bool MainMessageLoopMultithreadedWin::RunsTasksOnCurrentThread() const {
  return (thread_id_ == base::PlatformThread::CurrentId());
}

void MainMessageLoopMultithreadedWin::SetCurrentModelessDialog(
    HWND hWndDialog) {
  DCHECK(RunsTasksOnCurrentThread());

#if DCHECK_IS_ON()
  if (hWndDialog) {
    // A new dialog reference should not be set while one is currently set.
    DCHECK(!dialog_hwnd_);
  }
#endif
  dialog_hwnd_ = hWndDialog;
}

// static
HWND MainMessageLoopMultithreadedWin::CreateMessageWindow(HINSTANCE hInstance) {
  WNDCLASSEX wc = {0};
  wc.cbSize = sizeof(wc);
  wc.lpfnWndProc = MessageWndProc;
  wc.hInstance = hInstance;
  wc.lpszClassName = kWndClass;
  RegisterClassEx(&wc);

  return CreateWindow(kWndClass, 0, 0, 0, 0, 0, 0, HWND_MESSAGE, 0, hInstance,
                      0);
}

// static
LRESULT CALLBACK
MainMessageLoopMultithreadedWin::MessageWndProc(HWND hWnd,
                                                UINT message,
                                                WPARAM wParam,
                                                LPARAM lParam) {
  MainMessageLoopMultithreadedWin* self =
      GetUserDataPtr<MainMessageLoopMultithreadedWin*>(hWnd);

  if (self && message == self->task_message_id_) {
    // Execute the task.
    CefTask* task = reinterpret_cast<CefTask*>(wParam);
    task->Execute();

    // Release the reference added in PostTaskInternal. This will likely result
    // in |task| being deleted.
    task->Release();
  } else {
    switch (message) {
      case WM_NCDESTROY:
        // Clear the reference to |self|.
        SetUserDataPtr(hWnd, NULL);
        break;
    }
  }

  return DefWindowProc(hWnd, message, wParam, lParam);
}

void MainMessageLoopMultithreadedWin::PostTaskInternal(
    CefRefPtr<CefTask> task) {
  lock_.AssertAcquired();

  if (!message_hwnd_) {
    // Queue the task until the message loop starts running.
    queued_tasks_.push(task);
    return;
  }

  // Add a reference that will be released in MessageWndProc.
  task->AddRef();

  // Post the task for execution by the message window.
  PostMessage(message_hwnd_, task_message_id_,
              reinterpret_cast<WPARAM>(task.get()), 0);
}

}  // namespace client
