import django
import apps
import types
django.__path__.extend(__path__)

from django.contrib import auth
from django.conf import settings
from django.http import Http404

def _getdefault(name, default=None):
    try:
        default = getattr(settings, name)
    except: pass
    return default

auth.LOGIN_URL  = _getdefault('LOGIN_URL', auth.LOGIN_URL)
#auth.LOGOUT_URL = _getdefault('LOGIN_URL', auth.LOGOUT_URL)


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')
    try:
        ustr = unicode(string, 'utf8')
        return string
    except UnicodeError:
        try:
            ustr = unicode(string, 'us-ascii')
            try:
                return string.encode('utf8')
            except UnicodeError:
                return ustr.encode('utf8')
        except UnicodeError:
            return unicode(string).encode('utf8')
    return string

def safe_ascii_encode(ustring):
    if not isinstance(ustring, unicode):
        return ustring
    try:
        astr = str(ustring)
        return astr
    except UnicodeError:
        try:
            ustr = unicode(ustring, 'us-ascii')
            try:
                return str(ustr)
            except UnicodeError:
                return safe_utf8_encode(ustring)
        except UnicodeError:
            return str(ustr.encode('utf8'))
    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
