// Copyright 2018 Ryan Dahl <ry@tinyclouds.org>
// All rights reserved. MIT License.
#include <stdio.h>
#include <fstream>
#include <iterator>
#include <string>

#include "file_util.h"

namespace deno {

bool ReadFileToString(const char* fn, std::string* contents) {
  std::ifstream file(fn, std::ios::binary);
  if (file.fail()) {
    return false;
  }
  contents->assign(std::istreambuf_iterator<char>{file}, {});
  return !file.fail();
}

class StartupDataCppWriter {
 public:
  StartupDataCppWriter(const char* name, const char* filename,
                       const std::string& data)
      : name_(name),
        filename_(filename),
        data_(data),
        file_(filename_, std::ios::binary) {}

  bool Write() {
    if (file_.bad()) {
      return false;
    }
    WritePrefix();
    WriteData();
    WriteSuffix();

    file_.close();
    // printf("Wrote %s %d %s \n", name_, data_.size(), filename_);
    return !file_.bad();
  }

 private:
  void WritePrefix() {
    file_ << "// Autogenerated snapshot file. Do not edit.\n\n";
    file_ << "#include \"v8/include/v8.h\"\n\n";
    file_ << "namespace deno { \n\n";
  }

  void WriteSuffix() {
    char buffer[500];
    snprintf(buffer, sizeof(buffer), "v8::StartupData* StartupBlob_%s() {\n",
             name_);
    file_ << buffer;
    snprintf(buffer, sizeof(buffer), "  return &%s_blob;\n", name_);
    file_ << buffer;
    file_ << "}\n\n";
    file_ << "}  // namespace deno\n\n";
  }

  void WriteBinaryContentsAsCArray() {
    char buffer[5];
    for (size_t i = 0; i < data_.size(); i++) {
      if ((i & 0x1F) == 0x1F) file_ << "\n";
      if (i > 0) file_ << ",";
      snprintf(buffer, sizeof(buffer), "%u",
               static_cast<unsigned char>(data_.at(i)));
      file_ << buffer;
    }
    file_ << "\n";
  }

  void WriteData() {
    char buffer[500];
    snprintf(buffer, sizeof(buffer), "static const char %s_blob_data[] = {\n",
             name_);
    file_ << buffer;
    WriteBinaryContentsAsCArray();
    file_ << "};\n";
    snprintf(buffer, sizeof(buffer), "static const int %s_blob_size = %llu;\n",
             name_, static_cast<unsigned long long>(data_.size()));
    file_ << buffer;
    snprintf(buffer, sizeof(buffer), "static v8::StartupData %s_blob =\n",
             name_);
    file_ << buffer;
    snprintf(buffer, sizeof(buffer),
             "{ (const char*) %s_blob_data, %s_blob_size };\n", name_, name_);
    file_ << buffer;
  }

  const char* name_;
  const char* filename_;
  std::string data_;
  std::ofstream file_;
};

bool WriteDataAsCpp(const char* name, const char* filename,
                    const std::string& data) {
  StartupDataCppWriter writer(name, filename, data);
  return writer.Write();
}

}  // namespace deno