# Copyright 2021 The Pigweed Authors
#
# 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.
"""Finds components for a given manifest."""

from typing import Any, List, Optional, Tuple

import pathlib
import sys
import xml.etree.ElementTree


def _gn_str_out(name: str, val: Any):
    """Outputs scoped string in GN format."""
    print(f'{name} = "{val}"')


def _gn_list_str_out(name: str, val: List[Any]):
    """Outputs list of strings in GN format with correct escaping."""
    list_str = ','.join('"' + str(x).replace('"', r'\"').replace('$', r'\$') +
                        '"' for x in val)
    print(f'{name} = [{list_str}]')


def _gn_list_path_out(name: str,
                      val: List[pathlib.Path],
                      path_prefix: Optional[str] = None):
    """Outputs list of paths in GN format with common prefix."""
    if path_prefix is not None:
        str_val = list(f'{path_prefix}/{str(d)}' for d in val)
    else:
        str_val = list(str(d) for d in val)
    _gn_list_str_out(name, str_val)


def get_component(
    root: xml.etree.ElementTree.Element, component_id: str
) -> Tuple[Optional[xml.etree.ElementTree.Element], Optional[pathlib.Path]]:
    """Parse <component> manifest stanza.

    Schema:
        <component id="{component_id}" package_base_path="component">
        </component>

    Args:
        root: root of element tree.
        component_id: id of component to return.

    Returns:
        (element, base_path) for the component, or (None, None).
    """
    xpath = f'./components/component[@id="{component_id}"]'
    component = root.find(xpath)
    if component is None:
        return (None, None)

    try:
        base_path = pathlib.Path(component.attrib['package_base_path'])
        return (component, base_path)
    except KeyError:
        return (component, None)


def parse_defines(root: xml.etree.ElementTree.Element,
                  component_id: str) -> List[str]:
    """Parse pre-processor definitions for a component.

    Schema:
        <defines>
          <define name="EXAMPLE" value="1"/>
          <define name="OTHER"/>
        </defines>

    Args:
        root: root of element tree.
        component_id: id of component to return.

    Returns:
        list of str NAME=VALUE or NAME for the component.
    """
    xpath = f'./components/component[@id="{component_id}"]/defines/define'
    return list(_parse_define(define) for define in root.findall(xpath))


def _parse_define(define: xml.etree.ElementTree.Element) -> str:
    """Parse <define> manifest stanza.

    Schema:
        <define name="EXAMPLE" value="1"/>
        <define name="OTHER"/>

    Args:
        define: XML Element for <define>.

    Returns:
        str with a value NAME=VALUE or NAME.
    """
    name = define.attrib['name']
    value = define.attrib.get('value', None)
    if value is None:
        return name

    return f'{name}={value}'


def parse_include_paths(root: xml.etree.ElementTree.Element,
                        component_id: str) -> List[pathlib.Path]:
    """Parse include directories for a component.

    Schema:
        <component id="{component_id}" package_base_path="component">
          <include_paths>
            <include_path relative_path="./" type="c_include"/>
          </include_paths>
        </component>

    Args:
        root: root of element tree.
        component_id: id of component to return.

    Returns:
        list of include directories for the component.
    """
    (component, base_path) = get_component(root, component_id)
    if component is None:
        return []

    include_paths: List[pathlib.Path] = []
    for include_type in ('c_include', 'asm_include'):
        include_xpath = f'./include_paths/include_path[@type="{include_type}"]'

        include_paths.extend(
            _parse_include_path(include_path, base_path)
            for include_path in component.findall(include_xpath))
    return include_paths


def _parse_include_path(include_path: xml.etree.ElementTree.Element,
                        base_path: Optional[pathlib.Path]) -> pathlib.Path:
    """Parse <include_path> manifest stanza.

    Schema:
        <include_path relative_path="./" type="c_include"/>

    Args:
        include_path: XML Element for <input_path>.
        base_path: prefix for paths.

    Returns:
        Path, prefixed with `base_path`.
    """
    path = pathlib.Path(include_path.attrib['relative_path'])
    if base_path is None:
        return path
    return base_path / path


