// Copyright 2014 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 <memory>
#include <string>
#include <sysexits.h>

#include <base/cancelable_callback.h>
#include <base/command_line.h>
#include <base/json/json_reader.h>
#include <base/logging.h>
#include <base/memory/ref_counted.h>
#include <base/memory/weak_ptr.h>
#include <base/strings/stringprintf.h>
#include <base/values.h>
#include <brillo/any.h>
#include <brillo/daemons/dbus_daemon.h>
#include <brillo/data_encoding.h>
#include <brillo/dbus/data_serialization.h>
#include <brillo/dbus/dbus_method_invoker.h>
#include <brillo/errors/error.h>
#include <brillo/strings/string_utils.h>
#include <brillo/variant_dictionary.h>
#include <dbus/bus.h>
#include <dbus/message.h>
#include <dbus/object_proxy.h>
#include <dbus/object_manager.h>
#include <dbus/values_util.h>

#include "buffet/dbus-proxies.h"

using brillo::Error;
using brillo::ErrorPtr;
using org::chromium::Buffet::ManagerProxyInterface;

namespace {

void usage() {
  printf(R"(Possible commands:
  - TestMethod <message>
  - CheckDeviceRegistered
  - GetDeviceInfo
  - RegisterDevice param1=val1&param2=val2...
  - AddCommand '{"name":"command_name","parameters":{}}'
  - UpdateState prop_name prop_value
  - GetState
  - PendingCommands
  - SetCommandVisibility pkg1.cmd1[,pkg2.cm2,...] [all|cloud|local|none]
)");
}

// Helpers for JsonToAny().
template <typename T>
brillo::Any GetJsonValue(const base::Value& json,
                         bool (base::Value::*fnc)(T*) const) {
  T val;
  CHECK((json.*fnc)(&val));
  return val;
}

template <typename T>
brillo::Any GetJsonList(const base::ListValue& list);  // Prototype.

// Converts a JSON value into an Any so it can be sent over D-Bus using
// UpdateState D-Bus method from Buffet.
brillo::Any JsonToAny(const base::Value& json) {
  brillo::Any prop_value;
  switch (json.GetType()) {
    case base::Value::Type::NONE:
      prop_value = nullptr;
      break;
    case base::Value::Type::BOOLEAN:
      prop_value = GetJsonValue<bool>(json, &base::Value::GetAsBoolean);
      break;
    case base::Value::Type::INTEGER:
      prop_value = GetJsonValue<int>(json, &base::Value::GetAsInteger);
      break;
    case base::Value::Type::DOUBLE:
      prop_value = GetJsonValue<double>(json, &base::Value::GetAsDouble);
      break;
    case base::Value::Type::STRING:
      prop_value = GetJsonValue<std::string>(json, &base::Value::GetAsString);
      break;
    case base::Value::Type::BINARY:
      LOG(FATAL) << "Binary values should not happen";
      break;
    case base::Value::Type::DICTIONARY: {
      const base::DictionaryValue* dict = nullptr;  // Still owned by |json|.
      CHECK(json.GetAsDictionary(&dict));
      brillo::VariantDictionary var_dict;
      base::DictionaryValue::Iterator it(*dict);
      while (!it.IsAtEnd()) {
        var_dict.emplace(it.key(), JsonToAny(it.value()));
        it.Advance();
      }
      prop_value = var_dict;
      break;
    }
    case base::Value::Type::LIST: {
      const base::ListValue* list = nullptr;  // Still owned by |json|.
      CHECK(json.GetAsList(&list));
      CHECK(!list->empty()) << "Unable to deduce the type of list elements.";
      switch ((*list->begin())->GetType()) {
        case base::Value::Type::BOOLEAN:
          prop_value = GetJsonList<bool>(*list);
          break;
        case base::Value::Type::INTEGER:
          prop_value = GetJsonList<int>(*list);
          break;
        case base::Value::Type::DOUBLE:
          prop_value = GetJsonList<double>(*list);
          break;
        case base::Value::Type::STRING:
          prop_value = GetJsonList<std::string>(*list);
          break;
        case base::Value::Type::DICTIONARY:
          prop_value = GetJsonList<brillo::VariantDictionary>(*list);
          break;
        default:
          LOG(FATAL) << "Unsupported JSON value type for list element: "
                     << (*list->begin())->GetType();
      }
      break;
    }
    default:
      LOG(FATAL) << "Unexpected JSON value type: " << json.GetType();
      break;
  }
  return prop_value;
}

template <typename T>
brillo::Any GetJsonList(const base::ListValue& list) {
  std::vector<T> val;
  val.reserve(list.GetSize());
  for (const base::Value& v : base::ValueReferenceAdapter(list))
    val.push_back(JsonToAny(v).Get<T>());
  return val;
}

class Daemon final : public brillo::DBusDaemon {
 public:
  Daemon() = default;

