// 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 "tools/android/forwarder2/host_controller.h"

#include <string>

#include "base/basictypes.h"
#include "base/bind.h"
#include "base/bind_helpers.h"
#include "base/logging.h"
#include "base/memory/scoped_ptr.h"
#include "tools/android/forwarder2/command.h"
#include "tools/android/forwarder2/forwarder.h"
#include "tools/android/forwarder2/socket.h"

namespace forwarder2 {

// static
scoped_ptr<HostController> HostController::Create(
    int device_port,
    int host_port,
    int adb_port,
    int exit_notifier_fd,
    const ErrorCallback& error_callback) {
  scoped_ptr<HostController> host_controller;
  scoped_ptr<PipeNotifier> delete_controller_notifier(new PipeNotifier());
  scoped_ptr<Socket> adb_control_socket(new Socket());
  adb_control_socket->AddEventFd(exit_notifier_fd);
  adb_control_socket->AddEventFd(delete_controller_notifier->receiver_fd());
  if (!adb_control_socket->ConnectTcp(std::string(), adb_port)) {
    LOG(ERROR) << "Could not connect HostController socket on port: "
               << adb_port;
    return host_controller.Pass();
  }
  // Send the command to the device start listening to the "device_forward_port"
  bool send_command_success = SendCommand(
      command::LISTEN, device_port, adb_control_socket.get());
  CHECK(send_command_success);
  int device_port_allocated;
  command::Type command;
  if (!ReadCommand(
          adb_control_socket.get(), &device_port_allocated, &command) ||
      command != command::BIND_SUCCESS) {
    LOG(ERROR) << "Device binding error using port " << device_port;
    return host_controller.Pass();
  }
  host_controller.reset(
      new HostController(
          device_port_allocated, host_port, adb_port, exit_notifier_fd,
          error_callback, adb_control_socket.Pass(),
          delete_controller_notifier.Pass()));
  return host_controller.Pass();
}

HostController::~HostController() {
  DCHECK(deletion_task_runner_->RunsTasksOnCurrentThread());
  delete_controller_notifier_->Notify();
}

void HostController::Start() {
  thread_.Start();
  ReadNextCommandSoon();
}

HostController::HostController(
    int device_port,
    int host_port,
    int adb_port,
    int exit_notifier_fd,
    const ErrorCallback& error_callback,
    scoped_ptr<Socket> adb_control_socket,
    scoped_ptr<PipeNotifier> delete_controller_notifier)
    : self_deleter_helper_(this, error_callback),
      device_port_(device_port),
      host_port_(host_port),
      adb_port_(adb_port),
      global_exit_notifier_fd_(exit_notifier_fd),
      adb_control_socket_(adb_control_socket.Pass()),
      delete_controller_notifier_(delete_controller_notifier.Pass()),
      deletion_task_runner_(base::MessageLoop::current()->task_runner()),
      thread_("HostControllerThread") {}

void HostController::ReadNextCommandSoon() {
  thread_.task_runner()->PostTask(
      FROM_HERE, base::Bind(&HostController::ReadCommandOnInternalThread,
                            base::Unretained(this)));
}

void HostController::ReadCommandOnInternalThread() {
  if (!ReceivedCommand(command::ACCEPT_SUCCESS, adb_control_socket_.get())) {
    LOG(ERROR) << "Did not receive ACCEPT_SUCCESS for port: "
               << host_port_;
    OnInternalThreadError();
    return;
  }
  // Try to connect to host server.
  scoped_ptr<Socket> host_server_data_socket(new Socket());
  if (!host_server_data_socket->ConnectTcp(std::string(), host_port_)) {
    LOG(ERROR) << "Could not Connect HostServerData socket on port: "
               << host_port_;
    SendCommand(
        command::HOST_SERVER_ERROR, device_port_, adb_control_socket_.get());
    if (ReceivedCommand(command::ACK, adb_control_socket_.get())) {
      // It can continue if the host forwarder could not connect to the host
      // server but the device acknowledged that, so that the device could
      // re-try later.
      ReadNextCommandSoon();
      return;
    }
    OnInternalThreadError();
    return;
  }
  LOG(INFO) << "Will send HOST_SERVER_SUCCESS: " << host_port_;
  SendCommand(
      command::HOST_SERVER_SUCCESS, device_port_, adb_control_socket_.get());
  StartForwarder(host_server_data_socket.Pass());
  ReadNextCommandSoon();
}

void HostController::StartForwarder(
    scoped_ptr<Socket> host_server_data_socket) {
  scoped_ptr<Socket> adb_data_socket(new Socket());
  if (!adb_data_socket->ConnectTcp("", adb_port_)) {
    LOG(ERROR) << "Could not connect AdbDataSocket on port: " << adb_port_;
    OnInternalThreadError();
    return;
  }
  // Open the Adb data connection, and send a command with the
  // |device_forward_port| as a way for the device to identify the connection.
  SendCommand(command::DATA_CONNECTION, device_port_, adb_data_socket.get());

  // Check that the device received the new Adb Data Connection. Note that this
  // check is done through the |adb_control_socket_| that is handled in the
  // DeviceListener thread just after the call to WaitForAdbDataSocket().
  if (!ReceivedCommand(command::ADB_DATA_SOCKET_SUCCESS,
                       adb_control_socket_.get())) {
    LOG(ERROR) << "Device could not handle the new Adb Data Connection.";
    OnInternalThreadError();
    return;
  }
  forwarders_manager_.CreateAndStartNewForwarder(
      host_server_data_socket.Pass(), adb_data_socket.Pass());
}

void HostController::OnInternalThreadError() {
  UnmapPortOnDevice();
  self_deleter_helper_.MaybeSelfDeleteSoon();
}

void HostController::UnmapPortOnDevice() {
  Socket socket;
  if (!socket.ConnectTcp("", adb_port_)) {
    LOG(ERROR) << "Could not connect to device on port " << adb_port_;
    return;
  }
  if (!SendCommand(command::UNLISTEN, device_port_, &socket)) {
    LOG(ERROR) << "Could not send unmap command for port " << device_port_;
    return;
  }
  if (!ReceivedCommand(command::UNLISTEN_SUCCESS, &socket)) {
    LOG(ERROR) << "Unamp command failed for port " << device_port_;
    return;
  }
}

}  // namespace forwarder2