def parse_headers(root: xml.etree.ElementTree.Element,
                  component_id: str) -> List[pathlib.Path]:
    """Parse header files for a component.

    Schema:
        <component id="{component_id}" package_base_path="component">
          <source relative_path="./" type="c_include">
            <files mask="example.h"/>
          </source>
        </component>

    Args:
        root: root of element tree.
        component_id: id of component to return.

    Returns:
        list of header files for the component.
    """
    return _parse_sources(root, component_id, 'c_include')


def parse_sources(root: xml.etree.ElementTree.Element,
                  component_id: str) -> List[pathlib.Path]:
    """Parse source files for a component.

    Schema:
        <component id="{component_id}" package_base_path="component">
          <source relative_path="./" type="src">
            <files mask="example.cc"/>
          </source>
        </component>

    Args:
        root: root of element tree.
        component_id: id of component to return.

    Returns:
        list of source files for the component.
    """
    source_files = []
    for source_type in ('src', 'src_c', 'src_cpp', 'asm_include'):
        source_files.extend(_parse_sources(root, component_id, source_type))
    return source_files


def parse_libs(root: xml.etree.ElementTree.Element,
               component_id: str) -> List[pathlib.Path]:
    """Parse pre-compiled libraries for a component.

    Schema:
        <component id="{component_id}" package_base_path="component">
          <source relative_path="./" type="lib">
            <files mask="example.a"/>
          </source>
        </component>

    Args:
        root: root of element tree.
        component_id: id of component to return.

    Returns:
        list of pre-compiler libraries for the component.
    """
    return _parse_sources(root, component_id, 'lib')


def _parse_sources(root: xml.etree.ElementTree.Element, component_id: str,
                   source_type: str) -> List[pathlib.Path]:
    """Parse <source> manifest stanza.

    Schema:
        <component id="{component_id}" package_base_path="component">
          <source relative_path="./" type="{source_type}">
            <files mask="example.h"/>
          </source>
        </component>

    Args:
        root: root of element tree.
        component_id: id of component to return.
        source_type: type of source to search for.

    Returns:
        list of source files for the component.
    """
    (component, base_path) = get_component(root, component_id)
    if component is None:
        return []

    sources: List[pathlib.Path] = []
    source_xpath = f'./source[@type="{source_type}"]'
    for source in component.findall(source_xpath):
        relative_path = pathlib.Path(source.attrib['relative_path'])
        if base_path is not None:
            relative_path = base_path / relative_path

        sources.extend(relative_path / files.attrib['mask']
                       for files in source.findall('./files'))
    return sources


def parse_dependencies(root: xml.etree.ElementTree.Element,
                       component_id: str) -> List[str]:
    """Parse the list of dependencies for a component.

    Optional dependencies are ignored for parsing since they have to be
    included explicitly.

    Schema:
        <dependencies>
          <all>
            <component_dependency value="component"/>
            <component_dependency value="component"/>
            <any_of>
              <component_dependency value="component"/>
              <component_dependency value="component"/>
            </any_of>
          </all>
        </dependencies>

    Args:
        root: root of element tree.
        component_id: id of component to return.

    Returns:
        list of component id dependencies of the component.
    """
    dependencies = []
    xpath = f'./components/component[@id="{component_id}"]/dependencies/*'
    for dependency in root.findall(xpath):
        dependencies.extend(_parse_dependency(dependency))
    return dependencies


def _parse_dependency(dependency: xml.etree.ElementTree.Element) -> List[str]:
    """Parse <all>, <any_of>, and <component_dependency> manifest stanzas.

    Schema:
        <all>
          <component_dependency value="component"/>
          <component_dependency value="component"/>
          <any_of>
            <component_dependency value="component"/>
            <component_dependency value="component"/>
          </any_of>
        </all>

    Args:
        dependency: XML Element of dependency.

    Returns:
        list of component id dependencies.
    """
    if dependency.tag == 'component_dependency':
        return [dependency.attrib['value']]
    if dependency.tag == 'all':
        dependencies = []
        for subdependency in dependency:
            dependencies.extend(_parse_dependency(subdependency))
        return dependencies
    if dependency.tag == 'any_of':
        # Explicitly ignore.
        return []

    # Unknown dependency tag type.
    return []


