#!/usr/bin/python

import re,os,sys
import commands
from xml.dom import minidom
from xml.dom.ext import PrettyPrint
sys.path.append('../new_partition/')
import partition_data as p_d
import interface_partition



# xml file names
install_xml = '/var/install/install.xml'
config_xml  = '../xml/install_cfg.xml'

def to_xml_attr(doc, node, cls, name):
    ''' This method is called by to_xml. Its function is to create an attribute, and set its value based on xml data member
 doc - xml document
 node - xml node
 cls - python class/python instance
 name - attribute name'''
    attr = doc.createAttribute(name)
    attr.value = getattr(cls, name)
    node.setAttributeNode(attr)

class SerialNumber:
    ''' serial number '''
    value = ''
    @staticmethod
    def init_from_xml(node):
        ''' set value based on xml node '''
        SerialNumber.value = node.firstChild.data.encode('ascii')

    @staticmethod
    def to_xml(doc, p_node):
        ''' write SerialNumber into xml
doc - xml document instance
p_node - xml node (parent node)'''
        sn = doc.createElement('serial-number')
        data = doc.createTextNode(SerialNumber.value)
        sn.appendChild(data)
        p_node.appendChild(sn)

class Partition:
    ''' disk partition '''
    unit=''
    dict={}
    def __init__(self, dev, st, sz, tp, fs, fg, fr):
        ''' Partition init function '''
        self.device       = dev
        self.start        = st
        self.size         = sz
        self.type         = tp 
        self.filesystem   = fs
        self.flags        = fg
        self.from_os      = fr
        Partition.dict[dev] = self

    @staticmethod
    def check_partitions():
        cmd = "grep [a-zA-Z][0-9] /proc/partitions>/dev/null"
        ret = os.system(cmd)
        return ret

    @staticmethod
    def init_from_os():
        ''' create a Partition instance from hardware info'''
        Partition.unit='GB'
        cmd_cat = 'cat /proc/partitions'

        st,o = commands.getstatusoutput(cmd_cat)
        if st:
            print "Error cat : command not found or /proc/partitions dosen't exsit"
            return

        # an example of `cat /proc/partitions`
        # major minor  #blocks  name
        #
        # 8     0  488386584 sda
        # 8     1   97659103 sda1
        # 8     2    1951897 sda2
        # 8     3   97659135 sda3
        # 8     4  291113865 sda4
        # 8    16  244197527 sdb
        # 8    17   62918541 sdb1
        # 8    18    4200997 sdb2
        # 8    19          1 sdb3
        # 8    21    1238016 sdb5
        # 9     0     803136 md0

        l = [ s.split()[-1] for s in o.splitlines() if re.match(r'\s*\d+', s)]
        # devices : 1) sda, sdb(first if ), or md0 (second if)
        for d in [ i for i in l if not re.search(r'\d+', i)
                       or re.search(r'([a-zA-Z]+)', i).group(1) not in l]:
            st,o=commands.getstatusoutput('LANG=c parted /dev/%s unit %s print'%(d,Partition.unit))
            if st:
                # if a raid device wasn't formated, exec "parted it unit GB print" 
                # command will return a error info.
                continue
            # an example of o's content
            # Model: ATA Hitachi HDS72105 (scsi)
            # Disk /dev/sda: 500GB
            # Sector size (logical/physical): 512B/512B
            # Partition Table: msdos
            #
            # Number  Start   End    Size    Type     File system     Flags
            #  1      0.00GB  100GB  100GB   primary  ext3            boot
            #  2      100GB   102GB  2.00GB  primary  linux-swap(v1)
            #  3      102GB   202GB  100GB   primary  ext3
            #  4      202GB   500GB  298GB   primary  ext3

            located = False
            for s in o.splitlines():
                # Only match number, start, end, and size, that's enough.
                # And when in raid case, no type appears.
                title_p = re.compile('Number\s+Start\s+End\s+Size\s')
                if title_p.match(s):
                    nm_i = s.find('Number')
                    st_i = s.find('Start')
                    end_i = s.find('End')
                    sz_i = s.find('Size')
                    tp_i = s.find('Type')
                    fs_i = s.find('File system')
                    flg_i= s.find('Flags')
                    if tp_i < 0: tp_i=fs_i
                    located = True
                elif located:
                    Partition(d[:2] == 'md' and d or d+s[nm_i:st_i].strip(),  # device name
                              s[st_i:end_i].strip().rstrip(Partition.unit),   # start
                              s[sz_i:tp_i].strip().rstrip(Partition.unit), # size
                              s[tp_i:fs_i].strip(),      # type
                              re.search('swap', s[fs_i:flg_i]) and 'swap' or s[fs_i:flg_i].strip(),  # file system
                              s[flg_i:].strip(),                # flags
                              'yes'
                              )
    
    @staticmethod
    def init_from_xml(node):
        ''' create Partition instances from xml node '''
        Partition.unit = node.attributes['unit'].value.encode('ascii')
        for p in node.childNodes:
            if p.nodeType == node.ELEMENT_NODE and p.nodeName == 'partition':
                Partition(p.attributes['device'].value.encode('ascii'),\
                                p.attributes['start'].value.encode('ascii'),\
                                p.attributes['size'].value.encode('ascii'),\
                                p.attributes['type'].value.encode('ascii'),\
                                p.attributes['file-system'].value.encode('ascii'),\
                                p.attributes['flags'].value.encode('ascii'),\
                                p.attributes['from_os'].value.encode('ascii'))


    @staticmethod
    def to_xml(doc, p_node):
        ''' write all Partition instance into xml
doc - xml document instance
p_node - xml node (parent node)'''
        pts = doc.createElement("partitions")
        unit_attr = doc.createAttribute('unit')
        unit_attr.value = Partition.unit
        pts.setAttributeNode(unit_attr)
        P_keys = Partition.dict.keys()
        P_keys.sort()
        for k in P_keys:
            p = Partition.dict[k]
            pt = doc.createElement('partition')
            dev_attr             = doc.createAttribute('device')
            start_attr           = doc.createAttribute('start')
            size_attr            = doc.createAttribute('size')
            type_attr            = doc.createAttribute('type')
            fs_attr              = doc.createAttribute('file-system')
            flags_attr           = doc.createAttribute('flags')
            from_attr            = doc.createAttribute('from_os')
            dev_attr.value             = p.device
            start_attr.value           = p.start
            size_attr.value            = p.size
            type_attr.value            = p.type
            fs_attr.value              = p.filesystem
            flags_attr.value           = p.flags
            from_attr.value            = p.from_os
            pt.setAttributeNode(dev_attr)
            pt.setAttributeNode(start_attr)
            pt.setAttributeNode(size_attr)
            pt.setAttributeNode(type_attr)
            pt.setAttributeNode(fs_attr)
            pt.setAttributeNode(flags_attr)
            pt.setAttributeNode(from_attr)
            pts.appendChild(pt)
        p_node.appendChild(pts)

    @staticmethod
    def get_size(dev):
        try:
            return Partition.dict[dev].size
        except:
            return None

