/*
 * Copyright 2016 WebAssembly Community Group participants
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

//
// wasm2asm console tool
//

#include "parser/wat-parser.h"
#include "support/colors.h"
#include "support/file.h"
#include "wasm-io.h"
#include "wasm-validator.h"

#include "tool-options.h"
#include "tool-utils.h"

using namespace wasm;

int main(int argc, const char* argv[]) {
  bool debugInfo = false;
  std::string symbolMap;
  std::string sourceMapFilename;
  std::string sourceMapUrl;

  const std::string WasmAsOption = "wasm-as options";

  ToolOptions options("wasm-as",
                      "Assemble a .wat (WebAssembly text format) into a .wasm "
                      "(WebAssembly binary format)");
  options.extra["validate"] = "wasm";
  options
    .add("--output",
         "-o",
         "Output file",
         WasmAsOption,
         Options::Arguments::One,
         [](Options* o, const std::string& argument) {
           o->extra["output"] = argument;
           Colors::setEnabled(false);
         })
    .add("--validate",
         "-v",
         "Control validation of the output module",
         WasmAsOption,
         Options::Arguments::One,
         [](Options* o, const std::string& argument) {
           if (argument != "web" && argument != "none" && argument != "wasm") {
             Fatal() << "Valid arguments for --validate flag are 'wasm', "
                        "'web', and 'none'.\n";
           }
           o->extra["validate"] = argument;
         })
    .add("--debuginfo",
         "-g",
         "Emit names section and debug info",
         WasmAsOption,
         Options::Arguments::Zero,
         [&](Options* o, const std::string& arguments) { debugInfo = true; })
    .add("--source-map",
         "-sm",
         "Emit source map to the specified file",
         WasmAsOption,
         Options::Arguments::One,
         [&sourceMapFilename](Options* o, const std::string& argument) {
           sourceMapFilename = argument;
         })
    .add("--source-map-url",
         "-su",
         "Use specified string as source map URL",
         WasmAsOption,
         Options::Arguments::One,
         [&sourceMapUrl](Options* o, const std::string& argument) {
           sourceMapUrl = argument;
         })
    .add("--symbolmap",
         "-s",
         "Emit a symbol map (indexes => names)",
         WasmAsOption,
         Options::Arguments::One,
         [&](Options* o, const std::string& argument) { symbolMap = argument; })
    .add_positional("INFILE",
                    Options::Arguments::One,
                    [](Options* o, const std::string& argument) {
                      o->extra["infile"] = argument;
                    });
  options.parse(argc, argv);

  // default output is infile with changed suffix
  if (options.extra.find("output") == options.extra.end()) {
    options.extra["output"] =
      removeSpecificSuffix(options.extra["infile"], ".wat") + ".wasm";
  }

  auto input(read_file<std::string>(options.extra["infile"], Flags::Text));

  Module wasm;
  options.applyOptionsBeforeParse(wasm);

  auto parsed = WATParser::parseModule(wasm, input);
  if (auto* err = parsed.getErr()) {
    Fatal() << err->msg;
  }

  options.applyOptionsAfterParse(wasm);

  if (options.extra["validate"] != "none") {
    if (options.debug) {
      std::cerr << "Validating..." << std::endl;
    }
    if (!wasm::WasmValidator().validate(
          wasm,
          WasmValidator::Globally |
            (options.extra["validate"] == "web" ? WasmValidator::Web : 0))) {
      Fatal() << "Error: input module is not valid.\n";
    }
  }

  if (options.debug) {
    std::cerr << "writing..." << std::endl;
  }
  ModuleWriter writer(options.passOptions);
  writer.setBinary(true);
  writer.setDebugInfo(debugInfo);
  if (sourceMapFilename.size()) {
    writer.setSourceMapFilename(sourceMapFilename);
    writer.setSourceMapUrl(sourceMapUrl);
  }
  if (symbolMap.size() > 0) {
    writer.setSymbolMap(symbolMap);
  }
  writer.write(wasm, options.extra["output"]);

  if (options.debug) {
    std::cerr << "Done." << std::endl;
  }
}
