import logging
import time
data = {}


from orangescape.model.server.Context import getApplication
application =getApplication()
snapshotDef = None

def getSnapShot(key, modelname,method,action):
    global snapshotDef
    snapsheet = snapshotDef[key]
    if snapsheet['UserSheetName'] == modelname and snapsheet['Method'] == 'all':
        global application
        sheet = application.getSheetMetadata(modelname)
        Cells_List = sheet.getPublicCellMetadataDict().keys()
        logSession = snapsheet['logSession']
        logFormula = snapsheet['logFormula']
        return (Cells_List,logSession,logSession)
    elif snapsheet['UserSheetName'] == modelname and snapsheet['ActionName'] == action and snapsheet['Method'] == method:
        Cells_List = []
        logSession = snapsheet['logSession']
        logFormula = snapsheet['logFormula']
        for key in  snapsheet['SnapShotRef.Metrics'].keys():
            Cells_List.append(snapshotDef[key]['CellName'])
        return (Cells_List,logSession,logSession)
    else:
        if snapsheet.__contains__('SnapShot_Ref.SnapShot'):
            for key in snapsheet['SnapShot_Ref.SnapShot'].keys():
                Cells_List,logSession,logSession = getSnapShot(key,modelname,method,action)
                if Cells_List is not None:
                    return (Cells_List,logSession,logSession)
            return (None,None,None)
        else:
            return (None,None,None)

def getActiveSnapShot(modelname,method,action=None):
    global snapshotDef
    import appconfig
    appconfigDict = appconfig.__dict__
    snapshotDef = appconfigDict['snapshotDef']
    if snapshotDef is not None:
        logging.info(snapshotDef)
        for key in  snapshotDef['global']['Global_Ref.SnapShot'].keys():
            Cells_List,logSession,logSession = getSnapShot(key,modelname,action,method)
            if Cells_List is not None:
                logging.info(Cells_List)
                return (Cells_List,logSession,logSession)
        return (None,None,None)
    else:
        return (None,None,None)


def saveDebugData(session,DebugData,timeTaken,BaseModel):
    from orangescape.model.engine.Component import Component
    from orangescape.model.engine.execution.ExecutionTree import ExecutionTree
    global application
    UserRequestSheet = application.getSheetMetadata('UserRequests')
    userLoginModel = application.getSheetMetadata('UserLoginModel')
    referenceCell=UserRequestSheet.getPublicCellMetadata('UserLoginModelRef')
    component = Component(session)
    userInst = session.getUser()
    userloginId = userInst.getValue('UserLoginModel')
    userloginInst = session.get(userloginId , userLoginModel )
    instance = component.create(userloginInst ,referenceCell, {'UserId':userInst .getValue('SheetId'),'Company':userInst.getValue('Company'),'TimeTaken':timeTaken,'ModelName':BaseModel})
    AttachmentId = str(uuid.uuid1()) + '.txt'
    component.updateAttachmentWithId(instance, AttachmentId, DebugData, tag=False)
    startAct = UserRequestSheet.getWorkFlowRoot().getActivityDefinitionList()[0]
    component.submit(instance,startAct)
    session.commit()
    return True

def getCurrentMonitor():
    global data
    if hasattr(data, "CurrentMonitor") and data.CurrentMonitor:
        logging.info(data.CurrentMonitor)
        return data.CurrentMonitor
    else:
        return None


def startPerfMonitor(sheetname,method,actionName=None,sheetid=None,inputSheet=None,inputValues=None):
    from appconfig import DEBUGGER_ENABLED
    if DEBUGGER_ENABLED is not None:
        snapshot,logSession,logFormula = getActiveSnapShot(sheetname,method,actionName)
        if snapshot is not None:
            pm= PerfMonitor(sheetmetadataname=sheetname, method=method,actionName=actionName,snapshot=snapshot,sheetid=sheetid,logSession=logSession,logFormula=logFormula)
            pm.start(inputSheet=inputSheet,inputValues=inputValues)
            return pm
        else:
            return None
    else:
        return None


def stopPerfMonitor(pmObj,metrics=None):
    if pmObj is not None:
        pmObj.stop(metrics)

def startSessionFormulaMonitor(selfDict,formula=None):
    import appconfig as config
    if config.DEBUGGER_ENABLED is not None:
        currentMonitor = getCurrentMonitor()
        if currentMonitor and currentMonitor.logSession == 1.0 and selfDict['type'] == "Session":
            pm= PerfMonitor(sheetmetadataname=selfDict['SheetName'], method=selfDict['name'],logSession=1.0)
            pm.start(inputValues=selfDict['inputValues'])
            return pm
        elif currentMonitor and currentMonitor.logFormula == 1.0 and selfDict['name'] == "Formula":
            if formula is not None:
                snapshot,pm = None,None
                if formula.getCellMetadata():
                    if formula.getCellMetadata().getCellName():
                        snapshot = formula.getCellMetadata().getCellName()+' ( '+formula.getCellMetadata().getCellDisplayName()+' )'
                    else:
                        snapshot = formula.getCellMetadata().getCellDisplayName()
                elif formula.getActivityDefinition() and (formula.getActivityDefinition().getProcessType() == 'Workflow' or formula.getActivityDefinition().getProcessType() == 'Command'):
                    snapshot = formula.getActivityDefinition().getSheetName()+' ( '+formula.toString()+' in '+formula.getActivityDefinition().getProcessType()+' )'
                elif formula.getInputportMetadata() and formula.getInputportMetadata().getActivityDefinition().getProcessType() == 'Action':
                    from orangescape.model.server.util.metadatautil import getRootBranch
                    snapshot = formula.getInputportMetadata().getActivityDefinition().getNodeType()+' ( '+formula.toString()+' in '+getRootBranch(formula.getInputportMetadata().getActivityDefinition().getBranch()).getSheetName()+' )'
                if snapshot is not None:
                    pm= PerfMonitor(sheetmetadataname=selfDict['sheetName'], method=selfDict['name'],snapshot=snapshot)
                    pm.start(inputValues=selfDict['inputValues'])
                return pm
        else:
            return None
    else:
        return None

