"""
Generated by <Python Project Utils>
Visit the project in http://code.google.com/p/python-project-utils/
"""

import inspect
import re
import active_record.base
from context_container import ContextContainer
from context import Context

class Query(ContextContainer):
	order_pattern = re.compile(r"(\bASC\b|\bDESC\b)", re.IGNORECASE)

	def __init__(self):
		ContextContainer.__init__(self)

	def distinct(self, value = True):
		self.context[Context.Scopes.DISTINCT] = value

		return self

	def from_table(self, value):
		self.context[Context.Scopes.FROM] = value

		return self

	def group(self, *args):
		for arg in args:
			if type(arg) is str:
				self._add_coma(Context.Scopes.GROUP)
				self.context[Context.Scopes.GROUP] += arg.strip()
			elif type(arg) is list:
				self.group(*arg)
			else:
				self._raise_type_error(arg)

		return self

	def having(self, options, *values):
		for value in values:
			options = options.replace("?", str(value), 1)

		self.context[Context.Scopes.HAVING] = options

		return self

	def includes(self, *args):
		self._parse_arguments_to_list_scope(self.includes, Context.Scopes.INCLUDES, *args)

		return self

	def joins(self, *args):
		self._parse_arguments_to_list_scope(self.joins, Context.Scopes.JOINS, *args)

		return self

	def limit(self, value):
		self.context[Context.Scopes.LIMIT] = value

		return self

	def none(self):
		#TODO
		return []

	def offset(self, value):
		self.context[Context.Scopes.OFFSET] = value

		return self

	def order(self, *args, **kargs):
		for arg in args:
			value = ""

			if type(arg) is str:
				for token in arg.split(","):
					token = token.strip()

					if Query.order_pattern.search(token) is None:
						token += " ASC"

					if len(value) > 0:
						value += ","

					value += token
			elif type(arg) is list:
				self.order(*arg)
			elif type(arg) is dict:
				for column, order in arg.items():
					if len(value) > 0:
						value += ","

					value += str(column) + " " + str(order)
			else:
				self._raise_type_error(arg)

			if len(value) > 0:
				self._add_coma(Context.Scopes.ORDER)
				self.context[Context.Scopes.ORDER] += value

		if len(kargs) > 0:
			self.order(kargs)

		return self

	def preload(self, *args):
		return self.includes(*args)

	#def references(self, *args):
	#	self.context["distinct"] = value

	#	return self

	def reorder(self, *args):
		self.unescope(Context.Scopes.ORDER)

		return self.order(*args)

	def reverse_order(self):
		order_tokens = self.context[Context.Scopes.ORDER].split(",")
		self.context[Context.Scopes.ORDER] = ""

		for token in order_tokens:
			self._add_coma(Context.Scopes.ORDER)

			if token.split(" ")[1].upper() == "ASC":
				self.context[Context.Scopes.ORDER] += token[:-3] + "DESC"
			else:
				self.context[Context.Scopes.ORDER] += token[:-4] + "ASC"

		return self

	def select(self, *fields):
		self.context[Context.Scopes.SELECT] = ""

		for field in fields:
			self._add_coma(Context.Scopes.SELECT)
			self.context[Context.Scopes.SELECT] += field

		return self

	def uniq(self, value = True):
		return self.distinct(value)

	def unescope(self, *scopes):
		for scope in scopes:
			if scope in self.context:
				if type(self.context[scope]) is list:
					del self.context[scope][:]
				else:
					del self.context[scope]

		return self

	def where(self, options = None, *values, **kargs):
		if options is not None:
			if type(options) is str:
				options = [options]
				options.extend(values)

				return self.where(options)
			elif type(options) is list:
				option = options.pop(0)

				if option.find("?") > -1:
					for value in options:
						option = option.replace("?", self._convert_where_clause_value(value), 1)
				elif option.find(":") > -1:
					for key, value in options[0].items():
						option = option.replace(":" + key, self._convert_where_clause_value(value))
				elif option.find("%") > -1 and len(options) > 0:
					option = option % tuple(options)
			elif type(options) is dict:
				option = ""

				for key, value in options.items():
					if len(option) > 0:
						option += " AND "

					operator = "IN" if type(value) is list else "="
					option += key + " " + operator + " " + self._convert_where_clause_value(value)
			else:
				self._raise_type_error(options)

			self.context[Context.Scopes.WHERE].append(option)

		if len(kargs) > 0:
			self.where(kargs)

		return self

	def _add_coma(self, scope):
		if scope not in self.context:
			self.context[scope] = ""
		elif len(self.context[scope]) > 0:
			self.context[scope] += ","

	def _convert_where_clause_value(self, value):
		if type(value) is str:
			return "'" + value + "'"
		elif type(value) is list:
			items = value
			value = "("

			for item in items:
				if len(value) > 1:
					value += ","

				value += self._convert_where_clause_value(item)

			value += ")"

			return value
		else:
			return str(value)

	def _parse_arguments_to_list_scope(self, method, scope, *args):
		for arg in args:
			if type(arg) is str or type(arg) is dict:
				self.context[scope].append(arg)
			elif type(arg) is list:
				method.__call__(*arg)
			else:
				self._raise_type_error(arg)

	def _raise_type_error(self, value):
		raise TypeError("Unsupported type " + str(type(value)) +  ".")
