import re
import os
import Image

from decimal import Decimal
from django.template import Library
from django.conf import settings
from django.template.defaultfilters import stringfilter
from django.utils import formats
from django.utils.safestring import mark_safe
from django.utils.html import conditional_escape, strip_tags, urlize
from django.contrib.auth.models import AnonymousUser
from django.core.files.storage import default_storage

register = Library()


@register.filter(name="localize_date")
def localize_date(value, to_tz=None):
    from timezones.utils import adjust_datetime_to_timezone
    try:
        if to_tz is None:
            to_tz = settings.UI_TIME_ZONE

        from_tz = settings.TIME_ZONE

        return adjust_datetime_to_timezone(value, from_tz=from_tz, to_tz=to_tz)
    except AttributeError:
        return ''
localize_date.is_safe = True

@register.filter_function
def date_short(value, arg=None):
    """Formats a date according to the given format."""
    from django.utils.dateformat import format
    from tendenci.core.site_settings.utils import get_setting
    if not value:
        return u''
    if arg is None:
        s_date_format = get_setting('site', 'global', 'dateformat')
        if s_date_format:
            arg = s_date_format
        else:
            arg = settings.SHORT_DATETIME_FORMAT
    try:
        return formats.date_format(value, arg)
    except AttributeError:
        try:
            return format(value, arg)
        except AttributeError:
            return ''
date_short.is_safe = False

@register.filter_function
def date_long(value, arg=None):
    """Formats a date according to the given format."""
    from django.utils.dateformat import format
    from tendenci.core.site_settings.utils import get_setting
    if not value:
        return u''
    if arg is None:
        s_date_format = get_setting('site', 'global', 'dateformatlong')
        if s_date_format:
            arg = s_date_format
        else:
            arg = settings.DATETIME_FORMAT
    try:
        return formats.date_format(value, arg)
    except AttributeError:
        try:
            return format(value, arg)
        except AttributeError:
            return ''
date_long.is_safe = False

@register.filter_function
def date(value, arg=None):
    """Formats a date according to the given format."""
    from django.utils.dateformat import format
    if not value:
        return u''
    if arg is None:
        arg = settings.DATETIME_FORMAT
    else:
        if arg == 'long':
            return date_long(value)
        if arg == 'short':
            return date_short(value)
    try:
        return formats.date_format(value, arg)
    except AttributeError:
        try:
            return format(value, arg)
        except AttributeError:
            return ''
date_long.is_safe = False

@register.filter_function
def order_by(queryset, args):
    args = [x.strip() for x in args.split(',')]
    return queryset.order_by(*args)

@register.filter_function
def in_group(user, group):
    if group:
        if isinstance(user, AnonymousUser):
            return False
        return group in [dict['pk'] for dict in user.group_set.values('pk')]
    else:
        return False

@register.filter
def domain(link):
    from urlparse import urlparse
    link = urlparse(link)
    return link.hostname

@register.filter
def strip_template_tags(string):
    p = re.compile('{[#{%][^#}%]+[%}#]}')
    return re.sub(p, '', string)

@register.filter
@stringfilter
def stripentities(value):
    """Strips all [X]HTML tags."""
    from django.utils.html import strip_entities
    return strip_entities(value)
stripentities.is_safe = True

@register.filter
def format_currency(value):
    """format currency"""
    from tendenci.core.base.utils import tcurrency
    return tcurrency(value)
format_currency.is_safe = True

@register.filter
def get_object(obj):
    """return obj.object if this obj has the attribute of object"""
    if hasattr(obj, 'object'):
        return obj.object
    else:
        return obj

@register.filter
def scope(object):
    return dir(object)

@register.filter
def obj_type(object):
    """
    Return object type
    """
    return type(object)

@register.filter
def is_iterable(object):
    """
    Return boolean
    Is the object iterable or not
    """
    try:
        iter(object)
        return True
    except TypeError:
        return False

@register.filter
@stringfilter
def basename(path):
    from os.path import basename
    return basename(path)

@register.filter
def date_diff(value, date_to_compare=None):
    """Compare two dates and return the difference in days"""
    import datetime
    if not isinstance(value, datetime.datetime):
        return 0

    if not isinstance(date_to_compare, datetime.datetime):
        date_to_compare = datetime.datetime.now()

    return (date_to_compare - value).days

@register.filter
def first_chars(string, arg):
    """ returns the first x characters from a string """
    string = str(string)
    if arg:
        if not arg.isdigit():
            return string
        return string[:int(arg)]
    else:
        return string
    return string

@register.filter
def rss_date(value, arg=None):
    """Formats a date according to the given format."""
    from django.utils import formats
    from django.utils.dateformat import format
    from datetime import datetime

    if not value:
        return u''
    else:
        value = datetime(*value[:-3])
    if arg is None:
        arg = settings.DATE_FORMAT
    try:
        return formats.date_format(value, arg)
    except AttributeError:
        try:
            return format(value, arg)
        except AttributeError:
            return ''
rss_date.is_safe = False

