#
# Copyright 2008, 2010 Zuza Software Foundation
#
# This file is part of translate.
#
# translate 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.
#
# translate 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/>.
#

"""
Module for handling Qt Linguist Phrase Book (.qph) files.

Extract from the `Qt Linguist Manual: Translators
<http://doc.trolltech.com/4.3/linguist-translators.html>`_:
.qph Qt Phrase Book Files are human-readable XML files containing standard
phrases and their translations. These files are created and updated by Qt
Linguist and may be used by any number of projects and applications.

A DTD to define the format does not seem to exist, but the following `code
<http://qt.gitorious.org/qt/qt/blobs/4.7/tools/linguist/shared/qph.cpp>`_
provides the reference implementation for the Qt Linguist product.
"""

from lxml import etree

from translate.lang import data
from translate.misc.xml_helpers import safely_set_text
from translate.storage import lisa


class QphUnit(lisa.LISAunit):
    """A single term in the qph file."""

    rootNode = "phrase"
    languageNode = "source"
    textNode = ""
    namespace = ""

    def createlanguageNode(self, lang, text, purpose):  # ty:ignore[invalid-method-override]
        """Returns an xml Element setup with given parameters."""
        assert purpose
        langset = etree.Element(self.namespaced(purpose))
        safely_set_text(langset, text)
        return langset

    def _getsourcenode(self):
        return self.xmlelement.find(self.namespaced(self.languageNode))

    def _gettargetnode(self):
        return self.xmlelement.find(self.namespaced("target"))

    def getlanguageNodes(self):
        """We override this to get source and target nodes."""
        return [
            n for n in [self._getsourcenode(), self._gettargetnode()] if n is not None
        ]

    def addnote(self, text, origin=None, position="append") -> None:
        """Add a note specifically in a "definition" tag."""
        current_notes = self.getnotes(origin)
        self.removenotes(origin)
        note = etree.SubElement(self.xmlelement, self.namespaced("definition"))
        safely_set_text(note, "\n".join(filter(None, [current_notes, text.strip()])))

    def getnotes(self, origin=None):
        # TODO: consider only responding when origin has certain values
        notenode = self.xmlelement.find(self.namespaced("definition"))
        comment = ""
        if notenode is not None:
            comment = notenode.text
        return comment

    def removenotes(self, origin=None) -> None:
        """Remove all the translator notes."""
        note = self.xmlelement.find(self.namespaced("definition"))
        if note is not None:
            self.xmlelement.remove(note)


class QphFile(lisa.LISAfile):
    """Class representing a QPH file store."""

    UnitClass = QphUnit
    Name = "Qt Phrase Book"
    Mimetypes = ["application/x-qph"]
    Extensions = ["qph"]
    rootNode = "QPH"
    bodyNode = "QPH"
    XMLskeleton = """<!DOCTYPE QPH>
<QPH>
</QPH>
"""
    namespace = ""

    def initbody(self) -> None:
        """
        Initialises self.body so it never needs to be retrieved from the XML
        again.
        """
        self.namespace = self.document.getroot().nsmap.get(None, None)
        self.header = self.document.getroot()
        self.body = self.document.getroot()  # The root node contains the units

    def getsourcelanguage(self) -> str:
        """
        Get the source language for this .qph file.

        We don't implement setsourcelanguage as users really shouldn't be
        altering the source language in .qph files, it should be set correctly
        by the extraction tools.

        :return: ISO code e.g. af, fr, pt_BR
        """
        lang = data.normalize_code(self.header.get("sourcelanguage", "en"))
        if lang == "en-us":
            return "en"
        return lang

    def gettargetlanguage(self) -> str:
        """
        Get the target language for this .qph file.

        :return: ISO code e.g. af, fr, pt_BR
        """
        return data.normalize_code(self.header.get("language"))

    def settargetlanguage(self, targetlanguage: str) -> None:
        """
        Set the target language for this .qph file to *targetlanguage*.

        :param targetlanguage: ISO code e.g. af, fr, pt_BR
        """
        if targetlanguage:
            self.header.set("language", targetlanguage)

    def serialize(self, out) -> None:
        """
        Write the XML document to the file `out`.

        We have to override this to ensure mimic the Qt convention:
            - no XML declaration
        """
        self.document.write(
            out, pretty_print=True, xml_declaration=False, encoding="utf-8"
        )