class PerfMonitor:
    parent = None
    children = None
    outputMetrics = None
    method = None
    snapshot = None
    sheetid = None
    sheetmetadataname = None
    startTime = 0
    endTime = 0
    payload = None
    actionName = None
    inputMetrics = None
    logSession = None
    session = None
    def __init__(self,sheetmetadataname =None,method=None,actionName=None,snapshot=None,sheetid=None,logSession= None,logFormula=None,session=None):

        if method:
            self.method = method
        if actionName:
            self.actionName = actionName
        self.children = []
        self.sheetid = sheetid
        self.actionName = actionName
        self.sheetmetadataname = sheetmetadataname
        self.snapshot = snapshot
        self.logSession = logSession
        self.logFormula = logFormula
        self.session = session
    def addChild(self, child):
        self.children.append(child)

    def removeChild(self,child):
        if child in self.children:
            self.children.remove(child)

    def start(self,inputSheet=None,inputValues=None):
        self.startTime = time.time()
        global data
        if hasattr(data, "CurrentMonitor") and data.CurrentMonitor:
            self.parent = data.CurrentMonitor
            if self.parent.method == 'Main':
                self.parent.sheetmetadataname = self.sheetmetadataname
            self.parent.addChild(self)
            self.inputMetrics = dict()
            if inputValues is not None :
                    self.inputMetrics['InputValues'] = str(inputValues)
            elif self.snapshot is not None:
                for val in self.snapshot:
                    if inputSheet is not None:
                        self.inputMetrics[str(val)] = str(inputSheet.getValue(val))
            data.CurrentMonitor = self
        if self.method == 'Main':
            from orangescape.model.server.Context import getSnapshotAttachements
            getSnapshotAttachements(self.session)
            data.CurrentMonitor = self

    def stop(self,metrics=None):
        self.endTime = time.time()
        global data
        if self.parent:
            data.CurrentMonitor = self.parent
        self.outputMetrics = dict()
        if metrics is not None and self.snapshot is not None and self.method in ['read','new','update','create','workflow','action','Get','Command']:
            self.sheetid = metrics.getSheetId()
            for val in self.snapshot:
                self.outputMetrics[str(val)] = str(metrics.getValue(val))

        elif self.method == 'delete' and metrics is not None:
            for val in metrics:
                self.outputMetrics[str(val.getSheetId())] = str(val.getSheetMetadata().getSheetName())

        elif self.method == 'Formula'and metrics is not None:
            self.outputMetrics[str(self.snapshot)] = str(metrics)

        elif self.method in ['GetList','Query','QueryDS','DBQueryDS','ReportDS','Report']:
            self.outputMetrics['No of Results Obtaned'] = str(metrics)
        elif self.method.startswith('serialize'):
            self.outputMetrics['argList'] = str(metrics)
        else:
            self.outputMetrics = None


    def timetaken(self):
        return  round(self.endTime - self.startTime,4)

    def addJSON(self, strBuffer):
        children = 0
        strBuffer.append("{'type':'%s','sheetid':'%s','sheetmetadataname':'%s','method':'%s','time':'%s'"%(self.method,self.sheetid,self.sheetmetadataname,self.actionName,self.timetaken()))
        if self.outputMetrics is not None:
            strBuffer.append(",'outputMetrics':%s"%(self.outputMetrics))
        if self.inputMetrics is not None:
            strBuffer.append(",'inputMetrics':%s"%(self.inputMetrics))
        for child in self.children:
            if children == 0:
                children = 1
                strBuffer.append(",'payload':[")
            else:
                strBuffer.append(",")
            child.addJSON(strBuffer)
            strBuffer.append("}")
        if children == 1:
            strBuffer.append("]")

    def toJSON(self, url=None, action=None, user=None, session=None):
        global data
        data.CurrentMonitor = None
        strBuffer = list()
        strBuffer.append("{'url':'" + (url if url else "") + "', ")
        strBuffer.append("'user':'" + (user if user else "") + "', ")
        strBuffer.append("'SessionId':'" + (session if session else "") + "', ")
        strBuffer.append("'PerfMonitor_parent':")
        self.addJSON(strBuffer)
        strBuffer.append("}}")
        return ''.join(strBuffer)

