#!/c/Bin/Python/python.exe
#
#
#######################################################################
# Module imports
# TK related imports
from Tkinter import *
from Dialog import Dialog
from tkFileDialog import asksaveasfilename

# Simple DOM XML Parser
import xml.dom.minidom
# Misc system services
import sys, os, os.path, time, string

#######################################################################
# Settable variables
### Horizontal size of the Tk window
size = 600

### Fonts used in the dialogues
labelFont = ("Helvetica",12,"italic")
menuFont = ("Helvetica",10,"italic")
entryFont = ("Helvetica",12,"bold")

#######################################################################
# Global variables
### input file name
inputFile = None

# The head of the list of Addrs
Addrs = None

# Title of the full set (just store and save it...)
title = "W3C Communication Team"

#######################################################################
### Utilities

#
# 
#
def getText(nodeP):
    """Get the text information from a DOM node"""
    rc = ""
    for node in nodeP.childNodes:
        if node.nodeType == node.TEXT_NODE:
            rc = rc + node.data
    return rc

#
# 
#
def createAddrs(dom):
    """Create a linked list of Addr class instances from the XML description
    and return the first element of the list."""
    AddrsElements = dom.getElementsByTagName("Person")
    # Create the first Addr in the list:
    for i in range(len(AddrsElements)) :
        if i == 0 :
            AddrsFirst = AddrPrev = Addr(node=AddrsElements[0])
        else :
            ph = Addr(node=AddrsElements[i], previous=AddrPrev)
            AddrPrev = ph
    return AddrsFirst

        
########################################################################
#
# Addr class. It holds the information on an image: file name, description, date
# The class is also capable of printing its own content in xml format
#
class Addr:
    """Addr class. It holds the information on an image: file name, description, date
    The class is also capable of printing its own content in xml format"""
    def __init__(self, node=None, previous=None, adFile=None) :
        if adFile == None :
            # Information comes from a DOM node
            self.name = getText(node.getElementsByTagName("Name")[0])
            self.address = getText(node.getElementsByTagName("Address")[0])
            self.city = getText(node.getElementsByTagName("City")[0])
            try:
                self.zip = getText(node.getElementsByTagName("Zip")[0])
            except:
                self.zip = ""
            try:
                self.fax = getText(node.getElementsByTagName("Fax")[0])
            except:
                self.fax = ""
            try:
                self.pict = node.getElementsByTagName("Picture")[0]
                self.picture = self.pict.getAttribute("src")
                self.width   = self.pict.getAttribute("width")
                self.height   = self.pict.getAttribute("height")
            except:
                self.picture = self.width = self.height = ""
                self.pict = None
            self.email = getText(node.getElementsByTagName("Email")[0])
            self.country = getText(node.getElementsByTagName("Country")[0])
            
        else :
            # Information comes from a file, the rest must be
            # generated
            self.name = ""
            self.address = ""
            self.city = ""
            self.zip = ""
            self.faz = ""
            self.email = ""
            self.country = ""
            self.picture = self.width = self.height = ""
            self.pict = None

        # link settings for the previous and the next
        self.previous = previous
        self.next = None
        if previous != None :
            previous.next = self

    #
    # 
    #
    def pr(self,doc,parent) :
        """Add the content of the local element to a DOM Document
        doc:    a DOM Document element, to create new elements
        parent: the parent element"""
        pEl = doc.createElement("Person")
        
        pName = doc.createElement("Name")
        pName.appendChild(doc.createTextNode(self.name))
        pEl.appendChild(pName)

        pAddr = doc.createElement("Address")
        pAddr.appendChild(doc.createTextNode(self.address))
        pEl.appendChild(pAddr)

        pCity = doc.createElement("City")
        pCity.appendChild(doc.createTextNode(self.city))
        pEl.appendChild(pCity)

        p = doc.createElement("Zip")
        p.appendChild(doc.createTextNode(self.zip))
        pEl.appendChild(p)

        p = doc.createElement("Fax")
        p.appendChild(doc.createTextNode(self.fax))
        pEl.appendChild(p)
        
        p = doc.createElement("Email")
        p.appendChild(doc.createTextNode(self.email))
        pEl.appendChild(p)
        
        pCountry = doc.createElement("Country")
        pCountry.appendChild(doc.createTextNode(self.country))
        pEl.appendChild(pCountry)

        if self.pict :
            p = doc.createElement("Picture")
            p.setAttribute("width",self.width)
            p.setAttribute("height",self.height)
            p.setAttribute("src",self.picture)            
            pEl.appendChild(p)            

        parent.appendChild(pEl)

    #
    #
    #
    def prAll(self,doc,parent) :
        """Add the content of the local element to a DOM Document
        and then go to the next element in the list
        doc:    a DOM Document element, to create new elements
        parent: the parent element for this one"""
        self.pr(doc,parent)
        if self.next != None :
            self.next.prAll(doc,parent)
