#----------------------------------------------------------------------
# Copyright (c) 2012-2013 Raytheon BBN Technologies
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and/or hardware specification (the "Work") to
# deal in the Work without restriction, including without limitation the
# rights to use, copy, modify, merge, publish, distribute, sublicense,
# and/or sell copies of the Work, and to permit persons to whom the Work
# is furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be
# included in all copies or substantial portions of the Work.
#
# THE WORK IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
# OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
# HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
# WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE WORK OR THE USE OR OTHER DEALINGS
# IN THE WORK.
#----------------------------------------------------------------------

import sys
import datetime
import re
from xml.dom.minidom import *

import config
import resources
from resources import VMNode, NIC, Link, installItem, executeItem, \
    experimentHosts, experimentLinks, experimentNICs 

def parseRequestRspec(slice_urn, rspec) :
    """ This function parses a request Rspec and creates an in-memory 
        representation of the experimenter specified topology using 
        VMNode, NIC and Link objects.

        This function returns None if everything goes well.  In case of
        of an error it returns a string describing the error.
    """
    # Get the slice name.  This is the last part of the URN.  For example,
    #    the slice name in the URN urn:publicid:IDN+geni:gpo:gcf+slice+myslice
    #    is myslice.
    resources.sliceURN = slice_urn
    resources.sliceName = re.split(r'[:\+]+', slice_urn)[-1]

    # Parse the xml rspec
    rspec_dom = parseString(rspec)

    # Look for DOM objects tagged 'node'.  These are hosts requested by the 
    #    experimenter
    hostList = rspec_dom.getElementsByTagName('node')

    # For each host, extract experimenter specified information from DOM node
    hostCount = 0;      # Keep track of the number of hosts allocated
    for host in hostList : 
        hostCount += 1
        if hostCount >  VMNode.numVMs :
            config.logger.error('Experimenter requested more nodes than available')
            return 'Number of nodes requested exceeds availability.  Number of nodes available: %s' % VMNode.numVMs 

        # Create a VMNode object for this host and add it to our collection
        #    of hosts allocated to the experiment
        hostObject = VMNode(hostCount)
        experimentHosts[hostObject.containerName] = hostObject

        # Get information about the host from the rspec
        hostAttributes = host.attributes   # DOM attributes object 
                                           #    associated with the host
        if hostAttributes.has_key('client_id') :
            hostObject.nodeName = hostAttributes['client_id'].value

        # Get interfaces associated with the host
        netInterfaceList = host.getElementsByTagName('interface')
        interfaceCount = 0;   # Track num of interfaces requested for this node
        for netInterface in netInterfaceList :
            interfaceCount += 1
            if interfaceCount > 3 :
                config.logger.error('Exceeded number of interfaces available on node')
                return 'Attempted to request a node with more than three interfaces.'
            
            # Create a NIC object for this interface and add it to the list 
            #    of NICs associated with this hostObject
            nicObject = NIC()
            hostObject.NICs = hostObject.NICs + [nicObject]