// Copyright 2016 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 "garnet/bin/netconnector/netconnector_params.h"

#include <fuchsia/sys/cpp/fidl.h>
#include <rapidjson/document.h>

#include "garnet/lib/inet/ip_address.h"
#include "src/lib/files/file.h"
#include "src/lib/fxl/logging.h"
#include "src/lib/fxl/strings/split_string.h"

namespace netconnector {
namespace {

constexpr char kConfigServices[] = "services";
constexpr char kConfigDevices[] = "devices";
constexpr char kDefaultConfigFileName[] = "/pkg/data/netconnector.config";
}  // namespace

NetConnectorParams::NetConnectorParams(const fxl::CommandLine& command_line) {
  is_valid_ = false;

  listen_ = command_line.HasOption("listen");
  show_devices_ = command_line.HasOption("show-devices");

  if (listen_ && show_devices_) {
    FXL_LOG(ERROR) << "--listen and --show-devices are mutually exclusive";
    Usage();
    return;
  }

  std::string config_file_name;
  if (!command_line.GetOptionValue("config", &config_file_name)) {
    config_file_name = kDefaultConfigFileName;
  }

  if (config_file_name.empty()) {
    Usage();
    return;
  }

  if (listen_ && !ReadConfigFrom(config_file_name)) {
    FXL_LOG(ERROR) << "Failed to parse config file " << config_file_name;
    return;
  }

  is_valid_ = true;
}

void NetConnectorParams::Usage() {
  FXL_LOG(INFO) << "netconnector usage:";
  FXL_LOG(INFO) << "    netconnector [ options ]";
  FXL_LOG(INFO) << "options:";
  FXL_LOG(INFO)
      << "    --config=<file>                  read config file (default "
      << kDefaultConfigFileName << ")";
  FXL_LOG(INFO) << "    --show-devices                   show known devices";
  FXL_LOG(INFO) << "    --listen                         run as listener";
}

void NetConnectorParams::RegisterService(
    const std::string& name, fuchsia::sys::LaunchInfoPtr launch_info) {
  auto result =
      launch_infos_by_service_name_.emplace(name, std::move(launch_info));

  if (!result.second) {
    FXL_DCHECK(result.first != launch_infos_by_service_name_.end());
    result.first->second = std::move(launch_info);
  }
}

void NetConnectorParams::RegisterDevice(const std::string& name,
                                        const inet::IpAddress& address) {
  auto result = device_addresses_by_name_.emplace(name, address);

  if (!result.second) {
    FXL_DCHECK(result.first != device_addresses_by_name_.end());
    result.first->second = address;
  }
}

void NetConnectorParams::UnregisterDevice(const std::string& name) {
  device_addresses_by_name_.erase(name);
}

bool NetConnectorParams::ReadConfigFrom(const std::string& config_file_name) {
  std::string config_file_contents;
  return files::ReadFileToString(config_file_name, &config_file_contents) &&
         ParseConfig(config_file_contents);
}

bool NetConnectorParams::ParseConfig(const std::string& string) {
  rapidjson::Document document;
  document.Parse(string.data(), string.size());
  if (!document.IsObject())
    return false;

  auto iter = document.FindMember(kConfigServices);
  if (iter != document.MemberEnd()) {
    const auto& value = iter->value;
    if (!value.IsObject()) {
      return false;
    }

    for (const auto& pair : value.GetObject()) {
      if (!pair.name.IsString()) {
        return false;
      }

      auto launch_info = fuchsia::sys::LaunchInfo::New();
      if (pair.value.IsString()) {
        launch_info->url = pair.value.GetString();
      } else if (pair.value.IsArray()) {
        const auto& array = pair.value.GetArray();

        if (array.Empty() || !array[0].IsString()) {
          return false;
        }

        launch_info->url = array[0].GetString();
        for (size_t i = 1; i < array.Size(); ++i) {
          if (!array[i].IsString()) {
            return false;
          }

          launch_info->arguments.push_back(array[i].GetString());
        }
      } else {
        return false;
      }

      RegisterService(pair.name.GetString(), std::move(launch_info));
    }
  }

  iter = document.FindMember(kConfigDevices);
  if (iter != document.MemberEnd()) {
    const auto& value = iter->value;
    if (!value.IsObject()) {
      return false;
    }

    for (const auto& pair : value.GetObject()) {
      if (!pair.name.IsString() || !pair.value.IsString()) {
        return false;
      }

      inet::IpAddress address =
          inet::IpAddress::FromString(pair.value.GetString());
      if (!address.is_valid()) {
        FXL_LOG(ERROR) << "Config file contains invalid IP address "
                       << pair.value.GetString();
        return false;
      }

      RegisterDevice(pair.name.GetString(), address);
    }
  }

  return true;
}

}  // namespace netconnector