# End class Addr

    
########################################################################
#
#
# Addr Canvas: this is the real (Tk) application window
#
#
class AddrCanvas :
    """Addr Canvas: this is the real (Tk) application window"""
    # Init: create the Tk canvas and the description entries, and set the image to the
    # first Addrgraph
    def __init__(self) :
        # Initially, no image, just setting the various widgets
        self.imageItem = None
        self.currentAddr = Addrs
        self.changed = 1   # Because the image size values may have changed...

        # Root of the application
        self.root = root = Tk()
        # Use the title in the XML file (if any) as a window title
        root.title(title)
        # Exit should be controlled (see if a file has to be saved...)
        root.protocol("WM_DELETE_WINDOW",self.exit)

        # Menu with a save, save as, and exit entries
        menu = Menu(font=menuFont)
        root.config(menu=menu)
        filemenu = self.filemenu = Menu(menu,font=menuFont,tearoff=0)
        menu.add_cascade(label="File",menu=filemenu, font=menuFont)
        filemenu.add_command(label="Save", command=self.save, state=NORMAL)
        filemenu.add_command(label="Save As...", command=self.saveAs)
        filemenu.add_separator()
        filemenu.add_command(label="Append to...", command=self.append)
        filemenu.add_separator()
        filemenu.add_command(label="Exit", command=self.exit)

        # The canvas for the image, initially empty. Note that I use a grid!        
        self.canv = Canvas(root,width=size,height=25)
        self.canv.grid(row=0,columnspan=2)

        # Navigation to the next and previous images
        self.canv.bind("<Button-1>",self.prev)
        self.canv.bind("<Button-3>",self.next)

        # Description fields with their labels
        Label(root, text="Name:  ", font=labelFont).grid(row=1, column=0, sticky=W)
        self.nameEntry = Entry(root, width=80, font=entryFont)
        self.nameEntry.grid(row=1, column=1, sticky=W)

        # Description fields with their labels
        Label(root, text="Address:  ", font=labelFont).grid(row=2, column=0, sticky=W)
        self.addressEntry = Entry(root, width=80, font=entryFont)
        self.addressEntry.grid(row=2, column=1, sticky=W)

        Label(root, text="City:  ", font=labelFont).grid(row=3, column=0, sticky=W)
        self.cityEntry = Entry(root, width=80, font=entryFont)
        self.cityEntry.grid(row=3, column=1, sticky=W)

        Label(root, text="Zip:  ", font=labelFont).grid(row=4, column=0, sticky=W)
        self.zipEntry = Entry(root, width=80, font=entryFont)
        self.zipEntry.grid(row=4, column=1, sticky=W)

        Label(root, text="Country:  ", font=labelFont).grid(row=5, column=0, sticky=W)
        self.countryEntry = Entry(root, width=80, font=entryFont)
        self.countryEntry.grid(row=5, column=1, sticky=W)

        Label(root, text="Fax:  ", font=labelFont).grid(row=6, column=0, sticky=W)
        self.faxEntry = Entry(root, width=80, font=entryFont)
        self.faxEntry.grid(row=6, column=1, sticky=W)

        Label(root, text="Email:  ", font=labelFont).grid(row=7, column=0, sticky=W)
        self.emailEntry = Entry(root, width=80, font=entryFont)
        self.emailEntry.grid(row=7, column=1, sticky=W)

        Label(root, text="Picture:  ", font=labelFont).grid(row=8, column=0, sticky=W)
        self.pictureEntry = Entry(root, width=80, font=entryFont)
        self.pictureEntry.grid(row=8, column=1, sticky=W)

        Label(root, text="   width:", font=labelFont).grid(row=9, column=0, sticky=W)
        self.widthEntry = Entry(root, width=10, font=entryFont)
        self.widthEntry.grid(row=9, column=1, sticky=W)

        Label(root, text="   height:", font=labelFont).grid(row=10, column=0, sticky=W)
        self.heightEntry = Entry(root, width=10, font=entryFont)
        self.heightEntry.grid(row=10, column=1, sticky=W)

        # Everything is set up: set up the content with the current image (ie, the
        # first one)
        self.setImage()

        # Application main loop
        root.mainloop()

    #
    # 
    #
    def setImage(self) :
        """Change an image: change the description content, as well as the image
        to the global value of the current image"""

        # Set the description entries to their new values, and position the cursor
        self.nameEntry.delete(0,END)
        self.nameEntry.insert(0,self.currentAddr.name)
        self.nameEntry.icursor(END)
        
        self.addressEntry.delete(0,END)
        self.addressEntry.insert(0,self.currentAddr.address)
        self.addressEntry.icursor(END)

        self.cityEntry.delete(0,END)
        self.cityEntry.insert(0,self.currentAddr.city)
        self.cityEntry.icursor(END)

        self.zipEntry.delete(0,END)
        self.zipEntry.insert(0,self.currentAddr.zip)
        self.zipEntry.icursor(END)

        self.countryEntry.delete(0,END)
        self.countryEntry.insert(0,self.currentAddr.country)
        self.countryEntry.icursor(END)

        self.faxEntry.delete(0,END)
        self.faxEntry.insert(0,self.currentAddr.fax)
        self.faxEntry.icursor(END)

        self.emailEntry.delete(0,END)
        self.emailEntry.insert(0,self.currentAddr.email)
        self.emailEntry.icursor(END)

        self.pictureEntry.delete(0,END)
        self.pictureEntry.insert(0,self.currentAddr.picture)
        self.pictureEntry.icursor(END)

        self.widthEntry.delete(0,END)
        self.widthEntry.insert(0,self.currentAddr.width)
        self.widthEntry.icursor(END)
        
        self.heightEntry.delete(0,END)
        self.heightEntry.insert(0,self.currentAddr.height)
        self.heightEntry.icursor(END)

    #
    # update, if necessary, the description and data content
    # a change flag is also set, to ensure a warning to the user to save the content
    #
    def updateDesc(self) :
        """Update, if necessary, the description and data content"""
        if self.currentAddr.name != self.nameEntry.get() :
            self.currentAddr.name = self.nameEntry.get()
            self.changed = 1
            self.filemenu.entryconfig(0,state=NORMAL)
        if self.currentAddr.address != self.addressEntry.get() :
            self.currentAddr.address = self.addressEntry.get()
            self.changed = 1
            self.filemenu.entryconfig(0,state=NORMAL)
        if self.currentAddr.city != self.cityEntry.get() :
            self.currentAddr.city = self.cityEntry.get()
            self.changed = 1
            self.filemenu.entryconfig(0,state=NORMAL)
        if self.currentAddr.country != self.countryEntry.get() :
            self.currentAddr.country = self.countryEntry.get()
            self.changed = 1
            self.filemenu.entryconfig(0,state=NORMAL)
        if self.currentAddr.zip != self.zipEntry.get() :
            self.currentAddr.zip = self.zipEntry.get()
            self.changed = 1
            self.filemenu.entryconfig(0,state=NORMAL)
        if self.currentAddr.fax != self.faxEntry.get() :
            self.currentAddr.fax = self.faxEntry.get()
            self.changed = 1
            self.filemenu.entryconfig(0,state=NORMAL)
        if self.currentAddr.email != self.emailEntry.get() :
            self.currentAddr.email = self.emailEntry.get()
            self.changed = 1
            self.filemenu.entryconfig(0,state=NORMAL)
        if self.currentAddr.picture != self.pictureEntry.get() :
            self.currentAddr.picture = self.pictureEntry.get()
            self.changed = 1
            self.filemenu.entryconfig(0,state=NORMAL)
        if self.currentAddr.width != self.widthEntry.get() :
            self.currentAddr.width = self.widthEntry.get()
            self.changed = 1
            self.filemenu.entryconfig(0,state=NORMAL)
        if self.currentAddr.height != self.heightEntry.get() :
            self.currentAddr.height = self.heightEntry.get()
            self.changed = 1
            self.filemenu.entryconfig(0,state=NORMAL)

    #
    # Go to the next image (if any); save the description entries first
    # This is the callback to the right mouse button
    #
    def next(self,event) :
        """Go to the next image (if any)"""
        if self.currentAddr.next != None :
            self.updateDesc()
            self.currentAddr = self.currentAddr.next
            self.setImage()

    #        
    # Go the previous image (if any); save the description entries first
    # This is the callback to the left mouse button
    #
    def prev(self,event) :
        """Go the previous image (if any)"""
        if self.currentAddr.previous != None :
            self.updateDesc()
            self.currentAddr = self.currentAddr.previous
            self.setImage()

    #
    # Common root for saving content in a file; it sets up the
    # global XML elements
    def saveFile(self,filename) :
        """Common root for saving content in a file. It creates a complete
        DOM tree, and then prints it"""
        dom = xml.dom.minidom.Document()
        dom.appendChild(xsl)
        all = dom.createElement("Addresses")
        dom.appendChild(all)
        Addrs.prAll(dom,all)
        file = open(filename,'w')
        dom.writexml(file)
        file.flush()
        file.close()
        self.changed = 0
        self.filemenu.entryconfig(0,state=DISABLED)

    #
    # 
    #
    def saveAs(self) :
        """Callback for 'save as'"""
        f = asksaveasfilename(initialfile = inputFile)
        if f :
            if os.access(f,os.F_OK) == 1 :
                try :
                    os.remove(f+'.bak')
                except :
                    pass
                os.rename(f,f+'.bak')                
            self.saveFile(f)

    #
    # 
    #
    def save(self) :
        """Callback for 'save'. It also creates a backup file first
        (unless the program started from scratch)"""
        global inputFile
        self.updateDesc()
        if inputFile == " " :
            inputFile = asksaveasfilename(initialfile = "index.xml")
        else :
            try :
                if os.access(inputFile+'.bak',os.F_OK) == 1 :
                    os.remove(inputFile+'.bak')
                os.rename(sys.argv[1],inputFile+'.bak')
            except:
                pass
        self.saveFile(inputFile)

    #
    #
    #
    def append(self) :
        """Callback for 'Append To'."""
        f = asksaveasfilename(initialfile = "smallAddresses.xml")
        if f :
            if os.path.abspath(os.path.basename(inputFile)) == os.path.abspath(os.path.basename(f)) :
                d = Dialog(self.root,
                           title="Append to itself",
                           text="Append to the input file?",
                           bitmap="",
                           default="1",
                           strings=("Yes","No"))
                if d.num == 1 :
                    return
            if os.access(f,os.F_OK) == 1 :
                # The real append...
                dom = xml.dom.minidom.parse(f)
                try :
                    os.remove(f+'.bak')
                except :
                    pass
                os.rename(f,f+'.bak')
                # locate the root element, this will the parent to the
                # appended ones...
                self.updateDesc()
                allIm = dom.getElementsByTagName("Addresses")[0]
                Addrs.prAll(dom,allIm)
                file = open(f,'w')
                dom.writexml(file)
                file.flush()
                file.close()
                self.changed = 0
                self.filemenu.entryconfig(0,state=DISABLED)
            else :
                # There is no such file!!!
                self.saveFile(f)

    #
    # Callback for exit; see if a change has been done. If so a dialogue makes it
    # sure that the user can change the content first
    # This is also the callback for the window closure action
    #
    def exit(self) :
        self.updateDesc()
        if inputFile == None or self.changed :
            d = Dialog(self.root,
                       title="Content has changed",
                       text="Content has changed, save?",
                       bitmap="",
                       default="0",
                       strings=("Yes","No"))
            if d.num == 0 :
                self.save()
        self.root.quit()
    

#####################################################################################################
# Just the startup; in fact, the main function is used here only for aesthetic reasons...

def usage() :
    print "Usage: "
    print " %s -help|-h" % sys.argv[0]
    print "           Display this message" 
    print " %s file.xml" % sys.argv[0]
    print "           Start up interactive tool"
    print " %s -thumbnails|-th [imagefiles]+" % sys.argv[0]
    print "           Generate thumbnails"
    print " %s -init|-i [imagefiles]+" % sys.argv[0]
    print "           Generate thumbnails and start interaction"

def main() :
    global Addrs, inputFile
    inputFile = sys.argv[1]
    #print inputFile
    try :
        dom = xml.dom.minidom.parse(inputFile)
    except :
        print "Problems accessing the input xml file: ", sys.exc_info()[0]
        sys.exit()
    Addrs = createAddrs(dom)
    app = AddrCanvas()
    
main()
