#!/usr/bin/env python3
# Copyright lowRISC contributors (OpenTitan project).
# Copyright zeroRISC Inc.
# Licensed under the Apache License, Version 2.0, see LICENSE for details.
# SPDX-License-Identifier: Apache-2.0
r"""IP Generator: Produce IP blocks from IP templates
"""
import argparse
import logging
import sys
from pathlib import Path

from ipgen import (IpBlockRenderer, IpConfig, IpTemplate, TemplateParseError,
                   TemplateRenderError)


def init_logging(verbose: bool) -> None:
    """ Initialize the logging system """
    log_format = "%(filename)s:%(lineno)d: %(levelname)s: %(message)s"
    if verbose:
        logging.basicConfig(format=log_format, level=logging.DEBUG)
    else:
        logging.basicConfig(format=log_format)


def action_generate(ip_template: IpTemplate, args: argparse.Namespace) -> None:
    """ Handle the 'generate' action/subcommand. """
    overwrite_output_dir = args.force
    output_path = args.outdir

    # Read the IP configuration file.
    try:
        config_text = args.config_file.read_text(encoding="utf-8")
    except Exception as e:
        logging.error(f"Could not read config file: {e}")
        sys.exit(1)

    try:
        ip_config = IpConfig.from_text(ip_template.params, config_text,
                                       "the file passed to --config")
    except ValueError as e:
        logging.error(f"IP config creation failed with {e}")
        sys.exit(1)

    # Render the IP template into an IP block.
    try:
        renderer = IpBlockRenderer(ip_template, ip_config)
        renderer.render(output_path, overwrite_output_dir)
    except TemplateRenderError as e:
        logging.error(e.verbose_str())
        sys.exit(1)

    print(f"Wrote IP block {ip_config.instance_name!r} "
          f"from template {ip_template.name!r} to '{output_path}'.")


def action_describe(ip_template: IpTemplate, args: argparse.Namespace) -> None:
    """ Handle the 'describe' action/subcommand. """
    headline = f"IP template {ip_template.name!r}"
    print(headline)
    print('=' * len(headline))
    print()
    print(f"The template is stored in '{ip_template.template_path}'.")
    print()
    print("Template parameters")
    print("-------------------")
    print()
    for param in ip_template.params.values():
        print(f"{param.name}:")
        print(f"  Description: {param.desc}")
        print(f"  Type: {param.param_type}")
        print(f"  Default value: {param.default}")
        print()


def main() -> int:
    parser = argparse.ArgumentParser()

    # Shared arguments across all actions
    parent_parser = argparse.ArgumentParser(add_help=False)
    parent_parser.add_argument(
        "--verbose",
        help="More info messages",
        action="store_true",
    )
    parent_parser.add_argument(
        '-C',
        '--template-dir',
        type=Path,
        required=True,
        help='IP template directory',
    )

    subparsers = parser.add_subparsers(
        metavar='ACTION',
        title="actions",
        description=("Use 'ipgen.py ACTION --help' to learn more about the "
                     "individual actions."))
    subparsers.required = True

    # 'describe' subparser
    parser_describe = subparsers.add_parser(
        "describe",
        description="Show all information available for the IP template.",
        help="Show details about an IP template",
        parents=[parent_parser],
    )
    parser_describe.set_defaults(func=action_describe)

    # 'generate' subparser
    parser_generate = subparsers.add_parser(
        "generate",
        description="Generate an IP block from an IP template",
        help="Generate an IP block from an IP template",
        parents=[parent_parser],
    )
    parser_generate.add_argument(
        "-o",
        "--outdir",
        required=True,
        type=Path,
        help="output directory for the resulting IP block",
    )
    parser_generate.add_argument(
        "--force",
        "-f",
        required=False,
        default=False,
        action="store_true",
        help="overwrite the output directory, if it exists",
    )
    parser_generate.add_argument(
        "--config-file",
        "-c",
        required=True,
        type=Path,
        help="path to a configuration file",
    )
    parser_generate.set_defaults(func=action_generate)

    # Parse command line arguments, parse IP template, and invoke subparsers
    args = parser.parse_args()
    init_logging(args.verbose)

    try:
        ip_template = IpTemplate.from_template_path(args.template_dir)
    except (TemplateParseError, TemplateRenderError) as e:
        if args.verbose:
            # Show the full backtrace if operating in verbose mode.
            logging.exception(e)
        else:
            # Otherwise just log the problem itself in a more user-friendly way.
            logging.error(str(e))
        return 1

    args.func(ip_template, args)

    return 0


if __name__ == "__main__":
    sys.exit(main())