class Raid:
    ''' raid information '''
    dict = {}
    def __init__(self, dev, from_os, level, mp, fmt, filesystem,a_devs, s_devs=[]):
        ''' Raid init function '''
        self.device  = dev
        self.from_os = from_os
        self.level   = level
        self.mp   = mp
        self.fmt   = fmt
        self.filesystem   = filesystem
        self.active_components = a_devs
        self.spare_components  = s_devs
        Raid.dict[dev] = self

    @staticmethod
    def init_from_os():
        cmd = 'cat /proc/mdstat'
        st, o = commands.getstatusoutput(cmd)
        if st: return
        dev_p  = re.compile(r'''
                               ^(md\d+)\s*:   # md device
                              \s*active\s*   # "active"
                              (\w+)\s*       # raid type
                              ''', re.VERBOSE)

        for s in o.splitlines():
            dev_res = dev_p.split(s)
            if len(dev_res)>1: # matched
                # dev_res[0] is ''
                # dev_res[2] is 'raidX'
                raid_dev = dev_res[1]
                raid_level = dev_res[2][4:]
                act_cmpts =[]
                spr_cmpts =[]
                for ss in dev_res[3].split():
                    if re.search(r'\(S\)', ss):
                        spr_cmpts.append(ss[:ss.index('[')])
                    else:
                        act_cmpts.append(ss[:ss.index('[')])

                Raid(raid_dev, "yes", raid_level, '', 'no', '', act_cmpts, spr_cmpts)

    @staticmethod
    def add_component(node, l):
        ''' add component devices (in xml node) to list
node - xml node
l    - list
'''
        for sub in node.childNodes:
            if sub.nodeType == sub.ELEMENT_NODE and sub.nodeName == 'component':
                l.append(sub.firstChild.data.encode('ascii'))

    @staticmethod
    def init_from_xml(node):
        ''' create Raid instances from xml node '''
        for e in node.childNodes:
            if e.nodeType == e.ELEMENT_NODE and e.nodeName == 'raid':
                raid_dev = e.attributes['device'].value
                raid_from = e.attributes['from_os'].value
                raid_level = e.attributes['level'].value
                raid_mp = e.attributes['mp'].value
                raid_fmt = e.attributes['fmt'].value
                raid_fs = e.attributes['filesystem'].value
                act_cmpts = []
                spr_cmpts = []
                for sub_e in e.childNodes:
                    if sub_e.nodeType == sub_e.ELEMENT_NODE:
                        if sub_e.nodeName == 'active':
                            Raid.add_component(sub_e, act_cmpts)
                        elif sub_e.nodeName == 'spare':
                            Raid.add_component(sub_e, spr_cmpts)

                Raid(raid_dev, raid_from, raid_level, raid_mp, raid_fmt, raid_fs, act_cmpts, spr_cmpts)

    @staticmethod
    def to_xml(doc, p_node):
        ''' write all raid instance into xml
doc - xml document instance
p_node - xml node (parent node) '''
        raids = doc.createElement('raids')
        R_keys = Raid.dict.keys()
        R_keys.sort()
        for k in R_keys:
            r = Raid.dict[k]
            rd = doc.createElement('raid')

            rd_dev_attr = doc.createAttribute('device')
            rd_dev_attr.value = r.device
            rd.setAttributeNode(rd_dev_attr)

            rd_from_attr = doc.createAttribute('from_os')
            rd_from_attr.value = r.from_os
            rd.setAttributeNode(rd_from_attr)

            rd_level_attr = doc.createAttribute('level')
            rd_level_attr.value = r.level
            rd.setAttributeNode(rd_level_attr)

            rd_mp_attr = doc.createAttribute('mp')
            rd_mp_attr.value = r.mp
            rd.setAttributeNode(rd_mp_attr)

            rd_fmt_attr = doc.createAttribute('fmt')
            rd_fmt_attr.value = r.fmt
            rd.setAttributeNode(rd_fmt_attr)

            rd_fs_attr = doc.createAttribute('filesystem')
            rd_fs_attr.value = r.filesystem
            rd.setAttributeNode(rd_fs_attr)

            rd_act_elem = doc.createElement('active')
            for act_c in r.active_components:
                act_c_e = doc.createElement('component')
                act_c_tn = doc.createTextNode(act_c)
                act_c_e.appendChild(act_c_tn)
                rd_act_elem.appendChild(act_c_e)
            rd.appendChild(rd_act_elem)

            rd_spr_elem = doc.createElement('spare')
            for spr_c in r.spare_components:
                spr_c_e = doc.createElement('component')
                spr_c_tn = doc.createTextNode(spr_c)
                spr_c_e.appendChild(spr_c_tn)
                rd_spr_elem.appendChild(spr_c_e)
            rd.appendChild(rd_spr_elem)

            raids.appendChild(rd)

        p_node.appendChild(raids)
    #ri_tk_cmd.py use
    @staticmethod
    def get_size(dev):
        ''' calculate raid device size '''
        rd = Raid.dict[dev]
        Min = min([ float(interface_partition.get_num(p_d.Partition.dict[p_d.Partition.get_disk_from_partition('/dev/'+d)]\
				['partition']['/dev/'+d]['size'])) for d in rd.active_components])
        Sum = sum([ float(interface_partition.get_num(p_d.Partition.dict[p_d.Partition.get_disk_from_partition('/dev/'+d)]\
				['partition']['/dev/'+d]['size'])) for d in rd.active_components])
        #if rd.level == '0': return str(interface_partition.pretty_unit(Min*len(rd.active_components)))
        #elif rd.level == '1': return str(interface_partition.pretty_unit(Min*len(rd.active_components)/2))
        if rd.level == '0': return str(interface_partition.pretty_unit(Sum))
        elif rd.level == '1': return str(interface_partition.pretty_unit(Min))
        elif rd.level == '5': return str(interface_partition.pretty_unit(Min*(len(rd.active_components)-1)))

    @staticmethod
    def get_next_device():
        ''' get next available raid device name '''
        num_p = re.compile(r'md(\d+)')
        numbers = [ int(num_p.match(r).groups()[0]) for r in Raid.dict.keys()]
        numbers.sort()
        if numbers:
            return 'md%d' %(int(numbers[-1])+1)
        return 'md0'

    @staticmethod
    def dev_in_raid():
        """if the device in raid or not"""
        devices_in_raid=set()
        for r in Raid.dict.values():
            devices_in_raid.update(r.active_components)
            devices_in_raid.update(r.spare_components)
        return devices_in_raid

    @staticmethod
    def get_raid_from_partition(partition):
        for raid in Raid.dict.keys():
            for p in  Raid.dict[raid].active_components + Raid.dict[Raid].spare.components:
				if p == partition:
					return raid

