from orangescape.model.engine.engineconstants import WORKFLOW
from orangescape.model.engine.exception.Error import InstanceNotFoundError
from orangescape.model.engine.execution.DateandTime import NOW
from orangescape.model.engine.execution.ExecutionTree import ExecutionTree
from orangescape.model.engine.execution.exFunctions import getNumber
from orangescape.model.engine.util.NumericUtil import is_a_number
from orangescape.model.server.PerfMonitor import startPerfMonitor, stopPerfMonitor

from orangescape.model.server.SystemInterface import Engine
from orangescape.model.server.util.ServerUtil import _get_class
from orangescape.model.server.util.metadatautil import getShortCutByName
import logging
import appconfig as config

class Command:

## TODO need to update this method to dispatch custom actions
    def dispatch(self, session, command,*args):
        component = Component(session)
        command_method = getattr(component,command)
        return command_method(*args)


class Component(Engine):

    session = None

    def __init__(self, session):
        self.session = session

    def getSession(self):
        return self.session

    def recursiveExecution(self, et):
        referenceChanges = et.execute()
        while len(referenceChanges):
            et = ExecutionTree(self.session, referenceChanges)
            for instanceid, instanceDcellMap in referenceChanges.iteritems():
                if len(instanceDcellMap)>0:
                    metadata = instanceDcellMap[0].getRowMetadata().getSheetMetadata()
                    try:
                        sheet = self.session.get(instanceid, metadata)
                    except InstanceNotFoundError, e:
                        raise e
                    for dCell in instanceDcellMap:
                        et.addInputNode(sheet, dCell, sheet.get(dCell), True)
            referenceChanges = et.execute()

    def new(self, metadata, values=None, id=None):
        pm = startPerfMonitor(metadata.getSheetName(),'new','new',inputValues=values)
        if id is None and values:
            id = values.get('SheetId')
        et = ExecutionTree(self.session)
        sheet = self.createSheet(et, metadata, values,id=id)
        self.recursiveExecution(et)

        startActivity = metadata.getStartActivity()
        if (config.env != config.SL or self.session.__class__.__name__=='SLTransientSession') and startActivity and metadata.getSheetName()!='ProcessInstance' and self.session.getUser():
            self.submit(sheet, None)
        """If sheet is created through shortcut the corresponding action needs to be executed"""
        if values and values.has_key('ShortCut'):
            shortCut = getShortCutByName(metadata, values['ShortCut'])
            if shortCut:
                actionBranch = shortCut.getBranch()
                if actionBranch:
                    self.executeAction(sheet, actionBranch)
            else:
                logging.warn('Couldn\'t get the shortcut metadata named %s'%(values['ShortCut']))

        stopPerfMonitor(pm, sheet)
        return sheet;

    def create(self, parentSheet, referenceCell, values=None, id=None):
        parentMetadata = referenceCell.getReferredSheetMetadata()
        pm = startPerfMonitor(referenceCell.getSheetMetadata().getSheetName(),'create','create',inputValues=values)

        if parentMetadata and parentSheet.getSheetMetadata().getSheetId() == parentMetadata.getSheetId():
            if values is None:
                values = dict()
            values[referenceCell.getCellName()] = parentSheet.getSheetId()
            et = ExecutionTree(self.session)
            sheet = self.createSheet(et, referenceCell.getSheetMetadata(), values,id=id)
            self.recursiveExecution(et)
            stopPerfMonitor(pm, sheet)
            return sheet
        elif [cell.getSheetId() for cell in parentSheet.getSheetMetadata().getManyToOneList()].__contains__(referenceCell.getSheetId()):
            stopPerfMonitor(pm)
            return self.createUpdate(parentSheet, referenceCell, values)
        else:
            stopPerfMonitor(pm)
            raise Exception('There is no reference between %s and %s.%s'%(parentSheet.getSheetMetadata().getSheetName(), referenceCell.getSheetMetadata().getSheetName(), referenceCell.getCellName()))

    def replace(self, sheet, referenceKey, referenceValue):
        return self.update(sheet, {referenceKey:referenceValue})

    def createUpdate(self, childSheet, referenceCell, values=None,id=None):
        et = ExecutionTree(self.session)
        parentSheet = self.createSheet(et, referenceCell.getReferredSheetMetadata(), values,id=id)
        et.addInputNode(childSheet, referenceCell, parentSheet.getSheetId())
        self.recursiveExecution(et)
        return parentSheet

    def update(self, sheet, values=None):
        pm = startPerfMonitor(sheet.getSheetMetadata().getSheetName(),'update','update',inputSheet=sheet,inputValues=values)
        metadata = sheet.getSheetMetadata()
        if not values:
            values = dict()
        if not values.has_key('ModifiedAt'):
            values['ModifiedAt'] = NOW([])
        if not values.has_key('ModifiedBy'):
            values['ModifiedBy'] = self.session.getUser().getSheetId()

        et = ExecutionTree(self.session)
        self.buildDependency(et, values, sheet)
        self.recursiveExecution(et)
        result = self.session.get(sheet.getSheetId(), metadata)
        stopPerfMonitor(pm, sheet)
        return result

    def read(self, sheetId, metadata):
        sheet = self.session.get(sheetId, metadata)
        return sheet

    def delete(self, sheet):
        pm = startPerfMonitor(sheet.getSheetMetadata().getSheetName(),'delete','delete',sheetid=sheet.getSheetId(),inputSheet=sheet)

        et = ExecutionTree(self.session)
        delDict = dict()
        self.buildDeleteTree(sheet, et, delDict)
        self.recursiveExecution(et)
        for id, delSheet in delDict.iteritems():
            logging.info('Deleting sheet %s'%(delSheet.getSheetId()))
            self.__check_n_delete_attachment__(delSheet)
            self.session.delete(delSheet)
        stopPerfMonitor(pm, sheet)

    def batch_update(self, createdList, updatedDict, deletedList):
        """
        createdList = {metadata1Id :[{column1 : value1, column2 : value2}, {column1 : value1, column2 : value2},]}
        updatedDict = {
                   metadata1Id :{instance11id : {column1 : value1, column2 : value2},
                                 instance12id : {column1 : value1, column2 : value2}
                 }, metadata2Id :{instance21id : {column1 : value1, column2 : value2},
                                  instance22id : {column1 : value1, column2 : value2}}}
        delete = {metadata1Id:[instance1, instance2], metadata2Id:[instance1, instance2]}
        """
        et = ExecutionTree(self.session)
        newSheetIdList = {}
        if createdList:
            for metadataId, defaultValueList in createdList.iteritems():
                newSheetIdList[metadataId] = {}
                metadata = self.session.getApplication().getSheetMetadataById(metadataId)
                for values in defaultValueList:
                    sheet = self.createSheet(et, metadata, values,id=values.get('SheetId'))
                    newSheetIdList[metadataId][sheet.getSheetId()] = sheet.getSheetId()
        if updatedDict:
            for metadataId, valueList in updatedDict.iteritems():
                metadata = self.session.getApplication().getSheetMetadataById(metadataId)
                for id, values in valueList.iteritems():
                    sheet = self.session.get(id, metadata)
                    if not values:
                        values = dict()
                    if not values.has_key('ModifiedAt'):
                        values['ModifiedAt'] = NOW([])
                    if not values.has_key('ModifiedBy'):
                        values['ModifiedBy'] = self.session.getUser().getSheetId()
                    self.buildDependency(et, values, sheet)
        delDict = dict()
        if deletedList:
            for metadataId, idList in deletedList.iteritems():
                metadata = self.session.getApplication().getSheetMetadataById(metadataId)
                for id in idList:
                    sheet = self.session.get(id, metadata)
                    self.buildDeleteTree(sheet, et, delDict)
        self.recursiveExecution(et)

        newSheetList = {}
        for metadataId, idList in newSheetIdList.iteritems():
            newSheetList[metadataId] = {}
            metadata = self.session.getApplication().getSheetMetadataById(metadataId)
            startActivity = metadata.getStartActivity()

            for id in idList:
                sheet = self.session.get(id, metadata)
                if (config.env != config.SL or self.session.__class__.__name__=='SLTransientSession') and startActivity and metadata.getSheetName()!='ProcessInstance' and self.session.getUser():
                    self.submit(sheet, None)
                newSheetList[metadataId][sheet.getSheetId()] = sheet

        for id, delSheet in delDict.iteritems():
            logging.info('Deleting sheet %s'%(delSheet.getSheetId()))
            self.__check_n_delete_attachment__(delSheet)
            self.session.delete(delSheet)

        return newSheetList

    def __check_n_delete_attachment__(self, sheet):
        if sheet.getSheetMetadata().getPublicCellMetadataDict().has_key('Attachment'):
            logging.info('deleting attachment %s'%(sheet.getSheetId()))
            self.session.deleteAttachment(sheet.getSheetId())

        """Can this be done using a single execution tree for performance???"""
    def deleteAll(self,sheetList):
        for sheet in sheetList:
            self.delete(sheet)

    def submit(self, sheet, activityDef):
        from orangescape.model.engine.execution.ProcessUtil import process_module_pkg
        processNode = _get_class(process_module_pkg%(WORKFLOW))(self, sheet, activityDef)
        processNode.submit()
        if sheet.getSheetMetadata().getPublicCellMetadataDict().has_key('LockedBy'):
            self.update(sheet, {'LockedBy':None})

    def invoke(self, metadata, values, sheet=None, referenceCell=None):
        if values.__contains__('invoke'):
            invokeVal = values['invoke']
            if invokeVal.find('.')>0:
                if config.env == config.SL:
                    valList = invokeVal.split(".")
                    methodName = valList.pop()
                    moduleName = valList.pop()
                    invokeVal = moduleName+"."+methodName
                obj = _get_class(invokeVal)(self, metadata, values, sheet, referenceCell)
                return obj
            else:
                self.__execute_activity__(metadata, sheet, values)
        else:
            raise Exception('invoke is not specified in the values')

    def __execute_activity__(self, metadata, sheet, values):
        activityDefinition = metadata.getActivityDefinitionById(self.session.getModifiedIn())
        gridView = values.get('form')
        tilde = values['invoke'].find('~')
