from django import template
from django.template.base import TextNode, VariableNode, TemplateSyntaxError

from copy import copy

register = template.Library()

@register.tag( name = "menu" )
def do_menu( parser, token ):	
	tag_name, menu_name, opt_name = token.split_contents()
	return MenuNode( menu_name, opt_name )

class MenuNode( template.Node ):
	def __init__( self, menu_name, opt_name ):
		self.menu_name = menu_name
		self.opt_name = opt_name

	def _replaceUrlText( self, opt, active ):

		active_ = copy( active )

		for i in range( 0, len( active ) ):
			node = active_[ i ]

			if isinstance( node, VariableNode ):
				if node.filter_expression.token == u'text':
					active_[ i ] = TextNode( opt[ 1 ][ 0 ].s )
				elif node.filter_expression.token == u'url':
					active_[ i ] = TextNode( opt[ 0 ] )
		return active_
		

	def render( self, context ):
		menu = context[ '_menus' ][ self.menu_name ]

		active = menu[ '_defmenu_active' ]
		inactive = menu[ '_defmenu_inactive' ]
		opts = menu[ '_defmenu_opts' ]
		opt = opts[ self.opt_name ]

		result_list = []

		
		for opt_name in opts:
			opt = opts[ opt_name ]

			if self.opt_name == opt_name:								
				result_list.append( ( self._replaceUrlText( opt, active ) ).render( context ) )
			else:
				result_list.append( ( self._replaceUrlText( opt, inactive ) ).render( context ) )

		result_list.reverse()

		return " ".join( result_list )			

@register.tag( name = 'defmenu' )
def do_defmenu( parser, token ):
	nodelist = parser.parse( ( 'enddefmenu', ) )
	parser.delete_first_token()

	tag_name, menu_name = token.split_contents()

	return DefMenuNode( nodelist, menu_name )

class DefMenuNode( template.Node ):
	def __init__( self, nodelist, menu_name ):
		self.nodelist = nodelist
		self.menu_name = menu_name

	def render( self, context ):
		output = self.nodelist.render( context ) # applye children here

		if '_menus' not in context:
			context[ '_menus' ] = {}

		menu_name = self.menu_name
		context[ '_menus' ][ menu_name ] = {}
		menu = context[ '_menus' ][ menu_name ]

		try:
			menu[ '_defmenu_active' ] = context[ '_defmenu_active' ]
		except KeyError:
			raise TemplateSyntaxError( "An {% active %} block is not found inside the {% defmenu %} block." )
		try:
			menu[ '_defmenu_inactive' ] = context[ '_defmenu_inactive' ]
		except KeyError:
			raise TemplateSyntaxError( "An {% inactive %} block is not found inside the {% defmenu %} block." )
		try:
			menu[ '_defmenu_opts' ] = context[ '_defmenu_opts' ]
		except KeyError:
			raise TemplateSyntaxError( "The {% defmenu %} block must have at least one {% opt %} block inside." )

		del context[ '_defmenu_active' ]
		del context[ '_defmenu_inactive' ]
		del context[ '_defmenu_opts' ]

		return ""

@register.tag( name = 'active' )
def do_active( parser, token ):
	nodelist = parser.parse( ( 'endactive', ) )
	parser.delete_first_token()
	return ActiveNode( nodelist )

class ActiveNode( template.Node ):
	def __init__( self, nodelist ):
		self.nodelist = nodelist

	def render( self, context ):
		context[ '_defmenu_active' ] = self.nodelist

@register.tag( name = 'inactive' )
def do_inactive( parser, token ):
	nodelist = parser.parse( ( 'endinactive', ) )
	parser.delete_first_token()
	return InactiveNode( nodelist )

class InactiveNode( template.Node ):
	def __init__( self, nodelist ):
		self.nodelist = nodelist

	def render( self, context ):
		context[ '_defmenu_inactive' ] = self.nodelist


@register.tag( name = 'opt' )
def do_opt( parser, token ):
	nodelist = parser.parse( ( 'endopt', ) )
	parser.delete_first_token()

	tag_name, name, url = token.split_contents()

	return OptNode( nodelist, name, url )

class OptNode( template.Node ):
	def __init__( self, nodelist, name, url ):
		self.nodelist = nodelist
		self.name = name
		self.url = url

	def render( self, context ):
		if '_defmenu_opts' not in context:
			context['_defmenu_opts' ] = {}
		context[ '_defmenu_opts' ].update( { self.name: ( self.url, self.nodelist ) } )