#
# rw_config_file.py
#
# read or write an xml config file
#
# uses the config_file-0.2.dtd DTD file
#
# adam feuer
# 5/25/2000

RCS_ID =  '$Id: rw_config_file.py,v 1.4 2001/09/02 03:31:00 adamf Exp $'


# standard modules
import os
import string
import sys

from debug import debug

# XML modules
from xml.sax import saxexts, saxlib, saxutils

XML_PARSER = "xml.sax.drivers.drv_xmlproc"

# variable types
BOOLEAN = 'boolean'  # 1 or 0
INT = 'int'
FLOAT = 'float'
STRING = 'string'
LIST = 'list'

##################################################################
#
# varObj
#
class varObj:
    """container for variable contents and attributes"""

    def __init__(self):
        self.key = ''
        self.name = ''
        self.description = ''
        self.type = ''
        self.contents = ''
        self.order = 0

    def __repr__(self):
        return "[%s, %s, %s, %s, %s, %d]" % (self.key, self.name, self.description, self.type, self.contents, self.order)

    def correct_type(self):
        if self.type == INT:
            self.contents = int(self.contents)
        elif self.type == BOOLEAN:
            self.contents = int(self.contents)
        elif self.type == FLOAT:
            self.contents = float(self.contents)
        elif self.type == STRING:
            self.contents = "%s" % self.contents
        elif self.type == LIST:
            for item in self.contents[:]:
                item.correct_type()


##################################################################
#
# itemObj
#
class itemObj:
    """container for item contents and attributes"""

    def __init__(self):
        self.type = ''
        self.contents = ''
        self.order = 0

    def __repr__(self):
        return "[%s, %s, %d]" % (self.type, self.contents, self.order)

    def correct_type(self):
        if self.type == INT:
            self.contents = int(self.contents)
        elif self.type == BOOLEAN:
            self.contents = int(self.contents)
        elif self.type == FLOAT:
            self.contents = float(self.contents)
        elif self.type == STRING:
            self.contents = "%s" % self.contents
        elif self.type == LIST:
            pass

##################################################################
#
# comparison functions for sorting lists of varObj or itemObj
#
def _cmp_Obj(first,second):
    if first.order < second.order:
        return -1
    elif first.order == second.order:
        return 0
    else:
        return 1


##################################################################
#
# ConfDocHandler
#
class ConfDocHandler(saxlib.HandlerBase):
    """SAX document handler for parsing configuration file XML files-

    needs to be passed a dictionary object to fill up with data.
    """
    
    def __init__(self,dictionary):
        self.collecttext = 0        
        self.dict = dictionary
        self.text = ''
        self.key = ''

        self.varcounter = 0
        self.itemcounter = 0
            

    def characters(self, ch, start, length):
        if self.collecttext == 1:
            self.text = self.text + ch[start:start+length]

    def startElement(self, name, attrs):
        if name == 'config_file':
            pass
        elif name == 'variable':
            self.itemcounter = 0
            
            self.collecttext = 1
            self.key = attrs.get('key',None)        
            self.dict[self.key] = varObj()
            
            self.dict[self.key].order = self.varcounter
            self.varcounter = self.varcounter + 1
            
            self.dict[self.key].key =         self.key
            self.dict[self.key].name =        attrs.get('name',None)
            self.dict[self.key].description = attrs.get('description',None)
            self.dict[self.key].type =        attrs.get('type',None)

            if self.dict[self.key].type == LIST:
                # if it is a list, collecting should wait for item...
                self.collecttext = 0
                self.dict[self.key].contents = []
                
        elif name == 'item':
            self.collecttext = 1
            self.dict[self.key].contents.append(itemObj())
            self.dict[self.key].contents[-1].type = attrs.get('type', None)
            self.dict[self.key].contents[-1].order = self.itemcounter
            self.itemcounter = self.itemcounter + 1

                        

    def endElement(self, name):
        if name == 'config_file':
            debug.debug(3,"done reading config file.")
        elif name == 'variable':
            if self.dict[self.key].type != LIST:
                self.dict[self.key].contents = self.text
            self.text = ''
            self.collecttext = 0
        elif name == 'item':
            self.dict[self.key].contents[-1].contents = self.text
            self.text = ''
            self.collecttext = 0

##################################################################
#
# read_conf
#
def read_conf(file):
    """read a dictionary object of element objects from an XML file; return None if error
    """
    if file==None or type(file) != type(''):
        return None

    d ={}
    dh = ConfDocHandler(d)
    #parser = saxexts.make_parser(XML_PARSER)
    import xml.sax.drivers.drv_xmlproc
    parser = xml.sax.drivers.drv_xmlproc.create_parser()   # for use with Builder.py

    parser.setDocumentHandler(dh)
    parser.parse(file)

    for k in d.keys():
        d[k].correct_type()

    return d

##################################################################
#
# read_conf
#
def write_conf(file):
    """write a config file structure to an XML file.
    """
    if file==None or type(file) != type(''):
        return None

    d ={}
    dh = ConfDocHandler(d)
    parser = saxexts.make_parser(XML_PARSER)

    parser.setDocumentHandler(dh)
    parser.parse(file)

    for k in d.keys():
        d[k].correct_type()

    return d



##################################################################
#
# linearise_conf_dict
#

def linearise_conf_dict(conf_dict):
    """write a config dictionary object to an XML string; returns string

    """


    conf_dict_keys = conf_dict.keys()
    varObjList = []
    for key in conf_dict_keys:
        varObjList.append(conf_dict[key])

    varObjList.sort(_cmp_Obj)

    s = ''
    s = s + '<?xml version="1.0" ?>\n\n'
    s = s + '<config_file>\n'

    for variableObj in varObjList:
        s = s + '  <variable\n'

        s = s + '      key=         "'
        s = s + variableObj.key
        s = s + '"\n'
        
        s = s + '      name=        "'
        s = s + variableObj.name
        s = s + '"\n'
        
        s = s + '      description= "'
        s = s + variableObj.description
        s = s + '"\n'
        
        s = s + '      type=        "'
        s = s + variableObj.type
        s = s + '"\n'
        
        s = s + '  >'

        if type(variableObj.contents) != type([]):
            s = s + str(variableObj.contents)
        else:
            item_list = variableObj.contents
            item_list.sort(_cmp_Obj)
            for item in item_list:
                s = s + '\n'
                s = s + '    <item type= "'
                s = s + item.type
                s = s + '">'
                s = s + str(item.contents)
                s = s + '</item>'
            s = s + '\n  '

        s = s + '</variable>\n\n'

    s = s + '</conf_file>\n'

    return s

##################################################################
#
# write_conf
#

def write_conf(conf_dict,filename):
    """ write the conf_dict to an XML file; returns 0 if no error"""

    s = linearise_conf_dict(conf_dict)

    try:
        f = open(filename,'w')
        f.write(s)
        f.close()
        return 0
    except:
        return 1
      


##################################################################
#
#
#

if __name__ == "__main__":
    cd = read_conf('adzapper.conf.xml')

    write_conf(cd,"foo.xml")
    ncd = read_conf('foo.xml')
    write_conf(ncd,"foo1.xml")

