import logging
from orangescape.model.engine.engineconstants import OR_PROCESS, AND_PROCESS, REAL_OR_PROCESS
from appconfig import deployedat
import appconfig as config
from ServerUtil import geFinalEditorFormName,getFinalInboxFormName

def moveApproleToNextState(component, appRoleInst, companyInst):
    workFlowRootbranch = appRoleInst.getSheetMetadata().getWorkFlowRoot()
    if workFlowRootbranch:
        actList = workFlowRootbranch.getActivityDefinitionList()
        if len(actList) > 2 :
            if actList[1].getAssignedFor() == "AppRole" and appRoleInst.getValue('Status') == actList[0].getSheetId():
                logging.info('moveApproleToNextState %s'%(appRoleInst.getSheetName()))
                component.submit(appRoleInst, actList[0])
                component.update(appRoleInst,{'Tenant': companyInst.getSheetId()})

class MetadataSync:
    def __init__(self, component, globalInst):
        self.component = component
        self.session = component.getSession()
        self.application = self.session.getApplication()
        self.metadataModel = self.application.getSheetMetadata('Metadata')
        self.activityModel = self.application.getSheetMetadata('Activity')
        self.appRoleModel =  self.application.getSheetMetadata('AppRole')
        self.to_be_sync_metadata = dict()
        self.to_be_created_dict={}
        self.to_be_updated_dict={}
        self.getNewAppRoles(globalInst)
        self.syncMetadata(globalInst)

    def createObjects(self, globalInst):
        self.syncActivity()
        newSheetDict = self.component.batch_update(self.to_be_created_dict, self.to_be_updated_dict, None)
        self.component.update(globalInst,{'DeployedAt':deployedat})
        return newSheetDict

    def __generate_metadata_instance_id__(self, metadataId):
        return 'M_'+metadataId

    def __get_metadata_id__(self, metadataInstanceId):
        return metadataInstanceId[2:]

    def getNewAppRoles(self, globalInst):
        #Fetching appRole and converting into dict
        appRoles = self.application.getValue('AppRoles')
        appRoleDict = {}
        if appRoles:
            appRoleDict = eval(appRoles)
        #creating sheetName List for instance
        existingAppRoles = self.session.getList(globalInst, self.appRoleModel.getPublicCellMetadata('Global'))
        appRoleSheetNameList= [ ins.getSheetName() for ins in existingAppRoles ]
        #fetching new roles to be created
        newRoleList = set(appRoleDict.keys()).difference(appRoleSheetNameList)
        newRolesCreationList= [{'SheetName':key, 'Global':globalInst.getSheetId()} for key in newRoleList]
        self.to_be_created_dict[self.appRoleModel.getSheetId()]=newRolesCreationList

    def syncMetadata(self, globalInst):
        sysmodelExclusionList=['SheetMetadata','CellMetadata','RowMetadata','ColumnMetadata','Version','ActivityDefinition','SearchDefinition','GridView','GridRow','GridColumn','GridCell','Formula','Node','Branch','InputportMetadata','OutputportMetadata','Header','Hierarchy','Section','Style','Level','GridRowSpan','TableStyle','Criteria','Condition','LevelRowSpan','Button','ActivityPermission','Property','Range','RangeValue','CustomStyle','Folder','ShortCut']
        metadataDict = self.application.getSheetMetadataList()
        metadataMetadataId = self.application.getSheetMetadata('Metadata').getSheetId()
