from django.core.cache.backends.base import BaseCache
from django.utils.hashcompat import md5_constructor
from django.core.cache import get_cache,parse_backend_uri

class CacheClass(BaseCache,object):
	"""
	A cache backend that serves as a proxy to other backends and provides a fallback system
	>>> cache.set('foo','bar')
	>>> cache.get('foo')
	'bar'
	>>> cache['locmem'].get('foo')
	'bar' #fallback
	>>> cache['locmem'].set('foo','bazzz')
	>>> cache.get('foo')
	'bar'
	>>> cache['locmem'].get('foo')
	'bazzz'
	>>> cache.set_all('foo','bar',20)
	>>> cache.get('foo')
	'bar'
	>>> cache['locmem'].get('foo')
	'bar'
	>>> 
	
	"""
    def __init__(self, _, params):
		
		self.fallback = params.get('fallback',False)

		bs = params.get('backends')
		
		self.backends = {}
		self.default_backend = None
		bs = [b for b in bs.split(',')]
		for backend_uri in bs:
			scheme, host, params = parse_backend_uri(backend_uri)
			cache = get_cache(backend_uri)
			
			if self.default_backend is None:
				self.default_backend = cache
				self.backends[scheme] = cache
			elif self.fallback:
				self.backends[scheme] = fallback_backend(cache,self.default_backend)
			else:
				self.backends[scheme] = cache
		self.set = self.default_backend.set
		self.get = self.default_backend.get
		self.add = self.default_backend.add
		self.delete = self.default_backend.delete
		self.has_key = self.default_backend.has_key
		
    def get_backend(self,scheme):
	"""
	Returns the selected cache backend
	"""
	try:
		return self.backends[scheme]
	except KeyError:
		raise Exception("selected backend isn't set up")
	
    def set_all(self,*args,**kwargs):
	"""
	sets a value in all backends an once
	"""
	for backend in self.backends.itervalues():
		backend.set(*args,**kwargs)

    def __getitem__(self, key):
	return self.get_backend(key)

    def __setitem__(self,key):
	raise Exception("You can't edit the backends manually, use CACHE_BACKEND in settings.py")


class fallback_backend(object):
	"""
	A little class that wraps around a cache backend instance and provides fallback to the default backend
	"""
	def __init__(self,backend,fallback):
		self.backend = backend
		self.fallback = fallback
		self.set = self.backend.set
		self.add = self.backend.add
		self.delete = self.backend.delete
		self.has_key = self.backend.has_key

	def get(self,*args,**kwargs):

		value = self.backend.get(*args,**kwargs)
		if value is None:
			return self.fallback.get(*args,**kwargs)
		else:
			return value