#!/usr/bin/env python
# -*- coding: utf-8 -*-

"""
This module will process span tags.
"""

import re
import tkinter.ttk as tkinter_ttk	#Essential for ttk. commands
from tkinter import *				#Essential for root = Tk()
import tkinter as tk				#Essential for custom dialog box using tk. commands
from tkinter import messagebox		#Essential for messagebox
import GenUtils						#Need centerWindow()

text_type = str
characterize = chr

def GetCSSdescriptors(bk,SpanTagDict):
	"""
	Gets the css descriptors for each span tag that has been found and returns them as a list
	bk is the book object and SpanTagDict contains a list of unique span tags and their frequencies
	"""
	cssList=[]
	listTags=[]
	for (id, href) in bk.css_iter():
		css = bk.readfile(id)					#Read the css sheet
		if not isinstance(css, text_type):		#If the section is not str
			css = text_type(css, 'utf-8')		#then sets its type to 'utf-8'

		listTags = [ k for k in SpanTagDict.keys() ]
		for listItem in listTags:
			cssName = re.sub('(.*?)"(.*?)".*', '\\2',listItem)			#Strip listItem down to the css style name

			seekRegex = re.compile('(\.'+cssName+'[ ]?\{[^}]*?)\}')		#Set up a regular expression to find this style in the style sheet
			for match in seekRegex.finditer(css):						#Find the style in the style sheet with its details ie.styleName{style details}
				cssList.append(match.group(1)+'}')						#Append the style to the list cssList

	return (cssList)

def uCase(m):
		tempStr=m.group(2)
		while tempStr.find(">") !=-1:	  #strip tags - will not work for tags inside tags
			tempStr=re.sub(r'<[^>]+>',  "", tempStr)
		return (m.group(1).upper()+tempStr+"</p>")

def uCaseSmall(m):
		tempStr=m.group(2)
		while tempStr.find(">") !=-1:	  #strip tags - will not work for tags inside tags
			tempStr=re.sub(r'<[^>]+>',  "", tempStr)
		return ("""<span class="smallType">"""+m.group(1).upper()+"""</span>"""+ tempStr+"</p>")
		
def uCaseSmallItalics(m):
		tempStr=m.group(2)
		while tempStr.find(">") !=-1:	  #strip tags - will not work for tags inside tags
			tempStr=re.sub(r'<[^>]+>',  "", tempStr)
		return ("""<span class="uCaseSmallItalics">"""+m.group(1).upper()+"""</span>"""+ tempStr+"</p>")

#=============== NEW ==================================
def fnScrollable(event):
    #Set the scrollable region for the canvas and its width and height
    canvas.configure(scrollregion=canvas.bbox("all"), width=20, height=20)
#=============== NEW ENDS ==================================

def ShowdlgProcessSpanTags(root, SelectedHtmlList, SpanTagDict, bk, IDlist):
	"""
	This function is called by ProcessTags()
	The parameters are the main window object, the list containing the selected html files,
	and the directory that stores the list of unique span tag names and their frequencies
	The names of each unique span tag are stored in spanTagList
	A listbox displays the css descriptions of the span tags
	Labels for each unique tag are displayed with the frequency of their occurence.
	Combo boxes are displayed next to the labels.
	IMPORTANT: The combobox option exportselection must be set to 0
	After building this dialog with its widgets, centerWindow is called to centre this dialog box
	The function OK() is nested within ShowdlgProcessSpanTags() to avoid needing some global variables eg comboBox
	"""
	spanTagList=[]		#Clear list that holds the unique names of each span tag
	count=0				#initialise combobox counter to 0
	comboBox=[]			#Clear list that holds each combobox. 
