#    This is a component of AXIS, a front-end for emc
#    Copyright 2007 Anders Wallin <anders.wallin@helsinki.fi>
#
#    This program is free software; you can redistribute it and/or modify
#    it under the terms of the GNU General Public License as published by
#    the Free Software Foundation; either version 2 of the License, or
#    (at your option) any later version.
#
#    This program is distributed in the hope that it will be useful,
#    but WITHOUT ANY WARRANTY; without even the implied warranty of
#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#    GNU General Public License for more details.
#
#    You should have received a copy of the GNU General Public License
#    along with this program; if not, write to the Free Software
#    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

"""
    Parses a pyVCP XML file and creates widgets by calling pyvcp_widgets.py
"""

import sys; sys.path.append('/usr/lib/python%s/site-packages/oldxml' % sys.version[:3]) # python-xml 0.8.4-10ubuntu1 / hardy requires this
import xml.dom.minidom
import xml.dom.ext
from Tkinter import *
import sys, os
import emc
import pyvcp_widgets
import hal 
import time
import traceback

# this statement is required so that stuff from Tkinter
# is not included in the pydoc documentation __All__ should list all 
# functions in this module
__all__=["read_file","nodeiterator",
        "widget_creator","paramiterator","updater","create_vcp"]




def read_file():
    """
        Reads the XML file specified by global 'filename'
        finds the <pyvcp> element and starts the parsing of the 
        file by calling nodeiterator()
    """
    try:
        doc = xml.dom.minidom.parse(filename) 
    except xml.parsers.expat.ExpatError, detail:
        print "Error: could not open",filename,"!"
	print detail
        sys.exit(1)
    # find the pydoc element
    for e in doc.childNodes:
        if e.nodeType == e.ELEMENT_NODE and e.localName == "pyvcp":
            break

    if e.localName != "pyvcp":
        print "Error: no pyvcp element in file!"
        sys.exit()
    pyvcproot=e
    nodeiterator(pyvcproot,pyvcp0) 



num=0
def nodeiterator(node,widgetparent):
    """
        A recursive function that traverses the dom tree
        and calls widget_creator() when it finds a valid element
    """
    global num
    num+=1
    params=[]
    for e in node.childNodes:
        if e.nodeType == e.ELEMENT_NODE and (e.nodeName in pyvcp_widgets.elements):  
            params = paramiterator(e)  # find all the parameters for this node
            newwidget = widget_creator(widgetparent,e.nodeName,params)
            nodeiterator(e,newwidget)
      


widgets=[];
def widget_creator(parent,widget_name,params):
    """
       creates a pyVCP widget
           parent = parent widget
           widget_name = name of widget to be created 
           params = a list of parameters passed to the widget __init__
    """
 
    global widgets
  
    constructor = getattr(pyvcp_widgets, "pyvcp_" + str(widget_name))
    if hasattr(parent, "getcontainer"):
	container = parent.getcontainer()
    else:
	container = parent
    positional_params = (container, pycomp)
    
    try:
	widget = constructor(*positional_params, **params)
    except Exception, detail:
	raise SystemExit, "Error constructing %s(%s):\n%s" % (
			widget_name, params, detail)

    # pack the widget according to parent
    # either hbox or vbox
    if container==pyvcp0:
	widget.pack(side='top', fill=BOTH, expand=YES)
    else:
	parent.add(container, widget)
   
    # add the widget to a global list widgets
    # to enable calling update() later
    widgets.append(widget)

    return widget

def paramiterator(node):
    """ returns a list of all parameters for a widget element """
    outparams = {}
    for k, v in node.attributes.items():
	if v and v[0] in "{[(\"'":
	    v = eval(v)
	else:
	    try:
		v = int(v)
	    except ValueError:
		try:
		    v = float(v)
		except ValueError:
		    pass
	outparams[str(k)] = v

    for e in node.childNodes:
	if e.nodeType == e.ELEMENT_NODE \
		and (e.nodeName not in pyvcp_widgets.elements):
            try:
                v = eval(e.childNodes[0].nodeValue)
            except: 
                exc_type, exc_value, exc_tb = sys.exc_info()
                raise SystemExit, ("Error evaluating xml file:\n"
                    "Widget %s, Property %s\n%s: %s") % (
                        node.nodeName, e.nodeName, exc_type.__name__, exc_value)
	    outparams[str(e.nodeName)] = v
    return outparams



def updater():
     """ calls pyvcp_widgets.update() on each widget repeatedly every 100 ms """
     global widgets, pycomp
     for a in widgets:
          a.update(pycomp)
     pyvcp0.after(100,updater)




def create_vcp(master, comp = None, compname="pyvcp"):
    """ 
        create a pyVCP panel 
            master = Tkinter root window or other master container
            comp = HAL component
            compname = name of HAL component which is created if comp=None
    """
    global pyvcp0, pycomp
    pyvcp0 = master
    if comp is None:
        try: 
            comp = hal.component(compname)
        except:
            print "Error: Multiple components with the same name."
            sys.exit(0)

    pycomp = comp
    read_file() 
    updater()
    return comp
    
if __name__ == '__main__':
    print "You can't run vcpparse.py by itself..."

    
    



