// 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/serial/serial_api.h"

#include <algorithm>

#include "base/values.h"
#include "chrome/browser/extensions/extension_system.h"
#include "chrome/browser/extensions/api/serial/serial_connection.h"
#include "chrome/browser/extensions/api/serial/serial_event_dispatcher.h"
#include "chrome/browser/extensions/api/serial/serial_port_enumerator.h"
#include "chrome/common/extensions/api/serial.h"
#include "content/public/browser/browser_thread.h"

using content::BrowserThread;

namespace extensions {

namespace api {

namespace {

// It's a fool's errand to come up with a default bitrate, because we don't get
// to control both sides of the communication. Unless the other side has
// implemented auto-bitrate detection (rare), if we pick the wrong rate, then
// you're gonna have a bad time. Close doesn't count.
//
// But we'd like to pick something that has a chance of working, and 9600 is a
// good balance between popularity and speed. So 9600 it is.
const int kDefaultBufferSize = 4096;
const int kDefaultBitrate = 9600;
const serial::DataBits kDefaultDataBits = serial::DATA_BITS_EIGHT;
const serial::ParityBit kDefaultParityBit = serial::PARITY_BIT_NO;
const serial::StopBits kDefaultStopBits = serial::STOP_BITS_ONE;
const int kDefaultReceiveTimeout = 0;
const int kDefaultSendTimeout = 0;

const char kErrorConnectFailed[] = "Failed to connect to the port.";
const char kErrorSerialConnectionNotFound[] = "Serial connection not found.";
const char kErrorGetControlSignalsFailed[] = "Failed to get control signals.";

template <class T>
void SetDefaultScopedPtrValue(scoped_ptr<T>& ptr, const T& value) {
  if (!ptr.get())
    ptr.reset(new T(value));
}

}  // namespace

SerialAsyncApiFunction::SerialAsyncApiFunction()
    : manager_(NULL) {
}

SerialAsyncApiFunction::~SerialAsyncApiFunction() {}

bool SerialAsyncApiFunction::PrePrepare() {
  manager_ = ApiResourceManager<SerialConnection>::Get(GetProfile());
  DCHECK(manager_);
  return true;
}

bool SerialAsyncApiFunction::Respond() {
  return error_.empty();
}

SerialConnection* SerialAsyncApiFunction::GetSerialConnection(
    int api_resource_id) {
  return manager_->Get(extension_->id(), api_resource_id);
}

void SerialAsyncApiFunction::RemoveSerialConnection(int api_resource_id) {
  manager_->Remove(extension_->id(), api_resource_id);
}

SerialGetDevicesFunction::SerialGetDevicesFunction() {}

bool SerialGetDevicesFunction::Prepare() {
  set_work_thread_id(BrowserThread::FILE);
  return true;
}

void SerialGetDevicesFunction::Work() {
  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));

  std::vector<linked_ptr<serial::DeviceInfo> > devices;
  SerialPortEnumerator::StringSet port_names =
      SerialPortEnumerator::GenerateValidSerialPortNames();
  for (SerialPortEnumerator::StringSet::const_iterator iter =
          port_names.begin();
       iter != port_names.end();
       ++iter) {
    linked_ptr<serial::DeviceInfo> info(new serial::DeviceInfo);
    info->path = *iter;
    devices.push_back(info);
  }
  results_ = serial::GetDevices::Results::Create(devices);
}

SerialConnectFunction::SerialConnectFunction() {}

SerialConnectFunction::~SerialConnectFunction() {}

bool SerialConnectFunction::Prepare() {
  params_ = serial::Connect::Params::Create(*args_);
  EXTENSION_FUNCTION_VALIDATE(params_.get());

  // Fill in any omitted options to ensure a known initial configuration.
  if (!params_->options.get())
    params_->options.reset(new serial::ConnectionOptions());
  serial::ConnectionOptions* options = params_->options.get();

  SetDefaultScopedPtrValue(options->persistent, false);
  SetDefaultScopedPtrValue(options->buffer_size, kDefaultBufferSize);
  SetDefaultScopedPtrValue(options->bitrate, kDefaultBitrate);
  SetDefaultScopedPtrValue(options->cts_flow_control, false);
  SetDefaultScopedPtrValue(options->receive_timeout, kDefaultReceiveTimeout);
  SetDefaultScopedPtrValue(options->send_timeout, kDefaultSendTimeout);

  if (options->data_bits == serial::DATA_BITS_NONE)
    options->data_bits = kDefaultDataBits;
  if (options->parity_bit == serial::PARITY_BIT_NONE)
    options->parity_bit = kDefaultParityBit;
  if (options->stop_bits == serial::STOP_BITS_NONE)
    options->stop_bits = kDefaultStopBits;

  serial_event_dispatcher_ = SerialEventDispatcher::Get(GetProfile());
  DCHECK(serial_event_dispatcher_);

  return true;
}

