# Copyright 2013-2021 The Meson development team

# 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.
from __future__ import annotations

from .. import mesonlib, mparser
from .exceptions import InterpreterException, InvalidArguments
from ..coredata import UserOption


import collections.abc
import typing as T

if T.TYPE_CHECKING:
    from .baseobjects import TYPE_var, TYPE_kwargs, SubProject

def flatten(args: T.Union['TYPE_var', T.List['TYPE_var']]) -> T.List['TYPE_var']:
    if isinstance(args, mparser.BaseStringNode):
        assert isinstance(args.value, str)
        return [args.value]
    if not isinstance(args, collections.abc.Sequence):
        return [args]
    result: T.List['TYPE_var'] = []
    for a in args:
        if isinstance(a, list):
            rest = flatten(a)
            result = result + rest
        elif isinstance(a, mparser.BaseStringNode):
            result.append(a.value)
        else:
            result.append(a)
    return result

def resolve_second_level_holders(args: T.List['TYPE_var'], kwargs: 'TYPE_kwargs') -> T.Tuple[T.List['TYPE_var'], 'TYPE_kwargs']:
    def resolver(arg: 'TYPE_var') -> 'TYPE_var':
        if isinstance(arg, list):
            return [resolver(x) for x in arg]
        if isinstance(arg, dict):
            return {k: resolver(v) for k, v in arg.items()}
        if isinstance(arg, mesonlib.SecondLevelHolder):
            return arg.get_default_object()
        return arg
    return [resolver(x) for x in args], {k: resolver(v) for k, v in kwargs.items()}

def default_resolve_key(key: mparser.BaseNode) -> str:
    if not isinstance(key, mparser.IdNode):
        raise InterpreterException('Invalid kwargs format.')
    return key.value

def stringifyUserArguments(args: TYPE_var, subproject: SubProject, quote: bool = False) -> str:
    if isinstance(args, str):
        return f"'{args}'" if quote else args
    elif isinstance(args, bool):
        return 'true' if args else 'false'
    elif isinstance(args, int):
        return str(args)
    elif isinstance(args, list):
        return '[%s]' % ', '.join([stringifyUserArguments(x, subproject, True) for x in args])
    elif isinstance(args, dict):
        l = ['{} : {}'.format(stringifyUserArguments(k, subproject, True),
                              stringifyUserArguments(v, subproject, True)) for k, v in args.items()]
        return '{%s}' % ', '.join(l)
    elif isinstance(args, UserOption):
        from .decorators import FeatureNew
        FeatureNew.single_use('User option in string format', '1.3.0', subproject)
        return stringifyUserArguments(args.printable_value(), subproject)
    raise InvalidArguments('Value other than strings, integers, bools, options, dictionaries and lists thereof.')
