// Copyright 2020 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 "args.h"

#include <lib/async-loop/cpp/loop.h>
#include <lib/async-loop/default.h>
#include <lib/fidl-async/cpp/bind.h>

#include <map>

#include <fbl/auto_lock.h>
#include <fbl/mutex.h>
#include <zxtest/zxtest.h>

class FakeBootArgsServer final : public llcpp::fuchsia::boot::Arguments::Interface {
 public:
  FakeBootArgsServer() {}

  void SetBool(std::string key, bool value) {
    fbl::AutoLock lock(&lock_);
    bools_.insert_or_assign(key, value);
  }

  void SetString(std::string key, std::string value) {
    fbl::AutoLock lock(&lock_);
    strings_.insert_or_assign(key, value);
  }

  // llcpp::fuchsia::boot::Arguments::Interface methods:
  void GetString(::fidl::StringView key, GetStringCompleter::Sync& completer) {
    completer.Close(ZX_ERR_NOT_SUPPORTED);
  }

  void GetStrings(::fidl::VectorView<::fidl::StringView> keys,
                  GetStringsCompleter::Sync& completer) {
    fbl::AutoLock lock(&lock_);
    std::vector<fidl::StringView> values;
    for (auto& key : keys) {
      std::string key_str = std::string(key.data(), key.size());
      auto value = strings_.find(key_str);
      if (value != strings_.end()) {
        values.push_back(fidl::unowned_str(value->second));
      } else {
        values.push_back(fidl::StringView(nullptr, 0));
      }
    }
    completer.Reply(fidl::VectorView<fidl::StringView>(
        fidl::unowned_ptr_t<fidl::StringView>(values.data()), values.size()));
  }

  void GetBool(::fidl::StringView key, bool defaultval, GetBoolCompleter::Sync& completer) {
    fbl::AutoLock lock(&lock_);
    bool result = defaultval;
    auto value = bools_.find(std::string(key.data()));
    if (value != bools_.end()) {
      result = value->second;
    }
    completer.Reply(result);
  }

  void GetBools(::fidl::VectorView<llcpp::fuchsia::boot::BoolPair> keys,
                GetBoolsCompleter::Sync& completer) {
    fbl::AutoLock lock(&lock_);
    std::vector<uint8_t> values;
    for (auto& bool_pair : keys) {
      bool result = bool_pair.defaultval;
      std::string key = std::string(bool_pair.key.data(), bool_pair.key.size());
      auto value = bools_.find(key);
      if (value != bools_.end()) {
        result = value->second;
      } else {
      }
      values.push_back(result);
    }
    completer.Reply(fidl::VectorView<bool>(
        fidl::unowned_ptr_t<bool>(reinterpret_cast<bool*>(values.data())), values.size()));
  }

  void Collect(::fidl::StringView prefix, CollectCompleter::Sync& completer) {
    completer.Close(ZX_ERR_NOT_SUPPORTED);
  }

 private:
  fbl::Mutex lock_;
  std::map<std::string, bool> bools_ __TA_GUARDED(lock_);
  std::map<std::string, std::string> strings_ __TA_GUARDED(lock_);
};

class ArgsTest : public zxtest::Test {
 public:
  ArgsTest() : loop_(&kAsyncLoopConfigNoAttachToCurrentThread) { ASSERT_OK(loop_.StartThread()); }

  void SetUp() override {
    zx::channel client, server;
    ASSERT_OK(zx::channel::create(0, &client, &server));
    boot_args_server_.reset(new FakeBootArgsServer());
    fidl::BindSingleInFlightOnly(loop_.dispatcher(), std::move(server), boot_args_server_.get());
    boot_args_client_ = llcpp::fuchsia::boot::Arguments::SyncClient(std::move(client));
  }

  std::unique_ptr<FakeBootArgsServer> boot_args_server_;
  llcpp::fuchsia::boot::Arguments::SyncClient boot_args_client_;

 private:
  async::Loop loop_;
};

TEST_F(ArgsTest, CheckDisabled) {
  Arguments args;

  boot_args_server_->SetBool("virtcon.disable", false);
  ASSERT_EQ(ParseArgs(boot_args_client_, &args), ZX_OK);
  ASSERT_FALSE(args.disable);

  boot_args_server_->SetBool("virtcon.disable", true);
  ASSERT_EQ(ParseArgs(boot_args_client_, &args), ZX_OK);
  ASSERT_TRUE(args.disable);
}