void SerialConnectFunction::AsyncWorkStart() {
  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
  connection_ = CreateSerialConnection(params_->path, extension_->id());
  connection_->Open(base::Bind(&SerialConnectFunction::OnConnected, this));
}

void SerialConnectFunction::OnConnected(bool success) {
  DCHECK(connection_);

  if (success) {
    if (!connection_->Configure(*params_->options.get())) {
      connection_->Close();
      delete connection_;
      connection_ = NULL;
    }
  } else {
    delete connection_;
    connection_ = NULL;
  }

  BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
                          base::Bind(&SerialConnectFunction::FinishConnect,
                                     this));
}

void SerialConnectFunction::FinishConnect() {
  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
  if (!connection_) {
    error_ = kErrorConnectFailed;
  } else {
    int id = manager_->Add(connection_);
    serial::ConnectionInfo info;
    info.connection_id = id;
    if (connection_->GetInfo(&info)) {
      serial_event_dispatcher_->PollConnection(extension_->id(), id);
      results_ = serial::Connect::Results::Create(info);
    } else {
      connection_->Close();
      RemoveSerialConnection(id);
      error_ = kErrorConnectFailed;
    }
  }
  AsyncWorkCompleted();
}

SerialConnection* SerialConnectFunction::CreateSerialConnection(
    const std::string& port, const std::string& extension_id) const {
  return new SerialConnection(port, extension_id);
}

SerialUpdateFunction::SerialUpdateFunction() {}

SerialUpdateFunction::~SerialUpdateFunction() {}

bool SerialUpdateFunction::Prepare() {
  params_ = serial::Update::Params::Create(*args_);
  EXTENSION_FUNCTION_VALIDATE(params_.get());

  return true;
}

void SerialUpdateFunction::Work() {
  SerialConnection* connection = GetSerialConnection(params_->connection_id);
  if (!connection) {
    error_ = kErrorSerialConnectionNotFound;
    return;
  }
  bool success = connection->Configure(params_->options);
  results_ = serial::Update::Results::Create(success);
}

SerialDisconnectFunction::SerialDisconnectFunction() {}

SerialDisconnectFunction::~SerialDisconnectFunction() {}

bool SerialDisconnectFunction::Prepare() {
  params_ = serial::Disconnect::Params::Create(*args_);
  EXTENSION_FUNCTION_VALIDATE(params_.get());

  return true;
}

void SerialDisconnectFunction::Work() {
  SerialConnection* connection = GetSerialConnection(params_->connection_id);
  if (!connection) {
    error_ = kErrorSerialConnectionNotFound;
    return;
  }
  connection->Close();
  RemoveSerialConnection(params_->connection_id);
  results_ = serial::Disconnect::Results::Create(true);
}

SerialSendFunction::SerialSendFunction() {}

SerialSendFunction::~SerialSendFunction() {}

bool SerialSendFunction::Prepare() {
  params_ = serial::Send::Params::Create(*args_);
  EXTENSION_FUNCTION_VALIDATE(params_.get());

  return true;
}

void SerialSendFunction::AsyncWorkStart() {
  SerialConnection* connection = GetSerialConnection(params_->connection_id);
  if (!connection) {
    error_ = kErrorSerialConnectionNotFound;
    AsyncWorkCompleted();
    return;
  }

  if (!connection->Send(params_->data,
                        base::Bind(&SerialSendFunction::OnSendComplete,
                                   this))) {
    OnSendComplete(0, serial::SEND_ERROR_PENDING);
  }
}

void SerialSendFunction::OnSendComplete(int bytes_sent,
                                        serial::SendError error) {
  serial::SendInfo send_info;
  send_info.bytes_sent = bytes_sent;
  send_info.error = error;
  results_ = serial::Send::Results::Create(send_info);
  AsyncWorkCompleted();
}

SerialFlushFunction::SerialFlushFunction() {}

SerialFlushFunction::~SerialFlushFunction() {}

bool SerialFlushFunction::Prepare() {
  params_ = serial::Flush::Params::Create(*args_);
  EXTENSION_FUNCTION_VALIDATE(params_.get());
  return true;
}