#        if gridView is not None:
#            rootSheetMetadataId = values.get('rootSheetMetadataId')
#            if rootSheetMetadataId is not None:
#                rootMetadata = self.session.getApplication().getSheetMetadataById(rootSheetMetadataId)
#            else:
#                rootMetadata = metadata
#            rootSheetMetadataName = rootMetadata.getSheetName()
#            metadataDict = self.session.getApplication().getActionMapping().get(rootSheetMetadataName)
#            if not metadataDict:
#                if config.PERFMONITOR_ENABLED:
#                    pm.stop()
#                raise Exception('Metadata information not found in actionmapping for the sheet %s(%s)'%(rootMetadata.getSheetName(), rootMetadata.getSheetId()))
#            gridViewDict = metadataDict.get(gridView)
#            if not gridViewDict:
#                if config.PERFMONITOR_ENABLED:
#                    pm.stop()
#                raise Exception('From information not found in actionmapping for the sheet %s(%s) for the From %s(%s)'%(rootMetadata.getSheetName(), rootMetadata.getSheetId(), gridView, gridView))
#            branchId = gridViewDict.get(values['invoke'])
#            if branchId is None:
#                for key in gridViewDict.keys():
#                    if key.__contains__(values['invoke']):
#                        branchId = gridViewDict.get(key)
#                        break
#            if not branchId:
#                errMsg = 'Branch information not found in actionmapping for the sheet %s(%s) for the gridview %s(%s) for the value %s'%(rootMetadata.getSheetName(), rootMetadata.getSheetId(), gridView, gridView, values['invoke'])
#                if config.PERFMONITOR_ENABLED:
#                    pm.stop()
#                raise Exception(errMsg)
#
#            branch = metadata.getBranchById(branchId)
#        else:
        branchName = values['invoke']
        if tilde >= 0:
            branchName = values['invoke'][:tilde]
        branch = metadata.getBranch(branchName)

        if tilde >= 0:
            caption = values['invoke'][tilde+1:]
        else:
            caption = values['invoke']
        self.update(sheet, {'Caption':caption})
        if branch.getProcessType()==WORKFLOW:
            pm = startPerfMonitor(sheet.getSheetMetadata().getSheetName(),'workflow','workflow',sheetid=sheet.getSheetId(),inputSheet=sheet)
            logging.info(activityDefinition.getSheetName())
            self.submit(sheet, activityDefinition)
            stopPerfMonitor(pm, sheet)
        else:
            """Execute action chain"""
            self.executeAction(sheet, branch)

    def executeAction(self, sheet, rootBranch):
        pm = startPerfMonitor(sheet.getSheetMetadata().getSheetName(),'action',rootBranch.getSheetName(),sheetid=sheet.getSheetId(),inputSheet=sheet)
        if len(rootBranch.getActivityDefinitionList())>0:
            startAction = rootBranch.getActivityDefinitionList()[0]
            from orangescape.model.engine.execution.ProcessUtil import getProcessNode
            processNode = getProcessNode(self, startAction, sheet)
            activityId = processNode.execute()
            while activityId:
                activity = sheet.getSheetMetadata().getActivityDefinitionById(activityId)
                processNode = getProcessNode(self, activity, sheet)
                activityId = processNode.execute()
        else:
            logging.warn('There is no command defined in the action %s in the model %s'%(rootBranch.getSheetName(), sheet.getSheetMetadata().getSheetName()))
        stopPerfMonitor(pm, sheet)

    def buildDeleteTree(self, delSheet, et, delDict):
        if not delDict.__contains__(delSheet.getSheetId()):
            delDict[delSheet.getSheetId()]=delSheet
            sheetMetadata = delSheet.getSheetMetadata()

            for refCell in sheetMetadata.getOneToManyList():
                cascade = refCell.isCascade()
                childSheetList = self.session.getList(delSheet, refCell)
                if cascade:
                    for childSheet in childSheetList:
                        self.buildDeleteTree(childSheet, et, delDict)
                elif not refCell.isFormula():
                    for childSheet in childSheetList:
                        et.addInputNode(childSheet, refCell, None)

            for referenceCell in sheetMetadata.getManyToOneList():
                if not referenceCell.isFormula():
                    et.addInputNode(delSheet, referenceCell, None)

            if delSheet.getSheetMetadata().getPublicCellMetadataDict().has_key('ProcessInstance') and delSheet.getValue('ProcessInstance'):
                pi = self.session.get(delSheet.getValue('ProcessInstance'), self.session.getApplication().getSheetMetadata('ProcessInstance'))
                self.buildDeleteTree(pi, et, delDict)

    def createSheet(self, et, metadata, defaultValues=dict(), id=None):
        sheet = self.session.createModel(metadata,id)

        userid = None
        if id and (id in ('guest_chg', 'guest', 'OS')):
            userid = None
        else:
            userid = self.session.getUser().getSheetId()

        sysValus = {'SheetMetadataName' : sheet.getSheetMetadata().getSheetMetadataName(), 'SheetId' : sheet.getSheetId(),
                    'CreatedBy' : userid, 'ModifiedBy' : userid, 'CreatedAt' : NOW([]), 'ModifiedAt' : NOW([]),
                    'SheetName' : sheet.getSheetId()}
