#@+leo-ver=4
#@+node:@file import_cisco_config.py
"""Import cisco configuration files"""

from leoPlugins import *
from leoGlobals import *

try:
	import tkFileDialog
except ImportError:
	tkFileDialog = None

#@<< about this plugin >>
#@+node:<< about this plugin >>
#@+at 
#@nonl
# This plugin adds a menu item under the File->Import menu to import
# Cisco configuration files.
# 
# The plugin will:
# 
# 1) create a new node, under the current node, where the configuration will 
# be
# written. This node will typically have references to several sections (see 
# below).
# 
# 2) create sections (child nodes) for the indented blocks present in the 
# original
# config file. These child nodes will have sub-nodes grouping similar blocks 
# (e.g.
# there will be an 'interface' child node, with as many sub-nodes as there are 
# real
# interfaces in the configuration file).
# 
# 3) create sections for the custom keywords specified in the customBlocks[] 
# list in
# importCiscoConfig(). You can modify this list to specify different keywords. 
# DO
# NOT put keywords that are followed by indented blocks (these are taken care 
# of by
# point 2 above). The negated form of the keywords (for example, if the 
# keyword is
# 'service', the negated form is 'no service') is also included in the 
# sections.
# 
# 4) not display consecutive empty comment lines (lines with only a '!').
# 
# All created sections are alphabetically ordered.
# 
# Feedback on this plugin can be sent to Davide Salomoni 
# (dsalomoni@yahoo.com).
#@-at
#@-node:<< about this plugin >>
#@nl

if tkFileDialog:
	
	#@	@+others
	#@+node:create_import_cisco_menu
	def create_import_cisco_menu(tag, keywords):
		if	(tag=="open2" or
			(tag=="start2" and not keywords.has_key('c')) or
			(tag=="command2" and keywords.get("label")=="new")):
	
			c = top()
			importMenu = c.frame.menu.getMenu('import')
			newEntries = (
				("-", None, None),
				("Import C&isco Configuration", "Shift+Ctrl+I", importCiscoConfig))
			
			c.frame.menu.createMenuEntries(importMenu, newEntries)
	#@nonl
	#@-node:create_import_cisco_menu
	#@+node:importCiscoConfig
	def importCiscoConfig(event=None):
		c = top(); current = c.currentVnode()
		if current == None: return
		#@	<< open file >>
		#@+node:<< open file >>
		name = tkFileDialog.askopenfilename(
			title="Import Cisco Configuration File",
			filetypes=[("All files", "*")]
			)
		if name == "":	return
		
		v = current.insertAsNthChild(0)
		c.beginUpdate()
		v.setHeadString("cisco config: %s" % name)
		c.endUpdate()
		
		try:
			fh = open(name)
			es("importing: %s" % name)
			linelist = fh.read().splitlines()
			fh.close()
		except IOError,msg:
			es("error reading %s: %s" % (name, msg))
			return
		#@nonl
		#@-node:<< open file >>
		#@nl
	
		# define which additional child nodes will be created
		# these keywords must NOT be followed by indented blocks
		customBlocks = ['aaa','ip as-path','ip prefix-list','ip route',
						'ip community-list','access-list','snmp-server','ntp',
						'boot','service','logging']
		out = []
		blocks = {}
		children = []
		lines = len(linelist)
		i = 0
		skipToNextLine = 0
		# create level-0 and level-1 children
		while i<(lines-1):
			for customLine in customBlocks:
				if (linelist[i].startswith(customLine) or
					linelist[i].startswith('no %s' % customLine)):
					#@				<< process custom line >>
					#@+node:<< process custom line >>
					if not blocks.has_key(customLine):
						blocks[customLine] = []
						out.append(angleBrackets(customLine))
						# create first-level child
						child = v.insertAsNthChild(0)
						child.setHeadStringOrHeadline(angleBrackets(customLine))
						children.append(child)
					
					blocks[customLine].append(linelist[i])
					#@nonl
					#@-node:<< process custom line >>
					#@nl
					skipToNextLine = 1
					break
			if skipToNextLine:
				skipToNextLine = 0
			else:
				if linelist[i+1].startswith(' '):
					#@				<< process indented block >>
					#@+node:<< process indented block >>
					space = linelist[i].find(' ')
					if space == -1:
						space = len(linelist[i])
					key = linelist[i][:space]
					if not blocks.has_key(key):
						blocks[key] = []
						out.append(angleBrackets(key))
						# create first-level child
						child = v.insertAsNthChild(0)
						child.setHeadStringOrHeadline(angleBrackets(key))
						children.append(child)
					
					value = [linelist[i]]
					# loop through the indented lines
					i = i+1
					try:
						while linelist[i].startswith(' '):
							value.append(linelist[i])
							i = i+1
					except:
						# EOF
						pass
					i = i-1 # restore index
					# now add the value to the dictionary
					blocks[key].append(value)
					#@nonl
					#@-node:<< process indented block >>
					#@nl
				else:
					out.append(linelist[i])
			i=i+1
		# process last line
		out.append(linelist[i])
		
		#@	<< complete outline >>
		#@+node:<< complete outline >>
		# first print the level-0 text
		outClean = []
		prev = ''
		for line in out:
			if line=='!' and prev=='!':
				pass # skip repeated comment lines
			else:
				outClean.append(line)
			prev = line
		v.setBodyStringOrPane('\n'.join(outClean))
		
		# scan through the created outline and add children
		for child in children:
			# extract the key from the headline. Uhm... :)
			key = child.headString().split('<<'
				)[1].split('>>')[0].strip()
			if blocks.has_key(key):
				if type(blocks[key][0]) == type(''):
					# it's a string, no sub-children, so just print the text
					child.setBodyStringOrPane('\n'.join(blocks[key]))
				else:
					# it's a multi-level node
					for value in blocks[key]:
						# each value is a list containing the headline and then the text
						subchild = child.insertAsNthChild(0)
						subchild.setHeadStringOrHeadline(value[0])
						subchild.setBodyStringOrPane('\n'.join(value))
				child.sortChildren()
			else:
				# this should never happen
				es("Unknown key: %s" % key)
		v.sortChildren()
		#@nonl
		#@-node:<< complete outline >>
		#@nl
	#@nonl
	#@-node:importCiscoConfig
	#@-others
	
	if app.gui is None:
		app.createTkGui(__file__)

	if app.gui.guiName() == "tkinter":

		# Register the handlers...
		registerHandler(("start2","open2","command2"),
			create_import_cisco_menu)

		__version__ = "1.3" 
		plugin_signon(__name__)
#@-node:@file import_cisco_config.py
#@-leo
