class RestMiddleware(object):
	"""
		generic middleware that looks up model
		ids specified on the url path and stores it
		in a ``models'' dictionary in the request object.

		Accepts a ``model_map'' dictionary that specifies
		the mapping between path variable names ``(?P<name>)''
		and corresponding model managers.

		Example:
	    --------

		model_map = {
			'session': models.GameSession.objects,
		}

		url(r'^session/(?P<session>)/operation$) will lookup
		the appropriate `` GameSession'' object using
		the ``GameSession'''s model manager and stores
		it at ``request.models['session']''. A ``None''
		object will be stored if the model lookup was not
		successful.

	"""
	def __init__(self, model_map=None, require_login=True, prefetch_related=None, select_related=None):
		self.model_map = model_map if model_map else {}
		self.prefetch_related = prefetch_related if prefetch_related else {}
		self.select_related = select_related if select_related else {}
		self.require_login = bool(require_login)

	def process_view(self, request, view_func, view_args, view_kwargs):
		if self.require_login and (not hasattr(request, 'user') or not request.user.is_authenticated()):
			return redirect_to_login(request.get_full_path())
		else:
			if not hasattr(request, 'models'):
				request.models = {}

			for view_arg, pk in view_kwargs.iteritems():
				manager = self.model_map.get(view_arg)

				prefetch_related = self.prefetch_related.get(view_arg)
				if prefetch_related:
					manager = manager.prefetch_related(*prefetch_related)

				select_related = self.select_related.get(view_arg)
				if select_related:
					manager = manager.select_related(*select_related)

				if manager:
					try:
						obj = manager.get(pk=pk)
						request.models[view_arg] = obj
					except ObjectDoesNotExist:
						pass


class Game1RestMiddleware(RestMiddleware):
	def __init__(self, require_login=True, prefetch_related=None, select_related=None):
		model_map = {
			'session': models.GameSession.objects,
			'collectible': models.Collectible.objects.select_subclasses(),
			'category': models.Category.objects,
			'chest': models.TreasureChest.objects,
			'message': models.Message.objects,
			'image': models.Image.objects,
		}
		super(Game1RestMiddleware, self).__init__(
			model_map=model_map,
			require_login=require_login,
			prefetch_related=prefetch_related,
			select_related=select_related
		)

	def process_view(self, request, view_func, view_args, view_kwargs):
		result = super(Game1RestMiddleware, self).process_view(request, view_func, view_args, view_kwargs)
		try:
			rmodels = request.models
		except AttributeError:
			request.models = {}
			rmodels = request.models

		# pull the game session from
		# the chest or collectible if possible
		#
		# do not do this for other models, i.e. do not pull the chest from
		# a deposited collectible
		if not 'session' in rmodels:
			chest = rmodels.get('chest')
			if chest and chest.session:
				rmodels['session'] = chest.session
		if not 'session' in rmodels:
			collectible = rmodels.get('collectible')
			if collectible and collectible.session:
				rmodels['session'] = collectible.session

		return result