'''
Accessible Access Control 1.0
2012-2104 Michigan Technological University
Supported in part by NSF grants: DUE-1140512, DUE-1245310 and IIS-1319363
Developer: Yifei Li
Advisors:Dr. Steve Carr, Dr. Jean Mayo, Dr. Ching-Kuang Shene and Dr. Chaoli Wang
'''
'''
Created on Dec 20, 2011

@author: yifli
'''
from PyQt4.QtGui import QGraphicsScene, QInputDialog, QGraphicsLineItem, QPen, QGraphicsItem, QMenu, QColor, QMessageBox, QBrush, QFont, QFontMetrics, QApplication
from PyQt4.QtCore import QRectF, QPointF, Qt, QLineF, pyqtSignal, QStateMachine, QState, QString, QTimer
from DomainNode import DomainNode
from TypeNode import TypeNode
from EdgeItem import EdgeItem
from FileNode import FileNode
from FlagChooserDialog import FlagChooserDialog
from TypeChooserDialog import TypeChooserDialog
from NewFileNodeDialog import NewFileNodeDialog
import re, string, os, socket, datetime
        
class HighlightState(QState):
    def __init__(self, scene):
        QState.__init__(self)
        self.scene = scene
        
    def onEntry(self, evt):
        highlighted_items = set()
        highlighted_items.add(self.scene.highlightedItem)

        if ( isinstance(self.scene.highlightedItem, DomainNode) or 
             isinstance(self.scene.highlightedItem, TypeNode) ):
            
            for e in self.scene.highlightedItem.edgeList:
                highlighted_items.add(e)
                if e.startItem is self.scene.highlightedItem:
                    highlighted_items.add(e.endItem)
                else:
                    highlighted_items.add(e.startItem)
                    
            for item in self.scene.items():
                if isinstance(item, EdgeItem) and item.type == EdgeItem.FILE_CONN:
                    continue
                if not isinstance(item, FileNode) and item not in highlighted_items:
                    item.setOpacity(0.1)
        elif isinstance(self.scene.highlightedItem, EdgeItem):
            if self.scene.highlightedItem.type != EdgeItem.FILE_CONN:
                highlighted_items.add(self.scene.highlightedItem.startItem)
                highlighted_items.add(self.scene.highlightedItem.endItem)
                
                for item in self.scene.items():
                    if isinstance(item, EdgeItem) and item.type == EdgeItem.FILE_CONN:
                        continue

                    if not isinstance(item, FileNode) and item not in highlighted_items:
                        item.setOpacity(0.1)
                    
        self.scene.update()        
        
class RemoveState(QState):
    def __init__(self, scene):
        QState.__init__(self)
        self.scene = scene
    
    def onEntry(self, evt):
        dimmed_items = set()
        dimmed_items.add(self.scene.highlightedItem)

        if ( isinstance(self.scene.highlightedItem, DomainNode) or 
             isinstance(self.scene.highlightedItem, TypeNode) ):
            
            for e in self.scene.highlightedItem.edgeList:
                dimmed_items.add(e)
                    
        elif isinstance(self.scene.highlightedItem, EdgeItem):
            if self.scene.highlightedItem.type != EdgeItem.FILE_CONN:
                dimmed_items.add(self.scene.highlightedItem.startItem)
                dimmed_items.add(self.scene.highlightedItem.endItem)
            
        for item in self.scene.items():
            if item in dimmed_items:
                item.setOpacity(0.1)
            else:
                item.setOpacity(1.0)
        self.scene.update()
            
    def onExit(self, evt):
        self.scene.highlightedItem = None
        for item in self.scene.items():
            item.setOpacity(1.0)
        self.scene.update()

class DiagramScene(QGraphicsScene):
    animationStarted = pyqtSignal()
    animationStopped = pyqtSignal()
    nodeAdded = pyqtSignal(QGraphicsItem, QString)
    edgeAdded = pyqtSignal(QGraphicsItem, QString)
    nodeDeleted = pyqtSignal(QGraphicsItem)
    edgeDeleted = pyqtSignal(QGraphicsItem)
    itemMoved = pyqtSignal(QGraphicsItem, QPointF)
    initialDomainChanged = pyqtSignal(QGraphicsItem, str)
    nameChanged = pyqtSignal(QGraphicsItem, QString)
    typeChanged = pyqtSignal(QGraphicsItem, QGraphicsItem)
    flagChanged = pyqtSignal(QGraphicsItem, int)
    fileNodeAdded = pyqtSignal(QGraphicsItem, QString, QString, int)
    typeDeleted = pyqtSignal(QGraphicsItem)
    assignmentChanged = pyqtSignal(QGraphicsItem, QString)
    highlightItemClicked = pyqtSignal()

    Normal = 0
    InsertDomainNode = 1
    InsertTypeNode = 2
    InsertAutoConn = 3
    InsertExecConn = 4
    InsertTypeConn = 5
    Highlight = 6
    Test = 7
    
    def __init__(self, main):
        QGraphicsScene.__init__(self, main)
        self.hostname = socket.gethostname() 
        self.pid = os.getpid()
        self.date = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
        self.stuInfo = self.hostname+'.'+str(self.pid)+'.'+self.date
        
        self.main = main
        self.rightClickedItem = None   
        self.mode = self.Normal
        self.setSceneRect(QRectF(0, 0, 5000, 5000))
        self.initialDomain = None
        self.line = None
        self.movingItem = None
        self.domainGraphOnly = False
        self.showDomainDomainLabels = True
        self.showDomainTypeLabels = True
        self.typeGraphRoot = FileNode('', None, 2)
        self.typeGraphRoot.fullPath = '/'
        self.typeGraphRoot.inheritFromNode = None
        self.typeGraphRoot.setVisible(False)
        self.typeGraphRoot.setPos(2500,2500)#0.5*self.views()[0].geometry().width(), 0.5*self.views()[0].geometry().height())
        self.addItem(self.typeGraphRoot)
        self.typeGraph = {}
        self.highlightedItem = None
        self.typeChooser = TypeChooserDialog(self)
        self.typeChooser.accepted.connect(self.changeFileType)
        self.flagChooser = FlagChooserDialog()
        self.flagChooser.accepted.connect(self.changeFlag)
        self.newFileNodeDialog = NewFileNodeDialog(self)
        self.newFileNodeDialog.accepted.connect(self.addFileNode)
           
        self.stateMachine = QStateMachine()
        self.normalState = QState()
        self.highlightState = HighlightState(self)
        self.removeState = RemoveState(self)
        self.normalState.addTransition(self.highlightItemClicked, self.highlightState)
        self.highlightState.addTransition(self.highlightItemClicked, self.removeState)
        self.removeState.addTransition(self.highlightItemClicked, self.normalState)
        self.stateMachine.addState(self.normalState)
        self.stateMachine.addState(self.highlightState)
        self.stateMachine.addState(self.removeState)
        self.stateMachine.setInitialState(self.normalState)
           
        self.animationTimer = QTimer(self)
        self.timerInterval = 5000
        self.animationTimer.setInterval(self.timerInterval)
        self.animationTimer.timeout.connect(self.animateQuery)
        self.animationType = None
        self.animationStep = 0
        self.message = ''
          
