// Copyright 2019 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 <fcntl.h>
#include <lib/fit/defer.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <unistd.h>

#include <filesystem>
#include <fstream>
#include <iostream>
#include <optional>
#include <string>

#include "common.h"
#include "src/lib/fxl/command_line.h"
#include "src/lib/icu/tools/extractor/icu_headers.h"
#include "tz_ids.h"
#include "tz_version.h"

using icu_data_extractor::Command;
using icu_data_extractor::kArgIcuDataPath;
using icu_data_extractor::kArgTzResPath;
using icu_data_extractor::TzIds;
using icu_data_extractor::TzVersion;

// Wrapper around read-only mmap-ed files for easy resource cleanup.
//
// Instantiate using `MappedFile::Open()`.
// Get the file's contents using `MappedFile::data()`.
class MappedFile {
 public:
  // Maps a file into memory as read-only and returns a container.
  //
  // Returns `nullptr` if reading or mmapping fails.
  static std::unique_ptr<MappedFile> Open(const std::string& path) {
    int fd = open(path.c_str(), O_RDONLY);
    if (fd == -1) {
      return nullptr;
    }

    // Automatically close the file when this variable goes out of scope.
    auto close_fd = fit::defer([&fd, &path]() {
      if (close(fd) != 0) {
        std::cerr << "Failed to explicitly close file " << path
                  << " after opening it. Error: " << strerror(errno) << std::endl;
      }
    });

    struct stat st;
    if (fstat(fd, &st) != 0 || !S_ISREG(st.st_mode)) {
      return nullptr;
    }

    void* data = mmap(nullptr, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
    if (data == nullptr) {
      return nullptr;
    }

    return std::unique_ptr<MappedFile>(new MappedFile(st.st_size, data));
  }

  ~MappedFile() { munmap(data_, size_); }
  const void* data() const { return data_; }

 private:
  MappedFile(size_t size, void* data) : size_(size), data_(data) {}
  const size_t size_;
  void* data_;
};

int PrintUsage(const fxl::CommandLine& command_line,
               const std::vector<std::unique_ptr<Command>>& commands) {
  std::cout << "Usage: " << command_line.argv0() << " [OPTION]... COMMAND [COMMAND-OPTION]...\n\n"
            << "OPTIONS:\n"
            << "  --" << kArgIcuDataPath << "=FILE\t(required)\tPath to icudtl.dat\n"
            << "  --" << kArgTzResPath << "=DIR\t(required)\tPath to tzres directory\n"
            << "\n"
            << "COMMANDS:\n\n";

  for (const auto& command : commands) {
    command->PrintDocs(std::cout);
    std::cout << "\n\n\n";
  }

  std::cout << std::endl;

  return -1;
}

int main(int argc, const char** argv) {
  std::vector<std::unique_ptr<Command>> commands;
  commands.push_back(std::make_unique<TzVersion>());
  commands.push_back(std::make_unique<TzIds>());

  const std::vector<std::string> args(argv, argv + argc);
  std::vector<std::string>::const_iterator sub_first;
  const auto command_line =
      fxl::CommandLineFromIteratorsFindFirstPositionalArg(args.begin(), args.end(), &sub_first);

  std::string icu_data_path;
  if (!command_line.GetOptionValue(kArgIcuDataPath, &icu_data_path)) {
    return PrintUsage(command_line, commands);
  }

  std::optional<std::string> tz_res_path = std::nullopt;
  if (command_line.HasOption(kArgTzResPath)) {
    std::string tz_res_path_str;
    command_line.GetOptionValue(kArgTzResPath, &tz_res_path_str);
    tz_res_path = tz_res_path_str;
    setenv("ICU_TIMEZONE_FILES_DIR", tz_res_path_str.c_str(), 1);
  }

  // This will be unmapped automatically when the program exits.
  const std::unique_ptr<MappedFile> icu_data = MappedFile::Open(icu_data_path);
  if (icu_data == nullptr) {
    std::cerr << "Couldn't read file at " << icu_data_path << std::endl;
    return -1;
  }

  UErrorCode err = U_ZERO_ERROR;
  udata_setCommonData(icu_data->data(), &err);
  if (err != U_ZERO_ERROR) {
    std::cerr << "Error while loading from \"" << icu_data_path << "\": " << u_errorName(err)
              << std::endl;
    return -1;
  }

  if (command_line.positional_args().size() < 1) {
    return PrintUsage(command_line, commands);
  }

  const auto sub_command_line = fxl::CommandLineFromIterators(sub_first, args.end());
  const auto command_name = sub_command_line.argv0();

  // For two items, linear search is fast enough.
  const auto command_result = std::find_if(
      commands.begin(), commands.end(), [&command_name](const std::unique_ptr<Command>& command) {
        return command->Name() == command_name;
      });

  if (command_result != commands.end()) {
    return (*command_result)->Execute(command_line, sub_command_line);
  } else {
    std::cerr << "Unknown command " << command_name << std::endl;
    return PrintUsage(command_line, commands);
  }
}
