import logging
from xml.dom.minidom import parseString

from orangescape.model.server.util.ConversionUtil import categoryIdMapping, convertFromXMLFormat
from orangescape.model.server.util.metadatautil import getCellByName

def getText(nodelist):
    rc = ""
    for node in nodelist:
        if node.nodeType == node.TEXT_NODE:
            rc = rc + node.data
    return rc

class XMLImportService():
    def __init__(self, component, rootMetadata, xmlString):
        self.component = component
        self.session = component.getSession()
        self.rootMetadata = rootMetadata
        logging.info("The input xml is "+xmlString)
        self.dom = parseString(xmlString)

    def process(self):
        soapPrefix="urn:orangescape"
        rootNodeList = self.dom.getElementsByTagNameNS(soapPrefix,self.rootMetadata.getSheetName())

        values, oneToManyNodes = self.__get_values__(self.rootMetadata, rootNodeList[0])
        sheetId = values.get('SheetId')
        if sheetId:
            rootInstance = self.session.get(sheetId, self.rootMetadata)
            self.component.update(rootInstance, values)
        else:
            sheetName = values.get('SheetName')
            if sheetName is not None:
                rootInstance = self.session.getBySheetName(sheetName, self.rootMetadata)
                if rootInstance:
                    self.component.update(rootInstance, values)
                else:
                    rootInstance = self.component.new(self.rootMetadata, values)
            else:
                rootInstance = self.component.new(self.rootMetadata, values)
        self.__process_node__(rootInstance, oneToManyNodes)
        return rootInstance

    def __process_node__(self, parentInstance, oneToManyNodes):

        oneToManyRefCellList = parentInstance.getSheetMetadata().getOneToManyList()
        for oneToManyKey, node in oneToManyNodes.iteritems():
            i = node.localName.find('.')
            refCellName = node.localName[:i]
            childSheetName = node.localName[i+1:]

            validRef = False
            for oneToManyRefCell in oneToManyRefCellList:
                if oneToManyRefCell.getCellName().upper() == refCellName.upper() and oneToManyRefCell.getSheetMetadata().getSheetName().upper() == childSheetName.upper():
                    validRef = True

                    for childNode in node.childNodes:
                        if childNode.nodeType == childNode.ELEMENT_NODE and childNode.localName.upper() == childSheetName.upper():
                            values, childOneToManyNodes = self.__get_values__(oneToManyRefCell.getSheetMetadata(), childNode)

                            if values.has_key('SheetName'):
                                childInstance = self.session.getBySheetName(values['SheetName'], oneToManyRefCell.getSheetMetadata())
                                if childInstance:
                                    del values['SheetName']
                                    if childInstance.get(oneToManyRefCell) != parentInstance.getSheetId():
                                        values[oneToManyRefCell.getCellName()] = parentInstance.getSheetId()
                                    self.component.update(childInstance, values)
                                    logging.info('Updating %s Under %s with sheetName %s'%(oneToManyRefCell.getSheetMetadata().getSheetName(), parentInstance.getSheetId(), childInstance.getSheetName()))
                                else:
                                    childInstance = self.component.create(parentInstance, oneToManyRefCell, values)
                                    logging.info('Creating %s Under %s with sheetName %s'%(oneToManyRefCell.getSheetMetadata().getSheetName(), parentInstance.getSheetId(), childInstance.getSheetName()))
                            else:
                                childInstance = self.component.create(parentInstance, oneToManyRefCell, values)
                                logging.info('Creating %s Under %s with sheetName %s'%(oneToManyRefCell.getSheetMetadata().getSheetName(), parentInstance.getSheetId(), childInstance.getSheetName()))
                            self.__process_node__(childInstance, childOneToManyNodes)
            if not validRef:
                logging.warn('Invalid reference cell tag %s. Reference cell not found in OneToManyList of the model %s'%(node.localName, parentInstance.getSheetMetadata().getSheetName()))

    def __get_values__(self, metadata, node):
        oneToManyNodes = {}
        values = {}
        for n in node.childNodes:
            if n.nodeType == n.ELEMENT_NODE:
                if n.localName.find('.') > 0:
                    oneToManyNodes[n.localName] = n
                else:
                    cell = getCellByName(metadata, n.localName)
                    if cell:
                        if cell.isReferenceCell():
                            refSheetName = getText(n.childNodes)
                            refMetadata = cell.getReferredSheetMetadata()
                            refSheet = self.session.getBySheetName(refSheetName, refMetadata)
                            if refSheet:
                                values[cell.getCellName()] = refSheet.getSheetId()
                            else:
                                errorMessage = 'Referred sheet with SheetName %s not found for the reference cell %s in the model %s'%(refSheetName, cell.getCellName(), refMetadata.getSheetName())
                                logging.error(errorMessage)
                        else:
                            category = cell.getFinalCategory()
                            formatStr = cell.getFinalFormat()
                            values[cell.getCellName()] = convertFromXMLFormat(getText(n.childNodes), category, formatStr)
                    else:
                        logging.warn('Cell not found for the xml node %s for the sheet %s'%(cell.getCellName(), metadata.getSheetName()))

        return values, oneToManyNodes

    def getRootNode(self):
        soapPrefix=self.dom.childNodes[0].namespaceURI
        for node in soapXML.getElementsByTagNameNS(soapPrefix,"Body")[0].childNodes:
            if node.nodeType != node.TEXT_NODE:
                rootNode=node
                break
        return rootNode