#        self.typeLegendX = 1882
#        self.typeLegendY = 2288
          
        self.prevScrollBarX = 1670
        self.prevScrollBarY = 2054
            
    def deleteNode(self):
        if isinstance(self.rightClickedItem, TypeNode):
            for item in self.items():
                if isinstance(item, FileNode):
                    if item.type is self.rightClickedItem:
                        button = QMessageBox.question(self.rightClickedItem.parentWidget(), 'Warnning', 
                                                     'There exists directories/files whose type is %s. \
                                                     Do you still want to delete %s?' % (str(self.rightClickedItem.name), str(self.rightClickedItem.name)),
                                                     buttons = QMessageBox.Yes | QMessageBox.No)
                        if button == QMessageBox.Yes:
                            self.removeItem(item)
                            for e in self.items():
                                if isinstance(e, EdgeItem):
                                    if e.endItem == item or e.startItem == item:
                                        self.removeItem(e)
                            break
                        else:
                            return
        self.nodeDeleted.emit(self.rightClickedItem)
        
    def deleteEdge(self):
        self.edgeDeleted.emit(self.rightClickedItem)
        
    def changeItemName(self):
        if isinstance(self.rightClickedItem, TypeNode):
            name, accept = QInputDialog.getText(self.rightClickedItem.parentWidget(), 'Set Type Node Name', '', text=self.rightClickedItem.name)
            if accept:
                if name.isEmpty():
                    QMessageBox.critical(self.views()[0], 'Error', 'Type name cannot be empty')
                    return
                name = string.strip(str(name))
                for item in self.items():
                    if isinstance(item, TypeNode):
                        if name == item.name:
                            QMessageBox.critical(self.rightClickedItem.parentWidget(), 'Error', 'A type with the same name already exists')
                            return
                self.nameChanged.emit(self.rightClickedItem, name)
        elif isinstance(self.rightClickedItem, DomainNode):
            name, accept = QInputDialog.getText(self.rightClickedItem.parentWidget(), 'Set Domain Node Name', '', text=self.rightClickedItem.name)
            if accept:
                if name.isEmpty():
                    QMessageBox.critical(self.views()[0], 'Error', 'Domain name cannot be empty')
                    return
                
                name = string.strip(str(name))
                for item in self.items():
                    if isinstance(item, DomainNode):
                        if name == item.name:
                            QMessageBox.critical(self.rightClickedItem.parentWidget(), 'Error', 'A domain with the same name already exists')
                            return
                self.nameChanged.emit(self.rightClickedItem, name)  
        elif isinstance(self.rightClickedItem, EdgeItem):
            if self.rightClickedItem.type == EdgeItem.AUTO_CONN or self.rightClickedItem.type == EdgeItem.EXEC_CONN:
                descr, accept = QInputDialog.getText(self.rightClickedItem.parentWidget(), 'Set Entry Points', '', text=self.rightClickedItem.description)
                if accept:
                    if descr.isEmpty():
                        QMessageBox.critical(self.rightClickedItem.parentWidget(), 'Error',
                                             'Entry points cannot be empty')
                        return
                    p=re.compile(r'((/\w+)+(/{(\w+,)*\w+})?,\s*)*(/\w+)+(/{(\w+\s*,\s*)*\w+})?$')
                    descr = string.strip(str(descr))
                    if p.match(descr) is None:
                        QMessageBox.critical(self.rightClickedItem.parentWidget(), 'Error',
                                             'Separate entry point programs by comma. The format of an entry point program is either \
                                             /path/to/file or /path/to/{file1,...,fileN}')
                        return
                    self.nameChanged.emit(self.rightClickedItem, descr)
            elif self.rightClickedItem.type == EdgeItem.TYPE_CONN:
                descr, accept = QInputDialog.getText(self.rightClickedItem.parentWidget(), 'Set Permissions', '', text=self.rightClickedItem.description)
                if accept:
                    if descr.isEmpty():
                        QMessageBox.critical(self.rightClickedItem.parentWidget(), 'Error',
                                             'Permissions cannot be empty')
                        return
                    descr = string.strip(str(descr))
                    p = re.compile('[crxdw]+$')
                    if p.match(descr) is None:
                        QMessageBox.critical(self.rightClickedItem.parentWidget(), 'Error', 
                                             'Valid permissions are c, r, x, d and w')
                        return
                    else:
                        for i in 'crxdw':
                            if string.count(descr, i) > 1:
                                QMessageBox.critical(self.rightClickedItem.parentWidget(), 'Error',
                                                     'More than one occurrence of %s is found' % i)
                                return
                    
                    # make sure c only shows up once
                    if 'c' in descr:       
                        domain = self.rightClickedItem.startItem
                        for e in domain.edgeList:
                            if isinstance(e.endItem, TypeNode) and e.endItem is not self.rightClickedItem.endItem:
                                if 'c' in e.description:
                                    QMessageBox.critical(self.rightClickedItem.parentWidget(), 'Error',
                                                         'There should be only one c(create) among all the edges going out of this domain node to type nodes')
                                    return
                    
                    self.nameChanged.emit(self.rightClickedItem, descr)
        elif isinstance(self.rightClickedItem, FileNode):
            name, accept = QInputDialog.getText(self.rightClickedItem.parentWidget(), 'Set Type Node Name', '', text=self.rightClickedItem.name)
            if accept:
                if name.isEmpty():
                    QMessageBox.critical(self.views()[0], 'Error', 'File/Dir name cannot be empty')
                    return
                name = string.strip(str(name))
                for item in self.items():
                    if isinstance(item, FileNode):
                        if name == str(item.fullPath):
                            QMessageBox.critical(self.rightClickedItem.parentWidget(), 'Error', 'The same file/dir already exists')
                            return
                self.nameChanged.emit(self.rightClickedItem, name)

    def markInitialDomain(self):
        entryPoint, accept = QInputDialog.getText(self.views()[0], 'Set Entry Point', '', 
                                                  text=self.initialDomain.entryPoints if self.initialDomain is not None else '')
        if accept:
            if entryPoint.isEmpty():
                QMessageBox.critical(self.views()[0], 'Error', 'Entry point cannot be emtpy')
                return
            
            entryPoint = string.strip(str(entryPoint))
            self.initialDomainChanged.emit(self.rightClickedItem, entryPoint)
    
    def showTypeChooser(self):
        self.typeChooser.ui.typeComboBox.clear()
        for item in self.items():
            if isinstance(item, TypeNode):
                self.typeChooser.ui.typeComboBox.addItem(item.name)
        self.typeChooser.ui.typeComboBox.setCurrentIndex(self.typeChooser.ui.typeComboBox.findText(self.rightClickedItem.type.name))
        self.typeChooser.exec_()
        
    def changeFileType(self):
        for item in self.items():
            if isinstance(item, TypeNode):
                if item.name == self.typeChooser.ui.typeComboBox.currentText():
                    typeNode = item
                    break
        if self.rightClickedItem.type is not typeNode:
            self.typeChanged.emit(self.rightClickedItem, typeNode)
            
    def showFlagChooser(self):
        self.flagChooser.myExec(self.rightClickedItem)
    

    def changeFlag(self):
        if self.flagChooser.ui.sCheckBox.isChecked() and self.flagChooser.ui.rCheckBox.isChecked():
            newFlag = 3
        elif self.flagChooser.ui.sCheckBox.isChecked():
            newFlag = 1
        elif self.flagChooser.ui.rCheckBox.isChecked():
            newFlag = 2
        else:
            newFlag = 0
        
        if self.rightClickedItem.flag != newFlag:
            self.flagChanged.emit(self.rightClickedItem, newFlag)
            
    def showNewFileNodeDialog(self):
        self.newFileNodeDialog.myExec(self.rightClickedItem)
  
    def addFileNode(self):
        name = self.newFileNodeDialog.ui.nameLineEdit.text()
        if name.isEmpty():
            QMessageBox.critical(self.rightClickedItem.parentWidget(), 'Error', 
                                 'Name cannot be empty')
            return
        name = string.strip(str(name))
        type = self.newFileNodeDialog.ui.typeComboBox.currentText()
        if not self.newFileNodeDialog.ui.sCheckBox.isChecked() and not self.newFileNodeDialog.ui.rCheckBox.isChecked():
            flag = 0
        else:
            if self.newFileNodeDialog.ui.sCheckBox.isChecked() and self.newFileNodeDialog.ui.rCheckBox.isChecked():
                flag = 3
            else:
                if self.newFileNodeDialog.ui.sCheckBox.isChecked():
                    flag = 1
                elif self.newFileNodeDialog.ui.rCheckBox.isChecked():
                    flag = 2
        self.fileNodeAdded.emit(self.rightClickedItem, name, type, flag)
        
    def deleteType(self):
        self.typeDeleted.emit(self.rightClickedItem)    
        
    
    def changeAssignment(self):
        newAssign, accept = QInputDialog.getText(self.rightClickedItem.parentWidget(), 'Assignment', '', 
                                                 text=self.rightClickedItem.assignment)
        newAssign = string.strip(str(newAssign))
        if accept and self.rightClickedItem.assignment != newAssign:
            p = re.compile('^((-r|-s|-r -s|-s -r)?\s*(/|(/\w+)+,\s*)*(/|/\w+)+;\s*)*$')
            if p.match(newAssign) is None:
                QMessageBox.critical(self.rightClickedItem.parentWidget(), 'Error', 
                                     '[[-s|-r|-r -s] path1,...,pathN;]*')
                return
            else:
                # make sure there's no duplicated path
                components = string.replace(newAssign, '-r', '')
                components = string.replace(components, '-s', '')
                components = string.split(components, ';')[0:-1]
                fileSet = set()
                for files in components:
                    for f in string.split(string.strip(files), ','):
                        if f in fileSet:
                            QMessageBox.critical(self.rightClickedItem.parentWidget(), 'Error',
                                                 '%s is duplicated' % f)
                            return
                        else:
                            fileSet.add(string.strip(f))
                                                
                
                fileNodes = {}
                for item in self.items():
                    if isinstance(item, FileNode):
                        fileNodes[item.fullPath] = item
                        
                # make sure each file's parent does not contain -s
                for f in fileSet:
                    # check if f has an existing parent
                    lastSlashPos = string.rfind(f, '/')
                    if lastSlashPos != 0:
                        parentPath = f[0:lastSlashPos]
                        while parentPath != '':
                            if parentPath not in fileNodes:
                                f = f[0:lastSlashPos-1]
                                lastSlashPos = string.rfind(f,'/')
                            else:
                                if fileNodes[parentPath].flag == 1 or fileNodes[parentPath].flag == 3:
                                    if self.rightClickedItem is not fileNodes[parentPath].type:
                                        QMessageBox.critical(self.rightClickedItem.parentWidget(), 'Error',
                                                     '"%s" has a "-s" flag set on it but you are trying to \
                                                     set the type of its children "%s" to %s' % (parentPath, self.rightClickedItem.name, self.rightClickedItem.type.name))
                                        return
                            lastSlashPos = string.rfind(parentPath, '/')
                            parentPath = f[0:lastSlashPos]

                    else:
                        if self.typeGraphRoot.flag == 1 or self.typeGraphRoot.flag == 3:
                            if self.rightClickedItem is not self.typeGraphRoot.type:
                                QMessageBox.critical(self.rightClickedItem.parentWidget(), 'Error',
                                                     '"/" has a "-s" flag set on it but you are trying to \
                                                     set the type of its children "%s" to %s' % (f, self.rightClickedItem.name))
                                return
                # make sure parent is directory
                for f in fileSet:
                    parentPath = string.strip('/'.join(string.split(f, '/')[0:-1]))
                    if parentPath == '':
                        parentPath = '/'
                    if parentPath in fileNodes:
                        if fileNodes[parentPath].flag == 0 or fileNodes[parentPath].flag == 1:
                            QMessageBox.critical(self.rightClickedItem.parentWidget(), 'Error',
                                              'Turn %s into a directory first (add -r)' % parentPath)
                            return
            self.assignmentChanged.emit(self.rightClickedItem, newAssign)
                
    def showGeneralGraph(self):
        for item in self.items():
            item.setVisible(False)
        for item in self.items():
            if isinstance(item, TypeNode) or isinstance(item, DomainNode):
                item.setVisible(True)
            elif isinstance(item, FileNode):
                item.setVisible(False)
            elif isinstance(item, EdgeItem):
                if item.type == EdgeItem.FILE_CONN:
                    item.setVisible(False)
                else:
                    item.setVisible(True)
        
    def showTypeGraph(self):
        for item in self.items():
            item.setVisible(False)
        for item in self.items():
            if isinstance(item, FileNode):
                item.setVisible(True)
            elif isinstance(item, EdgeItem):
                if item.type == EdgeItem.FILE_CONN:
                    item.setVisible(True)
                else:
                    item.setVisible(False)
            elif isinstance(item, TypeNode) or isinstance(item, DomainNode):
                item.setVisible(False)
        
    
    def drawBackground(self, painter, rect):
        '''
        the purpose of overriding drawBackground is to draw legend for the type graph
        '''
        if self.main.ui.actionType_Graph.isChecked():
            self.prevScrollBarX = self.views()[0].horizontalScrollBar().value()
            self.prevScrollBarY = self.views()[0].verticalScrollBar().value()
	    # draw level circles
            painter.save()
            painter.setPen(QPen(Qt.DotLine))
            painter.setBrush(QBrush(QColor(240, 240, 240)))
            for level in self.typeGraph.keys():
                painter.drawArc(self.typeGraph[level][1], 0, 5760)
            painter.restore()
            
	    # draw legends
            xStart = self.views()[0].horizontalScrollBar().value()
            yStart = self.views()[0].verticalScrollBar().value()+100
            legend = []
            legend.append('No Type')
            for item in self.items():
                if isinstance(item, TypeNode):
                    legend.append(item)
            
            x = xStart
            y = yStart
            deltaY = 50
            font = self.font()
            font.setPixelSize(20)
            painter.setFont(font)
            painter.save()
            transform = painter.transform()
            transform.scale(1.0/painter.transform().m11(), 1.0/painter.transform().m22())
            painter.setTransform(transform)
            for i, item in enumerate(legend):
                y = y + deltaY
                
                if item == 'No Type':
                    painter.setBrush(QColor(0, 0, 0))
                    painter.drawRect(x, y, 60, 30)
                    painter.drawText(x, y+45, 'No Type')
                else:    
                    painter.setBrush(QColor(item.color[0], item.color[1], item.color[2]))
                    painter.drawRect(x, y, 60, 30)
                    painter.drawText(x,y+45,item.name)
            painter.restore()
        elif self.main.ui.actionGeneral_Graph.isChecked():
            self.prevScrollBarX = self.views()[0].horizontalScrollBar().value()
            self.prevScrollBarY = self.views()[0].verticalScrollBar().value()
            if self.initialDomain is not None:
                painter.save()
                transform = painter.transform()
                transform.scale(1.0/painter.transform().m11(), 1.0/painter.transform().m22())
                painter.setTransform(transform)
                x = self.views()[0].horizontalScrollBar().value()+50
                y = self.views()[0].verticalScrollBar().value()+20

                painter.drawText(QPointF(x,y), 'Entry point:' + self.initialDomain.entryPoints)
                painter.restore()    
        QGraphicsScene.drawBackground(self,painter,rect)
        self.main.view.viewport().update()
    
    def drawForeground(self, painter, rect):
        if not self.main.ui.actionView_SelfTest.isChecked() and self.message:
            painter.save()
            transform = painter.transform()
            transform.scale(1.0/painter.transform().m11(), 1.0/painter.transform().m22())
            painter.setTransform(transform)

            painter.setFont(QFont('Helvetica', 20))
            xStart = self.views()[0].horizontalScrollBar().value()+80
            yStart = self.views()[0].verticalScrollBar().value()+self.views()[0].viewport().height()-100
            painter.drawText(QRectF(xStart, yStart, self.views()[0].viewport().width()-200, self.views()[0].viewport().height()), self.message)
            painter.restore()
        QGraphicsScene.drawForeground(self, painter, rect)
        self.main.view.viewport().update()
        
    def contextMenuEvent(self, evt):
        if self.main.ui.actionView_SelfTest.isChecked():
            return
        if self.rightClickedItem:
            self.rightClickedItem.highlighted = False
        item = self.itemAt(evt.scenePos())
        
        menu = QMenu()

        if item is not None:
            self.clearSelection()
            item.setSelected(True)
            self.rightClickedItem = item
            
            if self.animationTimer.isActive():
                return

            if isinstance(item, DomainNode):
                initialDomainAction = menu.addAction('Mark As Initial Domain')
                changeNameAction = menu.addAction('Change Name')
                deleteAction = menu.addAction('Delete')
                deleteAction.triggered.connect(self.deleteNode)
                initialDomainAction.triggered.connect(self.markInitialDomain)
                changeNameAction.triggered.connect(self.changeItemName)
            elif isinstance(item, TypeNode):
                changeNameAction = menu.addAction('Change Name')
                deleteAction = menu.addAction('Delete')
                changeAssignmentAction = menu.addAction('Change Assignment')
                deleteAction.triggered.connect(self.deleteNode)
                changeNameAction.triggered.connect(self.changeItemName)
                changeAssignmentAction.triggered.connect(self.changeAssignment)
            elif isinstance(item, EdgeItem):
                if item.type == EdgeItem.TYPE_CONN:
                    item.highlighted = True
                    changeDescriptionAction = menu.addAction('Change Permission')
                elif item.type == EdgeItem.AUTO_CONN or item.type == EdgeItem.EXEC_CONN:
                    changeDescriptionAction = menu.addAction('Change Entry Points')
                changeDescriptionAction.triggered.connect(self.changeItemName)
                deleteAction = menu.addAction('Delete')
                deleteAction.triggered.connect(self.deleteEdge)
            elif isinstance(item, FileNode):
                changeNameAction = menu.addAction('Change Name')
                changeTypeAction = menu.addAction('Change Type')
                addAction = menu.addAction('Assign Type to a Child')
                deleteTypeAction = menu.addAction('Delete Type')
                changeFlagAction = menu.addAction('Change Flag')
                
                if self.rightClickedItem is self.typeGraphRoot:
                    changeNameAction.setDisabled(True)
                if self.rightClickedItem.flag == 0 or self.rightClickedItem.flag == 1 or self.rightClickedItem.flag == 3:
                    addAction.setDisabled(True)
                
                changeNameAction.triggered.connect(self.changeItemName)
                changeTypeAction.triggered.connect(self.showTypeChooser)
                addAction.triggered.connect(self.showNewFileNodeDialog)
                deleteTypeAction.triggered.connect(self.deleteType)
                changeFlagAction.triggered.connect(self.showFlagChooser)
        else:
            menu.addAction(self.views()[0].parent().ui.actionGeneral_Graph)
            menu.addAction(self.views()[0].parent().ui.actionType_Graph)
            menu.addSeparator()
            #menu.addAction(self.views()[0].parent().queryWindowDockWidget.toggleViewAction())
    
        menu.exec_(evt.screenPos())
    
    def wheelEvent(self, evt):
        if not self.main.ui.actionView_SelfTest.isChecked():
            QGraphicsScene.wheelEvent(self,evt)
            self.update()   
        
    def mousePressEvent(self, evt):
        if self.main.ui.actionView_SelfTest.isChecked():
            QGraphicsScene.mousePressEvent(self, evt)
            return
        if self.rightClickedItem:
            self.rightClickedItem.highlighted = False
        if evt.button() == Qt.LeftButton:
            # make sure the start item is a domain node
            if self.mode == self.InsertAutoConn or self.mode == self.InsertExecConn:
                item = self.itemAt(evt.scenePos())
                if not isinstance(item, DomainNode):
                    return

            if self.mode == self.InsertAutoConn or self.mode == self.InsertExecConn or self.mode == self.InsertTypeConn:
                self.line = QGraphicsLineItem(QLineF(evt.scenePos(), evt.scenePos()))
                if self.mode == self.InsertExecConn:
                    self.line.setPen(QPen(Qt.DashLine))
                self.addItem(self.line)
                
            if self.mode == self.Normal or self. mode == self.Test:
                self.movingItem = self.itemAt(evt.scenePos())
                if self.movingItem is not None:
                    self.oldPos = self.movingItem.pos()
                    '''Collect user operation data'''
                    if isinstance(self.movingItem, DomainNode):
                        message = "Clicked Domain Node "+self.movingItem.name
                    elif isinstance(self.movingItem, TypeNode):
                        message = "Clicked Type Node "+self.movingItem.name
                    elif isinstance(self.movingItem, EdgeItem):
                        if self.movingItem.type == EdgeItem.AUTO_CONN or \
                            self.movingItem.type == EdgeItem.EXEC_CONN:
                            first, second = ' Domain ', ' Domain '
                        elif self.movingItem.type == EdgeItem.TYPE_CONN:
                            first, second = ' Domain ', ' Type '
                        message = "Clicked Edge from "+first+self.movingItem.startItem.name+' to ' +second+self.movingItem.endItem.name\
                            + ' with label '+ self.movingItem.description
                    elif isinstance(self.movingItem, FileNode):
                        message = "Clicked File Node "+ self.movingItem.name+ " in Type "+ self.movingItem.type.name
                    self.main.writeToFile(self.main.logFile, self.main.getCurrentTimeString()+message +'\n')
            
            if self.mode == self.Highlight:
                message = ''
                item = self.itemAt(evt.scenePos())
                if self.highlightedItem is None:
                    self.highlightedItem = item
                    self.highlightItemClicked.emit()
                elif item is self.highlightedItem:
                    self.highlightItemClicked.emit()
                else:
                    if self.highlightState in self.stateMachine.configuration():
                        self.highlightItemClicked.emit()
                        self.highlightItemClicked.emit()
                    elif self.removeState in self.stateMachine.configuration():
                        self.highlightItemClicked.emit()
                    self.highlightedItem = item
                    self.highlightItemClicked.emit()
                '''Collect user operation data'''
                if isinstance(self.highlightedItem, DomainNode):
                    message = "Clicked Domain Node "+self.highlightedItem.name
                elif isinstance(self.highlightedItem, TypeNode):
                    message = "Clicked Type Node "+self.highlightedItem.name
                elif isinstance(self.highlightedItem, EdgeItem):
                    if self.highlightedItem.type == EdgeItem.AUTO_CONN or \
                        self.highlightedItem.type == EdgeItem.EXEC_CONN:
                        first, second = ' Domain ', ' Domain '
                    elif self.highlightedItem.type == EdgeItem.TYPE_CONN:
                        first, second = ' Domain ', ' Type '
                    message = "Clicked Edge from "+first+self.highlightedItem.startItem.name+' to ' +second+self.highlightedItem.endItem.name\
                        + ' with label '+ self.highlightedItem.description
                elif isinstance(self.highlightedItem, FileNode):
                    message = "Clicked File Node "+ self.highlightedItem.name+ " in Type "+ self.highlightedItem.type.name
                if message!= '':
                    self.main.writeToFile(self.main.logFile, self.main.getCurrentTimeString()+message +'\n')
            QGraphicsScene.mousePressEvent(self, evt)
            self.update()
    
    def mouseMoveEvent(self, evt):
        if self.main.ui.actionGeneral_Graph.isChecked():
            if self.line != None and self.mode == self.InsertAutoConn or self.mode == self.InsertExecConn or self.mode == self.InsertTypeConn:
                self.line.setLine(QLineF(self.line.line().p1(), evt.scenePos()))
            elif self.mode == self.Normal or self.mode == self.Test:
                QGraphicsScene.mouseMoveEvent(self, evt)
            self.update()
            
    def mouseReleaseEvent(self, evt):
        if self.main.ui.actionGeneral_Graph.isChecked():
            if self.rightClickedItem:
                self.rightClickedItem.highlight = False
            if evt.button() == Qt.LeftButton:
                if self.mode == self.Normal or self.mode == self.Test:
                    if self.movingItem is not None and self.oldPos != self.movingItem.pos():
                        self.itemMoved.emit(self.movingItem, self.oldPos)
                        '''Collect user operation data'''
                        if isinstance(self.movingItem, DomainNode):
                            message = "Moved Domain Node "+self.movingItem.name
                            self.main.writeToFile(self.main.logFile, self.main.getCurrentTimeString()+message+'\n')
                        elif isinstance(self.movingItem, TypeNode):
                            message = "Moved Type Node "+self.movingItem.name
                            self.main.writeToFile(self.main.logFile, self.main.getCurrentTimeString()+message+'\n')
                        self.movingItem = None
                elif self.mode == self.InsertDomainNode:
                    name, accept = QInputDialog.getText(self.views()[0], 'Set Domain Node Name', '', text='Domain')
                    if accept:
                        if name.isEmpty():
                            QMessageBox.critical(self.views()[0], 'Error', 'Domain name cannot be empty')
                            return
                        name = string.strip(str(name))
                        for item in self.items():
                            if isinstance(item, DomainNode):
                                if name == item.name:
                                    QMessageBox.critical(self.views()[0], 'Error', 'A domain with the same name already exists')
                                    return
    
                            
                        node = DomainNode()
                        node.setPos(evt.scenePos())
                        self.nodeAdded.emit(node, name)
                        self.main.writeToFile(self.main.logFile, self.main.getCurrentTimeString()+"Insert Domain Node: "+name+'\n')
                elif self.mode == self.InsertTypeNode:
                    name, accept = QInputDialog.getText(self.views()[0], 'Set Type Node Name', '', text='Type')
                    if accept:
                        if name.isEmpty():
                            QMessageBox.critical(self.views()[0], 'Error', 'Type name cannot be empty')
                            return
    
                        name = string.strip(str(name))
                        for item in self.items():
                            if isinstance(item, TypeNode):
                                if name == item.name:
                                    QMessageBox.critical(self.views()[0].parentWidget(), 'Error', 'A type with the same name already exists')
                                    return
        
                        node = TypeNode()
                        if node.counter >= len(TypeNode.ColorTable):
                            pass
                        else:
                            node.color = TypeNode.ColorTable[node.counter]
                        node.setPos(evt.scenePos())
                        self.nodeAdded.emit(node, name)
                        self.main.writeToFile(self.main.logFile, self.main.getCurrentTimeString()+"Insert Type Node: "+name+'\n')
                elif self.line is not None and self.mode == self.InsertAutoConn or self.mode == self.InsertExecConn or self.mode == self.InsertTypeConn:
                    startItems = self.items(self.line.line().p1())
                    endItems = self.items(self.line.line().p2())
                    self.removeItem(self.line)
                    self.line = None
                    
                    # find the start and end domain node/type node
                    startItem = endItem = None
                    for item in startItems:
                        if not isinstance(item, QGraphicsLineItem):
                            startItem = item
                     
                    for item in endItems:
                        if not isinstance(item, QGraphicsLineItem):
                            endItem = item
                    
                    if startItem is None or endItem is None:
                        return
                    
                    if self.mode == self.InsertTypeConn:
                        if startItem.__class__ is endItem.__class__:
                            return
                        else:
                            if isinstance(startItem, TypeNode) and isinstance(endItem, DomainNode):
                                startItem, endItem = endItem, startItem
                            
                            for e in startItem.edgeList:
                                if e.endItem is endItem:
                                    QMessageBox.critical(self.views()[0], 'Error', 
                                                         'There already exists an edge between %s and %s' % (startItem.name, endItem.name))
                                    return
                            
                            edge = EdgeItem(EdgeItem.TYPE_CONN, startItem, endItem)
                            
                            
                            edge.updatePosition()
                            self.addItem(edge)
    
                            perm, accept = QInputDialog.getText(self.views()[0], 'Permissions', '', text='')
                            if accept:
                                perm = string.strip(str(perm))
                                p = re.compile('[crxdw]+$')
                                if p.match(perm) is None:
                                    QMessageBox.critical(self.views()[0], 'Error', 
                                                         'Valid permissions are c, r, x, d and w')
                                    self.removeItem(edge)
                                    return
                                else:
                                    for i in 'crxdw':
                                        if string.count(perm, i) > 1:
                                            QMessageBox.critical(self.views()[0], 'Error',
                                                                 'More than one occurrence of %s is found' % i)
                                            self.removeItem(edge)
                                            return
                                    if 'c' in perm:       
                                        for e in startItem.edgeList:
                                            if isinstance(e.endItem, TypeNode) and e.endItem is not endItem:
                                                if 'c' in e.description:
                                                    QMessageBox.critical(startItem.parentWidget(), 'Error',
                                                                         'There should be only one c(create) among all the edges going out of this domain node to type nodes')
                                                    self.removeItem(edge)
                                                    return
                                    
                                self.removeItem(edge)       
                                self.edgeAdded.emit(edge, perm)
                                self.main.writeToFile(self.main.logFile, self.main.getCurrentTimeString()+"Insert Edge from Domain "+startItem.name+" to Type "+\
                                                 endItem.name+" with label "+perm+'\n')
                            else:
                                self.removeItem(edge)
                    else:
                        if not isinstance(endItem, DomainNode):
                            return
                        else:
                            for e in startItem.edgeList:
                                if e.endItem is endItem:
                                    QMessageBox.critical(self.views()[0], 'Error', 
                                                         'There already exists an edge between %s and %s' % (startItem.name, endItem.name))
                                    return
                                
                            if self.mode == self.InsertAutoConn:
                                edge = EdgeItem(EdgeItem.AUTO_CONN, startItem, endItem)
                            elif self.mode == self.InsertExecConn:
                                edge = EdgeItem(EdgeItem.EXEC_CONN, startItem, endItem)
                            edge.updatePosition()
                            self.addItem(edge)
    
                            trigger, accept = QInputDialog.getText(self.views()[0], 'Set Entry Points', '', text='')
                            if accept:
                                trigger = string.strip(str(trigger))
                                p=re.compile(r'((/\w+)+(/{(\w+,)*\w+})?,\s*)*(/\w+)+(/{(\w+\s*,\s*)*\w+})?$')
                                if p.match(trigger) is None:
                                    QMessageBox.critical(startItem.parentWidget(), 'Error',
                                                         'Separate entry point programs by comma. The format of an entry point program is either \
                                                         /path/to/file or /path/to/{file1,...,fileN}')
                                    self.removeItem(edge)
                                    return
    
                                self.removeItem(edge)
                                self.edgeAdded.emit(edge, trigger)
                                self.main.writeToFile(self.main.logFile, self.main.getCurrentTimeString()+"Insert Edge from Domain "+startItem.name+" to Domain "+\
                                                 endItem.name+" with label "+trigger+'\n')
                            else:
                                self.removeItem(edge)
        QGraphicsScene.mouseReleaseEvent(self, evt)
        self.update()
        
    def switchToGeneralGraphView(self):
        mainWindow = self.views()[0].parent()
        action = mainWindow.ui.actionGeneral_Graph
        if not action.isChecked():
            action.setChecked(True)
            self.main.viewModeChanged(action)
