// Copyright 2018 The Fuchsia 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 <dirent.h>
#include <fcntl.h>
#include <stdio.h>
#include <sys/stat.h>
#include <sys/types.h>

#include <fuchsia/developer/tiles/cpp/fidl.h>
#include <fuchsia/ui/gfx/cpp/fidl.h>
#include <lib/fdio/directory.h>
#include <lib/fdio/fd.h>
#include <lib/fdio/fdio.h>
#include <lib/fsl/io/fd.h>
#include <lib/sys/cpp/service_directory.h>
#include <src/lib/files/unique_fd.h>
#include <src/lib/fxl/command_line.h>
#include <src/lib/fxl/memory/unique_object.h>
#include <src/lib/fxl/strings/string_number_conversions.h>
#include <string>

using ControllerPtr = fuchsia::developer::tiles::ControllerSyncPtr;

struct UniqueDIRTraits {
  static DIR* InvalidValue() { return nullptr; }
  static bool IsValid(DIR* value) { return value != nullptr; }
  static void Free(DIR* dir) { closedir(dir); }
};

using UniqueDIR = fxl::UniqueObject<DIR*, UniqueDIRTraits>;

void Usage() {
  printf(
      "Usage: tiles_ctl <command>\n"
      "  Supported commands:\n"
      "    start\n"
      "    add [--disable-focus] <url> [<args>...]\n"
      "    remove <key>\n"
      "    list\n"
      "    quit\n");
}

std::string FirstNumericEntryInDir(const UniqueDIR& dir) {
  for (struct dirent* de = readdir(dir.get()); de != nullptr;
       de = readdir(dir.get())) {
    char* name = de->d_name;
    if (!name[0] && name[0] == '.')
      continue;
    if (name[0] >= '0' && name[0] <= '9') {
      return std::string(name);
    }
  }
  return "";
}

ControllerPtr FindTiles() {
  std::string sys_realm_entry;
  UniqueDIR sys(opendir("/hub/r/sys/"));
  if (sys.is_valid()) {
    sys_realm_entry = FirstNumericEntryInDir(sys);
    if (sys_realm_entry == "") {
      fprintf(stderr, "Couldn't find entry in system realm\n");
      return {};
    }
  } else {
    sys.reset(opendir("/"));
    sys_realm_entry = "hub";
  }
  std::string tiles_name = sys_realm_entry + "/c/tiles.cmx/";
  fxl::UniqueFD tile_component(
      openat(dirfd(sys.get()), tiles_name.c_str(), O_DIRECTORY | O_RDONLY));
  if (!tile_component.is_valid()) {
    fprintf(stderr,
            "Couldn't find tiles component in realm\n"
            "To start a new instance of tiles, run 'tiles_ctl start'\n");
    return {};
  }

  UniqueDIR tile_component_dir(fdopendir(tile_component.get()));
  std::string tile_realm_entry = FirstNumericEntryInDir(tile_component_dir);
  if (tile_realm_entry == "") {
    fprintf(stderr, "Couldn't find entry in tile component\n");
    return {};
  }
  std::string svc_name = tile_realm_entry + "/out/public";
  fxl::UniqueFD tile_svc(openat(dirfd(tile_component_dir.get()),
                                svc_name.c_str(), O_DIRECTORY | O_RDONLY));
  if (!tile_svc.is_valid()) {
    fprintf(stderr, "Couldn't open tile service directory\n");
    return {};
  }

  zx::channel svc_channel = fsl::CloneChannelFromFileDescriptor(tile_svc.get());
  ControllerPtr tiles;
  zx_status_t st = fdio_service_connect_at(
      svc_channel.release(), fuchsia::developer::tiles::Controller::Name_,
      tiles.NewRequest().TakeChannel().get());
  if (st != ZX_OK) {
    fprintf(stderr, "Couldn't connect to tile service: %d\n", st);
    return {};
  }
  return tiles;
}

bool Start() {
  auto services = sys::ServiceDirectory::CreateFromNamespace();

  fuchsia::sys::LaunchInfo launch_info;
  launch_info.url = "fuchsia-pkg://fuchsia.com/tiles#meta/tiles.cmx";

  fuchsia::sys::LauncherSyncPtr launcher;
  services->Connect(launcher.NewRequest());

  return launcher->CreateComponent(std::move(launch_info), {}) == ZX_OK;
}

bool Add(std::string url, bool allow_focus, std::vector<std::string> args) {
  auto tiles = FindTiles();
  if (!tiles)
    return false;
  uint32_t key = 0;
  fidl::VectorPtr<std::string> arguments;
  for (const auto& it : args) {
    arguments.push_back(it);
  }
  if (tiles->AddTileFromURL(url, allow_focus, std::move(arguments), &key) !=
      ZX_OK)
    return false;
  printf("Tile added with key %u\n", key);
  return true;
}

bool Remove(uint32_t key) {
  auto tiles = FindTiles();
  if (!tiles)
    return false;
  return tiles->RemoveTile(key) == ZX_OK;
}

bool List() {
  auto tiles = FindTiles();
  if (!tiles)
    return false;

  std::vector<uint32_t> keys;
  std::vector<std::string> urls;
  std::vector<fuchsia::ui::gfx::vec3> sizes;
  std::vector<bool> focusabilities;

  if (tiles->ListTiles(&keys, &urls, &sizes, &focusabilities) != ZX_OK)
    return false;

  printf("Found %lu tiles:\n", keys.size());
  for (size_t i = 0u; i < keys.size(); ++i) {
    printf("Tile key %u url %s size %.1fx%.1fx%.1f%s\n", keys.at(i),
           (urls.at(i)).c_str(), sizes.at(i).x, sizes.at(i).y, sizes.at(i).z,
           focusabilities.at(i) ? " (unfocusable)" : "");
  }
  return true;
}

bool Quit() {
  auto tiles = FindTiles();
  if (!tiles)
    return false;

  return tiles->Quit() == ZX_OK;
}

int main(int argc, const char** argv) {
  auto command_line = fxl::CommandLineFromArgcArgv(argc, argv);

  const auto& positional_args = command_line.positional_args();

  if (positional_args.empty()) {
    Usage();
    return 1;
  }

  const auto& cmd = positional_args[0];

  if (cmd == "start") {
    if (!Start()) {
      return 1;
    }
  } else if (cmd == "add") {
    if (positional_args.size() < 2) {
      Usage();
      return 1;
    }

    bool allow_focus = positional_args[1] != "--disable-focus";
    if (!allow_focus && positional_args.size() < 3) {
      Usage();
      return 1;
    }
    int adjust = allow_focus ? 0 : 1;
    auto url = positional_args[1 + adjust];
    std::vector<std::string> component_args{
        std::next(positional_args.begin(), 2 + adjust), positional_args.end()};
    if (!Add(url, allow_focus, component_args)) {
      return 1;
    }
  } else if (cmd == "remove") {
    if (positional_args.size() < 2) {
      Usage();
      return 1;
    }
    uint32_t key;
    if (!fxl::StringToNumberWithError(positional_args[1], &key)) {
      Usage();
      return 1;
    }
    if (!Remove(key)) {
      return 1;
    }
  } else if (cmd == "list") {
    if (!List())
      return 1;
  } else if (cmd == "quit") {
    if (!Quit()) {
      return 1;
    }
  } else {
    Usage();
    return 1;
  }

  return 0;
}