#        self.to_be_sync_metadata = dict([('M_'+metadataId, metadataMetadataId) for metadataId in metadataDict if metadataDict[metadataId] not in sysmodelExclusionList])
        for metadataId in metadataDict :
            model = self.application.getSheetMetadataById(metadataId)
            if metadataDict[metadataId] not in sysmodelExclusionList:
                self.to_be_sync_metadata['M_'+metadataId] = metadataMetadataId
        modelInsDict = self.session.getMulti(self.to_be_sync_metadata)
        to_be_updated_metadata_dict = dict()
        to_be_created_metadata_list = list()

        for sheetId in self.to_be_sync_metadata:
            model=self.application.getSheetMetadataById(self.__get_metadata_id__(sheetId))
            rootBranch = model.getWorkFlowRoot()
            activityDefinitionList = list()
            if rootBranch:
                activityDefinitionList = rootBranch.getActivityDefinitionList()

            if modelInsDict.get(sheetId):
                to_be_updated_value_dict = {}
                modelInst = modelInsDict[sheetId]
                if modelInst.getValue('ModelName')!=model.getValue('SheetName'):
                    to_be_updated_value_dict['ModelName'] = model.getValue('SheetName')
                if modelInst.getValue('MenuName')!=model.getValue('PublicName'):
                    to_be_updated_value_dict['MenuName'] = model.getValue('PublicName')
                if modelInst.getValue('Global')!= globalInst.getSheetId():
                    to_be_updated_value_dict['Global'] = globalInst.getSheetId()
                if modelInst.getValue('ModelId')!= model.getValue('SheetId'):
                    to_be_updated_value_dict['ModelId'] = model.getValue('SheetId')
                if rootBranch and model.isMonitorEnabled():
                    if modelInst.getValue('StartActivity')!= activityDefinitionList[0].getSheetId():
                        to_be_updated_value_dict['StartActivity'] = activityDefinitionList[0].getSheetId()
                    if modelInst.getValue('EndActivity')!= activityDefinitionList[1].getSheetId():
                        to_be_updated_value_dict['EndActivity'] = activityDefinitionList[-1].getSheetId()
                if modelInst.getValue('IsPublic')!= model.isPublic():
                    to_be_updated_value_dict['IsPublic'] = model.isPublic()

                if to_be_updated_value_dict:
                    to_be_updated_metadata_dict[self.__generate_metadata_instance_id__(model.getSheetId())] = to_be_updated_value_dict
            else:
                to_be_created_value_dict={'Global' : globalInst.getSheetId()}
                to_be_created_value_dict['SheetId'] = self.__generate_metadata_instance_id__(model.getValue('SheetId'))
                to_be_created_value_dict['ModelId'] = model.getValue('SheetId')
                to_be_created_value_dict['MenuName'] = model.getValue('PublicName')
                to_be_created_value_dict['ModelName'] = model.getValue('SheetName')
                if model.isMonitorEnabled() and rootBranch:
                    to_be_created_value_dict['StartActivity'] = activityDefinitionList[0].getSheetId()
                    to_be_created_value_dict['EndActivity'] = activityDefinitionList[-1].getSheetId()

                to_be_created_value_dict['IsPublic'] = model.isPublic()
                to_be_created_metadata_list.append(to_be_created_value_dict)
        if to_be_updated_metadata_dict:
            self.to_be_updated_dict[self.metadataModel.getSheetId()]=to_be_updated_metadata_dict
        self.to_be_created_dict[self.metadataModel.getSheetId()]=to_be_created_metadata_list

    def syncActivity(self):
        for metadataInstanceId in self.to_be_sync_metadata:
            self.syncActivityInSheet(metadataInstanceId)#self.application.getSheetMetadataById(__get_metadata_id__(modelId)))

    def syncActivityInSheet(self, metadataInstanceId):
        model = self.application.getSheetMetadataById(self.__get_metadata_id__(metadataInstanceId))
        rootWFbranch = model.getWorkFlowRoot()
        if model.isMonitorEnabled() and rootWFbranch:
            rootActivityList =rootWFbranch.getActivityDefinitionList()
            activityDict_in_sheet = dict()
            for activity in rootActivityList:
                self.get_Activity_in_Sheet(activity,activityDict_in_sheet,self.activityModel.getSheetId())

            activityInsDict = self.session.getMulti(activityDict_in_sheet)
            self.iterateActivity(activityInsDict, rootActivityList, metadataInstanceId, None)

    def iterateActivity(self, activityInsDict, activityList, metadataInstanceId, parentActivityId=None):
        to_be_created_activity_list=list()
        to_be_updated_activity_dict=dict()
        andOrRealOrActList=list()
        for activity in activityList:
            self.__create_OR_Update_ActivityInst__(activityInsDict, activity, metadataInstanceId, parentActivityId, to_be_created_activity_list, to_be_updated_activity_dict)

            if activity.getNodeType() == OR_PROCESS:
                for branch in activity.getBranchList():
                    self.iterateActivity(activityInsDict, branch.getActivityDefinitionList(), metadataInstanceId, parentActivityId)
            elif activity.getNodeType() in (AND_PROCESS, REAL_OR_PROCESS) :
                andOrRealOrActList.append(activity)

        self.create_or_update_component(to_be_created_activity_list, to_be_updated_activity_dict)
        for activityins in andOrRealOrActList:
            for branch in activityins.getBranchList():
                 self.iterateActivity(activityInsDict, branch.getActivityDefinitionList(), metadataInstanceId, activityins.getSheetId())

    def __create_OR_Update_ActivityInst__(self,activityInsDict, activity, metadataInstanceId, parentActivityId=None, to_be_created_activity_list =None , to_be_updated_activity_dict=None):
        activitySyncParam = ['SheetId', 'SheetName', 'SequenceNo', 'GoTo', 'NodeType']
        activityInst = activityInsDict.get(activity.getSheetId())
        if activityInst:
            to_be_updated_activty_value = {}
            for param in activitySyncParam:
                value = activity.getValue(param)
                instanceValue = activityInst.getValue(param)
                if param == 'GoTo' and value:
                    value = activity.getGoTo().getSheetId()
                if activityInst.getValue(param) != value:
                    to_be_updated_activty_value[param] = value
            if activityInst.getValue('ParentActivity') != parentActivityId:
                to_be_updated_activty_value['ParentActivity'] = parentActivityId
            if activityInst.getValue('EditorFormName') != geFinalEditorFormName(activity):
                to_be_updated_activty_value['EditorFormName'] = geFinalEditorFormName(activity)
            if activityInst.getValue('InboxFormName') != getFinalInboxFormName(activity):
                to_be_updated_activty_value['InboxFormName'] = getFinalInboxFormName(activity)

            if to_be_updated_activty_value:
                to_be_updated_activity_dict[activityInst.getSheetId()] = to_be_updated_activty_value
        else:
            to_be_created_activity_value={}
            for parameter in activitySyncParam:
                value = activity.getValue(parameter)
                if parameter == 'GoTo' and value:
                    value = activity.getGoTo().getSheetId()
                to_be_created_activity_value[parameter] =  value
            to_be_created_activity_value['ParentActivity'] = parentActivityId
            to_be_created_activity_value['Metadata'] = metadataInstanceId
            to_be_created_activity_value['EditorFormName'] = geFinalEditorFormName(activity)
            to_be_created_activity_value['InboxFormName'] = getFinalInboxFormName(activity)
            to_be_created_activity_list.append(to_be_created_activity_value)

    def get_Activity_in_Sheet(self, activity, activityDict_in_sheet, metadataId):
        activityDict_in_sheet[activity.getSheetId()]=metadataId
        if activity.getNodeType()==AND_PROCESS or activity.getNodeType()==OR_PROCESS or activity.getNodeType()==REAL_OR_PROCESS:
            for branch in activity.getBranchList():
                for act in branch.getActivityDefinitionList():
                    self.get_Activity_in_Sheet(act,activityDict_in_sheet,metadataId)

    def create_or_update_component(self, to_be_created_activity_list, to_be_updated_activity_dict):
        self.to_be_created_dict.setdefault(self.activityModel.getSheetId(), list()).extend(to_be_created_activity_list)

        if to_be_updated_activity_dict:
            self.to_be_updated_dict.setdefault(self.activityModel.getSheetId(), dict()).update(to_be_updated_activity_dict)