void SerialFlushFunction::Work() {
  SerialConnection* connection = GetSerialConnection(params_->connection_id);
  if (!connection) {
    error_ = kErrorSerialConnectionNotFound;
    return;
  }

  bool success = connection->Flush();
  results_ = serial::Flush::Results::Create(success);
}

SerialSetPausedFunction::SerialSetPausedFunction() {}

SerialSetPausedFunction::~SerialSetPausedFunction() {}

bool SerialSetPausedFunction::Prepare() {
  params_ = serial::SetPaused::Params::Create(*args_);
  EXTENSION_FUNCTION_VALIDATE(params_.get());

  serial_event_dispatcher_ = SerialEventDispatcher::Get(GetProfile());
  DCHECK(serial_event_dispatcher_);
  return true;
}

void SerialSetPausedFunction::Work() {
  SerialConnection* connection = GetSerialConnection(params_->connection_id);
  if (!connection) {
    error_ = kErrorSerialConnectionNotFound;
    return;
  }

  if (params_->paused != connection->paused()) {
    connection->set_paused(params_->paused);
    if (!params_->paused) {
      serial_event_dispatcher_->PollConnection(extension_->id(),
                                               params_->connection_id);
    }
  }

  results_ = serial::SetPaused::Results::Create();
}

SerialGetInfoFunction::SerialGetInfoFunction() {}

SerialGetInfoFunction::~SerialGetInfoFunction() {}

bool SerialGetInfoFunction::Prepare() {
  params_ = serial::GetInfo::Params::Create(*args_);
  EXTENSION_FUNCTION_VALIDATE(params_.get());

  return true;
}

void SerialGetInfoFunction::Work() {
  SerialConnection* connection = GetSerialConnection(params_->connection_id);
  if (!connection) {
    error_ = kErrorSerialConnectionNotFound;
    return;
  }

  serial::ConnectionInfo info;
  info.connection_id = params_->connection_id;
  connection->GetInfo(&info);
  results_ = serial::GetInfo::Results::Create(info);
}

SerialGetConnectionsFunction::SerialGetConnectionsFunction() {}

SerialGetConnectionsFunction::~SerialGetConnectionsFunction() {}

bool SerialGetConnectionsFunction::Prepare() {
  return true;
}

void SerialGetConnectionsFunction::Work() {
  std::vector<linked_ptr<serial::ConnectionInfo> > infos;
  const base::hash_set<int>* connection_ids = manager_->GetResourceIds(
      extension_->id());
  if (connection_ids) {
    for (base::hash_set<int>::const_iterator it = connection_ids->begin();
         it != connection_ids->end(); ++it) {
      int connection_id = *it;
      SerialConnection *connection = GetSerialConnection(connection_id);
      if (connection) {
        linked_ptr<serial::ConnectionInfo> info(new serial::ConnectionInfo());
        info->connection_id = connection_id;
        connection->GetInfo(info.get());
        infos.push_back(info);
      }
    }
  }
  results_ = serial::GetConnections::Results::Create(infos);
}

SerialGetControlSignalsFunction::SerialGetControlSignalsFunction() {}

SerialGetControlSignalsFunction::~SerialGetControlSignalsFunction() {}

bool SerialGetControlSignalsFunction::Prepare() {
  params_ = serial::GetControlSignals::Params::Create(*args_);
  EXTENSION_FUNCTION_VALIDATE(params_.get());

  return true;
}

void SerialGetControlSignalsFunction::Work() {
  SerialConnection* connection = GetSerialConnection(params_->connection_id);
  if (!connection) {
    error_ = kErrorSerialConnectionNotFound;
    return;
  }

  serial::DeviceControlSignals signals;
  if (!connection->GetControlSignals(&signals)) {
    error_ = kErrorGetControlSignalsFailed;
    return;
  }

  results_ = serial::GetControlSignals::Results::Create(signals);
}

SerialSetControlSignalsFunction::SerialSetControlSignalsFunction() {}

SerialSetControlSignalsFunction::~SerialSetControlSignalsFunction() {}

bool SerialSetControlSignalsFunction::Prepare() {
  params_ = serial::SetControlSignals::Params::Create(*args_);
  EXTENSION_FUNCTION_VALIDATE(params_.get());

  return true;
}

void SerialSetControlSignalsFunction::Work() {
  SerialConnection* connection = GetSerialConnection(params_->connection_id);
  if (!connection) {
    error_ = kErrorSerialConnectionNotFound;
    return;
  }

  bool success = connection->SetControlSignals(params_->signals);
  results_ = serial::SetControlSignals::Results::Create(success);
}

}  // namespace api

}  // namespace extensions
