# -*- coding: utf-8 -*-
from __future__ import unicode_literals

from builtins import chr, map, range, str
from urllib.parse import unquote
import hashlib
import re
import unicodedata

from datetime import datetime
from django.utils import formats, dateformat
from django.utils.encoding import force_str
from django.utils.functional import keep_lazy_text

from .decorators import simple_decorator  # NOQA


def format_datetime(value=None, date=True, time=True):
    if not date:
        format_type = 'TIME_FORMAT'
    elif not time:
        format_type = 'DATE_FORMAT'
    else:
        format_type = 'DATETIME_FORMAT'
    return dateformat.format(value or datetime.now(), formats.get_format(format_type))


def format_number(value=None, separator=','):
    if not value:
        return ''

    def split_thousands(s):
        if len(s) <= 3:
            return s
        return split_thousands(s[:-3]) + separator + s[-3:]
    return split_thousands(str(value))


# From http://stackoverflow.com/questions/517923/what-is-the-best-way-to-remove-accents-in-a-python-unicode-string
def strip_accents(txt):
    return unicodedata.normalize('NFD', str(txt)).encode('ascii', 'ignore').decode('ascii')


def latin1_safe_xml_encode(txt):
    return str(txt.encode('latin-1', 'xmlcharrefreplace'), 'latin-1')


xml_entity_table = bytes.maketrans(b' \'', b'--')


def format_xml_entity(txt):
    return strip_accents(txt).encode('ascii').upper().translate(xml_entity_table)


@keep_lazy_text
def truncate_chars(s, num):
    "Truncates a string after a certain number of characters."
    txt = force_str(s)
    length = int(num)
    if len(txt) > length:
        txt = txt[:length] + '...'
    return txt


rx_lettrine = re.compile(r"(\w)(\s)([\w-]+)([,.]{0,1}\s.*)", re.UNICODE | re.IGNORECASE)


def clean_lettrine(txt):
    """Vire les espaces ajoutés aux textes suite import QuarkXpress"""
    match = rx_lettrine.match(txt)
    if match:
        match = match.groups()
        supp_premier_espace = True
        if match[0] == 'A':
            if match[2] not in ('u', 'ux', 'vec', 'utour',):
                supp_premier_espace = False
        if supp_premier_espace:
            txt = rx_lettrine.sub(r'\1\3\4', txt)
    return txt


# From http://www.daniweb.com/code/snippet216865.html
#
# convert an integer to a roman numeral
# keep it reasonable since from 5000 on special characters are used
# see also: http://en.wikipedia.org/wiki/Roman_numerals
# tested with Python24       vegaseat        25jan2007
def int_to_roman(number):
    numerals = {1: "I", 4: "IV", 5: "V", 9: "IX", 10: "X", 40: "XL",
                50: "L", 90: "XC", 100: "C", 400: "CD", 500: "D", 900: "CM", 1000: "M"}
    result = ""
    for value, numeral in sorted(list(numerals.items()), reverse=True):
        while number >= value:
            result += numeral
            number -= value
    return result


# Inspired by http://stackoverflow.com/questions/92438/stripping-non-printable-characters-from-a-string-in-python
non_printable_re = re.compile('[%s]' % re.escape(''.join(map(chr, list(range(0, 9)) + list(range(11, 13)) + list(range(14, 32)) + list(range(127, 160))))))


def filter_non_printable(txt):
    return non_printable_re.sub('', txt)


def camelize(txt):
    return ' '.join([t.title() for t in txt.split(' ')])


def files_are_equal(f1, f2):
    if f1.size != f2.size:
        return False
    elif _digest_file(f1) != _digest_file(f2):
        return False
    return True


def _digest_file(f, chunk_size=8192):
    md5 = hashlib.md5()
    for chunk in iter(lambda: f.read(chunk_size), b""):
        md5.update(chunk)
    f.seek(0)
    return md5.digest()


def urldecode(url):
    out = {}
    get_params = (url.split('?')[1:] or [None])
    if get_params[0]:
        for param in get_params[0].split('&'):
            k, v = param.split('=')
            out[k] = unquote(v)
    return out
