# -*- coding: utf-8 -*-

import base64, string
from xml.marshal.generic import Marshaller, Unmarshaller
from django.db.models import Model
from django.db.models.loading import get_model

from django.db.models import query as django_query
from copy import copy

class QMarshaller (Marshaller) :

	def dumps (self, value, use_base64=False) :
		o = Marshaller.dumps(self, value)
		if use_base64 :
			return base64.b64encode(o)
		else :
			return o

	def _marshal(self, value, dict):
		if isinstance(value, Model) :
			meth = "m_django_object"
			return getattr(self, meth)(value, dict)

		return Marshaller._marshal(self, value, dict)

	def m_unicode (self, value, dict) :
		return self.m_string(value.encode("utf8"), dict)

	def m_django_object (self, object, dict) :
		name = "django_object"

		model_name = "%s.%s" % (object._meta.app_label, object._meta.module_name, )
		L = ["<%s model=\"%s\" pk=\"%s\">" % (name, model_name, object.pk)]
		L.append("</%s>" % name)
		return L

	def m_condition (self, c, dict, ) :
		name = "condition"
		k, v, = c
		L = ["<%s key=\"%s\">" % (name, k, )]
		L = L + self._marshal(v, dict)
		L.append("</%s>" % name)
		return L

	def m_Q (self, q, dict, ) :
		name = "Q"
		L = ["<%s>" % (name, )]
		for c in q.kwargs.items() :
			L = L + self.m_condition(c, dict)
		L.append("</%s>" % name)
		return L

	def m_QOr (self, q, dict, ) :
		name = "QOr"
		L = ["<%s operator=\"%s\">" % (name, q.operator.strip(), )]
		for elem in q.args :
			L = L + self._marshal(elem, dict)
		L.append("</%s>" % name)
		return L

	def m_QAnd (self, q, dict, ) :
		name = "QAnd"
		L = ["<%s operator=\"%s\">" % (name, q.operator.strip(), )]
		for elem in q.args :
			L = L + self._marshal(elem, dict)
		L.append("</%s>" % name)
		return L

class QUnmarshaller (Unmarshaller) :
	def __init__(self):
		self.unmarshal_meth.update(
			{
				"django_object": ("um_start_django_object", "um_end_django_object", ),
				"condition": ("um_start_condition", "um_end_condition", ),
				"Q": ("um_start_Q", "um_end_Q", ),
				"QOr": ("um_start_QOr", "um_end_QOr", ),
				"QAnd": ("um_start_QAnd", "um_end_QAnd", ),
			}
		)
		Unmarshaller.__init__(self)

	def loads (self, s, use_base64=False) :
		if use_base64 :
			s = base64.b64decode(s)

		return Unmarshaller.loads(self, s)

	def um_end_string(self, name):
		ds = self.data_stack
		ds[-1] = string.join(ds[-1], "").encode("utf8")

	def um_start_QOr (self, name, attrs) :
		pass

	def um_end_QOr (self, name) :
		q = django_query.QOr()

		for i in self.data_stack :
			q = q | i

		self.data_stack[:] = [q]

	def um_start_QAnd (self, name, attrs) :
		pass

	def um_end_QAnd (self, name) :
		q = django_query.QAnd()

		for i in self.data_stack :
			q = q & i

		self.data_stack[:] = [q]

	def um_start_Q (self, name, attrs) :
		pass

	def um_end_Q (self, name) :
		if len(self.data_stack) < 1 :
			self.data_stack.append(django_query.Q())
		else :
			key, value, = self.data_stack[-1]
			self.data_stack[-1] = django_query.Q(**{str(key): value})

	def um_start_condition (self, name, attrs) :
		self.data_stack.append(attrs.get("key"), )

	def um_end_condition (self, name) :
		key, value, = self.data_stack[-2:]

		self.data_stack[-2:] = [(key, value, )]

	def um_start_django_object (self, name, attrs) :
		m = get_model(*attrs.get("model").split("."))
		self.data_stack.append(m.objects.get(pk=attrs.get("pk")))

	def um_end_django_object (self, name) :
		pass


if __name__ == "__main__" :
	import sys, base64
	from django.contrib.auth import models as django_models
	qs = django_query.Q(username__contains="spike") | django_query.Q(email__contains="spike")

	_m = QMarshaller()
	a = _m.dumps(qs)

	print "Marshalled:"
	print a
	print

	_u = QUnmarshaller()
	qs = _u.loads(a)
	print "UnMarshalled:"
	print qs
	for i in qs.args :
		print i.kwargs
	print

