from django.forms import model_to_dict
from django.shortcuts import redirect
from django.http import JsonResponse
from django.views import generic
from django.views.generic.edit import CreateView
from django.contrib.auth.mixins import LoginRequiredMixin
from django.core.exceptions import PermissionDenied

import seminar.models as s
import seminar.models as m
from treenode import treelib
import treenode.forms as f
import treenode.templatetags as tnltt
import treenode.serializers as vr

import logging

logger = logging.getLogger(__name__)


class TNLData(object):
	def __init__(self,anode,parent=None, index=None):
		self.node = anode
		self.sernode = vr.TreeNodeSerializer(anode)
		self.children = []
		self.parent = parent
		self.tema_in_path = False
		self.index = index

		if parent:
			self.tema_in_path = parent.tema_in_path
		if isinstance(anode, m.TemaVCisleNode):
			self.tema_in_path = True

	def add_edit_options(self):
		self.deletable = tnltt.deletable(self)
		self.editable_siblings = tnltt.editableSiblings(self)
		self.editable_children = tnltt.editableChildren(self)
		self.text_only_subtree = tnltt.textOnlySubtree(self)
		self.can_podvesit_za = tnltt.canPodvesitZa(self)
		self.can_podvesit_pred = tnltt.canPodvesitPred(self)
		self.appendable_children = tnltt.appendableChildren(self)
		print("appChld",self.appendable_children)
		if self.parent:
			self.appendable_siblings = tnltt.appendableChildren(self.parent)
		else:
			self.appendable_siblings = []
	@classmethod
	def public_above(cls, anode):
		""" Returns output of verejne for closest Rocnik, Cislo or Problem above.
		(All of them have method verejne.)"""
		parent = anode # chceme začít už od konkrétního node včetně
		while True:
			rocnik = isinstance(parent, s.RocnikNode)
			cislo = isinstance(parent, s.CisloNode)
			uloha = (isinstance(parent, s.UlohaVzorakNode) or
				isinstance(parent, s.UlohaZadaniNode))
			tema = isinstance(parent, s.TemaVCisleNode)

			if (rocnik or cislo or uloha or tema) or parent==None:
				break
			else:
				parent = treelib.get_parent(parent)
		if rocnik:
			return parent.rocnik.verejne()
		elif cislo:
			return parent.cislo.verejne()
		elif uloha:
			return parent.uloha.verejne()
		elif tema:
			return parent.tema.verejne()
		elif None:
			print("Existuje TreeNode, který není pod číslem, ročníkem, úlohou"
			"ani tématem. {}".format(anode))
			return False

	@classmethod
	def all_public_children(cls, anode):
		for ch in treelib.all_children(anode):
			if TNLData.public_above(ch):
				yield ch
			else:
				continue

	@classmethod
	def from_treenode(cls, anode, user, parent=None, index=None):
		if TNLData.public_above(anode) or user.has_perm('auth.org'):
			out = cls(anode,parent,index)
		else:
			raise PermissionDenied()

		if user.has_perm('auth.org'):
			enum_children = enumerate(treelib.all_children(anode))
		else:
			enum_children = enumerate(TNLData.all_public_children(anode))

		for (idx,ch) in enum_children:
			outitem = cls.from_treenode(ch, user, out,  idx)
			out.children.append(outitem)
		out.add_edit_options()
		return out

	@classmethod
	def from_tnldata_list(cls, tnllist):
		"""Vyrobíme virtuální TNL, který nemá obsah, ale má za potomky všechna zadaná TNLData"""
		result = cls(None)
		for idx, tnl in enumerate(tnllist):
			result.children.append(tnl)
			tnl.parent = result
			tnl.index = idx
		result.add_edit_options()
		return result

	@classmethod
	def filter_treenode(cls, treenode, predicate):
		tnll = cls._filter_treenode_recursive(treenode, predicate) # TreeNodeList List :-)
		return TNLData.from_tnldata_list(tnll)

	@classmethod
	def _filter_treenode_recursive(cls, treenode, predicate):
		if predicate(treenode):
			return [cls.from_treenode(treenode)]
		else:
			found = []
			for tn in treelib.all_children(treenode):
				result = cls.filter_treenode(tn, predicate)
				# Result by v tuhle chvíli měl být seznam TNLDat odpovídající treenodům, jež matchnuly predikát.
				for tnl in result:
					found.append(tnl)
			return found

	def to_json(self):
		#self.node = anode
		#self.children = []
		#self.parent = parent
		#self.tema_in_path = False
		#self.index = index
		out = {}
		out['node'] = self.sernode.data
		out['children'] = [n.to_json() for n in self.children]
		out['tema_in_path'] = self.tema_in_path
		out['index'] = self.index
		out['deletable'] = self.deletable
		out['editable_siblings'] = self.editable_siblings
		out['editable_children'] = self.editable_children
		out['text_only_subtree'] = self.text_only_subtree
		out['can_podvesit_za'] = self.can_podvesit_za
		out['can_podvesit_pod'] = self.can_podvesit_pred
		out['appendable_children'] = self.appendable_children
		out['appendable_siblings'] = self.appendable_siblings

		return out



	def __repr__(self):
		return("TNL({})".format(self.node))


