// Copyright (c) 2012 The Chromium OS 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 "dbus_test.h"

#include <stdlib.h>
#include <sys/select.h>
#include <unistd.h>

#include <algorithm>

namespace {

const char kServerAddress[] = "unix:abstract=/org/chromium/DBusTest";

}  // namespace

DBusMatch::DBusMatch()
    : message_type_(DBUS_MESSAGE_TYPE_INVALID),
      as_property_dictionary_(false),
      send_reply_(false),
      send_error_(false),
      expect_serial_(false),
      matched_(false) {}

DBusMatch& DBusMatch::WithString(std::string value) {
  Arg arg;
  arg.type = DBUS_TYPE_STRING;
  arg.array = false;
  arg.string_value = value;

  if (send_reply_)
    reply_args_.push_back(arg);
  else
    args_.push_back(arg);
  return *this;
}

DBusMatch& DBusMatch::WithUnixFd(int value) {
  Arg arg;
  arg.type = DBUS_TYPE_UNIX_FD;
  arg.array = false;
  arg.int_value = value;

  if (send_reply_)
    reply_args_.push_back(arg);
  else
    args_.push_back(arg);
  return *this;
}

DBusMatch& DBusMatch::WithObjectPath(std::string value) {
  Arg arg;
  arg.type = DBUS_TYPE_OBJECT_PATH;
  arg.array = false;
  arg.string_value = value;

  if (send_reply_)
    reply_args_.push_back(arg);
  else
    args_.push_back(arg);
  return *this;
}

DBusMatch& DBusMatch::WithArrayOfStrings(std::vector<std::string> values) {
  Arg arg;
  arg.type = DBUS_TYPE_STRING;
  arg.array = true;
  arg.string_values = values;

  if (send_reply_)
    reply_args_.push_back(arg);
  else
    args_.push_back(arg);
  return *this;
}

DBusMatch& DBusMatch::WithArrayOfObjectPaths(std::vector<std::string> values) {
  Arg arg;
  arg.type = DBUS_TYPE_OBJECT_PATH;
  arg.array = true;
  arg.string_values = values;

  if (send_reply_)
    reply_args_.push_back(arg);
  else
    args_.push_back(arg);
  return *this;
}

DBusMatch& DBusMatch::WithNoMoreArgs() {
  Arg arg;
  arg.type = DBUS_TYPE_INVALID;

  args_.push_back(arg);
  return *this;
}

DBusMatch& DBusMatch::AsPropertyDictionary() {
  as_property_dictionary_ = true;
  return *this;
}

DBusMatch& DBusMatch::SendReply() {
  send_reply_ = true;
  expect_serial_ = true;
  return *this;
}

DBusMatch& DBusMatch::SendError(std::string error_name,
                                std::string error_message) {
  send_error_ = true;
  error_name_ = error_name;
  error_message_ = error_message;
  expect_serial_ = true;
  return *this;
}

DBusMatch& DBusMatch::SendReplyNoWait() {
  send_reply_ = true;
  expect_serial_ = false;
  return *this;
}

DBusMatch& DBusMatch::Send() {
  DBusMessage* message;
  if (message_type_ == DBUS_MESSAGE_TYPE_SIGNAL)
    message = dbus_message_new_signal(path_.c_str(), interface_.c_str(),
                                      member_.c_str());
  else if (message_type_ == DBUS_MESSAGE_TYPE_METHOD_CALL)
    message = dbus_message_new_method_call(NULL, path_.c_str(),
                                           interface_.c_str(), member_.c_str());
  else
    return *this;

  AppendArgsToMessage(message, &args_);
  SendMessage(conn_, message);

  dbus_message_unref(message);

  return *this;
}

void DBusMatch::ExpectMethodCall(std::string path,
                                 std::string interface,
                                 std::string method) {
  message_type_ = DBUS_MESSAGE_TYPE_METHOD_CALL;
  path_ = path;
  interface_ = interface;
  member_ = method;
}