@register.filter()
def obfuscate_email(email, linktext=None, autoescape=None):
    """
    Given a string representing an email address,
    returns a mailto link with rot13 JavaScript obfuscation.

    Accepts an optional argument to use as the link text;
    otherwise uses the email address itself.
    """
    if autoescape:
        esc = conditional_escape
    else:
        esc = lambda x: x

    email = re.sub('@', '\\\\100', re.sub('\.', '\\\\056', \
        esc(email))).encode('rot13')

    if linktext:
        linktext = esc(linktext).encode('rot13')
    else:
        linktext = email

    rotten_link = """<script type="text/javascript">document.write \
        ("<n uers=\\\"znvygb:%s\\\">%s<\\057n>".replace(/[a-zA-Z]/g, \
        function(c){return String.fromCharCode((c<="Z"?90:122)>=\
        (c=c.charCodeAt(0)+13)?c:c-26);}));</script>""" % (email, linktext)
    return mark_safe(rotten_link)
obfuscate_email.needs_autoescape = True

@register.filter_function
def split_str(s, args):
    """
    Split a string using the python string split method
    """
    if args:
        if isinstance(s, str):
            splitter = args[0]
            return s.split(splitter)
        return s
    return s

@register.filter_function
def str_basename(s):
    """
    Get the basename using the python basename method
    """
    return basename(s)

@register.filter
@stringfilter
def twitterize(value, autoescape=None):
    value = strip_tags(value)
    # Link URLs
    value = urlize(value, nofollow=False, autoescape=autoescape)

    # Link twitter usernames for the first person
    value = re.sub(r'(^[^:]+)', r'<a href="http://twitter.com/\1">\1</a>', value)
    # Link twitter usernames prefixed with @
    value = re.sub(r'(\s+|\A)@([a-zA-Z0-9\-_]*)\b', r'\1<a href="http://twitter.com/\2">@\2</a>', value)
    # Link hash tags
    value = re.sub(r'(\s+|\A)#([a-zA-Z0-9\-_]*)\b', r'\1<a href="http://search.twitter.com/search?q=%23\2">#\2</a>', value)
    return mark_safe(value)
twitterize.is_safe = True
twitterize.needs_autoescape = True

@register.filter
@stringfilter
def twitterdate(value):
    from datetime import datetime, timedelta
    time = value.replace(" +0000", "")
    dt = datetime.strptime(time, "%a, %d %b %Y %H:%M:%S")
    return dt + timedelta(hours=-6)


@register.filter
def thumbnail(file, size='200x200'):
    # defining the size
    x, y = [int(x) for x in size.split('x')]
    # defining the filename and the miniature filename
    filehead, filetail = os.path.split(file.name)
    basename, format = os.path.splitext(filetail)
    miniature = basename + '_' + size + format
    filename = file.name
    miniature_filename = os.path.join(filehead, miniature)
    filehead, filetail = os.path.split(file.url)
    miniature_url = filehead + '/' + miniature

    thumbnail_exist = False
    if default_storage.exists(miniature_filename):
        mt_filename = default_storage.modified_time(filename)
        mt_miniature_filename = default_storage.modified_time(
                                                miniature_filename)
        if mt_filename > mt_miniature_filename:
            # remove the miniature
            default_storage.delete(miniature_filename)
        else:
            thumbnail_exist = True

    # if the image wasn't already resized, resize it
    if not thumbnail_exist:
        #image = Image.open(filename)
        image = Image.open(default_storage.open(filename))
        image.thumbnail([x, y], Image.ANTIALIAS)

        f = default_storage.open(miniature_filename, 'w')
        image.save(f, image.format, quality=90, optimize=1)
        f.close()

    return miniature_url

@register.filter_function
def datedelta(dt, range_):
    from datetime import timedelta

    range_type = 'add'
    # parse the range
    if '+' in range_:
        range_ = range_[1:len(range_)]
    if '-' in range_:
        range_type = 'subtract'
        range_ = range_[1:len(range_)]
    k, v = range_.split('=')
    set_range = {
        str(k): int(v)
    }

    # set the date
    if range_type == 'add':
        dt = dt + timedelta(**set_range)
    if range_type == 'subtract':
        dt = dt - timedelta(**set_range)

    return dt

@register.filter
def split(str, splitter):
    return str.split(splitter)

@register.filter
def tag_split(str):
    str = "".join(str)
    str = str.replace(", ", ",")
    return str.split(",")

@register.filter
def make_range(value):
    try:
        value = int(value)
        if value > 0:
            return range(int(value))
        return []
    except:
        return []

@register.filter
def underscore_space(value):
    return value.replace("_", " ")

@register.filter
def format_string(value, arg):
    return arg % value

@register.filter
def md5_gs(value, arg=None):
    import hashlib
    from datetime import datetime, timedelta

    hashdt = ''
    if arg and int(arg):
        timestamp = datetime.now() + timedelta(hours=int(arg))
        hashdt = hashlib.md5(timestamp.strftime("%Y;%m;%d;%H;%M").replace(';0', ';')).hexdigest()
    return ''.join([value, hashdt])

@register.filter
def multiply(value, arg):
    return Decimal(str(value)) * Decimal(str(arg))