#=================== Nested Function: OK() ==================================================
	def OK(IDlist):

		for id in IDlist:
			html = bk.readfile(id)					#Read the section into html
			if not isinstance(html, text_type):		#If the section is not str
				html = text_type(html, 'utf-8')		#then sets its type to 'utf-8'
			html_orig = html						#Copy the result to html_orig

			for i in range(0,count):
				if comboBox[i].get() == "Delete tag":
					tagtoprocess=spanTagList[i]+"(.*?)</span>"
					html=re.sub(tagtoprocess, r'\1', html)
				elif comboBox[i].get() == "Change to <i>":
					tagtoprocess=spanTagList[i]+"(.*?)</span>"
					html=re.sub(tagtoprocess, r'<i>\1</i>', html)
				elif comboBox[i].get() == "Change to <b>":
					tagtoprocess=spanTagList[i]+"(.*?)</span>"
					html=re.sub(tagtoprocess, r'<b>\1</b>', html)
				elif comboBox[i].get() == "Change to uppercase":
					tagtoprocess=spanTagList[i]+"(.*?)</span>(.*?)</p>"
					html=re.sub(tagtoprocess, uCase, html)
				elif comboBox[i].get() == "Change to small uppercase":
					tagtoprocess=spanTagList[i]+"(.*?)</span>(.*?)</p>"
					html=re.sub(tagtoprocess, uCaseSmall, html)
				elif comboBox[i].get() == "Change to small uppercase italics":
					tagtoprocess=spanTagList[i]+"(.*?)</span>(.*?)</p>"
					html=re.sub(tagtoprocess, uCaseSmallItalics, html)
	
			if not (html == html_orig):	#If the text has changed then write the amended text to the book
				bk.writefile(id, html)
		dlgProcessSpanTags.destroy()
		return(0)

#=================== END Nested Function: OK() ==================================================

	dlgProcessSpanTags=tk.Toplevel(root)
	dlgTagframe = ttk.Frame(dlgProcessSpanTags, padding="5 5 5 5")
	dlgTagframe.grid(column=0, row=0, sticky=(N, W, E, S))
	dlgTagframe.columnconfigure(0, weight=1)
	dlgTagframe.rowconfigure(0, weight=1)
	
#=============== REMOVED FROM PREVIOUS VERSION ==================================	
	#Now create a frame in a frame for the combo boxes; the rows in dlgTagframe are too far apart for a decent display on screen 
	#comboboxFrame=ttk.Frame(dlgTagframe,padding="5 5 5 5")
	#comboboxFrame.grid(column=2, row=2, sticky=(N, W, E, S))

#=============== NEW ==================================
	#Create a frame in dlgTagframe for the list of span tags
	spanFrame=Frame(dlgTagframe, relief=GROOVE, width=50, height=100,bd=1)
	spanFrame.grid(column=2, row=2, sticky=(N, W, E, S)) #Position span frame in dlgTagframe 
	spanFrame.columnconfigure(0, weight=1, minsize=300) #Set minimum size of frame
	spanFrame.rowconfigure(0, weight=1, minsize=100)

	#Create a frame for the canvas in the spanFrame
	canvas=Canvas(spanFrame)
	canvas.grid(column=0, row=0, sticky=(N, W, E, S))

	#Put the vertical scrollbar in the spanFrame and associate it with the canvas
	vscrollbar=Scrollbar(spanFrame,orient="vertical",command=canvas.yview)
	canvas.configure(yscrollcommand=vscrollbar.set)
	vscrollbar.grid(column=1, row=0, sticky=(N,E,S))

	#Put the horizontal scrollbar in spanFrame and associate it with the canvas
	hscrollbar=Scrollbar(spanFrame,orient="horizontal",command=canvas.xview)
	canvas.configure(xscrollcommand=hscrollbar.set)
	hscrollbar.grid(column=0, row=1, sticky=(W,E,S))

	#Create a frame in the canvas to hold the span tag information (labels and comboboxes)
	InteriorFrame=Frame(canvas)
	canvas.create_window((0,0), window=InteriorFrame, anchor='nw')
	InteriorFrame.bind("<Configure>", fnScrollable)
