// Copyright lowRISC contributors.
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
// SPDX-License-Identifier: Apache-2.0

#include <assert.h>
#include <fstream>
#include <getopt.h>
#include <memory>
#include <sstream>
#include <string>

#include "sw/host/spiflash/ftdi_spi_interface.h"
#include "sw/host/spiflash/spi_interface.h"
#include "sw/host/spiflash/updater.h"
#include "sw/host/spiflash/verilator_spi_interface.h"

namespace {

using opentitan::spiflash::FtdiSpiInterface;
using opentitan::spiflash::SpiInterface;
using opentitan::spiflash::Updater;
using opentitan::spiflash::VerilatorSpiInterface;

constexpr char kUsageString[] = R"R( usage options:
  --input=Input image in binary format.

FTDI Options:
  [--dev-id="vid:pid"] FTDI device ID.
    vid: Vendor ID in string hex format.
    pid: Product ID in string hex format.
  [--dev-sn=string] FTDI serial number. Requires --dev-id to be set.

Verilator Options:
  [--verilator=filehandle] Enables Verilator mode with SPI filehandle.)R";

/** SPI flash configuration options. */
struct SpiFlashOpts {
  /** Input file in binary format. */
  std::string input;

  /** Target SPI device handle. */
  std::string target;

  /** Set to true to target Verilator environment. */
  bool verilator = false;

  /** FTDI configuration options. */
  FtdiSpiInterface::Options ftdi_options;
};

/**
 * Get `filename` contents and store them in `contents`. Using std::string for
 * `filename` because underlying open file call requires a C string.
 */
bool GetFileContents(const std::string &filename, std::string *contents) {
  assert(contents);
  std::ifstream file_stream(filename, std::ios::in | std::ios::binary);
  if (!file_stream) {
    std::cerr << "Unable to open: " << filename << " errno: " << errno
              << std::endl;
    return false;
  }
  std::ostringstream in_stream;
  in_stream << file_stream.rdbuf();
  file_stream.close();
  *contents = in_stream.str();
  return true;
}

/** Print help menu. */
static void PrintUsage(int argc, char *argv[]) {
  assert(argc >= 1);
  std::cerr << argv[0] << kUsageString << std::endl;
}

/*
 * Extract the vendor and product ID from `device_id` and store the values
 * in `options`.
 *
 * This function may throw exceptions.
 *
 * @return true on success.
 */
bool ParseDeviceID(const std::string &device_id, SpiFlashOpts *options) {
  size_t token_pos = device_id.find(':');
  if (token_pos == std::string::npos) {
    std::cerr << "Unable to find device separator ':' in --device-id."
              << std::endl;
    return false;
  }

  std::string vendor_id = device_id.substr(/*pos=*/0, /*len=*/token_pos);
  options->ftdi_options.device_vendor_id =
      std::stoi(vendor_id, /*pos=*/0, /*base=*/16);

  std::string product_id =
      device_id.substr(/*pos=*/token_pos + 1, /*len=*/std::string::npos);
  options->ftdi_options.device_product_id =
      std::stoi(product_id, /*pos=*/0, /*base=*/16);

  return true;
}

/*
 * Parse command line arguments and store results in `options`.
 */
bool ParseArgs(int argc, char **argv, SpiFlashOpts *options) {
  assert(options);
  const struct option long_options[] = {
      {"input", required_argument, nullptr, 'i'},
      {"dev-id", required_argument, nullptr, 'd'},
      {"dev-sn", required_argument, nullptr, 'n'},
      {"verilator", required_argument, nullptr, 's'},
      {"help", no_argument, nullptr, 'h'},
      {nullptr, no_argument, nullptr, 0}};

  while (true) {
    int c = getopt_long(argc, argv, "i:d:n:s:h?", long_options, nullptr);
    if (c == -1) {
      return true;
    }

    switch (c) {
      case 0:
        break;
      case 'i':
        options->input = optarg;
        break;
      case 'd':
        if (!ParseDeviceID(std::string(optarg), options)) {
          return false;
        }
        break;
      case 'n':
        options->ftdi_options.device_serial_number = optarg;
        break;
      case 's':
        options->verilator = true;
        options->target = optarg;
        break;
      case '?':
      case 'h':
        PrintUsage(argc, argv);
      default:;
    }
  }
  return true;
}

}  // namespace

int main(int argc, char **argv) {
  SpiFlashOpts spi_flash_options;
  if (!ParseArgs(argc, argv, &spi_flash_options)) {
    std::cerr << "Failed to parse command line options." << std::endl;
    return 1;
  }

  std::unique_ptr<SpiInterface> spi;
  if (spi_flash_options.verilator) {
    spi = std::make_unique<VerilatorSpiInterface>(spi_flash_options.target);
  } else {
    spi = std::make_unique<FtdiSpiInterface>(spi_flash_options.ftdi_options);
  }
  if (!spi->Init()) {
    return 1;
  }

  Updater::Options options;
  if (!GetFileContents(spi_flash_options.input, &options.code)) {
    return 1;
  }
  Updater updater(options, std::move(spi));
  return updater.Run() ? 0 : 1;
}