#        if userid and userid != 'guest':
#            sysValus['AssignedTo'] = self.session.getUser().getValue('UserId').split('@')[0]
        if self.session.getUser():
            if metadata.getPublicCellMetadataDict().has_key('Tenant') and self.session.getUser().getValue('Company'):
                sysValus['Tenant'] = self.session.getUser().getValue('Company')

        if metadata.getPublicCellMetadataDict().has_key('Metadata') and metadata.getSheetName() not in ('Activity'):
            metadataIns = self.session.getIfExists('M_'+metadata.getSheetId(), self.session.getApplication().getSheetMetadata('Metadata'))
            if metadataIns:
                sysValus['Metadata'] = metadataIns.getSheetId()
            else:
                logging.warn('Metadata instance not found for the model %s'%(metadata.getSheetName()))

        startActivity = metadata.getStartActivity()
        if startActivity:
            sysValus['Status'] = startActivity.getSheetId()

        if not defaultValues:
            defaultValues = sysValus
        else:
            sysValus.update(defaultValues)
            defaultValues = sysValus

        cellDict = sheet.getSheetMetadata().getPublicCellMetadataDict()
        if defaultValues is not None:
            for key, value in defaultValues.iteritems():
                cell = sheet.getCellMetadata(key)
                if not cell.isFormula() and cellDict.__contains__(key):
                    et.addInputNode(sheet, cell, value)

        for row in metadata.getRowMetadataList():
            for cellMetadata in row.getCellMetadataList():
                if cellMetadata and not cellMetadata.isFormula():
                    if cellMetadata.isNamedCell():
                        if defaultValues.has_key(cellMetadata.getCellName()):
                            continue
                        cellValue=cellMetadata.getDefaultValue()
                    else:
                        if cellMetadata.isStr():
                            cellValue = cellMetadata.getCellValue()
                        else:
                            cellValue = cellMetadata.getCellFloatValue()
                    et.addInputNode(sheet, cellMetadata, cellValue)
        return sheet

    def getConvertedValue(self, cell, value):
        if value is None:
            return value
        if cell.isStr():
            s = str(value)
            if s=='':
                return None
            return s
        else:
            if is_a_number(value):
                return getNumber(value)
            return None

    def buildDependency(self, et, values, target):
        for key, value in values.iteritems():
            cell = target.getCellMetadata(key)
            if not cell.isFormula():
                value = self.getConvertedValue(cell, value)
                et.addInputNode(target, cell, value)
            else:
                et.addIndependentFormula(target, cell)

    def buildAllInputCellDependency(self,sheet, et):
        metadata = sheet.getSheetMetadata()
        for row in metadata.getRowMetadataList():
            for cellMetadata in row.getCellMetadataList():
                if cellMetadata and not cellMetadata.isFormula():
                    et.addInputNode(sheet, cellMetadata, sheet.get(cellMetadata))
        return et

    def getAttachmentWithId(self, sheet):
        attachment = self.session.getAttachment(sheet.getSheetId())
        fileName=sheet.get(sheet.getCellMetadata('Attachment'))