void DBusMatch::CreateSignal(DBusConnection* conn,
                             std::string path,
                             std::string interface,
                             std::string signal_name) {
  message_type_ = DBUS_MESSAGE_TYPE_SIGNAL;
  path_ = path;
  interface_ = interface;
  member_ = signal_name;

  conn_ = conn;
  expect_serial_ = true;
  matched_ = true;
}

void DBusMatch::CreateMessageCall(DBusConnection* conn,
                                  std::string path,
                                  std::string interface,
                                  std::string method_name) {
  message_type_ = DBUS_MESSAGE_TYPE_METHOD_CALL;
  path_ = path;
  interface_ = interface;
  member_ = method_name;

  conn_ = conn;
  expect_serial_ = true;
  matched_ = true;
}

bool DBusMatch::MatchMessageArgs(DBusMessage* message, std::vector<Arg>* args) {
  DBusMessageIter iter;
  dbus_message_iter_init(message, &iter);
  for (std::vector<Arg>::iterator it = args->begin(); it != args->end(); ++it) {
    Arg& arg = *it;

    int type = dbus_message_iter_get_arg_type(&iter);
    if (type != arg.type)
      return false;

    if (arg.type == DBUS_TYPE_STRING || arg.type == DBUS_TYPE_OBJECT_PATH) {
      const char* str_value;
      dbus_message_iter_get_basic(&iter, &str_value);
      if (strcmp(str_value, arg.string_value.c_str()) != 0)
        return false;
    }
    // TODO(keybuk): additional argument types

    dbus_message_iter_next(&iter);
  }

  return true;
}

void DBusMatch::AppendArgsToMessage(DBusMessage* message,
                                    std::vector<Arg>* args) {
  DBusMessageIter message_iter;
  DBusMessageIter dict_array_iter;
  DBusMessageIter struct_iter;
  DBusMessageIter iter;

  if (as_property_dictionary_) {
    dbus_message_iter_init_append(message, &message_iter);
    dbus_message_iter_open_container(&message_iter, DBUS_TYPE_ARRAY, "{sv}",
                                     &dict_array_iter);
  } else {
    dbus_message_iter_init_append(message, &iter);
  }

  for (std::vector<Arg>::iterator it = args->begin(); it != args->end(); ++it) {
    Arg& arg = *it;

    if (as_property_dictionary_) {
      dbus_message_iter_open_container(&dict_array_iter, DBUS_TYPE_DICT_ENTRY,
                                       NULL, &struct_iter);

      const char* str_value = arg.string_value.c_str();
      dbus_message_iter_append_basic(&struct_iter, arg.type, &str_value);

      arg = *(++it);
    }

    const char *array_type, *element_type;
    switch (arg.type) {
      case DBUS_TYPE_STRING:
        array_type = DBUS_TYPE_ARRAY_AS_STRING DBUS_TYPE_STRING_AS_STRING;
        element_type = DBUS_TYPE_STRING_AS_STRING;
        break;
      case DBUS_TYPE_OBJECT_PATH:
        array_type = DBUS_TYPE_ARRAY_AS_STRING DBUS_TYPE_OBJECT_PATH_AS_STRING;
        element_type = DBUS_TYPE_OBJECT_PATH_AS_STRING;
        break;
      case DBUS_TYPE_UNIX_FD:
        array_type = DBUS_TYPE_ARRAY_AS_STRING DBUS_TYPE_UNIX_FD_AS_STRING;
        element_type = DBUS_TYPE_UNIX_FD_AS_STRING;
        break;
      default:
        abort();
        // TODO(keybuk): additional argument types
    }

    if (as_property_dictionary_) {
      dbus_message_iter_open_container(&struct_iter, DBUS_TYPE_VARIANT,
                                       arg.array ? array_type : element_type,
                                       &iter);
    }

    DBusMessageIter array_iter;
    if (arg.array) {
      dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, element_type,
                                       &array_iter);

      if (arg.type == DBUS_TYPE_STRING || arg.type == DBUS_TYPE_OBJECT_PATH) {
        for (std::vector<std::string>::const_iterator vit =
                 arg.string_values.begin();
             vit != arg.string_values.end(); ++vit) {
          const char* str_value = vit->c_str();
          dbus_message_iter_append_basic(&array_iter, arg.type, &str_value);
        }
      }
      // TODO(keybuk): additional element types

      dbus_message_iter_close_container(&iter, &array_iter);
    } else {
      if (arg.type == DBUS_TYPE_STRING || arg.type == DBUS_TYPE_OBJECT_PATH) {
        const char* str_value = arg.string_value.c_str();
        dbus_message_iter_append_basic(&iter, arg.type, &str_value);
      } else if (arg.type == DBUS_TYPE_UNIX_FD) {
        dbus_message_iter_append_basic(&iter, arg.type, &arg.int_value);
      }
      // TODO(keybuk): additional argument types
    }

    if (as_property_dictionary_) {
      dbus_message_iter_close_container(&struct_iter, &iter);
      dbus_message_iter_close_container(&dict_array_iter, &struct_iter);
    }
  }

  if (as_property_dictionary_)
    dbus_message_iter_close_container(&message_iter, &dict_array_iter);
}