def check_dependencies(root: xml.etree.ElementTree.Element,
                       component_id: str,
                       include: List[str],
                       exclude: Optional[List[str]] = None) -> bool:
    """Check the list of optional dependencies for a component.

    Verifies that the optional dependencies for a component are satisfied by
    components listed in `include` or `exclude`.

    Args:
        root: root of element tree.
        component_id: id of component to check.
        include: list of component ids included in the project.
        exclude: list of component ids explicitly excluded from the project.

    Returns:
        True if dependencies are satisfied, False if not.
    """
    xpath = f'./components/component[@id="{component_id}"]/dependencies/*'
    for dependency in root.findall(xpath):
        if not _check_dependency(dependency, include, exclude=exclude):
            return False
    return True


def _check_dependency(dependency: xml.etree.ElementTree.Element,
                      include: List[str],
                      exclude: Optional[List[str]] = None) -> bool:
    """Check a dependency for a component.

    Verifies that the given {dependency} is satisfied by components listed in
    `include` or `exclude`.

    Args:
        dependency: XML Element of dependency.
        include: list of component ids included in the project.
        exclude: list of component ids explicitly excluded from the project.

    Returns:
        True if dependencies are satisfied, False if not.
    """
    if dependency.tag == 'component_dependency':
        component_id = dependency.attrib['value']
        return component_id in include or (exclude is not None
                                           and component_id in exclude)
    if dependency.tag == 'all':
        for subdependency in dependency:
            if not _check_dependency(subdependency, include, exclude=exclude):
                return False
        return True
    if dependency.tag == 'any_of':
        for subdependency in dependency:
            if _check_dependency(subdependency, include, exclude=exclude):
                return True

        tree = xml.etree.ElementTree.tostring(dependency).decode('utf-8')
        print(f'Unsatisfied dependency from: {tree}', file=sys.stderr)
        return False

    # Unknown dependency tag type.
    return True


def create_project(
    root: xml.etree.ElementTree.Element,
    include: List[str],
    exclude: Optional[List[str]] = None
) -> Tuple[List[str], List[str], List[pathlib.Path], List[pathlib.Path],
           List[pathlib.Path], List[pathlib.Path]]:
    """Create a project from a list of specified components.

    Args:
        root: root of element tree.
        include: list of component ids included in the project.
        exclude: list of component ids excluded from the project.

    Returns:
        (component_ids, defines, include_paths, headers, sources, libs) for the
        project.
    """
    # Build the project list from the list of included components by expanding
    # dependencies.
    project_list = []
    pending_list = include
    while len(pending_list) > 0:
        component_id = pending_list.pop(0)
        if component_id in project_list:
            continue
        if exclude is not None and component_id in exclude:
            continue

        project_list.append(component_id)
        pending_list.extend(parse_dependencies(root, component_id))

    return (
        project_list,
        sum((parse_defines(root, component_id)
             for component_id in project_list), []),
        sum((parse_include_paths(root, component_id)
             for component_id in project_list), []),
        sum((parse_headers(root, component_id)
             for component_id in project_list), []),
        sum((parse_sources(root, component_id)
             for component_id in project_list), []),
        sum((parse_libs(root, component_id) for component_id in project_list),
            []),
    )


def project(manifest_path: pathlib.Path,
            include: Optional[List[str]] = None,
            exclude: Optional[List[str]] = None,
            path_prefix: Optional[str] = None):
    """Output GN scope for a project with the specified components.

    Args:
        manifest_path: path to SDK manifest XML.
        include: list of component ids included in the project.
        exclude: list of component ids excluded from the project.
        path_prefix: string prefix to prepend to all paths.
    """
    assert include is not None, "Project must include at least one component."

    tree = xml.etree.ElementTree.parse(manifest_path)
    root = tree.getroot()

    (component_ids, defines, include_dirs, headers, sources, libs) = \
        create_project(root, include, exclude=exclude)

    for component_id in component_ids:
        if not check_dependencies(
                root, component_id, component_ids, exclude=exclude):
            return

    _gn_list_str_out('defines', defines)
    _gn_list_path_out('include_dirs', include_dirs, path_prefix=path_prefix)
    _gn_list_path_out('public', headers, path_prefix=path_prefix)
    _gn_list_path_out('sources', sources, path_prefix=path_prefix)
    _gn_list_path_out('libs', libs, path_prefix=path_prefix)
