import django
import types

from django.contrib import auth
from django.conf import settings
from django.http import Http404
from django.core import signals
from django.dispatch import dispatcher

from datetime import timedelta, tzinfo
from django.utils import tzinfo

## Case Sensitive!!!
MASK_IN_EXCEPTION_EMAIL= ['password', 'protected', 'private' ] #'mail'

class fixedtimedelta(timedelta) :
    def __init__(self,*args,**kwargs):
        x = timedelta(*args, **kwargs)
        res = super(fixedtimedelta, self).__init__(*args,**kwargs)
        self._days = x.days
        self._seconds = x.seconds
        self._fixed_days = 0
        self._fixed_seconds = self._days*24*3600 + self._seconds
        return res
    @property
    def days(self): return 0
    @property
    def seconds(self): return self._fixed_seconds

tzinfo.timedelta = fixedtimedelta

def _getdefault(name, default=None):
    try:
        default = getattr(settings, name)
    except: pass
    return default


class Choices(dict):
    """A dictionary which behaves like a tuple/list thingie for django
    choice lists."""

    def __new__(cls, *args):
        obj = super(Choices, cls).__new__(cls)
        if args:
            obj._orig = list(args[0])
            obj.update(enumerate(*args))
        return obj
    def __len__(self):
        return len(self._orig)
    def __iter__(self):
        return iter(self._orig)
    @property
    def default(self):
        """default choice is the first key"""
        return self[0][0]
    def find(self, value, default=None):
        """Find they key for a verbose value (inverse lookup)"""
        ind = [y for x,y in self].index(value)
        if ind == -1: return default
        return self._orig[ind][0]
    def index(self, value):
        """Given a key, value, or (key, value) tuple, find the index"""
        ind = [x for x,y in self].index(value)
        if ind == -1:
            ind = [y for x,y in self].index(value)
        if ind == -1:
            ind = self._orig.index(value)

        return ind


def short_description(desc):
    short_desc = desc
    def decorator(func):
        func.short_description = short_desc
        return func
    return decorator

def bind_meth_to_class(cls, fname=None):
    """Monkey-Patch a method onto a class"""
    assert isinstance(cls, type)
    def bindmethod(func):
        name = fname
        if name is None: name = func.__name__
        #assert not hasattr(cls, name)
        unbound = types.UnboundMethodType(func, None, cls)
        setattr(cls, name, unbound)
        return func
    return bindmethod

def bind_prop_to_class(cls, fname=None):
    """Monkey-Patch a function, as a read-only property, onto a class"""
    assert isinstance(cls, type)
    def bindprop(func):
        name = fname
        if name is None: name = func.__name__
        #assert not hasattr(cls, name)
        prop = property(func)
        setattr(cls, name, prop)
        return func
    return bindprop

def safe_utf8_encode(string):
    if isinstance(string, unicode):
        return string.encode('utf8')
    if not isinstance(string, str):
        try:
            string = unicode(string)
        except (UnicodeError, UnicodeDecodeError, TypeError):
            try:
                string = str(string)
            except (UnicodeError, UnicodeDecodeError, TypeError):
                pass
    try:
        if isinstance(string, unicode):
            return string.encode('utf8')
        ustr = unicode(string, 'utf8')
        return ustr
    except (UnicodeError, UnicodeDecodeError, TypeError):
        try:
            ustr = unicode(string, 'us-ascii')
            try:
                return string.encode('utf8')
            except (UnicodeError, UnicodeDecodeError, TypeError):
                return ustr.encode('utf8')
        except (UnicodeError, UnicodeDecodeError, TypeError):
            try:
                return unicode(string).encode('utf8')
            except:
                # ok, we give up. its unicode,
                # but not recognizable utf8 encodible unicode
                tmp = repr(string)
                if tmp[0] == 'u': return tmp[2:-1]
                return unicode(tmp[1:-1]).encode('utf8')
    return string

def safe_ascii_encode(ustring):
    if isinstance(ustring, str):
        return ustring
    try:
        astr = str(ustring)
        return astr
    except (UnicodeError, UnicodeDecodeError, TypeError):
        try:
            ustr = unicode(ustring)
            ustr = unicode(ustr, 'us-ascii')
            try:
                return str(ustr)
            except (UnicodeError, UnicodeDecodeError, TypeError):
                return str(safe_utf8_encode(ustring))
        except (UnicodeError, UnicodeDecodeError, TypeError):
            return str(safe_utf8_encode(ustr))
    return ustring

def get_object_relations_or_404(klass, *args, **kwargs):
    try:
        return klass._default_manager.select_related().get(*args, **kwargs)
    except klass.DoesNotExist:
        raise Http404

def clean_request_for_except_repr(signal=None, sender=None, request=None):
    masked = False
    if not request or not request.POST: return False
    mutable = request.POST._mutable
    request.POST._mutable = True
    for name in request.POST:
        for mask in MASK_IN_EXCEPTION_EMAIL:
            if mask in name:
                request.POST[name]=u'xxHIDDENxx'
                masked=True
                break
    request.POST._mutable = mutable
    return masked

dispatcher.connect(clean_request_for_except_repr,
                   signal=signals.got_request_exception)