#        if attachment is None:
#            raise InstanceNotFoundError("Couldn't find the attachment for the model %s for the instance %s"%(sheet.getSheetMetadata().getSheetName(), sheet.getSheetId()))
        return fileName,attachment

    def updateAttachmentWithId(self, sheet, fileName, fileContent, tag=False):
        logging.info('Updating attachment file name %s for the instance %s'%(fileName, sheet.getSheetId()))
        self.update(sheet,{'Attachment':fileName})
        if not tag and self.session.getApplication().getSheetId()=='Application001':
            tag = 'VersionForDebug'
        self.session.updateAttachment(sheet.getSheetId(), fileContent, tag)
        return True

    def getAttachmentInstance(self, sheet, referenceCell, fileName):
        attachmentList = self.session.getList(sheet, referenceCell)
        for instance in attachmentList:
            if instance.getValue('Attachment')==fileName:
                return instance
        return None

    def deleteAttachmentWithId(self, sheet):
        attachmentInstance = self.session.getAttachment(sheet.getSheetId())
        if attachmentInstance is not None:
            self.update(sheet, {'Attachment':None})
            self.session.deleteAttachment(sheet.getSheetId())
        else:
            logging.error("Couldn't find the attachment for the model %s for the instance %s"%(sheet.getSheetMetadata().getSheetName(), sheet.getSheetId()))

    def updateAttachment(self, parentSheet, referenceCell, fileName, fileContent, tag=False):
        attachmentInstance =  self.getAttachmentInstance(parentSheet, referenceCell, fileName)
        if attachmentInstance is None:
            attachmentInstance = self.create(parentSheet, referenceCell, {'Attachment':fileName})