class MountPoint:
    ''' mount-points '''
    dict={}
    def __init__(self, dev, dir='', fs='', fm='no'):
        self.device     = dev
        self.directory  = dir
        self.filesystem = fs
        self.format     = fm
        MountPoint.dict[dev]=self

    @staticmethod
    def change(dev, dir, fs, fm):
        mp = MountPoint.dict[dev]
        mp.directory  = dir
        mp.filesystem = fs
        mp.format     = fm

    @staticmethod
    def init_from_internal():
        ''' init MountPoint from internal class Partition and class Raid '''
        # add raid device in dev_in_raid
        dev_in_raid = Raid.dev_in_raid()

        for dev in set([ k for k in Partition.dict.keys() if not re.search('extended',Partition.dict[k].type)]).difference(set(dev_in_raid)):
            if MountPoint.dict.has_key(dev): continue
            MountPoint(dev, fs=Partition.dict[dev].filesystem)

        for dev in Raid.dict.keys():
            if MountPoint.dict.has_key(dev): continue
            MountPoint(dev)

        # now delete unexist partition/raid mount point, or
        # partition that used in raid.
        s1 = set(MountPoint.dict.keys())
        s2 = set(Partition.dict.keys() + Raid.dict.keys()) - set(dev_in_raid)
        for dev in s1-s2:
            del MountPoint.dict[dev]


    @staticmethod
    def init_from_xml(node):
        ''' create MountPoint instances from xml node '''
        for m in node.childNodes:
            if m.nodeType == node.ELEMENT_NODE and m.nodeName == 'mount-point':
                MountPoint(m.attributes['device'].value.encode('ascii'), \
                               m.attributes['directory'].value.encode('ascii'), \
                               m.attributes['file-system'].value.encode('ascii'), \
                               m.attributes['format'].value.encode('ascii'))

    @staticmethod
    def to_xml(doc, p_node):
        ''' write all MountPoint instance into xml
doc - xml document instance
p_node - xml node (parent node)'''
        mps = doc.createElement('mount-points')
        M_keys = MountPoint.dict.keys()
        M_keys.sort()
        for k in M_keys:
            m = MountPoint.dict[k]
            mp = doc.createElement('mount-point')
            dev_attr = doc.createAttribute('device')
            dir_attr = doc.createAttribute('directory')
            fs_attr  = doc.createAttribute('file-system')
            fm_attr  = doc.createAttribute('format')
            dev_attr.value = m.device
            dir_attr.value = m.directory
            fs_attr.value  = m.filesystem
            fm_attr.value  = m.format
            mp.setAttributeNode(dev_attr)
            mp.setAttributeNode(dir_attr)
            mp.setAttributeNode(fs_attr)
            mp.setAttributeNode(fm_attr)
            mps.appendChild(mp)
        p_node.appendChild(mps)

    @staticmethod
    def get_size(dev):
        '''get size of this mount point '''
        if dev in Partition.dict.keys():
            return Partition.get_size(dev)
        elif dev in Raid.dict.keys():
            return Raid.get_size(dev)
        
    @staticmethod
    def check_data(dev,dr,fs):
        '''check mount point is feasible. dr is mount point, dev is device'''
        # check mount point is existent or not
        if dr and dr in [ m.directory for m in MountPoint.dict.values() if m.device !=dev ]:
            return False

        # if fs is swap, then dr must be none
        if fs == 'swap' and dr:
            return False

        # check mount point is special or not
        if dr in ['/etc','/bin','/sbin','/lib']:
            return False
        elif dr in ['/','/boot'] and fs in ['reiserfs','xfs']:
            return False

        return True

