# Copyright 2019 Google LLC
#
# 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
#
#     https://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.

"""Emboss C++ code generator.

This is a driver program that reads IR, feeds it to header_generator, and prints
the result.
"""

from __future__ import print_function

import argparse
import os
import sys

from compiler.back_end.cpp import header_generator
from compiler.util import error
from compiler.util import ir_data
from compiler.util import ir_data_utils


def _parse_command_line(argv):
  """Parses the given command-line arguments."""
  parser = argparse.ArgumentParser(description="Emboss compiler C++ back end.",
                                   prog=argv[0])
  parser.add_argument("--input-file",
                      type=str,
                      help=".emb.ir file to compile.")
  parser.add_argument("--output-file",
                      type=str,
                      help="Write header to file.  If not specified, write " +
                           "header to stdout.")
  parser.add_argument("--color-output",
                      default="if_tty",
                      choices=["always", "never", "if_tty", "auto"],
                      help="Print error messages using color.  'auto' is a "
                           "synonym for 'if_tty'.")
  parser.add_argument("--cc-enum-traits",
                      action=argparse.BooleanOptionalAction,
                      default=True,
                      help="""Controls generation of EnumTraits by the C++
                              backend""")
  return parser.parse_args(argv[1:])


def _show_errors(errors, ir, color_output):
  """Prints errors with source code snippets."""
  source_codes = {}
  for module in ir.module:
    source_codes[module.source_file_name] = module.source_text
  use_color = (color_output == "always" or
               (color_output in ("auto", "if_tty") and
                os.isatty(sys.stderr.fileno())))
  print(error.format_errors(errors, source_codes, use_color), file=sys.stderr)

def generate_headers_and_log_errors(ir, color_output, config: header_generator.Config):
  """Generates a C++ header and logs any errors.

  Arguments:
    ir: EmbossIr of the module.
    color_output: "always", "never", "if_tty", "auto"
    config: Header generation configuration.

  Returns:
    A tuple of (header, errors)
  """
  header, errors = header_generator.generate_header(ir, config)
  if errors:
    _show_errors(errors, ir, color_output)
  return (header, errors)

def main(flags):
  if flags.input_file:
    with open(flags.input_file) as f:
      ir = ir_data_utils.IrDataSerializer.from_json(ir_data.EmbossIr, f.read())
  else:
    ir = ir_data_utils.IrDataSerializer.from_json(ir_data.EmbossIr, sys.stdin.read())
  config = header_generator.Config(include_enum_traits=flags.cc_enum_traits)
  header, errors = generate_headers_and_log_errors(ir, flags.color_output, config)
  if errors:
    return 1
  if flags.output_file:
    with open(flags.output_file, "w") as f:
      f.write(header)
  else:
    print(header)
  return 0


if __name__ == '__main__':
  sys.exit(main(_parse_command_line(sys.argv)))
