// Copyright (c) 2012 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.

#include "chrome/browser/extensions/api/terminal/terminal_private_api.h"

#include "base/bind.h"
#include "base/json/json_writer.h"
#include "base/sys_info.h"
#include "base/values.h"
#include "chrome/browser/extensions/api/terminal/terminal_extension_helper.h"
#include "chrome/browser/extensions/event_router.h"
#include "chrome/browser/extensions/extension_service.h"
#include "chrome/browser/extensions/extension_system.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/common/extensions/api/terminal_private.h"
#include "chromeos/process_proxy/process_proxy_registry.h"
#include "content/public/browser/browser_thread.h"

namespace terminal_private = extensions::api::terminal_private;
namespace OnTerminalResize =
    extensions::api::terminal_private::OnTerminalResize;
namespace OpenTerminalProcess =
    extensions::api::terminal_private::OpenTerminalProcess;
namespace SendInput = extensions::api::terminal_private::SendInput;

namespace {

const char kCroshName[] = "crosh";
const char kCroshCommand[] = "/usr/bin/crosh";
// We make stubbed crosh just echo back input.
const char kStubbedCroshCommand[] = "cat";

const char* GetCroshPath() {
  if (base::SysInfo::IsRunningOnChromeOS())
    return kCroshCommand;
  else
    return kStubbedCroshCommand;
}

const char* GetProcessCommandForName(const std::string& name) {
  if (name == kCroshName)
    return GetCroshPath();
  else
    return NULL;
}

void NotifyProcessOutput(Profile* profile,
                         const std::string& extension_id,
                         pid_t pid,
                         const std::string& output_type,
                         const std::string& output) {
  if (!content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)) {
    content::BrowserThread::PostTask(content::BrowserThread::UI, FROM_HERE,
        base::Bind(&NotifyProcessOutput, profile, extension_id,
                                         pid, output_type, output));
    return;
  }

  scoped_ptr<base::ListValue> args(new base::ListValue());
  args->Append(new base::FundamentalValue(pid));
  args->Append(new base::StringValue(output_type));
  args->Append(new base::StringValue(output));

  if (profile &&
      extensions::ExtensionSystem::Get(profile)->event_router()) {
    scoped_ptr<extensions::Event> event(new extensions::Event(
        terminal_private::OnProcessOutput::kEventName, args.Pass()));
    extensions::ExtensionSystem::Get(profile)->event_router()->
        DispatchEventToExtension(extension_id, event.Pass());
  }
}

}  // namespace

