#!/usr/bin/python
# vi: ts=4 expandtab syntax=python
##############################################################################
# Copyright (c) 2008 IBM Corporation
# All rights reserved. This program and the accompanying materials
# are made available under the terms of the Eclipse Public License v1.0
# which accompanies this distribution, and is available at
# http://www.eclipse.org/legal/epl-v10.html
#
# Contributors:
# Marcos Cintron (IBM) - initial implementation
##############################################################################

import os
import sys
from stat import ST_SIZE

from ovf.OvfFile import OvfFile
from ovf.OvfReferencedFile import OvfReferencedFile
from ovf import Ovf
from ovf import validation
from ovf.commands import cli
from ovf.commands import VERSION_STR

USAGE = "usage: mkovf command -f <Ovf file path> [options]"

def initOVF(ovfFile, options=None):
    """
    This function creates an empy OVF.

    @param ovfFile: An OvfFile object.
    @type ovfFile: OvfFile
    """

    ovfFile.path = options.ovfFile
    ovfFile.createEnvelope()

def createReferences(ovfFile, options):
    """
    This function will create the 'References' section of the ovf. If the
    section already exists it will simply add the new file to the References
    section.
    Note::
        In order to create this section the Envelope for the document
        must have been created and refObj must contain the OvfReferencedFile
        object to be added to the OVF.

    @param ovfFile: An OvfFile object.
    @type ovfFile: OvfFile

    @param options: The options from the optparser.
    @type options: Optparser object.

    """
    checksum = None
    checksumStamp = None
    path = Ovf.href2abspath(options.href, options.ovfFile)
    if options.size == None:
        options.size = str(os.stat(path)[ST_SIZE])

    refObj = OvfReferencedFile(path, options.href, checksum, checksumStamp,
                               options.size, options.compression,
                               options.file_id, options.chunksize)

    ovfFile.addReferencedFile(refObj)
    ovfFile.createReferences()

def createDiskSection(ovfFile, options):
    """
    This function will create the disk section of an OVF.

    @param ovfFile: An OvfFile object.
    @type ovfFile: OvfFile

    @param options: The options from the optparser.
    @type options: Optparser object.

    """
    diskDict = []
    netDef = {}
    netDef['diskId'] = options.disk_id
    netDef['fileRef'] = options.fileRef
    netDef['capacity'] = options.capacity
    netDef['populatedSize'] = options.populatedSize
    netDef['format'] = options.format
    netDef['capacityAllocUnits'] = options.capacityAllocUnits
    netDef['parentRef'] = options.parentRef
    diskDict.append(netDef)

    ovfFile.createDiskSection(diskDict, options.info, options.infoID,
                              options.id, options.required)

def createNetworkSection(ovfFile, options):
    """
    This function creates a network section.

    @param ovfFile: An OvfFile object.
    @type ovfFile: OvfFile

    @param options: The options from the optparser.
    @type options: Optparser object.

    """
    dictList = []
    netDict = {}
    netDict['networkID'] = options.networkID
    netDict['networkName'] = options.networkName
    netDict['description'] = options.description

    dictList.append(netDict)
    ovfFile.createNetworkSection(dictList, options.info, options.infoID)

def createDeploymentOptions(ovfFile, options):
    """
    This section will create the Deployment Options Section OR add a
    configuration to an existing Deployment Options Section.

    @param ovfFile: An OvfFile object.
    @type ovfFile: OvfFile

    @param options: The options from the optparser.
    @type options: Optparser object.

    """
    default = None
    if options.default.lower() == "true":
        default = True
    if options.default.lower() == 'false':
        default = False

    deploymentSect = ovfFile.createDeploymentOptions(options.info,
                                                     options.infoID,
                                                     options.secID)
    if options.comment != None:
        ovfFile.createComment(options.comment, deploymentSect)
    ovfFile.addConfiguration(deploymentSect, options.configID, options.label,
                             options.description, options.labelID,
                             options.descID, default)

def createVirtualSysCollection(ovfFile, options):
    """
    This will create a Virtual system Colection or append a new Virtual System
    Collection to an already existing one.

    @param ovfFile: An OvfFile object.
    @type ovfFile: OvfFile

    @param options: The options from the optparser.
    @type options: Optparser object.
    """
    if options.id != None:
        node = Ovf.getContentEntities(ovfFile.envelope, options.id)[0]

        if Ovf.hasTagName(node, "VirtualSystemCollection"):
            ovfFile.createVirtualSystemCollection(options.vscID, options.info,
                                                  options.infoID, node)
    else:
        ovfFile.createVirtualSystemCollection(options.vscID, options.info,
                                              options.infoID)

def createVirtualSystem(ovfFile, options):
    """
    This function will create a Virtual System. If the options.id is not
    specified the new element will be appended to the Envelope. The
    options.id can only be the ID for an existing Virtual System Collection.

    @param ovfFile: An OvfFile object.
    @type ovfFile: OvfFile

    @param options: The options from the optparser.
    @type options: Optparser object.
    """
    if options.id != None:
        node = Ovf.getContentEntities(ovfFile.envelope, options.id)[0]

        if Ovf.hasTagName(node, "VirtualSystemCollection"):
            ovfFile.createVirtualSystem(options.vsID, options.info, 
                                        node, options.infoID)
    else:
        ovfFile.createVirtualSystem(options.vsID, options.info, None,
                                         options.infoID)

def createVirtualHardware(ovfFile, options):
    """
    This method will create a Virtual Hardware section.
    NOTE::
        This section does not currently have a way to uniquely identify it.
        So when attaching resources it will find the first instance of the
        section and add the resources to that node.

    @param ovfFile: An OvfFile object.
    @type ovfFile: OvfFile

    @param options: The options from the optparser.
    @type options: Optparser object.
    """
    
    vsNode = Ovf.getContentEntities(ovfFile.envelope, options.id, vsc=False)[0]

    virtualHardware = ovfFile.createVirtualHardwareSection(vsNode,
                                                           options.secID,
                                                           options.info,
                                                           options.infoID,
                                                           options.transport)

    systemDict = dict(Caption=options.caption,
                      Description=options.description,
                      VirtualSystemIdentifier=options.sysID,
                      VirtualSystemType=options.sysType)

    ovfFile.createSystem(virtualHardware, options.elementName, options.instanceID, systemDict)