#        if not tag and self.session.getApplication().getSheetId()=='Application001':
#            tag = 'VersionForDebug'
        self.session.updateAttachment(attachmentInstance.getSheetId(), fileContent, tag)
        return True

    def copyAttachment(self, srcParent, srcRefCell, parentSheet, referenceCell, fileName):
        srcAttachmentSheet =  self.getAttachmentInstance(srcParent, srcRefCell, fileName)
        if srcAttachmentSheet:
            return self.copyAttachmentWithId(srcAttachmentSheet, parentSheet, referenceCell)
        logging.info('copyAttachment failed couldn\'t find attachment with file name %s for the parent %s (%s)'%(fileName, srcParent.getSheetMetadata().getSheetName(), srcParent.getSheetId()))
        return None

    def copyAttachmentWithId(self, srcAttachmentSheet, parentSheet, referenceCell):
        targAttachmentSheet = self.create(parentSheet, referenceCell, {'SheetName': srcAttachmentSheet.getSheetName(), 'Attachment':srcAttachmentSheet.getValue('Attachment')})
        self.session.copyAttachment(srcAttachmentSheet.getSheetId(), targAttachmentSheet.getSheetId())
        return targAttachmentSheet

    def getAttachment(self, parentSheet, referenceCell, fileName):
        attachmentInstance = self.getAttachmentInstance(parentSheet, referenceCell, fileName)
        if attachmentInstance is None:
            raise InstanceNotFoundError("Couldn't find the %s(Attachment) %s for the instance %s of the sheet %s"%(referenceCell.getSheetMetadata().getSheetName(), fileName, parentSheet.getSheetName(), parentSheet.getSheetMetadata().getSheetName()))
        attachment = self.session.getAttachment(attachmentInstance.getSheetId())
        if attachment is None:
            raise InstanceNotFoundError("Couldn't find the %s %s for the instance %s of the sheet %s"%(referenceCell.getSheetMetadata().getSheetName(), fileName, parentSheet.getSheetName(), parentSheet.getSheetMetadata().getSheetName()))
        return attachment

    def getAttachmentList(self, parentSheet, referenceCell):
        attachmentList = self.session.getList(parentSheet, referenceCell)
        return attachmentList

    def deleteAttachment(self, parentSheet, referenceCell, fileName):
        attachmentInstance = self.getAttachmentInstance(parentSheet, referenceCell, fileName)
        if attachmentInstance is not None:
            self.delete(attachmentInstance)
        else:
            logging.error("Couldn't find the %s %s for the instance %s of the sheet %s for deleting the attachment"%(referenceCell.getSheetMetadata().getSheetName(), fileName, parentSheet.getSheetName(), parentSheet.getSheetMetadata().getSheetName()))

    def triggerSLA_Action(self):
        piMetadata = self.session.getApplication().getSheetMetadata('ProcessInstance')
        if not piMetadata.getPublicCellMetadataDict().has_key('SLA_Time'):
            logging.warn('ProcessInstance does not contains SLA information exit with out executing')
            return
        conditionList = list()
        conditionList.append((piMetadata.getPublicCellMetadata('NextTriggerTime').getSheetId(), '<=', NOW([]) ))
        conditionList.append((piMetadata.getPublicCellMetadata('Active').getSheetId(), '=', 1.0))
        basequery = ('and', conditionList )

        piList = self.session.advQuery(piMetadata, 1000, basequery)