void DBusMatch::SendMessage(DBusConnection* conn, DBusMessage* message) {
  dbus_bool_t success;
  dbus_uint32_t serial;
  success = dbus_connection_send(conn, message, &serial);

  if (success && expect_serial_)
    expected_serials_.push_back(serial);
}

bool DBusMatch::HandleServerMessage(DBusConnection* conn,
                                    DBusMessage* message) {
  // Make sure we're expecting a method call or signal of this name
  if (message_type_ == DBUS_MESSAGE_TYPE_METHOD_CALL &&
      !dbus_message_is_method_call(message, interface_.c_str(),
                                   member_.c_str()))
    return false;
  else if (message_type_ == DBUS_MESSAGE_TYPE_SIGNAL &&
           !dbus_message_is_signal(message, interface_.c_str(),
                                   member_.c_str()))
    return false;

  // Make sure the path is what we expected.
  if (path_.length() &&
      strcmp(path_.c_str(), dbus_message_get_path(message)) != 0)
    return false;

  // And the arguments.
  if (!MatchMessageArgs(message, &args_))
    return false;

  // Handle any actions.
  matched_ = true;
  if (send_reply_ || send_error_) {
    // Send out the reply
    DBusMessage* reply = NULL;
    if (send_reply_)
      reply = dbus_message_new_method_return(message);
    else if (send_error_)
      reply = dbus_message_new_error(message, error_name_.c_str(),
                                     error_message_.c_str());

    AppendArgsToMessage(reply, &reply_args_);
    SendMessage(conn, reply);

    dbus_message_unref(reply);
  }

  return true;
}

bool DBusMatch::HandleClientMessage(DBusConnection* conn,
                                    DBusMessage* message) {
  // From the client side we check whether the message has a serial number
  // we generated on our server side, and if so, remove it from the list of
  // those we're expecting to see.
  for (std::vector<dbus_uint32_t>::iterator it = expected_serials_.begin();
       it != expected_serials_.end(); ++it) {
    if (*it == dbus_message_get_serial(message)) {
      expected_serials_.erase(it);
      return true;
    }
  }

  return false;
}

bool DBusMatch::Complete() {
  return matched_ && expected_serials_.size() == 0;
}

DBusTest::DBusTest()
    : conn_(NULL), server_(NULL), server_conn_(NULL), dispatch_(false) {}

DBusTest::~DBusTest() {}

DBusMatch& DBusTest::ExpectMethodCall(std::string path,
                                      std::string interface,
                                      std::string method) {
  DBusMatch match;
  match.ExpectMethodCall(path, interface, method);
  pthread_mutex_lock(&mutex_);
  matches_.push_back(match);
  DBusMatch& ref = matches_.back();
  pthread_mutex_unlock(&mutex_);
  return ref;
}

