# Copyright (c) 2023 Project CHIP 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
#
# 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.

# This file contains private utilities for use by the `configure` script.
# It is self-contained and depends only on the Python 3 standard library.

import collections
import json
import os
import re
import sys
import urllib.request
import zipfile


def download_and_extract_zip(url, dest_dir, *member_names):
    file, *_ = urllib.request.urlretrieve(url)
    with zipfile.ZipFile(file) as zip:
        for member in zip.infolist():
            if member.filename in member_names:
                zip.extract(member, dest_dir)


def process_project_args(gn_args_json_file, *params):
    processor = ProjectArgProcessor(gn_args_json_file)
    processor.process_defaults()
    processor.process_env()
    processor.process_parameters(params)
    for arg, value in processor.args.items():
        info(" - %s = %s" % (arg, value))
        print("%s = %s" % (arg, value))


class ProjectArgProcessor:
    # Prefixes to try when mapping parameters to GN arguments
    BOOL_ARG_PREFIXES = ('is_', 'enable_', 'use_', 'chip_', 'chip_enable', 'chip_use_', 'chip_config_')
    GENERIC_ARG_PREFIXES = ('chip_', 'chip_config_')

    gn_args = {}  # GN arg -> type ('s'tring, 'b'ool, 'i'integer, '[' list, '{' struct)
    args = collections.OrderedDict()  # collected arguments

    def __init__(self, gn_args_json_file):
        # Parse `gn args --list --json` output and derive arg types from default values
        argtype = str.maketrans('"tf0123456789', 'sbbiiiiiiiiii')
        with open(gn_args_json_file) as fh:
            for arg in json.load(fh):
                self.gn_args[arg['name']] = arg['default']['value'][0].translate(argtype)

    def process_defaults(self):
        self.add_default('custom_toolchain', 'custom')

    def process_env(self):
        self.add_env_arg('target_cc', 'CC', 'cc')
        self.add_env_arg('target_cxx', 'CXX', 'cxx')
        self.add_env_arg('target_ar', 'AR', 'ar')
        self.add_env_arg('target_cflags', 'CPPFLAGS', list=True)
        self.add_env_arg('target_cflags_c', 'CFLAGS', list=True)
        self.add_env_arg('target_cflags_cc', 'CXXFLAGS', list=True)
        self.add_env_arg('target_cflags_objc', 'OBJCFLAGS', list=True)
        self.add_env_arg('target_ldflags', 'LDFLAGS', list=True)

    def add_arg(self, arg, value):
        # format strings and booleans as JSON, otherwise pass through as is
        self.args[arg] = (json.dumps(value) if self.gn_args.get(arg, 's') in 'sb' else value)

    def add_default(self, arg, value):
        """Add an argument, if supported by the GN build"""
        if arg in self.gn_args:
            self.add_arg(arg, value)

    def add_env_arg(self, arg, envvar, default=None, list=False):
        """Add an argument from an environment variable"""
        value = os.environ.get(envvar, default)
        if not value:
            return
        if not (type := self.gn_args.get(arg, None)):
            info("Warning: Not propagating %s, project has no build arg '%s'" % (envvar, arg))
            return
        self.args[arg] = json.dumps(value if type != '[' else value.split() if list else [value])

    def gn_arg(self, name, prefixes=(), type=None):
        """Finds the GN argument corresponding to a parameter name"""
        arg = name.translate(str.maketrans('-', '_'))
        candidates = [p + arg for p in (('',) + prefixes) if (p + arg) in self.gn_args]
        preferred = [c for c in candidates if self.gn_args[c] == type] if type else []
        if not (match := next(iter(preferred + candidates), None)):
            info("Warning: Project has no build arg '%s'" % arg)
        return match

    def process_triplet_parameter(self, name, value):
        if value is None:
            fail("Project option --%s requires an argument" % name)
        triplet = value.split('-')
        if len(triplet) not in (2, 3, 4):
            fail("Project option --%s argument must be a cpu-vendor-os[-abi] triplet" % name)
        prefix = 'host_' if name == 'build' else 'target_'  # "host" has different meanings in GNU and GN!
        self.add_arg(prefix + 'cpu', triplet[0])
        self.add_arg(prefix + 'os', triplet[1 if len(triplet) == 2 else 2])

    def process_enable_parameter(self, name, value):
        if not (arg := self.gn_arg(name[len('enable-'):], self.BOOL_ARG_PREFIXES, 'b')):
            return
        if self.gn_args[arg] != 'b':
            fail("Project build arg '%s' is not a boolean" % arg)
        if value != 'no' and value is not None:
            fail("Invalid argument for --%s, must be absent or 'no'" % name)
        self.add_arg(arg, value is None)

    def process_generic_parameter(self, name, value):
        if not (arg := self.gn_arg(name, self.GENERIC_ARG_PREFIXES)):
            return
        if self.gn_args[arg] == 'b':
            fail("Project build arg '%s' is a boolean, use --enable-..." % arg)
        if value is None:
            fail("Project option --%s requires an argument" % name)
        self.add_arg(arg, value)

    def process_parameter(self, name, value):
        if name in ('build', 'host', 'target'):
            self.process_triplet_parameter(name, value)
        elif name.startswith('enable-'):
            self.process_enable_parameter(name, value)
        else:
            self.process_generic_parameter(name, value)

    def process_parameters(self, args):
        """Process GNU-style configure command line parameters"""
        for arg in args:
            if not (m := re.fullmatch(r'--([a-z][a-z0-9-]*)(?:=(.*))?', arg)):
                fail("Invalid argument: '%s'" % arg)
            self.process_parameter(m.group(1), m.group(2))


def info(message):
    print(message, file=sys.stderr)


def fail(message):
    info("Error: " + message)
    sys.exit(1)


# `configure` invokes the top-level functions in this file by
# passing the function name and arguments on the command line.
[_, func, *args] = sys.argv
globals()[func](*args)