namespace extensions {

TerminalPrivateFunction::TerminalPrivateFunction() {}

TerminalPrivateFunction::~TerminalPrivateFunction() {}

bool TerminalPrivateFunction::RunImpl() {
  return RunTerminalFunction();
}

TerminalPrivateOpenTerminalProcessFunction::
    TerminalPrivateOpenTerminalProcessFunction() : command_(NULL) {}

TerminalPrivateOpenTerminalProcessFunction::
    ~TerminalPrivateOpenTerminalProcessFunction() {}

bool TerminalPrivateOpenTerminalProcessFunction::RunTerminalFunction() {
  scoped_ptr<OpenTerminalProcess::Params> params(
      OpenTerminalProcess::Params::Create(*args_));
  EXTENSION_FUNCTION_VALIDATE(params.get());

  command_ = GetProcessCommandForName(params->process_name);
  if (!command_) {
    error_ = "Invalid process name.";
    return false;
  }

  // Registry lives on FILE thread.
  content::BrowserThread::PostTask(content::BrowserThread::FILE, FROM_HERE,
      base::Bind(&TerminalPrivateOpenTerminalProcessFunction::OpenOnFileThread,
                 this));
  return true;
}

void TerminalPrivateOpenTerminalProcessFunction::OpenOnFileThread() {
  DCHECK(command_);

  chromeos::ProcessProxyRegistry* registry =
      chromeos::ProcessProxyRegistry::Get();
  pid_t pid;
  if (!registry->OpenProcess(
          command_, &pid,
          base::Bind(&NotifyProcessOutput, profile_, extension_id()))) {
    // If new process could not be opened, we return -1.
    pid = -1;
  }

  content::BrowserThread::PostTask(content::BrowserThread::UI, FROM_HERE,
      base::Bind(&TerminalPrivateOpenTerminalProcessFunction::RespondOnUIThread,
                 this, pid));
}

TerminalPrivateSendInputFunction::~TerminalPrivateSendInputFunction() {}

void TerminalPrivateOpenTerminalProcessFunction::RespondOnUIThread(pid_t pid) {
  SetResult(new base::FundamentalValue(pid));
  SendResponse(true);
}

bool TerminalPrivateSendInputFunction::RunTerminalFunction() {
  scoped_ptr<SendInput::Params> params(SendInput::Params::Create(*args_));
  EXTENSION_FUNCTION_VALIDATE(params.get());

  // Registry lives on the FILE thread.
  content::BrowserThread::PostTask(content::BrowserThread::FILE, FROM_HERE,
      base::Bind(&TerminalPrivateSendInputFunction::SendInputOnFileThread,
                 this, params->pid, params->input));
  return true;
}

void TerminalPrivateSendInputFunction::SendInputOnFileThread(pid_t pid,
    const std::string& text) {
  bool success = chromeos::ProcessProxyRegistry::Get()->SendInput(pid, text);

  content::BrowserThread::PostTask(content::BrowserThread::UI, FROM_HERE,
      base::Bind(&TerminalPrivateSendInputFunction::RespondOnUIThread, this,
      success));
}

void TerminalPrivateSendInputFunction::RespondOnUIThread(bool success) {
  SetResult(new base::FundamentalValue(success));
  SendResponse(true);
}

TerminalPrivateCloseTerminalProcessFunction::
    ~TerminalPrivateCloseTerminalProcessFunction() {}

bool TerminalPrivateCloseTerminalProcessFunction::RunTerminalFunction() {
  if (args_->GetSize() != 1)
    return false;
  pid_t pid;
  if (!args_->GetInteger(0, &pid))
    return false;

  // Registry lives on the FILE thread.
  content::BrowserThread::PostTask(content::BrowserThread::FILE, FROM_HERE,
      base::Bind(&TerminalPrivateCloseTerminalProcessFunction::
                 CloseOnFileThread, this, pid));

  return true;
}

void TerminalPrivateCloseTerminalProcessFunction::CloseOnFileThread(pid_t pid) {
  bool success = chromeos::ProcessProxyRegistry::Get()->CloseProcess(pid);

  content::BrowserThread::PostTask(content::BrowserThread::UI, FROM_HERE,
      base::Bind(&TerminalPrivateCloseTerminalProcessFunction::
                 RespondOnUIThread, this, success));
}

void TerminalPrivateCloseTerminalProcessFunction::RespondOnUIThread(
    bool success) {
  SetResult(new base::FundamentalValue(success));
  SendResponse(true);
}

TerminalPrivateOnTerminalResizeFunction::
    ~TerminalPrivateOnTerminalResizeFunction() {}

bool TerminalPrivateOnTerminalResizeFunction::RunTerminalFunction() {
  scoped_ptr<OnTerminalResize::Params> params(
      OnTerminalResize::Params::Create(*args_));
  EXTENSION_FUNCTION_VALIDATE(params.get());

  // Registry lives on the FILE thread.
  content::BrowserThread::PostTask(content::BrowserThread::FILE, FROM_HERE,
      base::Bind(&TerminalPrivateOnTerminalResizeFunction::OnResizeOnFileThread,
                 this, params->pid, params->width, params->height));

  return true;
}

void TerminalPrivateOnTerminalResizeFunction::OnResizeOnFileThread(pid_t pid,
                                                    int width, int height) {
  bool success = chromeos::ProcessProxyRegistry::Get()->OnTerminalResize(
      pid, width, height);

  content::BrowserThread::PostTask(content::BrowserThread::UI, FROM_HERE,
      base::Bind(&TerminalPrivateOnTerminalResizeFunction::RespondOnUIThread,
                 this, success));
}

void TerminalPrivateOnTerminalResizeFunction::RespondOnUIThread(bool success) {
  SetResult(new base::FundamentalValue(success));
  SendResponse(true);
}

}  // namespace extensions