#=============== NEW ENDS ==================================

	dlgProcessSpanTags.grab_set()	#Make dialog modal - ensures no more dialog windows are not opened until this dialog is destroyed
	cbChoices=("Delete tag", "Change to <i>", "Change to <b>", "No action", "Change to uppercase", "Change to small uppercase", "Change to small uppercase italics")

	tk.Label(dlgTagframe, text="CSS details").grid(column=0, row=1, sticky=W)

	lboxCSS = tk.Listbox(dlgTagframe, height=15, width=50, selectmode=SINGLE, exportselection=0)
	lboxCSS.grid(column=0, row=2, sticky=W)
	vscrollerCSS = tk.Scrollbar(dlgTagframe, orient=VERTICAL, command=lboxCSS.yview)
	vscrollerCSS.grid(column=1, row=2, sticky=(N,S,W))
	lboxCSS.configure(yscrollcommand=vscrollerCSS.set)

	hscrollerCSS = tk.Scrollbar(dlgTagframe, orient=HORIZONTAL, command=lboxCSS.xview)
	hscrollerCSS.grid(column=0, row=3, sticky=(N,E,W))
	lboxCSS.configure(xscrollcommand=hscrollerCSS.set)

	lboxCSS.bindtags((lboxCSS, dlgTagframe, "all"))			#Prevent selecting items in listbox - still allows scrolling

	CSSList=GetCSSdescriptors(bk,SpanTagDict)
	for item in CSSList:
		lboxCSS.insert(END, item)

	for tag, frequency in SpanTagDict.items():
		NextLabel=("{0} ({1})".format(tag, frequency))
		spanTagList.append(tag)
		count=count+1
#================= CHANGED ====================================	
		Label(InteriorFrame,text=NextLabel).grid(column=0, row=count, sticky=W)
		#tk.Label(comboboxFrame, text=NextLabel).grid(column=2, row=count, sticky=W)
		#comboBox.append(ttk.Combobox(comboboxFrame, state="readonly", values=cbChoices,exportselection=0, width=35))
		comboBox.append(ttk.Combobox(InteriorFrame, state="readonly", values=cbChoices,exportselection=0, width=35))
		comboBox[count-1].grid(column=1, row=count, sticky=W)	#Needs to be on a separate line, unlike checkboxes????
		comboBox[count-1].set("No action")						#Set default value
#================= CHANGED ====================================	
	tk.Label(dlgTagframe, text="").grid(column=0, row=9, sticky=(EW))	#Blank row
	myOKButton = tk.Button(dlgTagframe, text='OK', command=lambda: OK(IDlist)).grid(column=0, row=count+3, sticky=(E,W))
	#myOKButton = tk.Button(dlgTagframe, text='OK', command=lambda: OK(IDlist)).grid(column=2, row=count+3, sticky=(E,W))
#================= CHANGED ENDS ====================================		
	GenUtils.centerWindow(dlgProcessSpanTags)
	root.wait_window(dlgProcessSpanTags)	#Wait for dlgProcessSpanTags to be destroyed before the following code is executed
	return(0)

def ProcessTags(root, SelectedHtmlList, bk, prefs, IDlist):
	"""
	This function is called when the user clicks on 'Process span tags' in the main window
	The parameters are the main window object, the list that contains the selected html files, hte bk object and the preferences dictionary
	Puts all the span tags for the files selected into spanList.
	The name of each UNIQUE span tag in this list is stored in the global directory SpanTagDict with its frequency.
	The number of different span tags is printed and then the function ShowdlgProcessSpanTags() is called.
	"""
	spanList=[]	#Clear list containing span tags (inc duplicates)
	SpanTagDict={} #Clear dictionary
	SpanRegex = re.compile(r'(<span[^>]*)') 		#Regex expression for span tags. This does not have the closing '>' tag, so consecutive tags are found

	for id in IDlist:
		html = bk.readfile(id)					#Read the section into html
		if not isinstance(html, text_type):		#If the section is not str
			html = text_type(html, 'utf-8')		#then sets its type to 'utf-8'
		html_orig = html						#Copy the result to html_orig
		for foundMatch in SpanRegex.finditer(html):		#Find every span tag in the text html and add it to the list 'spanList', adding the closing '>' tag
			spanList.append(foundMatch.group(1)+'>')

	if spanList:														#If list contains tags
		#Determine the frequency of each tag and stores it with the tag name in the dictionary SpanTagDict
		SpanTagDict = dict((i, spanList.count(i)) for i in spanList)	#Copy list to dictionary

		CountOfDifferentSpanTags=len(SpanTagDict)
		ShowdlgProcessSpanTags(root, SelectedHtmlList, SpanTagDict, bk, IDlist)
	else:
		print("The selected html files do not contain span tags")
	return(0)