# SPDX-License-Identifier: GPL-2.0-only
#
# This file is part of Nominatim. (https://nominatim.org)
#
# Copyright (C) 2022 by the Nominatim developer community.
# For a full list of authors see the git log.
"""
Helper classes and function for writing result formatting modules.
"""
from typing import Type, TypeVar, Dict, Mapping, List, Callable, Generic, Any
from collections import defaultdict

T = TypeVar('T') # pylint: disable=invalid-name
FormatFunc = Callable[[T], str]

class ResultFormatter(Generic[T]):
    """ This class dispatches format calls to the appropriate formatting
        function previously defined with the `format_func` decorator.
    """

    def __init__(self, funcs: Mapping[str, FormatFunc[T]]) -> None:
        self.functions = funcs


    def list_formats(self) -> List[str]:
        """ Return a list of formats supported by this formatter.
        """
        return list(self.functions.keys())


    def supports_format(self, fmt: str) -> bool:
        """ Check if the given format is supported by this formatter.
        """
        return fmt in self.functions


    def format(self, result: T, fmt: str) -> str:
        """ Convert the given result into a string using the given format.

            The format is expected to be in the list returned by
            `list_formats()`.
        """
        return self.functions[fmt](result)


class FormatDispatcher:
    """ A factory class for result formatters.
    """

    def __init__(self) -> None:
        self.format_functions: Dict[Type[Any], Dict[str, FormatFunc[Any]]] = defaultdict(dict)


    def format_func(self, result_class: Type[T],
                    fmt: str) -> Callable[[FormatFunc[T]], FormatFunc[T]]:
        """ Decorator for a function that formats a given type of result into the
            selected format.
        """
        def decorator(func: FormatFunc[T]) -> FormatFunc[T]:
            self.format_functions[result_class][fmt] = func
            return func

        return decorator


    def __call__(self, result_class: Type[T]) -> ResultFormatter[T]:
        """ Create an instance of a format class for the given result type.
        """
        return ResultFormatter(self.format_functions[result_class])