 protected:
  int OnInit() override {
    int return_code = brillo::DBusDaemon::OnInit();
    if (return_code != EX_OK)
      return return_code;

    object_manager_.reset(new org::chromium::Buffet::ObjectManagerProxy{bus_});
    return_code = ScheduleActions();
    if (return_code == EX_USAGE) {
      usage();
    }
    return return_code;
  }

  void OnShutdown(int* return_code) override {
    if (*return_code == EX_OK)
      *return_code = exit_code_;
  }

 private:
  int ScheduleActions() {
    auto args = base::CommandLine::ForCurrentProcess()->GetArgs();

    // Pop the command off of the args list.
    std::string command = args.front();
    args.erase(args.begin());
    base::Callback<void(ManagerProxyInterface*)> job;
    if (command.compare("TestMethod") == 0) {
      if (!args.empty() && !CheckArgs(command, args, 1))
        return EX_USAGE;
      std::string message;
      if (!args.empty())
        message = args.back();
      job = base::Bind(&Daemon::CallTestMethod, weak_factory_.GetWeakPtr(),
                       message);
    } else if (command.compare("CheckDeviceRegistered") == 0 ||
               command.compare("cr") == 0) {
      if (!CheckArgs(command, args, 0))
        return EX_USAGE;
      job = base::Bind(&Daemon::CallCheckDeviceRegistered,
                       weak_factory_.GetWeakPtr());
    } else if (command.compare("RegisterDevice") == 0 ||
               command.compare("rd") == 0) {
      if (!args.empty() && !CheckArgs(command, args, 1))
        return EX_USAGE;
      std::string dict;
      if (!args.empty())
        dict = args.back();
      job = base::Bind(&Daemon::CallRegisterDevice, weak_factory_.GetWeakPtr(),
                       dict);
    } else if (command.compare("UpdateState") == 0 ||
               command.compare("us") == 0) {
      if (!CheckArgs(command, args, 2))
        return EX_USAGE;
      job = base::Bind(&Daemon::CallUpdateState, weak_factory_.GetWeakPtr(),
                       args.front(), args.back());
    } else if (command.compare("GetState") == 0 || command.compare("gs") == 0) {
      if (!CheckArgs(command, args, 0))
        return EX_USAGE;
      job = base::Bind(&Daemon::CallGetState, weak_factory_.GetWeakPtr());
    } else if (command.compare("AddCommand") == 0 ||
               command.compare("ac") == 0) {
      if (!CheckArgs(command, args, 1))
        return EX_USAGE;
      job = base::Bind(&Daemon::CallAddCommand, weak_factory_.GetWeakPtr(),
                       args.back());
    } else if (command.compare("PendingCommands") == 0 ||
               command.compare("pc") == 0) {
      if (!CheckArgs(command, args, 0))
        return EX_USAGE;
      // CallGetPendingCommands relies on ObjectManager but it is being
      // initialized asynchronously without a way to get a callback when
      // it is ready to be used. So, just wait a bit before calling its
      // methods.
      base::MessageLoop::current()->task_runner()->PostDelayedTask(
          FROM_HERE,
          base::Bind(&Daemon::CallGetPendingCommands,
                     weak_factory_.GetWeakPtr()),
          base::TimeDelta::FromMilliseconds(100));
    } else {
      fprintf(stderr, "Unknown command: '%s'\n", command.c_str());
      return EX_USAGE;
    }
    if (!job.is_null())
      object_manager_->SetManagerAddedCallback(job);
    timeout_task_.Reset(
        base::Bind(&Daemon::OnJobTimeout, weak_factory_.GetWeakPtr()));
    base::MessageLoop::current()->task_runner()->PostDelayedTask(
        FROM_HERE, timeout_task_.callback(), base::TimeDelta::FromSeconds(10));

    return EX_OK;
  }

  void OnJobComplete() {
    timeout_task_.Cancel();
    Quit();
  }