def createResources(ovfFile, options):
    """
    This section creates the resources for either a VirtualHardwareSection or
    ResourceAllocationSection.
    NOTE::
        Still need to fix this function to find the correct node given an id.
        The id to pass in to the flag --id is the VirtualSystem where the node
        resides if it is a VirtualHardware section or the id of the Virtual
        System collection if it is going to be attached to the
        ResourceAllocationSection.

    @param ovfFile: An OvfFile object.
    @type ovfFile: OvfFile

    @param options: The options from the optparser.
    @type options: Optparser object.
    """
    searchTag = lambda elem: (Ovf.hasTagName(elem, 
                                             'VirtualHardwareSection') or
                              Ovf.hasTagName(elem,
                                             'ResourceAllocationSection'))

    if options.id is not None:
        nodeList = Ovf.getNodes(ovfFile.envelope, (searchTag,),
                                (Ovf.hasAttribute, 'ovf:id', options.id))
    else:
        nodeList = Ovf.getNodes(ovfFile.envelope, (searchTag,))

    if nodeList == []:
        raise NotImplementedError("The section with id, " +
                                  str(options.id) + ", was not found.")


    if options.comment != None:
        ovfFile.createComment(options.comment, nodeList[0])
    if options.automaticAllocation == True:
        options.automaticAllocation = 'true'
    if options.automaticAllocation == False:
        options.automaticAllocation = 'false'
    refDefDict = {
             "Address": options.address,"AddressOnParent":options.addressOnParent,
             "AllocationUnits":options.allocUnits,
             "AutomaticAllocation":options.automaticAllocation ,
             "AutomaticDeallocation":options.autoDealloc,"Caption":options.caption,
             "Connection": options.connection,"ConsumerVisibility":options.consVis,
             "Description" : options.description,"ElementName":options.elementName,
             "HostResource":options.hostResource ,
             "InstanceID": options.resourceID ,   "Limit":options.limit ,
             "MappingBehavior":options.mapBehavior, "OtherResourceType":options.otherResourceType,
             "Parent":options.parent ,
              "PoolID":options.poolID, "Reservation":options.reservation,"ResourceSubType":options.resourceSubtype,
             "ResourceType":options.resourceType,"VirtualQuantity":options.virtualQuantity,"Weight":options.weight
         }
    ovfFile.addResourceItem(nodeList[0], refDefDict,
                            options.config, options.bound,
                            options.required)

def createResourceAlloc(ovfFile, options):
    """
    This function will help create the Resource Allocation Section.

    NOTE::
        There currently is no way to uniquely identify this section. So when
        attaching resources to the section, the createResources will find the
        first instance of this section.

    @param ovfFile: An OvfFile object.
    @type ovfFile: OvfFile

    @param options: The options from the optparser.
    @type options: Optparser object.
    """
    vscNode = Ovf.getContentEntities(ovfFile.envelope, options.id, vs=False)[0]

    ovfFile.createResourceAllocation(vscNode, options.info, options.infoID,
                                     options.config, options.bound,
                                     options.secID)

def createAnnotationSection(ovfFile, options):
    """
    This function will create an annotation for a Virtual System or
    Virtual System Collection.

    @param ovfFile: An OvfFile object.
    @type ovfFile: OvfFile

    @param options: The options from the optparser.
    @type options: Optparser object.
    """
    node = Ovf.getContentEntities(ovfFile.envelope, options.id)[0]

    ovfFile.createAnnotationSection(options.annotation, options.info, node,
                                    options.infoID)

def createProductSection(ovfFile, options):
    """
    This function creates the product section.

    @param ovfFile: An OvfFile object.
    @type ovfFile: OvfFile

    @param options: The options from the optparser.
    @type options: Optparser object.
    """
    node = Ovf.getContentEntities(ovfFile.envelope, options.id)[0]

    prodList = [("Product", options.product),
                ("Vendor", options.vendor),
                ("Version", options.productVersion),
                ("FullVersion", options.fullVersion),
                ("ProductUrl", options.prodURL),
                ("VendorUrl", options.vendorURL),
                ("AppUrl", options.appURL)]

    ovfFile.createProductSection(node, options.info, prodList,
                                 options.classDesc, options.instance,
                                 options.secID, options.infoID)

def createIconType(ovfFile, options):
    """
    For the product section this function will create an Icon node.
    NOTE::
        To find the specific product section both options.classDesc and
        options.instance must be passed in.

    @param ovfFile: An OvfFile object.
    @type ovfFile: OvfFile

    @param options: The options from the optparser.
    @type options: Optparser object.
    """
    prodNode = findProdNode(ovfFile, options.classDesc, options.instance)

    if prodNode == None and (options.instance != None
                             or options.classDesc != None):
        errMsg = "The Product Section with class description was not found."
        raise NotImplementedError(errMsg)
    ovfFile.createIconType(prodNode, options.fileRef, options.height,
                           options.width, options.mimeType)

def createCategory(ovfFile, options):
    """
    For the product section this function will create a category node.
    NOTE::
        To find the specific product section both options.classDesc and
        options.instance must be passed in.

    @param ovfFile: An OvfFile object.
    @type ovfFile: OvfFile

    @param options: The options from the optparser.
    @type options: Optparser object.
    """
    errMsg = "The Product Section with class description was not found."
    prodNode = findProdNode(ovfFile, options.classDesc, options.instance)

    if prodNode == None and (options.instance != None
                             or options.classDesc != None):
        raise NotImplementedError(errMsg)
    ovfFile.createCategory(prodNode, options.category)

