# Copyright (C) 2020-2022 HERE Global B.V. and its affiliate(s).
# All rights reserved.
#
# This software and other materials contain proprietary information
# controlled by HERE and are protected by applicable copyright legislation.
# Any use and utilization of this software and other materials and
# disclosure to any third parties is conditional upon having a separate
# agreement with HERE for the access, use, utilization or disclosure of this
# software. In the absence of such agreement, the use of the software is not
# allowed.

"""
This module provides a ``PropertiesDict`` class to be used for handling Java properties files
which converts number values to int or float.
"""
import re
from typing import Any, Dict

from jproperties import Properties

NUMBER = re.compile(
    "[+-]?(\\d*\\.\\d+|\\d+(\\.\\d+)?)([eE][+\\-]?\\d+)?(?=$|[ \\t]*([\\$\\}\\],#\\n\\r]|//))",
    re.DOTALL,
)


class PropertiesDict:
    """
    This class wraps the reading of Java properties files.
    """

    def __init__(self, props: Dict[str, Any]):
        """
        Creates a new Java properties wrapper instance.

        :param props: a dictionary of key-value-pairs where the keys are strings and the values
                      could be anything (mostly strings but also converted numbers (int, float)
        """
        self._props = props

    @property
    def properties(self) -> Dict[str, Any]:
        """The Java properties representation of the document in a python dictionary"""  # noqa
        return self._props

    @classmethod
    def _convert_if_number(cls, kv):
        rx_match = NUMBER.match(kv[1])
        if rx_match:
            number = rx_match.group(0)
            try:
                return kv[0], int(number, 10)
            except ValueError:
                return kv[0], float(number)
        else:
            return kv

    @classmethod
    def parse(cls, path) -> Dict[str, Any]:
        """
        Parses a Java properties file and returns it as a python dictionary.

        :param path: path to a Java properties file.
        :return: dictionary of key-value-pairs where the keys are strings and the values
                 could be anything (mostly strings but also converted numbers (int, float)
        """
        _jprops = Properties()
        with open(path, "rb") as f:
            _jprops.load(f, "utf-8")
        # filter comment lines which start with //
        _props = dict(
            filter(
                lambda kv: all(isinstance(x, str) and not x.startswith("//") for x in kv),
                _jprops.properties.items(),
            )
        )
        # and convert numbers
        _props = dict(map(cls._convert_if_number, _props.items()))
        return PropertiesDict(_props).properties