class Network:
    ''' network '''
    hostname      ='localhost'
    configuration =''
    domain        = 'in.linx'
    ip            = '192.168.1.109'
    mask          = '255.255.255.0'
    gateway       = '192.168.1.1'
    primary_dns   = '192.168.1.1'
    secondary_dns = ''

    @staticmethod
    def init_from_xml(node):
        ''' init Network from xml node '''
        for k in node.attributes.keys():
            setattr(Network, k, node.attributes[k].value.encode('ascii'))

    @staticmethod
    def to_xml(doc, p_node):
        ''' write Network into xml
doc - xml document instance
p_node - xml node (parent node)'''
        ntwk = doc.createElement('network')
        for nm in ('hostname', 'configuration', 'ip', 'mask', 'gateway', 'primary_dns', 'secondary_dns', 'domain'):
            to_xml_attr(doc, ntwk, Network, nm)
        p_node.appendChild(ntwk)

class Group:
    ''' software package group '''
    dict = {}
    def __init__(self, n, i):
        self.name = n
        self.install = i
        self.description = ''
        self.mandatory = []
        self.selection = 'manual'
        self.optional = []
        Group.dict[n] = self

    @staticmethod
    def handle_release_node(r_node):
        ''' This method is called by init_from_config_xml
r_node - release node '''
        for i in r_node.childNodes:
            if i.nodeType == i.ELEMENT_NODE and i.nodeName == 'including':
                Group(i.attributes['group'].value, \
                      i.attributes['install'].value == 'mandatory' and 'mandatory' or 'no')

    @staticmethod
    def handle_group_node(g_node):
        ''' This method is called by init_from_config_xml
g_node - group node '''
        g = Group.dict[g_node.attributes['name'].value]
        for n in g_node.childNodes:
            if n.nodeType == n.ELEMENT_NODE:
                if n.nodeName == 'description':
                    g.description = n.firstChild.data
                elif n.nodeName == 'including':
                    if n.attributes['install'].value == 'mandatory':
                        g.mandatory.append(n.attributes['package'].value.encode('ascii'))
                    else:
                        g.optional.append([n.attributes['package'].value.encode('ascii'), 'no'])

    @staticmethod
    def init_from_config_xml(node):
        ''' init Group instances from config xml
 node - root node of config xml'''
        rls_list = [r for r in node.childNodes
                    if r.nodeType == r.ELEMENT_NODE and r.nodeName == 'release']
        grp_list = [g for g in node.childNodes
                    if g.nodeType == g.ELEMENT_NODE and g.nodeName == 'group']
        Group.handle_release_node(rls_list[0])
        for g in grp_list:
            Group.handle_group_node(g)

    @staticmethod
    def init_from_install_xml(node):
        ''' init Group instances from install xml
 node - install xml 'groups' node'''
        for grp in node.childNodes:
            if grp.nodeType == grp.ELEMENT_NODE and grp.nodeName == 'group':
                g = Group(grp.attributes['name'].value, grp.attributes['install'].value)
                for grp_chld in grp.childNodes:
                    if grp_chld.nodeType == grp_chld.ELEMENT_NODE:
                        if grp_chld.nodeName == 'description':
                            g.description = grp_chld.firstChild.data
                        elif grp_chld.nodeName == 'mandatory':
                            g.mandatory.extend([pkg.attributes['name'].value for pkg in grp_chld.childNodes
                                                if pkg.nodeType == pkg.ELEMENT_NODE and pkg.nodeName == 'package'])
                        elif grp_chld.nodeName == 'optional':
                            g.optional.extend([[pkg.attributes['name'].value, pkg.attributes['install'].value] for pkg in grp_chld.childNodes
                                               if pkg.nodeType == pkg.ELEMENT_NODE and pkg.nodeName == 'package'])
                            g.selection = grp_chld.attributes['selection'].value
    init_from_xml = init_from_install_xml
    @staticmethod
    def to_xml(doc, p_node):
        ''' write Group instances into xml
doc - xml document instance
p_node - xml node (parent node)'''
        grps = doc.createElement('groups')
        for g in Group.dict.values():
            grp = doc.createElement('group')
            name_attr = doc.createAttribute('name')
            name_attr.value = g.name
            grp.setAttributeNode(name_attr)

            inst_attr = doc.createAttribute('install')
            inst_attr.value = g.install
            grp.setAttributeNode(inst_attr)

            if g.description:
                dscp = doc.createElement('description')
                dscp_data = doc.createTextNode(g.description)
                dscp.appendChild(dscp_data)
                grp.appendChild(dscp)

            if g.mandatory:
                mndt = doc.createElement('mandatory')
                for m in g.mandatory:
                    pkg = doc.createElement('package')
                    pname_attr = doc.createAttribute('name')
                    pname_attr.value = m
                    pkg.setAttributeNode(pname_attr)

                    mndt.appendChild(pkg)
                grp.appendChild(mndt)

            if g.optional:
                optl = doc.createElement('optional')
                sel_attr = doc.createAttribute('selection')
                sel_attr.value = g.selection
                optl.setAttributeNode(sel_attr)
                for o in g.optional:
                    pkg = doc.createElement('package')
                    pname_attr = doc.createAttribute('name')
                    pname_attr.value = o[0]
                    pkg.setAttributeNode(pname_attr)
                    pinst_attr = doc.createAttribute('install')
                    pinst_attr.value = o[1]
                    pkg.setAttributeNode(pinst_attr)
                    optl.appendChild(pkg)
                grp.appendChild(optl)
            grps.appendChild(grp)
        p_node.appendChild(grps)
    @staticmethod
    def get_install_pkgs():
        ''' get package names that should be installed '''
        l = []
        for g in Group.dict.values():
            if g.install != 'no':
                l.extend([ p for p in g.mandatory ])
                if g.selection == 'manual':
                    l.extend([ p[0] for p in g.optional if p[1] == 'yes' ])
                elif g.selection == 'all':
                    l.extend([ p[0] for p in g.optional ])
                else: # selection is 'none'
                    pass
        return l

