/*
 * Copyright 2015 Google Inc. All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "cobalt/debug/debug_server.h"

#include <string>

#include "base/bind.h"
#include "base/location.h"
#include "base/logging.h"
#include "base/values.h"
#include "cobalt/debug/debug_client.h"

namespace cobalt {
namespace debug {

namespace {
// Error response message field.
const char kErrorMessage[] = "error.message";
const char kResult[] = "result";
}  // namespace

void DebugServer::AddClient(DebugClient* client) { clients_.insert(client); }

void DebugServer::RemoveClient(DebugClient* client) { clients_.erase(client); }

DebugServer::DebugServer(script::GlobalEnvironment* global_environment,
                         const dom::CspDelegate* csp_delegate)
    : ALLOW_THIS_IN_INITIALIZER_LIST(script_runner_(new DebugScriptRunner(
          global_environment, csp_delegate,
          base::Bind(&DebugServer::OnEventInternal, base::Unretained(this))))),
      message_loop_(MessageLoop::current()),
      is_paused_(false),
      // No manual reset, not initially signaled.
      command_added_while_paused_(false, false) {}

DebugServer::~DebugServer() {
  // Notify all clients.
  // |detach_reason| argument from set here:
  // https://developer.chrome.com/extensions/debugger#type-DetachReason
  const std::string detach_reason = "target_closed";
  for (std::set<DebugClient*>::iterator it = clients_.begin();
       it != clients_.end(); ++it) {
    (*it)->OnDetach(detach_reason);
  }
}

base::optional<std::string> DebugServer::CreateRemoteObject(
    const script::OpaqueHandleHolder* object, const std::string& params) {
  DCHECK(thread_checker_.CalledOnValidThread());
  return script_runner_->CreateRemoteObject(object, params);
}

void DebugServer::SendCommand(const std::string& method,
                              const std::string& json_params,
                              CommandCallback callback) {
  // Create a closure that will run the command and the response callback.
  // The task is either posted to the debug target (WebModule) thread if
  // that thread is running normally, or added to a queue of debugger tasks
  // being processed while paused.
  CommandCallbackInfo callback_info(callback);
  base::Closure command_and_callback_closure =
      base::Bind(&DebugServer::DispatchCommand, base::Unretained(this), method,
                 json_params, callback_info);

  if (is_paused_) {
    DispatchCommandWhilePaused(command_and_callback_closure);
  } else {
    message_loop_->PostTask(FROM_HERE, command_and_callback_closure);
  }
}

void DebugServer::DispatchCommand(std::string method, std::string json_params,
                                  CommandCallbackInfo callback_info) {
  DCHECK(thread_checker_.CalledOnValidThread());

  // Find the command in the registry and parse the JSON parameter string.
  // The |params| may be NULL, if the command takes no parameters.
  CommandRegistry::iterator iter = command_registry_.find(method);
  JSONObject params = JSONParse(json_params);
  JSONObject response;

  if (iter != command_registry_.end()) {
    // Everything is looking good so far - run the command function and take
    // ownership of the response object.
    response.reset(iter->second.Run(params).release());
  } else {
    DLOG(WARNING) << "Unknown command: " << method << ": " << json_params;
  }

  if (!response) {
    // Something went wrong, generate an error response.
    response.reset(new base::DictionaryValue());
    response->SetString("error.message", "Could not execute request.");
  }

  // Serialize the response object and run the callback.
  DCHECK(response);
  std::string json_response = JSONStringify(response);
  callback_info.message_loop->PostTask(
      FROM_HERE, base::Bind(callback_info.callback, json_response));
}

void DebugServer::DispatchCommandWhilePaused(
    const base::Closure& command_and_callback_closure) {
  // We are currently paused, so the debug target (WebModule) thread is
  // blocked and processing debugger commands locally. Add the command closure
  // to the queue of commands pending while paused and signal the blocked
  // thread to let it know there's something to do.
  base::AutoLock auto_lock(command_while_paused_lock_);
  DCHECK(is_paused_);
  commands_pending_while_paused_.push_back(command_and_callback_closure);
  command_added_while_paused_.Signal();
}

void DebugServer::HandlePause() {
  // Pauses JavaScript execution by blocking the debug target (WebModule)
  // thread while processing debugger commands that come in on other threads
  // (e.g. from DebugWebServer).

  // Must be called on the thread of the debug target (WebModule).
  DCHECK(thread_checker_.CalledOnValidThread());

  while (is_paused_) {
    command_added_while_paused_.Wait();

    while (true) {
      base::Closure task;
      {
        base::AutoLock auto_lock(command_while_paused_lock_);
        if (commands_pending_while_paused_.empty()) {
          break;
        }
        task = commands_pending_while_paused_.front();
        commands_pending_while_paused_.pop_front();
      }
      task.Run();
    }
  }
}

void DebugServer::OnEvent(const std::string& method, const JSONObject& params) {
  OnEventInternal(method, JSONStringify(params));
}

void DebugServer::OnEventInternal(
    const std::string& method, const base::optional<std::string>& json_params) {
  for (std::set<DebugClient*>::iterator it = clients_.begin();
       it != clients_.end(); ++it) {
    (*it)->OnEvent(method, json_params);
  }
}

void DebugServer::AddCommand(const std::string& method,
                             const Command& callback) {
  DCHECK_EQ(command_registry_.count(method), 0);
  command_registry_[method] = callback;
}

void DebugServer::RemoveCommand(const std::string& method) {
  DCHECK_EQ(command_registry_.count(method), 1);
  command_registry_.erase(method);
}

JSONObject DebugServer::RunScriptCommand(const std::string& command,
                                         const JSONObject& params) {
  std::string json_params = params ? JSONStringify(params) : "";
  std::string json_result;
  bool success = script_runner_->RunCommand(command, json_params, &json_result);

  JSONObject response(new base::DictionaryValue());
  if (success) {
    JSONObject result = JSONParse(json_result);
    if (result) {
      response->Set(kResult, result.release());
    }
  } else {
    response->SetString(kErrorMessage, json_result);
  }
  return response.Pass();
}

bool DebugServer::RunScriptFile(const std::string& filename) {
  return script_runner_->RunScriptFile(filename);
}

void DebugServer::SetPaused(bool is_paused) {
  // Must be called on the thread of the debug target (WebModule).
  DCHECK(thread_checker_.CalledOnValidThread());

  is_paused_ = is_paused;
  if (is_paused) {
    HandlePause();
  }
}

}  // namespace debug
}  // namespace cobalt
