# Data model for representing parameter lists in various parts of the interface.
#
# Author: Malte J. Ziebarth (malte.ziebarth@tum.de)
#
# Copyright (C) 2025 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 Technical University of Munich
# SPDX-License-Identifier: EUPL-1.2
# SPDX-FileContributor: Malte J. Ziebarth <malte.ziebarth@tum.de>

from typing import Self
from abc import ABCMeta
from .parameter import PythonInputParameter, PythonOutputParameter, \
    CTypeParameterByValue, CTypeParameterByRef, Forward

Parameter = PythonInputParameter | PythonOutputParameter | \
    (CTypeParameterByValue | CTypeParameterByRef)

#
# 0. Base class for parameter lists
# =================================
# This join some of their common functionality (parameter ordering,
# name uniqueness.)
#
class ParameterList[T: Parameter](metaclass=ABCMeta):
    """
    """
    parameters: list[T]
    pnames: set[str]
    ptype: type[T]


    def __init__(self, ptype: type[T]):
        self.parameters = []
        self.pnames = set()
        self.ptype = ptype

    def append(self, p: T):
        p_name = p.name if isinstance(p.name, str) else p.name.name
        if p_name in self.pnames:
            pname = p.name
            if isinstance(pname, Forward):
                raise RuntimeError(
                    f"A parameter named ('{pname.name}', '{pname.varname}') "
                    "is a duplicate."
                )
            else:
                raise RuntimeError(
                    f"A parameter named '{pname}' is a duplicate."
                )
        self.pnames.add(p_name)
        self.parameters.append(p)


    def __iadd__(self, p: T) -> Self:
        self.append(p)
        return self

    def parameter_type_name(self) -> str:
        return self.ptype.parameter_type_name()




class PythonInputParameters(ParameterList[PythonInputParameter]):
    """
    """
    def __init__(self):
        super().__init__(PythonInputParameter)


class PythonOutputParameters(ParameterList[PythonOutputParameter]):
    """
    """
    def __init__(self):
        super().__init__(PythonOutputParameter)


class CTypeParameters(ParameterList[CTypeParameterByValue | CTypeParameterByRef]):
    """
    """
    def __init__(self):
        # Here we use, as a hack, the fact that both parameters
        # behave similarly with regards to what ParameterList
        # checks:
        super().__init__(CTypeParameterByValue)



#
# Lits of parsed C parameters:
#