#             self.showGeneralGraph()
#             self.views()[0].centerOn(2500, 2500)
#             self.views()[0].fitGeneralGraph()

    def switchToTypeGraphView(self):
        mainWindow = self.views()[0].parent()
        mainWindow.editActionGroup.setDisabled(True)
        action = mainWindow.ui.actionType_Graph
        if not action.isChecked():
            action.setChecked(True)
            self.main.viewModeChanged(action)
#             self.showTypeGraph()
#             self.views()[0].centerOn(self.typeGraphRoot)
#             self.views()[0].fitTypeGraph()
       
    def stopAnimationTimer(self):
        self.animationTimer.stop()
        self.animationStopped.emit()
        mainWindow = self.views()[0].parent()
        mainWindow.ui.actionNormal_Mode.setEnabled(True)
        mainWindow.ui.actionHighlight_Mode.setEnabled(True)
        mainWindow.ui.actionDomain_Node.setEnabled(True)
        mainWindow.ui.actionType_Node.setEnabled(True)
        mainWindow.ui.actionAuto_Connection.setEnabled(True)
        mainWindow.ui.actionExec_Connection.setEnabled(True)
        mainWindow.ui.actionType_Connection.setEnabled(True)

    def startAnimationTimer(self):
        self.animationTimer.start()
        self.animationStarted.emit()
        mainWindow = self.views()[0].parent()
        mainWindow.ui.actionNormal_Mode.setEnabled(True)
        mainWindow.ui.actionHighlight_Mode.setEnabled(True)
        mainWindow.ui.actionDomain_Node.setEnabled(False)
        mainWindow.ui.actionType_Node.setEnabled(False)
        mainWindow.ui.actionAuto_Connection.setEnabled(False)
        mainWindow.ui.actionExec_Connection.setEnabled(False)
        mainWindow.ui.actionType_Connection.setEnabled(False)

    def exitAnimation(self):
        self.message = ''
        for item in self.items():
            if item not in (self.main.selfTestViewScene.interfaceQuesItems | \
                            self.main.selfTestViewScene.interfaceTableItems):
                if item.highlighted:
                    item.highlighted = False
        self.stopAnimationTimer()
        self.animationStep = 0
                   
    def animateQuery0(self, filename, typeNode):
        '''
        type of a file
        '''
        self.switchToGeneralGraphView()
        self.animationType = 0
        self.animationParameters = [filename, typeNode]
        typeNode.highlighted = True
        self.message = 'The type of %s is %s' % (str(filename), str(typeNode.name))
        self.update()
        self.startAnimationTimer()
        
    def animateQuery1(self, filename, typeNode, domains, types, fileNodes):
        '''
        files which can be accessed by a binary
        '''
        self.switchToGeneralGraphView()
        self.animationType = 1
        self.animationParameters = [filename, typeNode, domains, types, fileNodes]
        typeNode.highlighted = True
        self.message = 'The type of %s is %s' % (str(filename), str(typeNode.name))
        self.update()
        self.startAnimationTimer()
            
    def animateQuery2(self, filename, mode, typeNode, domains, types, fileNodes):
        '''
        files which can be accessed by a binary in certain mode
        '''
        self.switchToGeneralGraphView()
        self.animationType = 2
        self.animationParameters = [filename, mode, typeNode, domains, types, fileNodes]
        typeNode.highlighted = True
        self.message = 'The type of %s is %s' % (str(filename), str(typeNode.name))
        self.update()
        self.startAnimationTimer()
    
    def animateQuery3(self, domainNode, mode, typeNodes, fileNodes):
        '''
        files that can be accessed in a mode from a domain
        '''
        self.switchToGeneralGraphView()
        self.animationType = 3
        self.animationParameters = [domainNode, mode, typeNodes, fileNodes]
        domainNode.highlighted = True
        if fileNodes:
            for e in domainNode.edgeList:
                if e.endItem in typeNodes:
                    e.highlighted = True
                    e.endItem.highlighted = True
            self.message = 'Domain %s has permission %s on types %s' % (domainNode.name, str(mode), str([t.name for t in typeNodes]))
        else:
            self.message = 'No files are accessible from domain %s in mode %s' % (domainNode.name, str(mode))
        self.update()
        self.startAnimationTimer()
        
    def animateQuery4(self, filename1, filename2, mode, typeNode1, typeNode2, domains, intermediateDomains, domainsWithEntryPoint):
        '''
        If a binary can access a file with a certain access mode
        '''
        self.switchToGeneralGraphView()
        self.animationType = 4
        self.animationParameters = [filename1, filename2, mode, typeNode1, typeNode2, domains, intermediateDomains, domainsWithEntryPoint]
        typeNode1.highlighted = True
        typeNode2.highlighted = True
        typeNode2.highlightColor = QColor(0, 100, 0)
        self.message = 'The types of %s and %s are %s and %s' % (str(filename1), str(filename2), str(typeNode1.name), str(typeNode2.name))
        self.update()
        self.startAnimationTimer()
    
    def animateQuery5(self, filename, typeNode, domains):
        '''
        Domains from which a binary can be executed
        '''
        self.switchToGeneralGraphView()
        self.animationType = 5
        self.animationParameters = [filename, typeNode, domains]
        typeNode.highlighted = True
        self.message = 'The type of %s is %s' % (str(filename), str(typeNode.name))
        self.update()
        self.startAnimationTimer()

    def animateQuery6(self, filename, mode, typeNode, domains):
        '''
        Domains from which a file can be accessed in a certain access mode'
        '''
        self.switchToGeneralGraphView()
        self.animationType = 6
        self.animationParameters = [filename, mode, typeNode, domains]
        typeNode.highlighted = True
        self.message = 'The type of %s is %s' % (str(filename), str(typeNode.name))
        self.update()
        self.startAnimationTimer()
        
    def animateQuery7(self, fileNodes):
        self.switchToTypeGraphView()
        self.animationType = 7
        if fileNodes:
            for f in fileNodes:
                f.highlighted = True
            self.message = 'Directories/Files highlighted do not have assigned types'
        else:
            self.message = 'All the files have assigned types'
        self.update()
        self.startAnimationTimer()

    def animateQuery8(self, mode, typeFileMap):
        self.switchToGeneralGraphView()
        self.animationType = 8
        self.animationParameters = [mode, typeFileMap]
        types = self.animationParameters[1].keys()
        type = types[self.animationStep]
        type.highlighted = True
        for e in type.edgeList:
            e.highlighted = True
        self.message = 'No domain has permission %s on %s' % (mode, str(type.name))
        self.animationStep += 1
        self.update()
        self.startAnimationTimer()
        
    def animateQuery9(self, filename, success, domain, fileType, edge, defaultType, fileNode):
        self.switchToGeneralGraphView()
        self.animationType = 9
        self.animationParameters = [filename, success, domain, fileType, edge, defaultType, fileNode]
        domain.highlighted = True
        fileType.highlighted = True
        if not success:
            self.message = 'The type of %s is %s; however, domain %s does not have write access to it' % (filename, fileType.name, domain.name)
        else:
            if defaultType.name == '':
                self.message = 'File %s created by domain %s has type %s' % (filename, domain.name, fileType.name)
            else:               
                if fileType is defaultType:
                    edge.highlighted = True
                    self.message = 'File %s created by domain %s has type %s because it is the default type of any file created by the domain' % (filename, domain.name, fileType.name)
                else:
                    defaultType.highlighted = True
                    defaultType.highlightColor = QColor(0, 100, 0)
                    edge.highlighted = True
                    self.message = 'The type of %s is %s, and it is different from the default type %s of any file created by domain %s. Check if %s has static flag set' % \
                                    (filename, fileType.name, defaultType.name, domain.name, fileNode.fullPath)
        self.update()
        self.startAnimationTimer()
        
    def animateQuery10(self, filename, success, domain, fileType, edge, resultingDomains):
        self.switchToGeneralGraphView()
        self.animationType = 10
        self.animationParameters = [filename, success, domain, fileType, edge, resultingDomains]
        domain.highlighted = True
        fileType.highlighted = True
        self.message = 'The type of %s is %s' % (filename, fileType.name)
        self.update()
        self.startAnimationTimer()
    
    def animateQuery(self):
        if self.animationType == 0:
            typeNode = self.animationParameters[1]
            typeNode.highlighted = False
            self.message = ''
            self.stopAnimationTimer()
        elif self.animationType == 1:
            if self.animationStep == 0:
                typeNode = self.animationParameters[1]
                domains = self.animationParameters[2]
                # highlight edges with 'e'
                for d in domains:
                    d.highlighted = True
                    for e in d.edgeList:
                        if e.endItem is typeNode:
                            e.highlighted = True
                self.message = 'Domain(s) %s have executable permission on type %s' % (str([d.name for d in domains]), str(typeNode.name))
                self.animationStep += 1
            elif self.animationStep == 1:
                typeNode = self.animationParameters[1]
                domains = self.animationParameters[2]
                types = self.animationParameters[3]
                for t in types:
                    t.highlighted = True
                
                for d in domains:
                    for e in d.edgeList:
                        if isinstance(e.endItem, TypeNode):
                            e.highlighted = True

                self.message = 'Domain(s) %s can access files in %s' % (str([d.name for d in domains]), str([t.name for t in types]))
                self.animationStep += 1
            elif self.animationStep == 2:
                fileNodes = self.animationParameters[4]
                types = self.animationParameters[3]
                self.switchToTypeGraphView()
                for f in fileNodes:
                    f.highlighted = True
                self.message = 'The directories/files whose types are in %s are highlighted' % str([t.name for t in types])
                self.animationStep += 1
            elif self.animationStep == 3:
                self.exitAnimation()
        elif self.animationType == 2:
            if self.animationStep == 0:
                typeNode = self.animationParameters[2]
                domains = self.animationParameters[3]
                # highlight edges with 'e'
                for d in domains:
                    d.highlighted = True
                    for e in d.edgeList:
                        if e.endItem is typeNode:
                            e.highlighted = True
                self.message = 'Domain(s) %s have executable permission on type %s' % (str([d.name for d in domains]), str(typeNode.name))
                self.animationStep += 1
            elif self.animationStep == 1:
                mode = str(self.animationParameters[1])
                typeNode = self.animationParameters[2]
                domains = self.animationParameters[3]
                types = self.animationParameters[4]
                for item in self.items():
                    if isinstance(item, EdgeItem) or isinstance(item, TypeNode):
                        if item.highlighted:
                            item.highlighted = False
                
                for t in types:
                    t.highlighted = True
                
                for d in domains:
                    for e in d.edgeList:
                        if isinstance(e.endItem, TypeNode):
                            if mode in e.description:
                                e.highlighted = True

                self.message = 'Domain(s) %s can access files in %s with permission %s' % (str([d.name for d in domains]), str([t.name for t in types]), mode)
                self.animationStep += 1
            elif self.animationStep == 2:
                fileNodes = self.animationParameters[5]
                self.switchToTypeGraphView()
                types = self.animationParameters[4]
                for f in fileNodes:
                    f.highlighted = True
                self.message = 'The directories/files whose types are in %s are highlighted' % str([t.name for t in types])
                self.animationStep += 1
            elif self.animationStep == 3:
                self.exitAnimation()
        elif self.animationType == 3:
            if self.animationStep == 0:
                fileNodes = self.animationParameters[-1]
                typeNodes = self.animationParameters[-2]
                if not fileNodes:
                    self.exitAnimation()
                else:
                    self.switchToTypeGraphView()
                    for f in fileNodes:
                        f.highlighted = True
                    self.message = 'The directories/files whose types are in %s are highlighted' % str([t.name for t in typeNodes])
                    self.animationStep += 1
            else:
                self.exitAnimation()
        elif self.animationType == 4:
            if self.animationStep == 0:
                typeNode1 = self.animationParameters[3]
                domains = self.animationParameters[5]
                for d in domains:
                    d.highlighted = True
                    for e in d.edgeList:
                        if e.endItem is typeNode1:
                            e.highlighted = True
                self.message = 'Domain(s) %s have executable permission on type %s' % (str([str(d.name) for d in domains]), str(typeNode1.name))
                self.animationStep += 1
            elif self.animationStep == 1:
                mode = self.animationParameters[2]
                typeNode2 = self.animationParameters[4]
                typeNode1 = self.animationParameters[3]
                domains = self.animationParameters[5]
                intermediateDomains = self.animationParameters[6]
                  
                for d in domains:
                    d.highlighted = False
                    for e in d.edgeList:
                        e.highlighted = False 
                effectiveDomains = []
                for dlist in intermediateDomains:
                    if len(dlist) == 1:
                        for d in dlist:
                            d.highlighted = True
                            for e in d.edgeList:
                                if e.endItem is typeNode2 and str(mode) in e.description:
                                    e.highlighted = True
                            effectiveDomains.append(d.name)
                    if effectiveDomains:
                        self.message = 'Domain(s) %s among %s have permission %s on type %s' % \
                        (str(effectiveDomains), 
                         str([str(d.name) for d in domains]),
                         str(mode),
                         typeNode2.name)
                    else:
                        self.message = 'No domain among %s have permission %s on type %s' % \
                        (str([str(d.name) for d in domains]),
                         str(mode),
                         typeNode2.name)
                self.animationStep += 1
            elif self.animationStep == 2:
                binaryname = str(self.animationParameters[0])
                domainsWithEntryPoint = list(self.animationParameters[-1])
                intermediateDomains = self.animationParameters[6]
                for dlist in intermediateDomains:
                    if len(dlist) == 1:
                        for d in dlist:
                            d.highlighted = False
                            for e in d.edgeList:
                                    e.highlighted = False
                for d in domainsWithEntryPoint:
                    d.highlighted = True
                    for e in d.edgeList:
                        if e.type == EdgeItem.AUTO_CONN or e.type == EdgeItem.EXEC_CONN:
                            binaries = list(self.main.queryWindow.getEntryPointFromEdgeDescription([e.description]))
                            if binaryname in binaries:
                                e.highlighted = True
                if domainsWithEntryPoint:
                    self.message = 'Domain(s) %s can execute the binary to transition to another domain' % \
                        (str([d.name for d in domainsWithEntryPoint]))
                    self.animationStep += 1
                else:
                    self.message = '%s is not an entry point program of any domain'
                    self.animationStep = 4#go to check 3 step domain transition access to file'''
            elif self.animationStep == 3:
                mode = str(self.animationParameters[2])
                typeNode2 = self.animationParameters[4]
                intermediateDomains = self.animationParameters[6]
                domainsWithEntryPoint = self.animationParameters[-1]
                for d in domainsWithEntryPoint:
                    d.highlighted = False
                transferDomains = []
                for dlist in intermediateDomains:
                    if len(dlist) == 2:
                        dlist[0].highlighted = True
                        dlist[1].highlighted = True
                        for e in dlist[0].edgeList:
                            if e.startItem == dlist[0] and e.endItem == dlist[1]:
                                e.highlighted = True
                        for e in dlist[1].edgeList:
                            if e.startItem == dlist[1] and e.endItem is typeNode2 and mode in e.description:
                                e.highlighted = True
                        transferDomains.append(str([d.name for d in dlist]))
                if transferDomains:
                    self.message = 'The transitions between Domains %s can execute the binary as entry point and the resulting domain has permission %s on type %s' % \
                    (str(transferDomains),\
                     str(mode),\
                     typeNode2.name)
                else:
                    self.message = 'The resulting domains of the transition(s) can not access the file with permission %s'%\
                     str(mode)
                self.animationStep += 1
            elif self.animationStep == 4:
                mode = str(self.animationParameters[2])
                if mode != 'x':
                    typeNode2 = self.animationParameters[4]
                    typeNode2.highlightColor = QColor(255, 0, 0 )
                    self.exitAnimation()  
                typeNode2 = self.animationParameters[4]
                intermediateDomains = self.animationParameters[6]
                domainsWithEntryPoint = self.animationParameters[-1]
                transferDomains = []
                for dlist in intermediateDomains:
                    if len(dlist) == 3:
                        dlist[0].highlighted = True
                        dlist[1].highlighted = True
                        dlist[2].highlighted = True
                        for e in dlist[0].edgeList:
                            if e.startItem == dlist[0] and e.endItem == dlist[1]:
                                e.highlighted = True
                        for e in dlist[1].edgeList:
                            if e.startItem == dlist[1] and e.endItem == dlist[2]:
                                e.highlighted = True
                        transferDomains.append(str([d.name for d in dlist]))
                if transferDomains:
                    self.message = 'In the transition(s) between domains %s, the first domain can execute the binary as entry point to get to the second domain, and then the second domain can execute the file as entry point program to get to the third domain' % \
                    (str(transferDomains))
                    self.animationStep += 1  
                else:
                    typeNode2 = self.animationParameters[4]
                    typeNode2.highlightColor = QColor(255, 0, 0 )
                    self.exitAnimation()  
            elif self.animationStep == 5:
                typeNode2 = self.animationParameters[4]
                typeNode2.highlightColor = QColor(255, 0, 0 )
                self.exitAnimation()
        elif self.animationType == 5:
            if self.animationStep == 0:
                typeNode = self.animationParameters[1]
                domains = self.animationParameters[2]
                for d in domains:
                    d.highlighted = True
                    for e in d.edgeList:
                        if e.endItem is typeNode:
                            e.highlighted = True
                self.message = 'Domain(s) %s have executable permission on type %s' % (str([str(d.name) for d in domains]), str(typeNode.name))
                self.animationStep += 1
            elif self.animationStep == 1:
                self.exitAnimation()
        elif self.animationType == 6:
            if self.animationStep == 0:
                mode = str(self.animationParameters[1])
                typeNode = self.animationParameters[2]
                domains = self.animationParameters[3]
                for d in domains:
                    d.highlighted = True
                    for e in d.edgeList:
                        if e.endItem is typeNode:
                            if mode in e.description:
                                e.highlighted = True
                self.message = 'Domain(s) %s have permission %s on type %s' % (str([str(d.name) for d in domains]), mode, str(typeNode.name))
                self.animationStep += 1
            elif self.animationStep == 1:
                self.exitAnimation()
        elif self.animationType == 7:
            self.exitAnimation()
        elif self.animationType == 8:
            typeFileMap = self.animationParameters[1]
            mode = self.animationParameters[0]
            if self.animationStep < len(typeFileMap.keys()):
                for item in self.items():
                    if item.highlighted:
                        item.highlighted = False

                type = typeFileMap.keys()[self.animationStep]
                type.highlighted = True
                for e in type.edgeList:
                    e.highlighted = True
                self.message = 'No domain has permission %s on %s' % (mode, str(type.name))
                self.animationStep += 1
            elif self.animationStep == len(typeFileMap.keys()):
                self.switchToTypeGraphView()
                files = typeFileMap.values()
                dirs = []
                for files in typeFileMap.values():
                    for f in files:
                        f.highlighted = True
                        dirs.append(f)
                self.message = 'Files under directories %s cannot be accessed with permission %s' % \
                                (str([str(d.fullPath) for d in dirs]), self.animationParameters[0])
                self.animationStep += 1
            else:
                self.exitAnimation()
        elif self.animationType == 9:
            if self.animationStep == 0:
                defaultType = self.animationParameters[5]
                if defaultType.name == '':
                    self.exitAnimation()
                else:
                    fileType = self.animationParameters[3]
                    if fileType is defaultType:
                        self.exitAnimation()
                    else:
                        filename = self.animationParameters[0]
                        domain = self.animationParameters[2]
                        self.switchToTypeGraphView()
                        fileNode = self.animationParameters[-1]
                        fileNode.highlighted = True
                        if fileNode.flag == 1 or fileNode.flag == 3:
                            type = self.animationParameters[3]
                            self.message = 'File %s created by domain %s is forced to have type %s because of the static flag' % (filename, domain.name, type.name)
                        else:
                            type = self.animationParameters[5]
                            self.message = 'File %s created by domain %s has type %s since no static flag is found' % \
                                            (filename, domain.name, type.name)
                        self.animationStep += 1
            elif self.animationStep == 1:
                self.animationParameters[5].highlightColor = QColor(255, 0, 0)
                self.exitAnimation()     
        elif self.animationType == 10:
            if self.animationStep == 0:
                filename = self.animationParameters[0]
                domain = self.animationParameters[2]
                fileType = self.animationParameters[3]
                edge = self.animationParameters[4]
                if edge.type == EdgeItem.AUTO_CONN:
                    self.message = 'There is an auto transition through this binary to be checked first.'
                    self.animationStep += 1
                    self.update()
                else:
                    if edge.description != '':
                        if edge.startItem is domain and edge.endItem is fileType:
                            edge.highlighted = True
                            self.message = 'Executing %s from domain %s is successful because the domain has "execute" permission on the type. The resulting domain is the domain itself' % \
                                            (self.animationParameters[0], domain.name)
                            self.animationStep += 1
                            self.update()
                            return
                    self.message = 'Domain %s does not have "executable" permission on type %s. Now checking if the file is an entry point to another domain.' % \
                                (domain.name, fileType.name)
                    self.animationStep += 1
            elif self.animationStep == 1:
                filename = self.animationParameters[0]
                domain = self.animationParameters[2]
                fileType = self.animationParameters[3]
                edge = self.animationParameters[4]
                if edge.description != '':
                    if edge.startItem is domain and edge.endItem is fileType:
                        self.exitAnimation()
                    elif edge.type == EdgeItem.AUTO_CONN:
                        edge.highlighted = True
                        edge.endItem.highlighted = True
                        self.message = 'File %s is an entry point to domain %s, which is the resulting domain of executing the file from domain %s' % \
                        (filename, edge.endItem.name, domain.name)
                    elif edge.type == EdgeItem.EXEC_CONN:
                        resultingDomains = self.animationParameters[-1]
                        for e in domain.edgeList:
                            if e.endItem in resultingDomains:
                                e.highlighted = True
                                e.endItem.highlighted = True
                        self.message = 'File %s is an entry point to domains %s, and the resulting domains of executing the file can be any one of them' %\
                                        (filename, str([d.name for d in resultingDomains]))
                else:
                    self.message = 'File %s is neither in any type which domain %s has "executable" permission on, nor an entry point program which can be executed by the domain' % \
                                    (filename, domain.name)
                self.animationStep += 1
            else:
                self.exitAnimation()    
        self.update()
            
            
        
             
            

            