def createProperty(ovfFile, options):
    """
    For the product section this function will create a property section.
    NOTE::
        To find the specific product section both options.classDesc and
        options.instance must be passed in.

    @param ovfFile: An OvfFile object.
    @type ovfFile: OvfFile

    @param options: The options from the optparser.
    @type options: Optparser object.
    """
    prodNode = findProdNode(ovfFile, options.classDesc, options.instance)

    if prodNode == None and (options.instance != None
                             or options.classDesc!=None):
        errMsg = ("The Product Section with" + str(options.classDesc) +
                  " and " + str(options.instance) + " was not found.")
        raise NotImplementedError(errMsg)

    prop = ovfFile.createProperty(prodNode, options.key,
                                  options.type,options.value,
                                  options.userConfig,
                                  options.required,
                                  options.secID)


    if options.description != None:
        ovfFile.createDescription(prop, options.description,
                                       options.descID)
    if options.label != None:
        ovfFile.createLabel(prop, options.label, options.labelID)

def createEulaSection(ovfFile, options):
    """
    This function will create the EULA section. This section can be attached
    to either a Virtual System or Virtual System Collection through the id.

    @param ovfFile: An OvfFile object.
    @type ovfFile: OvfFile

    @param options: The options from the optparser.
    @type options: Optparser object.
    """
    node = Ovf.getContentEntities(ovfFile.envelope, options.id)[0]

    eula = ovfFile.createEulaSection(options.info, node, options.infoID,
                                     options.secID)
    ovfFile.addLicense(eula, options.agreement, options.licenseID)


def createStartup(ovfFile, options):
    """
    This function will create the startup section for a Virtual System
    Collection.

    @param ovfFile: An OvfFile object.
    @type ovfFile: OvfFile

    @param options: The options from the optparser.
    @type options: Optparser object.
    """
    node = Ovf.getContentEntities(ovfFile.envelope, options.id, vs=False)[0]

    startupNode = ovfFile.createStartupSection(node, options.info,
                                               options.infoID,options.secID)
    ovfFile.addStartupItem(startupNode, options.entityName,
                                 options.order, options.startDelay,
                                 options.waitForGuest, options.startAction,
                                 options.stopDelay, options.stopAction)

def createOperatingSystem(ovfFile, options):
    """
    This function creates the Operating System for a Virtual System.

    @param ovfFile: An OvfFile object.
    @type ovfFile: OvfFile

    @param options: The options from the optparser.
    @type options: Optparser object.
    """
    node = Ovf.getContentEntities(ovfFile.envelope, options.id, vsc=False)[0]

    ovfFile.createOperatingSystem(node, options.secID, options.info,
                            options.infoID, options.description,
                            options.descriptionID)

def createInstallSection(ovfFile, options):
    """
    This method creates the install section used to describe a Virtual System.

    @param ovfFile: An OvfFile object.
    @type ovfFile: OvfFile

    @param options: The options from the optparser.
    @type options: Optparser object.
    """
    node = Ovf.getContentEntities(ovfFile.envelope, options.id, vsc=False)[0]

    ovfFile.createInstallSection(node, options.info, options.infoID,
                                 options.initBoot, options.bootStopdelay,
                                 options.secID)

def changeLanguage(ovfFile, options):
    """
    This function changes the langauge described in the ovf.

    @param ovfFile: An OvfFile object.
    @type ovfFile: OvfFile

    @param options: The options from the optparser.
    @type options: Optparser object.
    """
    ovfFile.envelope.setAttribute("xml:lang", options.language)

def mergeOVF(ovfFile, options):
    """
    This function will merge two or more OVF files into a single new OVF file.

    NOTE::
        This has not been implemented yet.

    @param ovfFile: An OvfFile object.
    @type ovfFile: OvfFile

    @param options: The options from the optparser.
    @type options: Optparser object.
    """
    print >> sys.stderr, "Method not implemented yet."
    return 1

def findProdNode(ovfFile, classId=None, instance=None):
    """
    This will find the node of a given product section. If no class or instance
    is provided the function will return the first node that is of type Product
    Section.

    NOTE::
        Both classDesc and instance are used to uniquely identify a
        ProductSection.

    @param ovfFile: An OvfFile object.
    @type ovfFile: OvfFile

    @param classDesc: The class described by the section.
    @type classDesc: String.

    @param instance: The instance of the section.
    @type instance: String
    """
    
    if classId != None:
        if instance != None:
            criteria = ((Ovf.hasAttribute, "ovf:class", classId),
                        (Ovf.hasAttribute, "ovf:instance", instance))
        else:
            criteria = (Ovf.hasAttribute, "ovf:class", classId)
    else:
        criteria = ()

    nodeList = Ovf.getElementsByTagName(ovfFile.envelope,
                                        "ProductSection",
                                        *criteria)

    if len(nodeList) == 1:
        return nodeList[0]
    elif len(nodeList) == 0:
        raise NotImplementedError("No ProductSection was found.")
    else:
        raise

def validateOVF(ovfFile, options):
    """
    This method validates the ovf against the schema.

    @param ovfFile: An OvfFile object.
    @type ovfFile: OvfFile

    @param options: The options from the optparser.
    @type options: Optparser object.
    """
    ovf = options.ovfFile
    if not options.schema:
        schema =  '../../schemas/ovf-envelope.xsd'
    else:
        schema = options.schema

    if not os.path.exists(schema):
        print >> sys.stderr, "ERROR: Schema file not found"
        return 1

    if not os.path.exists(ovf):
        print >> sys.stderr, "ERROR: OVF file not found"
        return 1

    msgHandler = validation.ErrorHandler()
    ret = validation.validateOVF(schema, ovf, msgHandler)

    for each in msgHandler.error_list:
        print "E: %s" % each

    for each in msgHandler.warning_list:
        print "W: %s" % each

    if ret == 0:
        print ovf + " validates"
    return ret