DBusMatch& DBusTest::CreateSignal(std::string path,
                                  std::string interface,
                                  std::string signal_name) {
  DBusMatch match;
  match.CreateSignal(server_conn_, path, interface, signal_name);
  pthread_mutex_lock(&mutex_);
  matches_.push_back(match);
  DBusMatch& ref = matches_.back();
  pthread_mutex_unlock(&mutex_);
  return ref;
}

DBusMatch& DBusTest::CreateMessageCall(std::string path,
                                       std::string interface,
                                       std::string signal_name) {
  DBusMatch match;
  match.CreateMessageCall(server_conn_, path, interface, signal_name);
  pthread_mutex_lock(&mutex_);
  matches_.push_back(match);
  DBusMatch& ref = matches_.back();
  pthread_mutex_unlock(&mutex_);
  return ref;
}

void DBusTest::WaitForMatches() {
  for (;;) {
    pthread_mutex_lock(&mutex_);
    size_t incomplete_matches = 0;
    for (std::vector<DBusMatch>::iterator it = matches_.begin();
         it != matches_.end(); ++it) {
      DBusMatch& match = *it;
      if (!match.Complete())
        ++incomplete_matches;
    }
    pthread_mutex_unlock(&mutex_);

    if (!incomplete_matches)
      break;

    // Fish a message from the queue.
    DBusMessage* message;
    while ((message = dbus_connection_borrow_message(conn_)) == NULL)
      dbus_connection_read_write(conn_, -1);

    // Allow matches to verify the serial of the message.
    pthread_mutex_lock(&mutex_);
    for (std::vector<DBusMatch>::iterator it = matches_.begin();
         it != matches_.end(); ++it) {
      DBusMatch& match = *it;

      if (match.HandleClientMessage(conn_, message))
        break;
    }
    pthread_mutex_unlock(&mutex_);

    // Throw it back and dispatch.
    dbus_connection_return_message(conn_, message);
    dbus_connection_dispatch(conn_);
  }

  pthread_mutex_lock(&mutex_);
  matches_.erase(matches_.begin(), matches_.end());
  pthread_mutex_unlock(&mutex_);
}

void DBusTest::SetUp() {
  dbus_threads_init_default();

  // Create the D-Bus server that will accept a connection for us, since
  // there's no "just give me a socketpair" option in libdbus.
  server_ = dbus_server_listen(kServerAddress, NULL);
  ASSERT_TRUE(server_ != NULL);

  dbus_server_set_new_connection_function(server_, NewConnectionThunk, this,
                                          NULL);

  dbus_bool_t success;
  success = dbus_server_set_watch_functions(
      server_, AddWatchThunk, RemoveWatchThunk, WatchToggledThunk, this, NULL);
  ASSERT_TRUE(success);

  success = dbus_server_set_timeout_functions(server_, AddTimeoutThunk,
                                              RemoveTimeoutThunk,
                                              TimeoutToggledThunk, this, NULL);
  ASSERT_TRUE(success);

  // Open a connection to our server, this returns the "client" side of the
  // connection.
  conn_ = dbus_connection_open_private(kServerAddress, NULL);
  ASSERT_TRUE(conn_ != NULL);

  // The "server" side of the connection comes from the NewConnection method
  // we set above. Dispatch until we have it.
  while (!server_conn_)
    DispatchOnce();

  // Now we set off "main loop" in the background to dispatch until the
  // client is disconnected by the TearDown method.
  int r;
  r = pthread_mutex_init(&mutex_, NULL);
  ASSERT_EQ(0, r);

  dispatch_ = true;
  r = pthread_create(&thread_id_, NULL, DispatchLoopThunk, this);
  ASSERT_EQ(0, r);
}

void DBusTest::TearDown() {
  WaitForMatches();

  // Close the client end of the connection, this will result in a signal
  // within the dispatch loop of the server.
  if (conn_) {
    dbus_connection_flush(conn_);
    dbus_connection_close(conn_);
    dbus_connection_unref(conn_);
    conn_ = NULL;
  }

  // Join the thread and wait for it to finish dispatch.
  if (dispatch_)
    pthread_join(thread_id_, NULL);
  pthread_mutex_destroy(&mutex_);

  // Clean up the server end of the connection and the server itself.
  if (server_conn_) {
    dbus_connection_flush(server_conn_);
    dbus_connection_close(server_conn_);
    dbus_connection_unref(server_conn_);
    server_conn_ = NULL;
  }

  dbus_server_disconnect(server_);
  dbus_server_unref(server_);
  server_ = NULL;

  dbus_shutdown();
}