class Service:
    ''' service '''
    list = []
    def __init__(self, nm, nb, sc, st, p):
        ''' init method
nm - name
nb - number
sc - script
st - start (yes/no/disable)
p  - pkg, that includes this service
'''
        self.name   = nm
        self.number = nb
        self.script = sc
        self.start  = st
        self.package = p
        Service.list.append(self)

    @staticmethod
    def init_from_config_xml(root):
        ''' init Service instances from config xml
 root - root node of config xml '''
        for p in root.childNodes:
            if p.nodeType == p.ELEMENT_NODE and p.nodeName == 'package':
                for s in p.childNodes:
                    if s.nodeType == s.ELEMENT_NODE and s.nodeName == 'service':
                        Service(s.attributes['name'].value, \
                                    s.attributes['number'].value, \
                                    s.attributes['script'].value, \
                                    'disable', \
                                    p.attributes['name'].value )

    @staticmethod
    def change_state():
        ''' Based on package information in Group class, change 'start' data member
 from 'disable' to 'no', or from 'yes'/'no' to 'disable' '''
        l = Group.get_install_pkgs()

        for s in Service.list:
            if s.package in l:
                if s.start == 'disable':
                    s.start = 'no'
            else:
                s.start = 'disable'

    @staticmethod
    def init_from_install_xml(node):
        ''' init Service instances from install xml
node - install xml 'services' node'''
        for srv in node.childNodes:
            if srv.nodeType == srv.ELEMENT_NODE and srv.nodeName == 'service':
                Service(srv.attributes['name'].value, \
                            srv.attributes['number'].value, \
                            srv.attributes['script'].value, \
                            srv.attributes['start'].value, \
                            srv.attributes['package'].value)

    init_from_xml = init_from_install_xml
    @staticmethod
    def to_xml(doc, p_node):
        ''' write Service instances into xml
doc - xml document instance
p_node - xml node (parent node)'''
        srvs = doc.createElement('services')
        for s in Service.list:
            srv = doc.createElement('service')
            for n in ('name', 'number', 'script', 'start', 'package'):
                to_xml_attr(doc, srv, s, n)
            srvs.appendChild(srv)
        p_node.appendChild(srvs)

