
from django.db import (models,connection)
from django.db.models import Lookup
from django.db.models.fields import Field
from django.forms.models import model_to_dict

# https://docs.djangoproject.com/en/dev/howto/custom-lookups/ #
class NotExactLookup(Lookup):
	lookup_name = 'nexact'
	def as_sql(self, compiler, connection):
		lhs, lhs_params = self.process_lhs(compiler, connection)
		rhs, rhs_params = self.process_rhs(compiler, connection)
		params = lhs_params + rhs_params
		return '%s <> %s' % (lhs, rhs), params
	# 
# 
Field.register_lookup(NotExactLookup)

class CommonModel(models.Model):
	created = models.DateTimeField(blank=True, null=True, editable=False, auto_now_add=True)
	updated = models.DateTimeField(blank=True, null=True, editable=False, auto_now=True)
	class Meta:
		abstract = True
	# 
	"""
	@classmethod
	def _fields(self):
		_rm = ['created','updated']
		_fields = [i.name if i.db_column is None else i.db_column for i in self._meta.get_fields(include_parents=True,include_hidden=True)]
		_fields = [i for i in _fields if i not in _rm]
		return _fields
	# 
	"""
	"""
	@classmethod
	def _2dict(self,data):
		# if data.__class__.__name__ == 'QueryDict' or data.__class__.__name__ != 'dict': data = self._2dict(data);
		# if data.__class__.__name__ != 'dict': raise ValueError('type "data" harus "dict" biasa! pake "_2dict" dulu.');
		if data.__class__.__name__ != 'dict':
			return {k:v for k,v in data.items()}
		return data
	# 
	"""
	@classmethod
	def _sanitize_values(self,**values):
		# v = self._2dict(v)
		if 'csrfmiddlewaretoken' in values: del values['csrfmiddlewaretoken'];
		return values
	# 
	@classmethod
	def _sanitize_keys(self,**keys):
		# k = self._2dict(k)
		return keys
	# 
	@classmethod
	def _sanitize_result(self,data):
		data = model_to_dict(data)
		if '_pk' in data: data['pk'] = data['_pk'];
		if '_is' in data: data['is'] = data['_is'];
		if '_type' in data: data['type'] = data['_type'];
		return data
	# 
	@classmethod
	def _create(self,**values):
		return self.objects.create(**self._sanitize_values(**values))
	#

	@classmethod
	def _update(self, values={}, keys={}):
		return self.objects.filter(**self._sanitize_keys(**keys)).update(**self._sanitize_values(**values))

	# 
	@classmethod
	def _delete(self,**keys):
		return self.objects.filter(**keys).delete()
	# 
	@classmethod
	def _read_one(self,asis=False,**keys):
		entry = self.objects.get(**keys)
		if asis == False: entry = self._sanitize_result(entry);
		return entry
	# 
	@classmethod
	def _read_many(self,asis=False,**keys):
		context = self.objects.filter(**keys)
		if asis: return context;
		entries = []
		for entry in context.all():
			entries.append(self._sanitize_result(entry))
		return entries
	# 
# 

class RecursiveModel(CommonModel):
	_pk = models.AutoField(db_column='pk',primary_key=True)
	pk_parent = models.IntegerField()
	class Meta:
		abstract = True
	# 
	@classmethod
	def _recursive_reverse(self,sups=None,deep=0,**keys):
		if sups == None: sups = [];
		if deep >= 10: return;
		for subs in self.objects.filter(**keys):
			subs = self._sanitize_result(subs)
			keys['pk'] = subs['pk_parent']
			sups.append(subs)
			self._recursive_reverse(sups=sups,deep=deep+1,**keys)
		# 
		sups.reverse()
		return sups
	# 
	@classmethod
	def _recursive(self,sups=None,deep=0,flat=False,**keys):
		if sups == None: sups = [];
		if deep >= 10: return;
		for current in self.objects.filter(**keys):
			current = self._sanitize_result(current)
			current['deep'] = deep;

			keys['pk_parent'] = current['pk']
			subs_count = self.objects.filter(**keys).count()
			if subs_count > 0:
				if flat:
					self._recursive(sups=sups,deep=deep+1,flat=True,**keys)
				else:
					current['subs'] = []
					self._recursive(sups=current['subs'],deep=deep+1,**keys)
				# 
			# 
			if self._recursive_validate(current): sups.append(current);
		# 
		return sups
	# 
	@classmethod
	def _recursive_validate(self,current):
		return True
	# 
	@classmethod
	def _delete_recursive(self,pk):
		self._delete(pk=pk)
		for i in self._recursive(flat=True,pk_parent=pk):
			self._delete(pk=i['pk'])
		# 
	# 
# 