def main():
    #The version=VERSION_STR is the version of the OVF.
    cliParser = cli.CLI(commands, common, usage=USAGE, version=VERSION_STR)
    command, options, args = cliParser.parseArgs()

    ovfFile = None

    if options.ovfFile:
        try:
            if command != 'init':
                ovfFile = OvfFile(options.ovfFile)
            else:
                ovfFile = OvfFile()
        except Exception,e:
            raise e

    else:
        raise NotImplementedError(
              "Please pass the path to an OVF file with the flag -f.")

    commands[command]['func'](ovfFile, options)

    if command != 'validate':
        ovfFile.writeFile(None, True, options.encoding)

commands = {

   "init" : {
      "func" :initOVF,
      "help" : "Create a brand new OVF with just a root, 'Envelope', node.",
      "args" : (
      ),

   },
   "efile" : {
      "func":createReferences,
      "help" : "Create an efile section",
      "args" : (
         { "flags" : [ "-i","--ovfID" ],
           "parms" : { "dest" : "file_id",
                      "help" : "Defines the unique ID within the OVF." },
           "required": True
         },
         { "flags" : [ "-n", "--href" ],
           "parms" : { "dest" : "href","help":"Set the href attribute."+
                   " If no URI schema is given the href must resolve to a"+
                   " file relative to the location of the OVF descriptor"+
                   " itself. Two different files shall not have identical"+
                   " href attributes." },
           "required": True
         },
         { "flags" : [ "-s", "--size" ],
           "parms" : { "dest" : "size","help":"The size of the file in bytes."+
                       " If none is given the size will be acquired for that"+
                       " file." }},

         { "flags" : [ "-c", "--compression" ],
           "parms" : { "dest" : "compression","help": "Defines the"+
                    " compression of the file, if any. If none is given the"+
                    " compression shall be determined. Specifying 'identity'"+
                    " states that no compression is used. If the href is an"+
                    " HTTP or HTTPS URI, then the compression may be"+
                    " specified by the HTTP server." }},

         { "flags" : [ "-C", "--chunksize" ],
           "parms" : { "dest" : "chunksize","help":"Defines the chunksize for"+
                    " the file, if any." }}
      )
   },
   "disk" : {
      "func":createDiskSection,
      "help" : "Creates a disk section.",
      "args" : (
         { "flags" : [ "-i","--diskID" ],
           "parms" : { "dest" : "disk_id","help": "The id for the disk."},
           "required": True
         },
         { "flags" : [ "-c", "--capacity" ],
           "parms" : { "dest" : "capacity","help" :"The capacity of the given"+
                    " disk." },
           "required": True
         },
         { "flags" : [ "-F","--format" ],
           "parms" : { "dest" : "format","help" : "Disk format." },
           "required": True
         },
         { "flags" : [ "-r", "--fileRef" ],
           "parms" : { "dest" : "fileRef","help" : "File reference.  The"+
                    " ovfID of corresponding File element in references"+
                    " section."}
         },
         { "flags" : [ "-s", "--size" ],
           "parms" : { "dest" : "populatedSize","help": "Populated size"+
                    " in bytes."}
         },
         { "flags" : [ "-u", "--capacityAlloc" ],
           "parms" : { "dest" : "capacityAllocUnits","help" : "Capacity"+
                    " allocation Units." }
         },
         { "flags" : [ "-p", "--parentRef" ],
           "parms" : { "dest" : "parentRef","help" :"Reference to parent"+
                    " diskID. In order to specify this the parent must"+
                    " have already been specified." }
         },
         { "flags" : [ "-m", "--info" ],
           "parms" : { "dest" : "info","help" : "The information to describe"+
                    " the section." }
         },
         { "flags" : [ "-y"],
           "parms" : { "dest" : "infoID","help" : "The id of the section's"+
                    " information." }
         },
         { "flags" : [ "-q", "--notrequired"],
           "parms" : { "dest" : "required", "action": "store_false",
                    "default": True,
                    "help" : "Defines if the section is not required."},
        }
      )
   },
  "net" : {
      "func":createNetworkSection,
      "help" : "Creates a Network Section.",
      "args" : (
         { "flags" : [ "-i","--netID" ],
           "parms" : { "dest" : "networkID", "action":"store","help" :
                    "Defines the unique ID for the network within the OVF." },
           "required": True
         },
         { "flags" : [ "-m", "--info" ],
           "parms" : { "dest" : "info","help" : "The information to describe"+
                    " the section." }},
         { "flags" : [ "-y","--infoID"],
           "parms" : { "dest" : "infoID","help" : "The id of the section's"+
                    " information." }},
         { "flags" : [ "-e", "--networkName" ],
           "parms" : { "dest" : "networkName","help":"The name of the network"+
                     " being created." },
           "required": True
         },
         { "flags" : [ "-d", "--description" ],
           "parms" : { "dest" : "description","help": "Describe the network"+
                    " being created."},
           "required": True
         },
         { "flags" : [ "-c", "--descID" ],
           "parms" : { "dest" : "descID","help": "The ID for the description"+
                    " of the network."}},
      )
   },
   "deploy" : {
      "func":createDeploymentOptions,
      "help" : "Creates a Deploymen Options Section.",
      "args" : (
         { "flags" : [ "-i","--configID" ],
           "parms" : { "dest" : "configID", "action":"store","help" :
                      "Defines the unique ID for the configuration within the"+
                      "OVF." },
           "required": True
         },
         { "flags" : [ "-m", "--info" ],
           "parms" : { "dest" : "info","help" : "The information to describe"+
                    " the section."},
           "required": True
         },
         { "flags" : [ "-y","--infoID"],
           "parms" : { "dest" : "infoID","help" : "The id of the section's"+
                    " information." }},
         { "flags" : [ "-l", "--label" ],
           "parms" : { "dest" : "label","help":"The label used to describe"+
                    " the configuration."}},
         { "flags" : [ "-b", "--labelID" ],
           "parms" : { "dest" : "labelID","help": "The ID for the label"+
                    " created."}},
         { "flags" : [ "-d", "--description" ],
           "parms" : { "dest" : "description","help": "The description for"+
                      " the given configuration."}},
         { "flags" : [ "-c", "--descID" ],
           "parms" : { "dest" : "descID","help": "The ID for the description"+
                    " of the configuration created."}},
         { "flags" : [ "-r", "--default" ],
           "parms" : { "dest" : "default","help": "Specifies if the"+
                    " configuration is a default one. This is a Boolean"+
                    ", (True,False)"}},
      )
   },
   "vsc" : {
      "func":createVirtualSysCollection,
      "help" : "Creates a Virtual System Collection",
      "args" : (
         { "flags" : [ "-i","--vscID" ],
           "parms" : { "dest" : "vscID", "action":"store","help" : "Defines"+
                    " the unique ID for the Virtual System Collection within"+
                    " the OVF."},
           "required": True
         },
         { "flags" : [ "-m", "--info" ],
           "parms" : { "dest" : "info","help" : "The information to describe"+
                    " the section."},
           "required": True
         },
        { "flags" : [ "-y","--infoID"],
           "parms" : { "dest" : "infoID","help" : "The id of the section's"+
                    " information."}},
      )
   },
   "vs" : {
      "func":createVirtualSystem,
      "help" : "Creates a Virtual System.",
      "args" : (
         { "flags" : [ "-i","--vsID" ],
           "parms" : { "dest" : "vsID", "action":"store","help" : "Defines"+
                      " the unique ID for the Virtual System within the OVF."},
           "required": True
         },
         { "flags" : [ "-m", "--info" ],
           "parms" : { "dest" : "info","help" : "The information to describe"+
                    " the section."},
           "required": True
         },
        { "flags" : [ "-y","--infoID"],
           "parms" : { "dest" : "infoID","help" : "The id of the section's"+
                    " information."} },
      )
   },
   "virthw" : {
      "func":createVirtualHardware,
      "help" : "Creates a Virtual Hardware Section.",
      "args" : (

         { "flags" : [ "--instanceID" ],
           "parms" : { "dest" : "instanceID", "action":"store","help" :
                       "Defines the ID of the instance of the System." },
           "required": True },
         { "flags" : [ "-s","--sysID" ],
           "parms" : { "dest" : "sysID", "action":"store","help" :
                       "Defines the ID for the System." } },
         { "flags" : [ "-m", "--info" ],
           "parms" : { "dest" : "info","help" : "The information to describe"+
                       " the section."},
           "required": True
         },
         { "flags" : [ "-y","--infoID"],
           "parms" : { "dest" : "infoID","help" : "The id of the section's"+
                       " information."} },
         { "flags" : [ "-t","--transport"],
           "parms" : { "dest" : "transport","help" : "Transport that"+
                       " specifies how properties are passed to the virtual"+
                       " machine."} },
         { "flags" : [ "-d", "--description" ],
           "parms" : { "dest" : "description","help": "The description for"+
                       " the given configuration."} },
         { "flags" : [ "-c", "--caption" ],
           "parms" : { "dest" : "caption","help": "Caption used to describe"+
                       " the Virtual Hardwre."} },
         { "flags" : [ "-p", "--type" ],
           "parms" : { "dest" : "sysType","help": "The type of the"+
                       "VirtualSystem being described."} },
         { "flags" : [ "-n", "--elementName" ],
           "parms" : { "dest" : "elementName","help": "A unique name for the"+
                       " hardware being described."},
           "required": True }
      )
   },
   "resource" : {
      "func":createResources,
      "help" : "Define resources.",
      "args" : (
         { "flags" : [ "--elementName"],
           "parms" : { "dest" : "elementName","help" : "A human-readable"+
                      " description of the content. For example,"+
                      " '256MB memory'."} },
         { "flags" : [ "-k","--resourceType"],
           "parms" : { "dest" : "resourceType","help" : "Specifies the kind"+
                      " of device that is being described."},
           "required": True
         },
         { "flags" : [ "-i" ,"--resourceID"],
           "parms" : { "dest" : "resourceID","help": "The id for the"+
                    " resource."},
           "required": True
         },
         { "flags" : [ "-d", "--description" ],
           "parms" : { "dest" : "description","help" : "A human-readable"+
                    " description of the meaning of the information."},
           "required": True
         },
         { "flags" : [ "-a","--address" ],
           "parms" : { "dest" : "address","help" : "Address for an Ethernet"+
                    " adapter, this will be the MAC address."} },
         { "flags" : [ "-p", "--addressOnParent" ],
           "parms" : { "dest" : "addressOnParent","help" : "For a device,"+
                      " this specifies its location on the controller."} },
         { "flags" : [ "-u", "--allocUnits" ],
           "parms" : { "dest" : "allocUnits","help": "Specifies the units of"+
                    " allocation used. Example: 'MegaBytes'"} },
         { "flags" : [ "-t", "--automaticAllocation" ],
           "parms" : { "action":"store_true","dest" : "automaticAllocation",
                    "help" : "For devices that are connectable, this"+
                    " specifies whether the device should be connected at"+
                    " power on."} },
         { "flags" : [ "-o", "--autoDealloc" ],
           "parms" : { "dest" : "autoDealloc","help" : "Auto deallocate."+
                    " Boolean (True | False)"} },
        { "flags" : [ "-c", "--caption" ],
           "parms" : { "dest" : "caption","help" : "A human-readable"+
                    " description of the content."} },
        { "flags" : [ "-n","--connection"],
           "parms" : { "dest" : "connection","help" : "For an Ethernet"+
                    " adapter this specifies the abstract network connection"+
                    " for the virtual machine.The network connection MUST be"+
                    " listed in the NetworkSection at the outermost envelope"+
                    " level."} },
        { "flags" : [ "-v","--consVis"],
           "parms" : { "dest" : "consVis","help" : "Integer of consumer"+
                    " visibility."} },
        { "flags" : [ "-r","--hostResource"],
           "parms" : { "dest" : "hostResource","help" : "Abstractly specifies"+
                    " how a device shall be connecting to a resource on the"+
                    " deployment platform. Allowed options are either 'true'"+
                    " OR 'false'."} },
        { "flags" : [ "-l","--limit"],
           "parms" : { "dest" : "limit","help" : "Specifies the maximum"+
                    " quantity  or resources  that will be granted."} },
        { "flags" : [ "-m","--mapBehavior"],
           "parms" : { "dest" : "mapBehavior","help" : "Map behavior."} },
         { "flags" : [ "-e","--otherResourceType"],
           "parms" : { "dest" : "otherResourceType","help" : "Specifies the"+
                    " kind of device that is being described."} },
        { "flags" : [ "-j","--parent"],
           "parms" : { "dest" : "parent","help" : "The instanceId of the"+
                    " parent controller."} },
        { "flags" : [ "-w","--poolID"],
           "parms" : { "dest" : "poolID","help" : "The instanceId of the"+
                    " parent controller."} },
        { "flags" : [ "-z","--reservation"],
           "parms" : { "dest" : "reservation","help" : "Specifies the minimum"+
                    " quantity of resources guranteed to be available."} },
        { "flags" : [ "-b","--resourceSubtype"],
           "parms" : { "dest" : "resourceSubtype","help" : "Specifies the"+
                      " kind of device that is being described."} },
        { "flags" : [ "-g","--virtualQuantity"],
           "parms" : { "dest" : "virtualQuantity","help" : "Specifies the"+
                    " quantity of resources presented."} },
         { "flags" : [ "-s","--weight"],
           "parms" : { "dest" : "weight","help" : "Specifies the relative"+
                    " priority for this allocation in relation to other"+
                    " allocations."} },
        { "flags" : [ "-y","--required"],
           "parms" : { "action":"store_true","dest" : "required","help"
                    : "Specifies if the section is required. Boolean"+
                    " (True | False)."} },
        { "flags" : ["--config"],
           "parms" : { "dest" : "config","help" : "A comma-separated list of"+
                    " configuration names."} },
        { "flags" : [ "-x","--bound"],
           "parms" : { "dest" : "bound","help" : "Specify ranges of the Item"+
                    " element. The ONLY valid values are 'min','max'"+
                    " ,'normal'."} },
      )
   },
   "resAlloc" : {
      "func":createResourceAlloc,
      "help" : "Creates a Resource Allocation Section. ",
      "args" : (
         { "flags" : [ "-m", "--info" ],
           "parms" : { "dest" : "info","help" : "The information to describe"+
                   " the section."},
           "required": True
         },
        { "flags" : [ "-y","--infoID"],
           "parms" : { "dest" : "infoID","help" : "The id of the section's"+
                    " information."}},
        { "flags" : ["-c","--config"],
           "parms" : { "dest" : "config","help" : "A comma-separated list of"+
                    " configuration names."} },
        { "flags" : [ "-x","--bound"],
           "parms" : { "dest" : "bound","help" : "Specify ranges of the Item"+
                    " element. The ONLY valid values are 'min','max',"+
                    " 'normal'."} },
      ),
   },
   "annotate" : {
      "func":createAnnotationSection,
      "help" : "Creates Annotation Section.",
      "args" : (
         { "flags" : [ "-m", "--info" ],
           "parms" : { "dest" : "info","help" : "The information to describe"+
                    " the section."},
           "required": True
         },
        { "flags" : [ "-y","--infoID"],
           "parms" : { "dest" : "infoID","help" : "The id of the section's"+
                    " information."}},
        { "flags" : ["-a","--annotation"],
           "parms" : { "dest" : "annotation","help" : "The text for the"+
                    " annotation."},
           "required": True
        },

      ),
   },
   "product" : {
      "func":createProductSection,
      "help" : "Creates the Product Section.",
      "args" : (
         { "flags" : [ "-m", "--info" ],
           "parms" : { "dest" : "info","help" : "The information to describe"+
                    " the section."},
           "required": True
         },
        { "flags" : [ "-y","--infoID"],
           "parms" : { "dest" : "infoID","help" : "The id of the section's"+
                    " information."}},
        { "flags" : ["-p","--product"],
           "parms" : { "dest" : "product","help" : "This is the product being"+
                    " described in the section."},
           "required": True
        },
        { "flags" : ["-v","--productVersion"],
           "parms" : { "dest" : "productVersion","help" : "The version of the"+
                    " product."} },
        { "flags" : ["-c","--classDesc"],
           "parms" : { "dest" : "classDesc","help" : "Unique identifier for"+
                    " the software product using the reverse domain name"+
                    " convention. Example: com.xen.tools. If more than one"+
                    " product section is present then classDesc and instance"+
                    " must be defined."} },
        { "flags" : ["-n","--instance"],
           "parms" : { "dest" : "instance","help" : "The instance of the"+
                    " product section. Example: com.xen.tools.1."} },
        { "flags" : ["-d","--vendor"],
           "parms" : { "dest" : "vendor",
                      "help" : "The vendor for the product."} },
        { "flags" : ["-o","--fullVersion"],
           "parms" : { "dest" : "fullVersion",
                      "help" : "The full version of the product."} },
        { "flags" : ["-r","--prodURL"],
           "parms" : { "dest" : "prodURL",
                      "help" : "The URL for the product."} },
        { "flags" : ["-u","--vendorURL"],
           "parms" : { "dest" : "vendorURL",
                      "help" : "The URL for the vendor."} },
         { "flags" : ["-a","--appURL"],
           "parms" : { "dest" : "appURL",
                      "help" : "The URL for the application."} },


      ),
   },
   "property" : {
      "func":createProperty,
      "help" : "Creates a Property for the Product Section. ",
      "args" : (
        { "flags" : [ "-r", "--req" ],
           "parms" : { "action":"store_true","dest" : "required",
                      "help" : "Specify if the section is required."} },
        { "flags" : ["-s","--classDesc"],
           "parms" : { "dest" : "classDesc","help" : "Must be provided to"+
                    " identify Product Section. Unique identifier for the"+
                    " software product using the reverse domain name"+
                    " convention. Example: com.xen.tools. If more than one"+
                    " product section is present then classDesc and instance"+
                    " must be defined."},
           "required": True
        },
        { "flags" : ["-n","--instance"],
           "parms" : { "dest" : "instance","help" : "Must be provided to"+
                    " identify Product Section. The instance of the product"+
                    " section. Example: com.xen.tools.1."},
           "required": True
        },
        { "flags" : [ "-t","--type"],
           "parms" : { "dest" : "type","help" : "For the property of the"+
                    " product this specifies the type for the section."}},
        { "flags" : ["-v","--value"],
           "parms" : { "dest" : "value","help" : "For the property of the"+
                    " product this specifies the value for the section."} },
        { "flags" : [ "-c","--userConfig"],
           "parms" : {"action":"store_true", "dest" : "userConfig",
                    "help" : "For the property of the product this is a"+
                    " boolean value that specifies if this section is user"+
                    " configurable."} },
        { "flags" : [ "-l", "--label" ],
           "parms" : { "dest" : "label","help":"For the property of the"+
                    " product this specifies the label used to describe the"+
                    " configuration."}},
        { "flags" : [ "-b", "--labelID" ],
           "parms" : { "dest" : "labelID","help": "For the property of the"+
                    " product this specifies the ID for the label created."}},
        { "flags" : [ "-d", "--description" ],
           "parms" : { "dest" : "description","help": "For the property of"+
                      " the product this specifies the description for the"+
                      " given configuration."}},
        { "flags" : [ "-e", "--descID" ],
           "parms" : { "dest" : "descID","help": "For the property of the"+
                      " product this specifies the ID for the description of"+
                      " the configuration created."}},
        { "flags" : [ "-k", "--key" ],
           "parms" : { "dest" : "key","help": "For the property of the"+
                      " product this specifies the key."},
           "required": True
        },
      ),
   },
   "category" : {
      "func":createCategory,
      "help" : "Creates Creates the category that helps define a product"+
      " section.",
      "args" : (
        { "flags" : ["-s","--classDesc"],
           "parms" : { "dest" : "classDesc","help" : "Must be provided to"+
                      " identify Product Section. Unique identifier for the"+
                      " software product using the reverse domain name"+
                      " convention. Example:com.xen.tools. If more than one"+
                      " product section is present then classDesc and"+
                      " instance must be defined."} },
        { "flags" : ["-n","--instance"],
           "parms" : { "dest" : "instance","help" : "Must be provided to"+
                      " identify Product Section. The instance of the product"+
                      " section. Example: com.xen.tools.1."} },
        { "flags" : ["-c","--category" ],
           "parms" : { "dest" : "category", "action":"store",
                      "help" : "Description of the category."}},

      )
   },
   "icon" : {
      "func":createIconType,
      "help" : "Creates the category that helps define a product section.",
      "args" : (
        { "flags" : ["-n","--fileRef"],
           "parms" : { "dest" : "fileRef","help" : "The file reference for"+
                      " the given icon."} },
        { "flags" : ["--height"],
           "parms" : { "dest" : "height","help" : "The heigh of the image."}},
        { "flags" : ["-w","--width" ],
           "parms" : { "dest" : "width", "action":"store","help" : "The width"+
                      " of the image."}},
        { "flags" : ["-t","--mimeType" ],
           "parms" : { "dest" : "mimeType", "action":"store","help" : "The"+
                      " mimeType of the image."}},
         { "flags" : ["-s","--classDesc"],
           "parms" : { "dest" : "classDesc","help" : "Must be provided to"+
                      " identify Product Section. Unique identifier for the"+
                      " software product using the reverse domain name"+
                      " convention. Example: com.xen.tools. If more than one"+
                      " product section is present then classDesc and"+
                      " instance must be defined."} },
        { "flags" : ["--instance"],
           "parms" : { "dest" : "instance","help" : "Must be provided to"+
                      " identify Product Section. The instance of the product"+
                      " section. Example: com.xen.tools.1."} },
      )
   },
    "license" : {
      "func":createEulaSection,
      "help" : "Create the legal temrs for using a particular entity. ",
      "args" : (
         { "flags" : [ "-m", "--info" ],
           "parms" : { "dest" : "info",
                    "help" : "The information to describe the section."},
           "required": True
         },
        { "flags" : [ "-y","--infoID"],
           "parms" : { "dest" : "infoID",
                      "help" : "The id of the section's information."}},
        { "flags" : ["-a","--agreement"],
           "parms" : { "dest" : "agreement",
                      "help" : "The terms of the license."},
           "required": True
        },
        { "flags" : [ "-i","--licenseID"],
           "parms" : { "dest" : "licenseID",
                      "help" : "Unique ID for the given license agreement."} },
      ),
   },
   "startup" : {
      "func":createStartup,
      "help" : "Create the startup section for either a Virtual System or a"+
               " Virtual System Collection.",
      "args" : (
         { "flags" : [ "-m", "--info" ],
           "parms" : { "dest" : "info","help" : "The information to describe"+
                    " the section."},
           "required": True
         },
        { "flags" : [ "-y","--infoID"],
           "parms" : { "dest" : "infoID","help" : "The id of the section's"+
                    " information."}},
        { "flags" : ["-n","--entityName"],
           "parms" : { "dest" : "entityName","help" : "The entity name within"+
                    " a collection."} },
        { "flags" : [ "-o","--order"],
           "parms" : { "dest" : "order","help" : "Specifies the startup order"+
                    ", starting from 0. Items with same order identifier may"+
                    " be started up concurrently. The order is reversed for"+
                    " shutdown. Default order is 0.."},
           "required": True
        },
       { "flags" : ["-s","--startDelay"],
           "parms" : { "dest" : "startDelay","help" : "Supported only for a"+
                    " Virtual System. Specifies a delay in seconds to wait"+
                    " until proceeding to the next order in the start"+
                    " sequence. Default is 0."} },
       { "flags" : ["-w","--waitForGuest"],
           "parms" : { "action": "store_true","dest" : "waitForGuest",
                    "help" : " Supported only for a Virtual System. Allows"+
                    " the platform to resume the startup sequence after the"+
                    " guest has reported is ready. Default is False.."} },
       { "flags" : [ "-t", "--startAction" ],
           "parms" : { "dest" : "startAction",
                      "help" : "Supported only for a Virtual System."+
                      " Specifies the the start action to use. Valid values"+
                      " are 'powerOn' and none.The default value is"+
                      " 'powerOn'."}},
       { "flags" : [ "-p", "--stopDelay" ],
           "parms" : { "dest" : "stopDelay","help" : "Supported only for a"+
                    " Virtual System. Specifies a delay in seconds to wait"+
                    " until proceeding to the previous order in the sequence."+
                    " The default is 0."} },
       { "flags" : [ "-a", "--stopAction" ],
           "parms" : { "dest" : "stopAction","help" : "Supported only for a"+
                    " Virtual System.. Specifies the stop action to use."+
                    " Valid values are 'powerOff' ,'guestShutdown', and"+
                    " 'none'. The default is 'powerOff'."} },
      ),
   },
   "os" : {
      "func":createOperatingSystem,
      "help" : "Creates the operating systems section for a Virtual System.",
      "args" : (
         { "flags" : [ "-i","--descriptionID" ],
           "parms" : { "dest" : "descriptionID", "action":"store",
                      "help" : "The id for the description."}},
         { "flags" : [ "-d","--description" ],
           "parms" : { "dest" : "description", "action":"store",
                      "help" : "The description of the operating system.."}},
         { "flags" : [ "-n","--name" ],
           "parms" : { "dest" : "name", "action":"store",
                      "help" : "Unique name for the section."}},
         { "flags" : [ "-m", "--info" ],
           "parms" : { "dest" : "info",
                      "help" : "The information to describe the section."}},
        { "flags" : [ "-y","--infoID"],
           "parms" : { "dest" : "infoID",
                      "help" : "The id of the section's information."}},
      )
   },
    "install" : {
      "func":createInstallSection,
      "help" : "Creates the install section used to describe a virtual system"+
               " in a virtual system collection.",
      "args" : (
         { "flags" : [ "-i","--initBoot" ],
           "parms" : { "dest" : "initBoot", "action":"store_true",
                      "help" : "Specifies if the virtual machine needs to be"+
                        " initially booted to install and configure"+
                        " software."}},
         { "flags" : [ "-b","--bootStopdelay" ],
           "parms" : { "dest" : "bootStopdelay", "action":"store",
                      "help" : "Specifies a delay in seconds to wait for"+
                      " the virtual machine to power off."}},
         { "flags" : [ "-m", "--info" ],
           "parms" : { "dest" : "info","help" : "The information to describe"+
                    " the section."},
           "required": True
         },
        { "flags" : [ "-y","--infoID"],
           "parms" : { "dest" : "infoID","help" : "The id of the section's"+
                " information."}},
      )
   },
    "validate" : {
      "func":validateOVF,
      "help" : "Verifies the OVF against the schema.",
      "args" : (
         { "flags" : [ "-x", "--schema"],
           "parms" : { "dest" : "schema","action":"store",
                      "help": "Provide the path to the schema." },
           "required": True
         },
      ),
   },
    "lang" : {
      "func":changeLanguage,
      "help" : "Change the language of the OVF.",
      "args" : (
         { "flags" : [ "-l", "--language"],
           "parms" : { "dest" : "language","action":"store",
                      "help": "Define the language." },
           "required": True
         },
      ),
   },
   "merge" : {
      "func": mergeOVF,
      "help" : "Change the language of the OVF.",
      "args" : (
         { "flags" : [ "-o", "--ovf1"],
           "parms" : { "dest" : "ovf1","action":"store",
                      "help": "OVF to merege." }
         },
          { "flags" : [ "-v", "--ovf2"],
           "parms" : { "dest" : "ovf2","action":"store",
                      "help": "OVF to merege." }
         },
      ),
   },

}
common = (
   { "flags" : [ "--comment" ],
     "parms" : { "dest" : "comment", "help": "Comment to add." }
   },
   { "flags" : [ "--encoding" ],
           "parms" : { "dest" : "encoding",
                      "help" : "Defines the encoding used for the OVF." }
    },
   { "flags" : ["--secID" ],
     "parms" : { "dest" : "secID","help":"OVF id of the section."} ,
   },
   { "flags" : [ "-f", "--file" ],
     "parms" : { "dest" : "ovfFile", "help": "Target OVF." },
     "required": True
   },
   { "flags" : [ "--id" ],
     "parms" : { "dest" : "id","help":"ID of the section to attach to."}
   },
   { "flags" : [ "--use-section" ],
     "parms" : { "dest" : "sectionInfo","help":"Based on the Info for a given"+
                " section add a child to the section with the matching Info."}
   },
)

if __name__ == "__main__":
    main()