def prepar_installation():
    '''create file called 'intall.xml',which contains the information about the  installation'''
    to_xml()
    xmldoc = minidom.parse(install_xml)
    root = xmldoc.firstChild
    return root.toxml()

def init():
    ''' initialize '''
    #Partition.init_from_os()
    #Raid.init_from_os()
    #MountPoint.init_from_internal()
    xmldoc_cfg = minidom.parse(config_xml)
    root_cfg   = xmldoc_cfg.firstChild
    Group.init_from_config_xml(root_cfg)
    Service.init_from_config_xml(root_cfg)

def init_from_xml():
    ''' get data in file (install.xml)'''
    xmldoc = minidom.parse(install_xml)
    root = xmldoc.firstChild
    for n in root.childNodes:
        if n.nodeType == n.ELEMENT_NODE:
            if n.nodeName == 'serial-number':
                SerialNumber.init_from_xml(n)
            elif n.nodeName == 'disks':
                p_d.Partition.init_from_xml(n)
            elif n.nodeName == 'raids':
                Raid.init_from_xml(n)
            elif n.nodeName == 'network':
                Network.init_from_xml(n)
            elif n.nodeName == 'groups':
                Group.init_from_xml(n)
            elif n.nodeName == 'services':
                Service.init_from_xml(n)
            elif n.nodeName == 'stategrid':
                StateGrid.init_from_xml(n)
            elif n.nodeName == 'finishstate':
                FinishState.init_from_xml(n)

