# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
# MIT License. See license.txt

from __future__ import unicode_literals
import frappe
from frappe.utils import now
from frappe.model.document import Document
from frappe.model.naming import append_number_if_name_exists
from frappe.website.utils import cleanup_page_name, get_home_page
from frappe.website.render import clear_cache
from frappe.modules import get_module_name
from frappe.website.router import get_page_context_from_template, get_page_context

class WebsiteGenerator(Document):
	website = frappe._dict(
		page_title_field = "name"
	)

	def autoname(self):
		if self.meta.autoname != "hash":
			self.name = self.get_page_name()
			append_number_if_name_exists(self)

	def onload(self):
		self.get("__onload").update({
			"is_website_generator": True,
			"website_route": self.get_route(),
			"published": self.website_published()
		})

	def validate(self):
		self.set_parent_website_route()

		if not self.page_name:
			self.page_name = self.make_page_name()

		if self.meta.get_field("page_name") and not self.get("__islocal"):
			current_route = self.get_route()
			current_page_name = self.page_name
			# page name changed, rename everything
			if current_page_name and current_page_name != self.page_name:
				self.update_routes_of_descendants(current_route)

	def on_update(self):
		clear_cache(self.get_route())
		if getattr(self, "save_versions", False):
			frappe.add_version(self)

	def get_route(self, doc = None):
		self.get_page_name()
		return make_route(self)

	def clear_cache(self):
		clear_cache(self.get_route())

	def get_page_name(self):
		return self.get_or_make_page_name()

	def get_or_make_page_name(self):
		page_name = self.get("page_name")
		if not page_name:
			page_name = self.make_page_name()
			self.set("page_name", page_name)

		return page_name

	def make_page_name(self):
		return cleanup_page_name(self.get(self.website.page_title_field or "name"))

	def before_rename(self, oldname, name, merge):
		self._local = self.get_route()
		self.clear_cache()

	def after_rename(self, olddn, newdn, merge):
		if getattr(self, "_local"):
			self.update_routes_of_descendants(self._local)
		self.clear_cache()

	def on_trash(self):
		self.clear_cache()

	def website_published(self):
		if self.website.condition_field:
			return self.get(self.website.condition_field) and True or False
		else:
			return True

	def set_parent_website_route(self):
		parent_website_route_field = self.website.parent_website_route_field
		if parent_website_route_field:
			field = self.meta.get_field(parent_website_route_field)
			parent = self.get(parent_website_route_field)
			if parent:
				parent_doc = frappe.get_doc(field.options, parent)
				if parent_doc.website_published():
					self.parent_website_route = parent_doc.get_route()
				else:
					self.parent_website_route = None

	def update_routes_of_descendants(self, old_route = None):
		if not self.is_new() and self.meta.get_field("parent_website_route"):
			if not old_route:
				old_route = frappe.get_doc(self.doctype, self.name).get_route()

			if old_route and old_route != self.get_route():
				# clear cache of old routes
				old_routes = frappe.get_all(self.doctype, filters={"parent_website_route": ("like", old_route + "%")})

				if old_routes:
					for like_old_route in old_routes:
						clear_cache(frappe.get_doc(self.doctype, like_old_route.name).get_route())

					frappe.db.sql("""update `tab{0}` set
						parent_website_route = replace(parent_website_route, %s, %s),
						modified = %s,
						modified_by = %s
						where parent_website_route like %s""".format(self.doctype),
						(old_route, self.get_route(), now(), frappe.session.user, old_route + "%"))

	def get_route_context(self):
		route = frappe._dict()
		route.update({
			"doc": self,
			"page_or_generator": "Generator",
			"ref_doctype":self.doctype,
			"idx": self.idx,
			"docname": self.name,
			"page_name": self.get_page_name(),
			"controller": get_module_name(self.doctype, self.meta.module),
		})

		route.update(self.website)

		if not route.page_title:
			route.page_title = self.get(self.website.page_title_field or "name")

		return route

	def get_parents(self, context):
		# already set
		if context.parents:
			return context.parents

		home_page = get_home_page()

		parents = []
		me = self
		while me:
			_parent_field = me.website.parent_website_route_field
			_parent_val = me.get(_parent_field) if _parent_field else None

			# if no parent and not home page, then parent is home page
			if not _parent_val and me.get_route() != home_page:
				# parents.append(frappe._dict(name=home_page, title=get_page_context(home_page).title))
				break

			elif _parent_val:
				df = me.meta.get_field(_parent_field)
				if not df:
					break
				parent_doc = frappe.get_doc(df.options, _parent_val)

				if not parent_doc.website_published():
					break

				if parent_doc:
					parent_info = frappe._dict(name = parent_doc.get_route(),
						title= parent_doc.get(parent_doc.website.page_title_field or "name"))
				else:
					parent_info = frappe._dict(name=self.parent_website_route,
						title=self.parent_website_route.replace("_", " ").title())

				if parent_info.name in [p.name for p in parents]:
					raise frappe.ValidationError, "Recursion in parent link"

				parents.append(parent_info)
				me = parent_doc
			else:
				# parent route is a page e.g. "blog"
				if me.get("parent_website_route"):
					page_route = get_page_context_from_template(me.parent_website_route)
					if page_route:
						parents.append(frappe._dict(name = page_route.name,
							title=page_route.page_title))
				me = None

		parents.reverse()
		return parents

	def get_parent(self):
		parent_website_route_field = self.website.parent_website_route_field
		if parent_website_route_field:
			return self.get(parent_website_route_field)

	def get_children(self, context=None):
		children = []
		route = self.get_route()
		if route==get_home_page():
			children = frappe.db.sql("""select url as name, label as page_title
				from `tabTop Bar Item` where parentfield='sidebar_items'
			order by idx""", as_dict=True)
			route = ""

		if not children and self.meta.get_field("parent_website_route"):
			children = self.get_children_of(route)

			if not children and self.parent_website_route:
				children = self.get_children_of(self.parent_website_route)

		return children

	def get_children_of(self, route):
		"""Return list of children of given route, for generating index in Web Page"""

		condition = 'parent_website_route = %s'
		if route=="index" or not route:
			condition = 'ifnull(parent_website_route, "") = %s and name != "index"'
			route = ""

		children = frappe.db.sql("""select name, page_name,
			parent_website_route, {title_field} as title from `tab{doctype}`
			where {condition}
			order by {order_by}""".format(
				doctype = self.doctype,
				title_field = self.website.page_title_field or "name",
				order_by = self.website.order_by or "idx asc",
				condition = condition
			), route, as_dict=True)

		for c in children:
			c.name = make_route(c)

		return children

	def has_children(self, route):
		return frappe.db.sql('''select name from `tab{0}`
			where parent_website_route = %s limit 1'''.format(self.doctype), route)

	def get_next(self):
		if self.meta.get_field("parent_website_route") and self.parent_website_route:
			route = self.get_route()
			parent = frappe.get_doc(self.doctype, self.get_parent())
			siblings = parent.get_children()
			for i, r in enumerate(siblings):
				if i < len(siblings) - 1:
					if route==r.name:
						return siblings[i+1]

			out = parent.get_next()
			out.next_parent = True
			return out
		else:
			return frappe._dict()

def make_route(doc):
	parent = doc.get("parent_website_route", "")
	return ((parent + "/") if parent else "") + doc.page_name