void DBusTest::NewConnectionThunk(DBusServer* server,
                                  DBusConnection* conn,
                                  void* data) {
  DBusTest* test = static_cast<DBusTest*>(data);
  test->NewConnection(server, conn);
}

void DBusTest::NewConnection(DBusServer* server, DBusConnection* conn) {
  ASSERT_TRUE(server_conn_ == NULL);

  dbus_bool_t success;
  success = dbus_connection_set_watch_functions(
      conn, AddWatchThunk, RemoveWatchThunk, WatchToggledThunk, this, NULL);
  ASSERT_TRUE(success);

  success = dbus_connection_set_timeout_functions(
      conn, AddTimeoutThunk, RemoveTimeoutThunk, TimeoutToggledThunk, this,
      NULL);
  ASSERT_TRUE(success);

  success = dbus_connection_add_filter(conn, HandleMessageThunk, this, NULL);
  ASSERT_TRUE(success);

  server_conn_ = conn;
  dbus_connection_ref(server_conn_);
}

dbus_bool_t DBusTest::AddWatchThunk(DBusWatch* watch, void* data) {
  DBusTest* test = static_cast<DBusTest*>(data);
  return test->AddWatch(watch);
}

dbus_bool_t DBusTest::AddWatch(DBusWatch* watch) {
  watches_.push_back(watch);
  return TRUE;
}

void DBusTest::RemoveWatchThunk(DBusWatch* watch, void* data) {
  DBusTest* test = static_cast<DBusTest*>(data);
  test->RemoveWatch(watch);
}

void DBusTest::RemoveWatch(DBusWatch* watch) {
  std::vector<DBusWatch*>::iterator it =
      find(watches_.begin(), watches_.end(), watch);
  if (it != watches_.end())
    watches_.erase(it);
}

void DBusTest::WatchToggledThunk(DBusWatch* watch, void* data) {
  DBusTest* test = static_cast<DBusTest*>(data);
  test->WatchToggled(watch);
}

void DBusTest::WatchToggled(DBusWatch* watch) {}

dbus_bool_t DBusTest::AddTimeoutThunk(DBusTimeout* timeout, void* data) {
  DBusTest* test = static_cast<DBusTest*>(data);
  return test->AddTimeout(timeout);
}

dbus_bool_t DBusTest::AddTimeout(DBusTimeout* timeout) {
  timeouts_.push_back(timeout);
  return TRUE;
}

void DBusTest::RemoveTimeoutThunk(DBusTimeout* timeout, void* data) {
  DBusTest* test = static_cast<DBusTest*>(data);
  test->RemoveTimeout(timeout);
}

void DBusTest::RemoveTimeout(DBusTimeout* timeout) {
  std::vector<DBusTimeout*>::iterator it =
      find(timeouts_.begin(), timeouts_.end(), timeout);
  if (it != timeouts_.end())
    timeouts_.erase(it);
}

void DBusTest::TimeoutToggledThunk(DBusTimeout* timeout, void* data) {
  DBusTest* test = static_cast<DBusTest*>(data);
  test->TimeoutToggled(timeout);
}

void DBusTest::TimeoutToggled(DBusTimeout* timeout) {}

DBusHandlerResult DBusTest::HandleMessageThunk(DBusConnection* conn,
                                               DBusMessage* message,
                                               void* data) {
  DBusTest* test = static_cast<DBusTest*>(data);
  return test->HandleMessage(conn, message);
}

