#
# Copyright 2009 Zuza Software Foundation
#
# This file is part of the Translate Toolkit.
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, see <http://www.gnu.org/licenses/>.

"""Contains the placeable that represents a terminology term."""

from __future__ import annotations

from typing import Any

from translate.storage.placeables import StringElem, base

__all__ = ("TerminologyPlaceable", "parsers")


class TerminologyPlaceable(base.Ph):
    """
    Terminology distinguished from the rest of a string by being
    a placeable.
    """

    matchers: list[Any] = []
    """A list of matcher objects to use to identify terminology."""
    translations: list[str] = []
    """The available translations for this placeable."""

    def __init__(self, *args, **kwargs) -> None:
        self.translations = []
        super().__init__(*args, **kwargs)

    @classmethod
    def parse(cls, pstr):
        parts = []
        matches = []
        match_info = {}

        for matcher in cls.matchers:
            matches.extend(matcher.matches(pstr))
            match_info.update(matcher.match_info)

        lastend = 0

        # This function will sort a list of matches according to the
        # match's starting position, putting the one with the longer
        # source text first, if two are the same.
        matches.sort(key=lambda x: len(x.source), reverse=True)
        matches.sort(key=lambda x: match_info[x.source]["pos"])

        for match in matches:
            info = match_info[match.source]
            if info["pos"] < lastend:
                continue
            end = info["pos"] + len(match.source)
            if "newtermlen" in info:
                end = info["pos"] + info["newtermlen"]

            if lastend < info["pos"]:
                parts.append(StringElem(pstr[lastend : info["pos"]]))

            term_string = pstr[info["pos"] : end]
            term_placeable = cls([term_string])
            parts.append(term_placeable)

            # Get translations for the placeable
            for m in matches:
                m_info = match_info[m.source]
                m_end = m_info["pos"]
                if "newtermlen" in m_info:
                    m_end += m_info["newtermlen"]
                else:
                    m_end += len(m.source)
                if info["pos"] == m_info["pos"] and end == m_end:
                    term_placeable.translations.append(m.target)

            # remove duplicates:
            term_placeable.translations = list(set(term_placeable.translations))

            lastend = end
        if lastend != len(pstr) and parts:
            parts.append(StringElem(pstr[lastend:]))

        return parts or None

    def translate(self):
        return self.translations[0] if self.translations else super().translate()


parsers = [TerminologyPlaceable.parse]