  void OnJobTimeout() {
    fprintf(stderr, "Timed out before completing request.");
    Quit();
  }

  void ReportError(Error* error) {
    fprintf(stderr, "Failed to receive a response: %s\n",
            error->GetMessage().c_str());
    exit_code_ = EX_UNAVAILABLE;
    OnJobComplete();
  }

  bool CheckArgs(const std::string& command,
                 const std::vector<std::string>& args,
                 size_t expected_arg_count) {
    if (args.size() == expected_arg_count)
      return true;
    fprintf(stderr, "Invalid number of arguments for command '%s'\n",
            command.c_str());
    return false;
  }

  void CallTestMethod(const std::string& message,
                      ManagerProxyInterface* manager_proxy) {
    ErrorPtr error;
    std::string response_message;
    if (!manager_proxy->TestMethod(message, &response_message, &error)) {
      return ReportError(error.get());
    }
    printf("Received a response: %s\n", response_message.c_str());
    OnJobComplete();
  }

  void CallCheckDeviceRegistered(ManagerProxyInterface* manager_proxy) {
    ErrorPtr error;
    std::string device_id;
    if (!manager_proxy->CheckDeviceRegistered(&device_id, &error)) {
      return ReportError(error.get());
    }

    printf("Device ID: %s\n",
           device_id.empty() ? "<unregistered>" : device_id.c_str());
    OnJobComplete();
  }

  void CallRegisterDevice(const std::string& args,
                          ManagerProxyInterface* manager_proxy) {
    std::string ticket_id;
    if (!args.empty()) {
      auto key_values = brillo::data_encoding::WebParamsDecode(args);
      for (const auto& pair : key_values) {
        if (pair.first == "ticket_id")
          ticket_id = pair.second;
      }
    }

    ErrorPtr error;
    std::string device_id;
    if (!manager_proxy->RegisterDevice(ticket_id, &device_id, &error)) {
      return ReportError(error.get());
    }

    printf("Device registered: %s\n", device_id.c_str());
    OnJobComplete();
  }

  void CallUpdateState(const std::string& prop,
                       const std::string& value,
                       ManagerProxyInterface* manager_proxy) {
    ErrorPtr error;
    std::string error_message;
    std::unique_ptr<base::Value> json(
        base::JSONReader::ReadAndReturnError(value, base::JSON_PARSE_RFC,
                                             nullptr, &error_message)
            .release());
    if (!json) {
      Error::AddTo(&error, FROM_HERE, brillo::errors::json::kDomain,
                   brillo::errors::json::kParseError, error_message);
      return ReportError(error.get());
    }

    brillo::VariantDictionary property_set{{prop, JsonToAny(*json)}};
    if (!manager_proxy->UpdateState(property_set, &error)) {
      return ReportError(error.get());
    }
    OnJobComplete();
  }

  void CallGetState(ManagerProxyInterface* manager_proxy) {
    std::string json;
    ErrorPtr error;
    if (!manager_proxy->GetState(&json, &error)) {
      return ReportError(error.get());
    }
    printf("%s\n", json.c_str());
    OnJobComplete();
  }

  void CallAddCommand(const std::string& command,
                      ManagerProxyInterface* manager_proxy) {
    ErrorPtr error;
    std::string id;
    if (!manager_proxy->AddCommand(command, &id, &error)) {
      return ReportError(error.get());
    }
    OnJobComplete();
  }

  void CallGetPendingCommands() {
    printf("Pending commands:\n");
    for (auto* cmd : object_manager_->GetCommandInstances()) {
      printf("%10s - '%s' (id:%s)\n", cmd->state().c_str(), cmd->name().c_str(),
             cmd->id().c_str());
    }
    OnJobComplete();
  }

  std::unique_ptr<org::chromium::Buffet::ObjectManagerProxy> object_manager_;
  int exit_code_{EX_OK};
  base::CancelableCallback<void()> timeout_task_;

  base::WeakPtrFactory<Daemon> weak_factory_{this};
  DISALLOW_COPY_AND_ASSIGN(Daemon);
};

}  // anonymous namespace

int main(int argc, char** argv) {
  base::CommandLine::Init(argc, argv);
  base::CommandLine* cl = base::CommandLine::ForCurrentProcess();
  base::CommandLine::StringVector args = cl->GetArgs();
  if (args.empty()) {
    usage();
    return EX_USAGE;
  }

  Daemon daemon;
  return daemon.Run();
}