DBusHandlerResult DBusTest::HandleMessage(DBusConnection* conn,
                                          DBusMessage* message) {
  if (dbus_message_is_signal(message, DBUS_INTERFACE_LOCAL, "Disconnected")) {
    dispatch_ = false;
    return DBUS_HANDLER_RESULT_HANDLED;
  }

  pthread_mutex_lock(&mutex_);
  for (std::vector<DBusMatch>::iterator it = matches_.begin();
       it != matches_.end(); ++it) {
    DBusMatch& match = *it;

    if (match.HandleServerMessage(conn, message)) {
      pthread_mutex_unlock(&mutex_);
      return DBUS_HANDLER_RESULT_HANDLED;
    }
  }
  pthread_mutex_unlock(&mutex_);

  return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
}

void* DBusTest::DispatchLoopThunk(void* ptr) {
  DBusTest* test = static_cast<DBusTest*>(ptr);
  return test->DispatchLoop();
}

void* DBusTest::DispatchLoop() {
  while (dispatch_)
    DispatchOnce();

  return NULL;
}

void DBusTest::DispatchOnce() {
  fd_set readfds, writefds;
  int nfds = 0;
  int r;

  // Ideally we'd just use dbus_connection_read_write_dispatch() here, but
  // we have to deal with both the server itself and its connection, so we
  // have to do it all by hand.
  FD_ZERO(&readfds);
  FD_ZERO(&writefds);

  for (std::vector<DBusWatch*>::iterator it = watches_.begin();
       it != watches_.end(); ++it) {
    DBusWatch* watch = *it;

    if (!dbus_watch_get_enabled(watch))
      continue;

    int fd = dbus_watch_get_unix_fd(watch);
    if (fd + 1 > nfds)
      nfds = fd + 1;

    unsigned int flags = dbus_watch_get_flags(watch);
    if (flags & DBUS_WATCH_READABLE)
      FD_SET(fd, &readfds);
    if (flags & DBUS_WATCH_WRITABLE)
      FD_SET(fd, &writefds);
  }

  // Only block in select for the interval of the smallest timeout; this
  // isn't quite right according to the D-Bus spec, since the interval is
  // supposed to be since the time the timeout was added or toggled, but
  // it's good enough for the purposes of testing.
  DBusTimeout* earliest_timeout = NULL;
  struct timeval timeval;

  for (std::vector<DBusTimeout*>::iterator it = timeouts_.begin();
       it != timeouts_.end(); ++it) {
    DBusTimeout* timeout = *it;

    if (!dbus_timeout_get_enabled(timeout))
      continue;

    if (!earliest_timeout || (dbus_timeout_get_interval(timeout) <
                              dbus_timeout_get_interval(earliest_timeout)))
      earliest_timeout = timeout;
  }

  if (earliest_timeout) {
    int interval = dbus_timeout_get_interval(earliest_timeout);
    timeval.tv_sec = interval / 1000;
    timeval.tv_usec = (interval % 1000) * 1000;

    r = select(nfds, &readfds, &writefds, NULL, &timeval);
  } else {
    r = select(nfds, &readfds, &writefds, NULL, NULL);
  }

  ASSERT_LE(0, r);

  // Handle the timeout if we didn't poll for anything else.
  if (r == 0 && earliest_timeout)
    dbus_timeout_handle(earliest_timeout);

  // Handle the watches, use a copy of the vector since a watch handler
  // might remove other watches in the vector.
  std::vector<DBusWatch*> immutable_watches = watches_;
  for (std::vector<DBusWatch*>::iterator it = immutable_watches.begin();
       it != immutable_watches.end(); ++it) {
    DBusWatch* watch = *it;

    int fd = dbus_watch_get_unix_fd(watch);
    unsigned int flags = 0;

    if (FD_ISSET(fd, &readfds))
      flags |= DBUS_WATCH_READABLE;
    if (FD_ISSET(fd, &writefds))
      flags |= DBUS_WATCH_WRITABLE;

    if (flags)
      dbus_watch_handle(watch, flags);
  }

  // Dispatch data on the server-side of the connection.
  while (server_conn_ &&
         dbus_connection_dispatch(server_conn_) == DBUS_DISPATCH_DATA_REMAINS)
    ;
}