def init_from_xml_and_os():
    ''' init all classes in this module from file and os '''
    xmldoc = minidom.parse(install_xml)
    root = xmldoc.firstChild
    for n in root.childNodes:
        if n.nodeType == n.ELEMENT_NODE:
            if n.nodeName == 'serial-number':
                SerialNumber.init_from_xml(n)
            elif n.nodeName == 'network':
                Network.init_from_xml(n)
            elif n.nodeName == 'groups':
                Group.init_from_xml(n)
            elif n.nodeName == 'services':
                Service.init_from_xml(n)
    Partition.init_from_os()
    Raid.init_from_os()
    MountPoint.init_from_internal()

def to_xml():
    ''' write internal data into xml file '''
    f = file(install_xml, 'w')
    xmldoc = minidom.Document()
    root   = xmldoc.createElement('install')
    xmldoc.appendChild(root)

    SerialNumber.to_xml(xmldoc, root)
    p_d.Partition.to_xml(xmldoc, root)
    Raid.to_xml(xmldoc, root)
    Network.to_xml(xmldoc, root)
    Group.to_xml(xmldoc, root)
    Service.to_xml(xmldoc, root)
    FinishState.to_xml(xmldoc, root)

    PrettyPrint(xmldoc, f)
    f.close()

class StateGrid():
    ''' state grid custom install data '''
    username      = ''
    home_dir      = ''
    shell         = ''
 
    @staticmethod
    def init_from_xml(node):
        ''' init State Grid data from xml node '''
        for k in node.attributes.keys():
            setattr(StateGrid, k, node.attributes[k].value.encode('ascii'))

    @staticmethod
    def to_xml(doc, p_node):
        ''' write State Grid data  into xml
doc - xml document instance
p_node - xml node (parent node)'''
        stgd = doc.createElement('stategrid')
	for st in ('username','home_dir','shell'):
		to_xml_attr(doc, stgd, StateGrid, st)

        p_node.appendChild(stgd)

class FinishState():
    ''' decide reboot or shutdown or keep current status when finishing
    OS install, flag include three value: reboot, shutdown, nothing'''
    flag = ''
 
    @staticmethod
    def init_from_xml(node):
        ''' init finish state flag from xml node '''
        #FinishState.flag = node.firstChild.data.encode('ascii')
        for k in node.attributes.keys():
            setattr(FinishState, k, node.attributes[k].value.encode('ascii'))

    @staticmethod
    def to_xml(doc, p_node):
        ''' write reboot or not flag  into xml
doc - xml document instance
p_node - xml node (parent node)'''
        std = doc.createElement('finishstate')
	for ft in ('flag',):
		to_xml_attr(doc, std, FinishState, ft)

        p_node.appendChild(std)