#        piList = self.session.query(piMetadata, 1000, basequery)
        for pi in piList:
            if pi.getValue('InstanceMetadata'):
                sheetMetadata = self.session.getApplication().getSheetMetadataById(pi.getValue('InstanceMetadata')[2:])
                activityDefinition = sheetMetadata.getActivityDefinitionById(pi.getValue('InstanceActivity'))
                triggerAction = self.__getSLA_TriggerAction__(sheetMetadata, activityDefinition)
                if triggerAction:
                    sheet = self.session.get(pi.getValue('InstanceId'), sheetMetadata)
                    self.session.setModifiedIn(activityDefinition.getSheetId())
                    self.update(sheet, {'ModifiedIn':pi.getSheetId()})
                    self.executeAction(sheet, triggerAction)
                    self.update(pi, {'Counter':(pi.getValue('Counter') or 0.0)+1.0})
                else:
                    logging.warn('Triger action not found for the activity %s for the model %s for the processs %s'%(activityDefinition.getSheetName(), sheetMetadata.getSheetName(), pi.getSheetId()))

                    """This is a temp code for fixing a bug in older data"""
                    rootBranch = sheetMetadata.getWorkFlowRoot()
                    if rootBranch:
                        workflow_end = rootBranch.getActivityDefinitionList()[-1]
                        if pi.getValue('InstanceActivity')==workflow_end.getSheetId():
                            logging.info('Disabling SLA for Closed process %s'%(pi.getSheetId()))
                            self.update(pi, {'Iterations':None, 'SLA_Time':None})
                    """***************************************************"""

    def __getSLA_TriggerAction__(self, sheetMetadata, activityDefinition):
        from orangescape.model.engine.execution.ProcessUtil import getInputportByParamName
        ipPort = getInputportByParamName(activityDefinition, 'SLA-Action')
        if ipPort:
            action = sheetMetadata.getBranchById(ipPort.getStringValue())
            return action
        return None


class SecondaryComponent(Component):

    def __init__(self, session):
        Component.__init__(self, session)

    def updateCells(self, metadata, cells):
        instances = self.session.advQuery(metadata)
        et = ExecutionTree(self.session)
        for instance in instances:
            for cellMetadata in cells:
                if cellMetadata.isNamedCell():
                    cellValue=cellMetadata.getDefaultValue()
                else :
                    if cellMetadata.isStr():
                        cellValue = cellMetadata.getCellValue()
                    else:
                        cellValue = cellMetadata.getCellFloatValue()

                if cellValue is not None and not cellMetadata.isReferenceCell():
                    instance.set(cellMetadata, cellValue)
                et.addPrivateCell(instance, cellMetadata)
            self.session.put(instance)
        self.recursiveExecution(et)

    def updateCell(self,instance,cellMetadata,cellValue):
        et = ExecutionTree(self.session)
        instance.set(cellMetadata, cellValue)
        self.session.put(instance)
        et.addPrivateCell(instance, cellMetadata)
        et.execute()