class TreeNodeView(generic.DetailView):
	model = s.TreeNode
	template_name = 'treenode/treenode.html'

	def get_context_data(self,**kwargs):
		context = super().get_context_data(**kwargs)
		context['tnldata'] = TNLData.from_treenode(self.object,self.request.user)
		return context


class TreeNodeJSONView(generic.DetailView):
	model = s.TreeNode

	def get(self,request,*args, **kwargs):
		self.object = self.get_object()
		data = TNLData.from_treenode(self.object,self.request.user).to_json()
		return JsonResponse(data)


class TreeNodePridatView(generic.View):
	type_from_str = {
		'rocnikNode': m.RocnikNode,
		'cisloNode': m.CisloNode,
		'castNode': m.CastNode,
		'textNode': m.TextNode,
		'temaVCisleNode': m.TemaVCisleNode,
		'reseniNode': m.ReseniNode,
		'ulohaZadaniNode': m.UlohaZadaniNode,
		'ulohaVzorakNode': m.UlohaVzorakNode,
		'pohadkaNode': m.PohadkaNode,
		'orgText': m.OrgTextNode,
		}

	def post(self, request, *args, **kwargs):
		######## FIXME: ROZEPSANE, NEFUNGUJE, DOPSAT !!!!!! ###########
		node = s.TreeNode.objects.get(pk=self.kwargs['pk'])
		kam = self.kwargs['kam']
		co = self.kwargs['co']
		typ = self.type_from_str[co]

		raise NotImplementedError('Neni to dopsane, dopis to!')

		if kam not in ('pred','syn','za'):
			raise ValidationError('Přidat lze pouze před nebo za node nebo jako syna')

		if co == m.TextNode:
			new_obj = m.Text()
			new_obj.save()
		elif co == m.CastNode:
			new_obj = m.CastNode()
			new_obj.nadpis = request.POST.get('pridat-castNode-{}-{}'.format(node.id,kam))
			new_obj.save()
		elif co == m.ReseniNode:
			new_obj = m
			pass
		elif co == m.UlohaZadaniNode:
			pass
		elif co == m.UlohaReseniNode:
			pass
		else:
			new_obj = None


		if kam == 'pred':
			pass


		if kam == 'syn':
			if typ == m.TextNode:
				text_obj = m.Text()
				text_obj.save()
				node = treelib.create_child(node, typ, text=text_obj)
			else:
				node = treelib.create_child(node, typ)
		if kam == 'za':
			if typ == m.TextNode:
				text_obj = m.Text()
				text_obj.save()
				node = treelib.create_node_after(node, typ, text=text_obj)
			else:
				node = treelib.create_node_after(node, typ)

		return redirect(node.get_admin_url())


class TreeNodeSmazatView(generic.base.View):
	def post(self, request, *args, **kwargs):
		node = s.TreeNode.objects.get(pk=self.kwargs['pk'])
		if node.first_child:
			raise NotImplementedError('Mazání TreeNode se syny není zatím podporováno!')
		treelib.disconnect_node(node)
		node.delete()
		return redirect(request.headers.get('referer'))


class TreeNodeOdvesitPrycView(generic.base.View):
	def post(self, request, *args, **kwargs):
		node = s.TreeNode.objects.get(pk=self.kwargs['pk'])
		treelib.disconnect_node(node)
		node.root = None
		node.save()
		return redirect(request.headers.get('referer'))


class TreeNodePodvesitView(generic.base.View):
	def post(self, request, *args, **kwargs):
		node = s.TreeNode.objects.get(pk=self.kwargs['pk'])
		kam = self.kwargs['kam']
		if kam == 'pred':
			treelib.lower_node(node)
		elif kam == 'za':
			raise NotImplementedError('Podvěsit za není zatím podporováno')
		return redirect(request.headers.get('referer'))


class TreeNodeProhoditView(generic.base.View):
	def post(self, request, *args, **kwargs):
		node = s.TreeNode.objects.get(pk=self.kwargs['pk'])
		treelib.swap_succ(node)
		return redirect(request.headers.get('referer'))
		#FIXME ve formulari predat puvodni url a vratit redirect na ni

class SirotcinecView(generic.ListView):
	model = s.TreeNode
	template_name = 'treenode/orphanage.html'

	def get_queryset(self):
		return s.TreeNode.objects.not_instance_of(s.RocnikNode).filter(root=None,prev=None,succ=None,father_of_first=None)

# FIXME pouzit Django REST Framework
class TextWebView(generic.DetailView):
	model = s.Text

	def get(self,request,*args, **kwargs):
		self.object = self.get_object()
		return JsonResponse(model_to_dict(self.object,exclude='do_cisla'))


class VueTestView(generic.TemplateView):
	template_name = 'treenode/vuetest.html'


class NahrajObrazekKTreeNoduView(LoginRequiredMixin, CreateView):
	model = s.Obrazek
	form_class = f.NahrajObrazekKTreeNoduForm

	def get_initial(self):
		initial = super().get_initial()
		initial['na_web'] = self.request.FILES['upload']
		return initial


	def form_valid(self,form):
		print(self.request.headers)
		print(self.request.headers['Textid'])
		print(form.instance)
		print(form)
		self.object = form.save(commit=False)
		print(self.object.na_web)
		self.object.text = m.Text.objects.get(pk=int(self.request.headers['Textid']))
		self.object.save()

		return JsonResponse({"url":self.object.na_web.url})