# Parsing C++ function signatures
#
# Author: Malte J. Ziebarth (malte.ziebarth@tum.de)
#
# Copyright (C) 2025-2026 Technische Universität München
#
# Licensed under the EUPL, Version 1.2 or – as soon they will be approved by
# the European Commission - subsequent versions of the EUPL (the "Licence");
# You may not use this work except in compliance with the Licence.
# You may obtain a copy of the Licence at:
#
# https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the Licence is distributed on an "AS IS" basis,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the Licence for the specific language governing permissions and
# limitations under the Licence.
#
# SPDX-FileCopyrightText: 2025-2026 Technical University of Munich
# SPDX-License-Identifier: EUPL-1.2
# SPDX-FileContributor: Malte J. Ziebarth <malte.ziebarth@tum.de>

from typing import Sequence
from .variable import parse_variable
from .usertypes import UserTypeDict
from .sizecontrol import SizeControl
from ..language.fundamental import FBP_TO_FBP
from ..language.cpp import CppArgumentType, L1Type

CParameterList = Sequence[tuple[CppArgumentType, str]]

class Function:
    """
    Representation of a C function wrapped by the Funktionsklempner
    framework.
    """
    name: str
    cparams: CParameterList
    fk_namespace: str
    size_control: SizeControl


    def __init__(self,
            name: str,
            C_parameters: CParameterList,
            fk_namespace: str,
            size_control: SizeControl
        ):
        # Init:
        assert isinstance(name, str)
        print(f"Function(name={name})")
        self.name = name
        self.cparams = C_parameters
        self.fk_namespace = fk_namespace
        self.size_control = size_control




def parse_function_signature(
        f: str,
        user_types: UserTypeDict,
        fk_namespace: str,
        size_control: SizeControl,
        strict: bool
    ) -> Function:
    """
    Parses the signature of a single function.
    """
    # Initializing the return parameters:

    # Split the arguments in parentheses:
    argsplit = f.split('(')
    if len(argsplit) != 2:
        raise RuntimeError(
            "Cannot split definition '" + f + "' into function name "
            "and argument list. Need exactly one opening parenthesis."
        )
    argssplitsplit = argsplit[1].split(')')
    if len(argssplitsplit) != 2:
        raise RuntimeError(
            "Need exactly one closing parenthesis in function definition. "
            "Violating definition: '" + f + "'."
        )

    # Now split at the commata to seperate the arguments.
    # However: we need to take into consideration the template arguments---also
    # there, we might find commata! (e.g. QuantityArray<U,T>)
    # So, we jointly parse for angle bracket enclosure '<>'
    args: list[str] = []
    i0 = 0
    bracket_level = 0
    ARGUMENTS = argssplitsplit[0]
    for i,c in enumerate(ARGUMENTS):
        if c == ',' and bracket_level == 0:
            # Split!
            if i - i0 > 0:
                args.append(ARGUMENTS[i0:i])
            else:
                raise RuntimeError(
                    f"Found empty argument in argument string '{f}'"
                )
            i0 = i+1
        elif c == '<':
            bracket_level += 1
        elif c == '>':
            bracket_level -= 1
    if i0 < len(ARGUMENTS):
        args.append(ARGUMENTS[i0:])


    # Function name and return value:
    retval, fname = argsplit[0].split()

    # Ensure that the return value is void:
    if retval != "void":
        message = (
            "Return value of the wrapped function is currently "
            "not used. Consider passing your return value via a "
            "pointer argument."
        )
        if strict:
            raise RuntimeError(message)
        else:
            print(message)

    type_map: dict[str, L1Type] = {
        **user_types.types,
        **FBP_TO_FBP
    }

    parsed_args: CParameterList = [
        parse_variable(a, type_map, fk_namespace) for a in args
    ]

    return Function(
        fname,
        parsed_args,
        fk_namespace,
        size_control
    )