"""
Utility functions for converting content and some shared by other libraries
"""

import re
import os
from git import Repo, InvalidGitRepositoryError, NoSuchPathError
from elifetools import utils as etoolsutils


def repl(match):
    "Convert hex to int to unicode character"
    chr_code = int(match.group(1), 16)
    return chr(chr_code)


def entity_to_unicode(string):
    """
    Quick convert unicode HTML entities to unicode characters
    using a regular expression replacement
    """
    # Selected character replacements that have been seen
    replacements = []
    replacements.append((r"&alpha;", "\u03b1"))
    replacements.append((r"&beta;", "\u03b2"))
    replacements.append((r"&gamma;", "\u03b3"))
    replacements.append((r"&delta;", "\u03b4"))
    replacements.append((r"&epsilon;", "\u03b5"))
    replacements.append((r"&ordm;", "\u00ba"))
    replacements.append((r"&iuml;", "\u00cf"))
    replacements.append((r"&ldquo;", '"'))
    replacements.append((r"&rdquo;", '"'))

    # First, replace numeric entities with unicode
    string = re.sub(r"&#x(....);", repl, string)
    # Second, replace some specific entities specified in the list
    for entity, replacement in replacements:
        string = re.sub(entity, replacement, string)
    return string


def remove_tag(tag_name, string):
    """
    Remove open and close tags - the tags themselves only - using
    a non-greedy angle bracket pattern match
    """
    if not string:
        return string
    pattern = re.compile("</?" + tag_name + ".*?>")
    string = pattern.sub("", string)
    return string


def replace_tags(string, from_tag="i", to_tag="italic"):
    """
    Replace tags such as <i> to <italic>
    <sup> and <sub> are allowed and do not need to be replaced
    This does not validate markup
    """
    string = string.replace("<" + from_tag + ">", "<" + to_tag + ">")
    string = string.replace("</" + from_tag + ">", "</" + to_tag + ">")
    return string


def attr_names(attr_map):
    """return a list of attribute names from the map"""
    if attr_map:
        return list(sorted(attr_map.keys()))
    return []


def attr_string(attr_map):
    """string of tag attributes and values"""
    string = ""
    if attr_map:
        for key, value in sorted(attr_map.items()):
            attr = '%s="%s"' % (
                key,
                etoolsutils.escape_ampersand(value).replace('"', "&quot;"),
            )
            string = " ".join([string, attr])
    return string


def set_attr_if_value(obj, attr_name, value):
    "shorthand method to set object values if the value is not none"
    if value is not None:
        setattr(obj, attr_name, value)


def is_year_numeric(value):
    "True if value is all digits"
    if value and re.match("^[0-9]+$", value):
        return True
    return False


def version_from_xml_filename(filename):
    "extract the numeric version from the xml filename"
    try:
        filename_parts = filename.split(os.sep)[-1].split("-")
    except AttributeError:
        return None
    if len(filename_parts) == 3:
        try:
            return int(filename_parts[-1].lstrip("v").rstrip(".xml"))
        except ValueError:
            return None
    else:
        return None


def get_last_commit_to_master(repo_path="."):
    """
    returns the last commit on the master branch. It would be more ideal to get the commit
    from the branch we are currently on, but as this is a check mostly to help
    with production issues, returning the commit from master will be sufficient.
    """
    last_commit = None
    repo = None
    try:
        repo = Repo(repo_path)
    except (InvalidGitRepositoryError, NoSuchPathError):
        repo = None
    if repo:
        try:
            last_commit = repo.commits()[0]
        except AttributeError:
            # Optimised for version 0.3.2.RC1
            last_commit = repo.head.commit
    return str(last_commit)


def calculate_journal_volume(pub_date, year):
    """
    volume value is based on the pub date year
    pub_date is a python time object
    """
    try:
        volume = str(pub_date.tm_year - year + 1)
    except TypeError:
        volume = None
    except AttributeError:
        volume = None
    return volume


def author_name_from_json(author_json):
    "concatenate an author name from json data"
    author_name = None
    if author_json.get("type"):
        if author_json.get("type") == "group" and author_json.get("name"):
            author_name = author_json.get("name")
        elif author_json.get("type") == "person" and author_json.get("name"):
            if author_json.get("name").get("preferred"):
                author_name = author_json.get("name").get("preferred")
    return author_name


def text_from_affiliation_elements(department, institution, city, country):
    "format an author affiliation from details"
    return ", ".join(
        element for element in [department, institution, city, country] if element
    )