TEST_F(ArgsTest, CheckBootBools) {
  boot_args_server_->SetBool("virtcon.disable", true);
  boot_args_server_->SetBool("virtcon.keep-log-visible", true);
  boot_args_server_->SetBool("virtcon.keyrepeat", true);
  boot_args_server_->SetBool("virtcon.hide-on-boot", true);

  Arguments args;
  ASSERT_EQ(ParseArgs(boot_args_client_, &args), ZX_OK);

  ASSERT_TRUE(args.disable);
  ASSERT_TRUE(args.repeat_keys);
  ASSERT_TRUE(args.keep_log_visible);
  ASSERT_TRUE(args.hide_on_boot);
}

TEST_F(ArgsTest, CheckColorScheme) {
  // Default scheme.
  Arguments args;
  ASSERT_EQ(ParseArgs(boot_args_client_, &args), ZX_OK);
  ASSERT_EQ(args.color_scheme->front, 0x0F);
  ASSERT_EQ(args.color_scheme->back, 0x00);

  // Dark Scheme.
  {
    boot_args_server_->SetString("virtcon.colorscheme", "dark");
    Arguments args;
    ASSERT_EQ(ParseArgs(boot_args_client_, &args), ZX_OK);
    ASSERT_EQ(args.color_scheme->front, 0x0F);
    ASSERT_EQ(args.color_scheme->back, 0x00);
  }

  // Light Scheme.
  {
    boot_args_server_->SetString("virtcon.colorscheme", "light");
    Arguments args;
    ASSERT_EQ(ParseArgs(boot_args_client_, &args), ZX_OK);
    ASSERT_EQ(args.color_scheme->front, 0x00);
    ASSERT_EQ(args.color_scheme->back, 0x0F);
  }

  // Special Scheme.
  {
    boot_args_server_->SetString("virtcon.colorscheme", "special");
    Arguments args;
    ASSERT_EQ(ParseArgs(boot_args_client_, &args), ZX_OK);
    ASSERT_EQ(args.color_scheme->front, 0x0F);
    ASSERT_EQ(args.color_scheme->back, 0x04);
  }

  // Nonsense string == default scheme
  {
    boot_args_server_->SetString("virtcon.colorscheme", "myamazingtheme");
    Arguments args;
    ASSERT_EQ(ParseArgs(boot_args_client_, &args), ZX_OK);
    ASSERT_EQ(args.color_scheme->front, 0x0F);
    ASSERT_EQ(args.color_scheme->back, 0x00);
  }
}

TEST_F(ArgsTest, CheckFont) {
  // Default
  Arguments args;
  ASSERT_EQ(ParseArgs(boot_args_client_, &args), ZX_OK);
  ASSERT_EQ(args.font, &gfx_font_9x16);

  // 9x16
  {
    boot_args_server_->SetString("virtcon.font", "9x16");
    Arguments args;
    ASSERT_EQ(ParseArgs(boot_args_client_, &args), ZX_OK);
    ASSERT_EQ(args.font, &gfx_font_9x16);
  }

  // 18x32
  {
    boot_args_server_->SetString("virtcon.font", "18x32");
    Arguments args;
    ASSERT_EQ(ParseArgs(boot_args_client_, &args), ZX_OK);
    ASSERT_EQ(args.font, &gfx_font_18x32);
  }

  // Nonsense string == default
  {
    boot_args_server_->SetString("virtcon.font", "ONEMILLION");
    Arguments args;
    ASSERT_EQ(ParseArgs(boot_args_client_, &args), ZX_OK);
    ASSERT_EQ(args.font, &gfx_font_9x16);
  }
}

TEST_F(ArgsTest, CheckKeymap) {
  // Default
  Arguments args;
  ASSERT_EQ(ParseArgs(boot_args_client_, &args), ZX_OK);
  ASSERT_EQ(args.keymap, qwerty_map);

  // qwerty
  {
    boot_args_server_->SetString("virtcon.keymap", "qwerty");
    Arguments args;
    ASSERT_EQ(ParseArgs(boot_args_client_, &args), ZX_OK);
    ASSERT_EQ(args.keymap, qwerty_map);
  }

  // dvorak
  {
    boot_args_server_->SetString("virtcon.keymap", "dvorak");
    Arguments args;
    ASSERT_EQ(ParseArgs(boot_args_client_, &args), ZX_OK);
    ASSERT_EQ(args.keymap, dvorak_map);
  }

  // nonsense string == defaul
  {
    boot_args_server_->SetString("virtcon.keymap", "randomizedlayout");
    Arguments args;
    ASSERT_EQ(ParseArgs(boot_args_client_, &args), ZX_OK);
    ASSERT_EQ(args.keymap, qwerty_map);
  }
}
