'''
Created on May 10, 2016

@author: manwang
'''
from PyQt4.QtCore import *
from PyQt4.QtGui import *
import MyFunctions
import random
        
class FileDialog(QFileDialog):
    def __init__(self, *args):
        QFileDialog.__init__(self, *args)
        self.setOption(self.DontUseNativeDialog, True)
        self.setFileMode(self.ExistingFiles)
        btns = self.findChildren(QPushButton)
        self.openBtn = [x for x in btns if 'open' in str(x.text()).lower()][0]
        self.openBtn.clicked.disconnect()
        self.openBtn.clicked.connect(self.openClicked)
        self.tree = self.findChild(QTreeView)
        self.main = args[0]
        self.selectedFiles = []
        
    def openClicked(self):
        import os
        inds = self.tree.selectionModel().selectedIndexes()
        files = []
        for i in inds:
            if i.column() == 0:
                files.append(os.path.join(str(self.directory().absolutePath()), str(i.data().toString())))
        self.selectedFiles = files
        if self.selectedFiles:
            self.main.selfTestViewScene.setObjUI(self.selectedFiles[0])
        self.hide()
        self.main.selfTestViewScene.settingChanged()
        
    def filesSelected(self):
        return self.selectedFiles
    
class SelfTestScene(QWidget):
    ROLEPERM_QUES = 0
    USERPERM_QUES = 1
    ROLEINHER_QUES = 2
    USERROLE_QUES = 3
    QUES_INFO = [['Can the role access the object with the specified permission?', 'Yes', 'No'],\
                 ['Can the user access the object with the specified permission?', 'Yes', 'No'],\
                 ['Which pair of roles below has the relationship of the first role inheriting the second role?'], \
                 ['Based on the role inheritance, which roles does the user occupy?']
                ]
    ANIMTESTEPS = [3, 4, 1, 1]
    
    def __init__(self, parent, main):
        QWidget.__init__(self, parent)
        self.main = main
        self.scene = main.scene
        self.initParam()
        self.setupWidget(parent)
        self.initQuestion()
        
    def initParam(self):
        self.spec = None
        self.interfaceQuesItems = set()
        self.interfaceTableItems = set()
        self.objDir = None
        self.settingPermInfo = None
        self.settingIsChanged = True
        self.chosenAnswer = None
        self.answer = None
        self.w = None
        self.oldHighlightMode, self.oldHighlightScheme = None, None
        
    def createGraphicsTextItem(self, scene, text, fontsize=20, isQuesItem = True):
        item = QGraphicsTextItem(text)
        MyFunctions.setFontForUI(item, fontsize)
        scene.addItem(item)
        if isQuesItem:
            self.interfaceQuesItems.add(item)
        else:
            self.interfaceTableItems.add(item)
        return item
            
    def setupWidget(self, parent):
        self.setupTableViews()
        self.tableViewQuestionConf.setGeometry(0, 0, self.scene.sceneRect().width(), 0.5*self.scene.sceneRect().height())
        self.interfaceTableItems.add(self.tableViewQuestionConf)
        
        self.questionType = QComboBox()
        self.questionType.addItem('Role Permission')
        self.questionType.addItem('User Permission')
        MyFunctions.setFontForUI(self.questionType, 20)
        self.createUIInScene(self.questionType)
        self.questionType.activated.connect(self.questionTypeChanged)

    def setCellText(self, r, c, text, font = QFont('Courier', 18), isBold = False):
        item = QTableWidgetItem(QString(text))
        font.setBold(isBold)
        item.setFont(font)
        item.setTextAlignment(Qt.AlignCenter)
        item.setFlags(item.flags() &~Qt.ItemIsEditable)
        self.tableViewQuestionConf.setItem(r, c, item)
        return item
        
    def createLineEditAndButtonCombo(self, r, c, btnText='Random', isLineEdit = False):
        widget = QWidget()
        hlayout = QHBoxLayout(widget)
        if isLineEdit:
            lineEdit = QLineEdit()
        else:
            lineEdit = QComboBox()
            lineEdit.setSizeAdjustPolicy(QComboBox.AdjustToContents)
            lineEdit.setEditable(True)
            lineEdit.completer().setCompletionMode(QCompleter.PopupCompletion)

        button = QPushButton(btnText)
        hlayout.addWidget(lineEdit)
        hlayout.addWidget(button)
        hlayout.setContentsMargins(0, 0, 0, 0)
        widget.setLayout(hlayout)
        self.tableViewQuestionConf.setCellWidget(r,c,widget)
        return lineEdit, button
    
    def setupTableViews(self):
        self.tableViewQuestionConf = QTableWidget(self.main.view)
        self.tableViewQuestionConf.setRowCount(2)
        self.tableViewQuestionConf.setColumnCount(5)
        self.tableViewQuestionConf.verticalHeader().setVisible(False)
        self.tableViewQuestionConf.horizontalHeader().setVisible(False)
        '''1'''
        self.tableViewQuestionConf.clear()
        self.setCellText(0, 1, 'Role', QFont('Courier', 20))
        self.setCellText(1, 0, 'Name', QFont('Courier', 20))
        self.setCellText(0,3, 'Object', QFont('Courier', 20))
        self.setCellText(0,4, 'Permission', QFont('Courier', 20))
        self.setCellText(1,2, 'Directory', QFont('Courier', 20))
        self.lineEdit11, self.randomPBtn11 = self.createLineEditAndButtonCombo(1,1)
        self.objDirLineEdit, self.objDirLoadPBtn = self.createLineEditAndButtonCombo(1,3, '...')
        self.permLineEdit, self.permRandomPBtn = self.createLineEditAndButtonCombo(1,4)
        for i in xrange(1, 8):
            self.permLineEdit.addItem(MyFunctions.convertOctToRWXString(i))
        self.objDirLineEdit.setVisible(True)
        self.objDirLoadPBtn.setVisible(True)
        self.permLineEdit.setVisible(True)
        self.permRandomPBtn.setVisible(True)
        
        for c in xrange(self.tableViewQuestionConf.columnCount()):
            for r in xrange(self.tableViewQuestionConf.rowCount()): 
                if self.tableViewQuestionConf.item(r, c) == None:
                    self.setCellText(r, c, '')
                if c < 2:
                    color = QColor(234, 250, 241)
                elif c < 4:
                    color = QColor(252, 243, 207)
                else:
                    color = QColor(250, 219, 216)
                self.tableViewQuestionConf.item(r, c).setData(Qt.BackgroundRole, QVariant(QBrush(color)))
        self.tableViewQuestionConf.verticalHeader().setResizeMode(QHeaderView.Stretch)
        self.tableViewQuestionConf.horizontalHeader().setResizeMode(QHeaderView.Stretch)
        
        self.objDirLoadPBtn.clicked.connect(self.setObjPath)
        self.objDirLineEdit.highlighted.connect(lambda dirIndex: self.showWholePathAsHint(dirIndex))
        self.randomPBtn11.clicked.connect(self.random11)
        self.permRandomPBtn.clicked.connect(self.randomGetPerm)
        
        self.lineEdit11.currentIndexChanged.connect(self.settingChanged)
        self.permLineEdit.currentIndexChanged.connect(self.settingChanged)
        self.objDirLineEdit.editTextChanged.connect(self.settingChanged)
        
    def createUIInScene(self, widget, isQuesItem = True):
        proxyWidget = QGraphicsProxyWidget()
        proxyWidget.setWidget(widget)
        proxyWidget.setZValue(1)
        self.scene.addItem(proxyWidget)
        if isQuesItem:
            self.interfaceQuesItems.add(proxyWidget)
            self.interfaceQuesItems.add(widget)
        else:
            self.interfaceTableItems.add(proxyWidget)
            self.interfaceTableItems.add(widget)
        return proxyWidget
    
    def initQuestion(self):        
        self.labelQuestion = QGraphicsTextItem('Question Type: ')
        MyFunctions.setFontForUI(self.labelQuestion, 25)
        if self.labelQuestion not in self.scene.items():
            self.scene.addItem(self.labelQuestion)
            self.interfaceQuesItems.add(self.labelQuestion)
            self.labelQuestionText = self.createGraphicsTextItem(self.scene, self.QUES_INFO[self.ROLEPERM_QUES][0], 25)
            self.quesTextWidth = self.labelQuestionText.boundingRect().width()
            
            self.answerWidget = QWidget()
            self.answerWidget.setStyleSheet("background-color: white")
            answerLayout = QVBoxLayout()
            answerLayout.setMargin(0)
            self.answerRadioBtn1 = QRadioButton('Yes')
            self.answerRadioBtn1.setStyleSheet("background-color: white")
            MyFunctions.setFontForUI(self.answerRadioBtn1, 25)
            self.answerRadioBtn2 = QRadioButton('No')
            self.answerRadioBtn2.setStyleSheet("background-color: white")
            MyFunctions.setFontForUI(self.answerRadioBtn2, 25)
            self.answerRadioBtn3 = QRadioButton()
            self.answerRadioBtn3.setStyleSheet("background-color: white")
            MyFunctions.setFontForUI(self.answerRadioBtn3, 25)
            self.answerRadioBtn4 = QRadioButton()
            self.answerRadioBtn4.setStyleSheet("background-color: white")
            MyFunctions.setFontForUI(self.answerRadioBtn4, 25)
            answerLayout.addWidget(self.answerRadioBtn1)
            answerLayout.addWidget(self.answerRadioBtn2)
            answerLayout.addWidget(self.answerRadioBtn3)
            answerLayout.addWidget(self.answerRadioBtn4)
            self.answerWidget.setLayout(answerLayout)
            self.createUIInScene(self.answerWidget)
            self.interfaceQuesItems.add(self.answerRadioBtn1)
            self.interfaceQuesItems.add(self.answerRadioBtn2)
            self.interfaceQuesItems.add(self.answerRadioBtn3)
            self.interfaceQuesItems.add(self.answerRadioBtn4)
            
            self.nextExplainPBtn = QPushButton('Explain')
            MyFunctions.setFontForUI(self.nextExplainPBtn, 25)
            self.createUIInScene(self.nextExplainPBtn)
            self.nextExplainPBtn.setStyleSheet("background-color: #328930")

            self.nextSkipPBtn = QPushButton('Check')
            MyFunctions.setFontForUI(self.nextSkipPBtn, 25)
            self.createUIInScene(self.nextSkipPBtn)
            
            self.correctnessTextItem = self.createGraphicsTextItem(self.scene,'', 25)
                    
            self.explainTextEdit = QTextEdit()
            MyFunctions.setFontForUI(self.explainTextEdit, 20)
            self.explainTextEditProxy = self.createUIInScene(self.explainTextEdit)
              
            self.answerRadioBtn1.clicked.connect(self.rBtn1Clicked)
            self.answerRadioBtn2.clicked.connect(self.rBtn2Clicked)
            self.answerRadioBtn3.clicked.connect(self.rBtn3Clicked)
            self.answerRadioBtn4.clicked.connect(self.rBtn4Clicked)
        
            self.nextSkipPBtn.clicked.connect(self.checkAnswer)
            self.nextExplainPBtn.clicked.connect(self.explainAnswer)
            
    def updateLayout(self):
        ratio = 0.3
        self.tableViewQuestionConf.setGeometry(0, 0, self.scene.sceneRect().width(), ratio*self.scene.sceneRect().height())
        self.labelQuestion.setPos(10, (ratio+0.01)*self.scene.sceneRect().height())
        if self.quesTextWidth > self.scene.sceneRect().width():
            self.labelQuestionText.setTextWidth(self.scene.sceneRect().width())
        else:
            self.labelQuestionText.setTextWidth(self.quesTextWidth)
        
        xinter = self.labelQuestionText.boundingRect().width()
        self.labelQuestionText.setPos(ratio*(self.scene.sceneRect().width()-xinter),\
                                    self.labelQuestion.pos().y()+self.labelQuestion.boundingRect().height()+5)
        self.answerWidget.setGeometry(self.labelQuestionText.pos().x()+10, self.labelQuestionText.pos().y()+self.labelQuestionText.boundingRect().height()+5, \
                                           self.answerWidget.geometry().width(), self.answerWidget.geometry().height())
        xinter = self.nextExplainPBtn.geometry().width()
        yinter = self.nextExplainPBtn.geometry().height()
        self.nextExplainPBtn.setGeometry(self.scene.sceneRect().width()-10-xinter, self.scene.sceneRect().height()-10-yinter, \
                                         xinter, yinter)
        xinter = self.nextSkipPBtn.geometry().width()
        self.nextSkipPBtn.setGeometry(self.nextExplainPBtn.pos().x()-xinter-10, self.nextExplainPBtn.pos().y(), \
                                         self.nextExplainPBtn.geometry().width(), self.nextSkipPBtn.geometry().height())
        self.correctnessTextItem.setPos(self.nextSkipPBtn.geometry().x(), self.nextSkipPBtn.geometry().y()-self.nextSkipPBtn.geometry().height()-5)
        self.questionType.setGeometry(self.labelQuestion.pos().x()+self.labelQuestion.boundingRect().width(), \
                                      (ratio+0.01)*self.scene.sceneRect().height(), \
                                      self.questionType.geometry().width(), \
                                      self.questionType.geometry().height())
        if self.questionType.currentIndex() == self.USERPERM_QUES or \
            self.questionType.currentIndex() == self.ROLEPERM_QUES:
            self.answerRadioBtn3.setVisible(False)
            self.answerRadioBtn4.setVisible(False)
        else:
            self.answerRadioBtn3.setVisible(True)
            self.answerRadioBtn4.setVisible(True)
        y = self.answerWidget.geometry().y()+self.answerWidget.geometry().height()+5
        self.explainTextEditProxy.setGeometry(QRectF(self.labelQuestionText.pos().x(), y, \
                                         self.correctnessTextItem.pos().x() - self.answerWidget.pos().x() - 20, \
                                         max(self.correctnessTextItem.pos().y()-y-5, 0)))
        
    def setVisibilityOfSceneItems(self, flag):
        for i in self.interfaceQuesItems:
            i.setVisible(flag)
        self.tableViewQuestionConf.setVisible(flag)
        for i in self.interfaceTableItems:
            i.setVisible(flag)
        
    def setTableBackgroundColor(self, endr, endc, isEnabled):
        for c in xrange(endc):
            for r in xrange(endr): 
                item = self.tableViewQuestionConf.item(r, c)
                if isEnabled:
                    if c < 2:
                        color = QColor(234, 250, 241)
                    elif c < 4:
                        color = QColor(252, 243, 207)
                    else:
                        color = QColor(250, 219, 216)
                else:
                    color = Qt.lightGray
                item.setData(Qt.BackgroundRole, QVariant(QBrush(color)))
                
    def questionTypeChanged(self):
        qtype = self.questionType.currentIndex()
        if qtype == self.ROLEPERM_QUES:
            self.rolePermUIsetting()
        elif qtype == self.USERPERM_QUES:
            self.userPermUIsetting()
        self.updateUIContents()
        self.updateLayout()
        self.settingChanged()
        
    def generateChoices(self):
        if self.questionType.currentIndex() == self.ROLEPERM_QUES:
            self.generateChoicesForRolePermQues()
        elif self.questionType.currentIndex() == self.USERPERM_QUES:
            self.generateChoicesForUserPermQues()
        
    def generateChoicesForRolePermQues(self):
        self.answerRadioBtn1.setText(self.QUES_INFO[self.ROLEPERM_QUES][1])
        self.answerRadioBtn2.setText(self.QUES_INFO[self.ROLEPERM_QUES][2])
    
    def generateChoicesForUserPermQues(self):
        self.answerRadioBtn1.setText(self.QUES_INFO[self.ROLEPERM_QUES][1])
        self.answerRadioBtn2.setText(self.QUES_INFO[self.ROLEPERM_QUES][2])
    
    def rolePermUIsetting(self):
        '''
        0 |     1   | 2 |  3   |     4
        0 | role    | 2 | obj  | perm(letter)
        1 | name    |   | dir  | p
        2 |         |   | user | 
        3 |         |   | group|
        4 |         |   | perm | 
        '''
        self.tableViewQuestionConf.item(0,1).setText('Role')
        self.tableViewQuestionConf.item(1,0).setText('Name')
        self.tableViewQuestionConf.item(0,3).setText('Object')
        self.tableViewQuestionConf.item(0,4).setText('Permission')
        self.tableViewQuestionConf.item(1,2).setText('Directory')
        self.objDirLineEdit.setVisible(True)
        self.objDirLoadPBtn.setVisible(True)
        self.permLineEdit.setVisible(True)
        self.permRandomPBtn.setVisible(True)
        self.labelQuestionText.setPlainText(self.QUES_INFO[self.ROLEPERM_QUES][0])
        self.quesTextWidth = self.labelQuestionText.boundingRect().width()
        
    def userPermUIsetting(self):
        '''
        0 |     1   | 2 |  3   |     4
        0 |   user  | 2 | obj  | perm(letter)
        1 |   name  |   | dir  | p
        2 |         |   | user | 
        3 |         |   | group|
        4 |         |   | perm | 
        '''
        self.tableViewQuestionConf.item(0,1).setText('User')
        self.tableViewQuestionConf.item(1,0).setText('Name')
        self.tableViewQuestionConf.item(0,3).setText('Object')
        self.tableViewQuestionConf.item(0,4).setText('Permission')
        self.tableViewQuestionConf.item(1,2).setText('Directory')
        self.objDirLineEdit.setVisible(True)
        self.objDirLoadPBtn.setVisible(True)
        self.permLineEdit.setVisible(True)
        self.permRandomPBtn.setVisible(True)
        self.labelQuestionText.setPlainText(self.QUES_INFO[self.USERPERM_QUES][0])
        self.quesTextWidth = self.labelQuestionText.boundingRect().width()
        
    '''model logic'''
    def role1InheritRole2(self, role1, role2):
        if role1 == role2:
            return True
        if role1 in self.main.role_adjmat.keys():
            children = self.main.role_adjmat[role1].children
            onelevelchildren = list(children)
            while onelevelchildren!=[]:
                role = onelevelchildren.pop(0)
                chi = self.main.role_adjmat[role].children
                onelevelchildren.extend(list(chi))
                children = children.union(chi)
            if role2 in children:
                return True
            else:
                return False
            
    def findAllChildren(self, rolename):
        children = []
        if rolename in self.main.role_adjmat.keys():
            children = self.main.role_adjmat[rolename].children
            onelevelchildren = list(children)
            while onelevelchildren!=[]:
                role = onelevelchildren.pop(0)
                chi = self.main.role_adjmat[role].children
                onelevelchildren.extend(list(chi))
                children = children.union(chi)
        return children
    
    def convertOctStringToRWXSet(self, permOctString):
        permRWXSet = set(MyFunctions.convertOctToRWXString(int(permOctString)))
        permRWXSet.discard('-')
        return permRWXSet
        
    def generateRandomPermissionInOctal(self):
        special = [0, 1, 2, 4, 3, 6, 7]
        specialNum = random.choice(special)
        usernum = random.randrange(0, 8)
        groupnum = random.randrange(0, 8)
        othernum = random.randrange(0, 8)
        permstr = str(specialNum)+str(usernum)+str(groupnum)+str(othernum)
        return permstr

    def resetAnimatedItems(self):
        self.resetSpec()
        self.main.animationStep = 0
        self.explainTextEdit.clear()
        
    def onAnimateSelfTest(self):
        if self.questionType.currentIndex() == self.ROLEPERM_QUES:
            self.onAnimateSelfTest_RolePerm()
        elif self.questionType.currentIndex() == self.ROLEPERM_QUES:
            self.onAnimateSelfTest_UserPerm()
    
    def resetSpec(self):
        self.main.clickedNode = None
        self.main.roleHighlightScheme = self.oldHighlightMode
        self.main.highlightmode = self.oldHighlightScheme
        self.oldHighlightMode, self.oldHighlightScheme = None, None
        text = str(self.main.specDialog.ui.specTextEdit.toPlainText())
        self.main.specDialog.ui.specTextEdit.clear()
        self.main.specDialog.ui.specTextEdit.setPlainText(text)
        
    def rolePermHighlightSpec(self, rolename):
        rolenode = None
        for r in self.main.roleCompactNodes:
            if rolename == r.name:
                rolenode = r
        self.main.clickedNode = rolenode
        self.oldHighlightMode= self.main.highlightmode
        self.oldHighlightScheme = self.main.roleHighlightScheme
        self.main.highlightmode = self.main.HIGHLIGHT_HIER_MODE
        self.main.roleHighlightScheme = self.main.ROLE_HIGHLIGHT_CHILDREN
        self.main.policyManager.highlightChildrenNodesRoleNode(rolenode)
        self.main.specDialog.getSpecFromVisualization()
        
    def userPermHighlightSpec(self, username):
        usernode = None
        for u in self.main.userNodes:
            if username == u.name:
                usernode = u
        self.main.clickedNode = usernode
        self.oldHighlightMode= self.main.highlightmode
        self.oldHighlightScheme = self.main.roleHighlightScheme
        self.main.highlightmode = self.main.HIGHLIGHT_HIER_MODE
        self.main.roleHighlightScheme = self.main.ROLE_HIGHLIGHT_CHILDREN
        self.main.policyManager.highlightNodeWithBorderUserNode(usernode)
        self.main.specDialog.getSpecFromVisualization()
        
    def getPermForRole(self, role):
        roleAccessObjMain = {}
        roleAccessObj = {}
        roleChildren = set(self.findAllChildren(role))
        item = self.main.role_res_mat[role]
        for k, v in item.iteritems():
            roleAccessObjMain.update({k: [v]})
        for c in roleChildren:
            item = self.main.role_res_mat[c]
            for k, v in item.iteritems():
                if k not in roleAccessObj.keys():
                    roleAccessObj.update({k: [v]})
                else:
                    roleAccessObj[k].append(v)
        targetPerm = str(self.permLineEdit.currentText())
        permset = set(targetPerm)
        permset.discard('-')
        targetObj = str(self.objDirLineEdit.currentText())
        targetObjList = targetObj.split('/')
        path = ''
        roleperms = set()
        for i in targetObjList:
            if path=='/':
                path+=i
            else:
                path+='/'+i
            if path != targetObj:
                if path in roleAccessObjMain.keys():
                    for p in roleAccessObjMain[path]:
                        if p.recursive:
                            roleperms = p.perms
            else:
                if path in roleAccessObjMain.keys():
                    for p in roleAccessObjMain[path]:
                        roleperms = p.perms
        if (not roleperms) and roleAccessObj:
            for i in targetObjList:
                if path=='/':
                    path+=i
                else:
                    path+='/'+i
                if path != targetObj:
                    if path in roleAccessObj.keys():
                        for p in roleAccessObj[path]:
                            if p.recursive:
                                roleperms = p.perms
                else:
                    if path in roleAccessObj.keys():
                        for p in roleAccessObj[path]:
                            roleperms = p.perms
        return roleAccessObj, roleChildren, roleperms, permset
    
    def getPermForUser(self, user):
        roles = set()
        self.answer = []
        permset = set()
        roleAccessObjTotal, roleChildrenTotal, rolepermsTotal = {}, set(), set()
        if user in self.main.user_role_mat.keys():
            roles = self.main.user_role_mat[user]
        for r in roles:
            roleAccessObj, roleChildren, roleperms, permset = self.getPermForRole(r)
            for k, v in roleAccessObj.iteritems():
                if k not in roleAccessObjTotal.keys():
                    roleAccessObjTotal.update({k: [v]})
                else:
                    roleAccessObjTotal[k].append(v)
            roleChildrenTotal = roleChildrenTotal.union(roleChildren)
            rolepermsTotal = rolepermsTotal.union(roleperms)
        self.answer = [roles, roleAccessObjTotal, roleChildrenTotal, rolepermsTotal, permset]
            
    def onAnimateSelfTest_RolePerm(self, roleAccessObj, roleChildren, roleperms, permset):
        role = str(self.lineEdit11.currentText())
        if self.main.animationStep == 0:
            self.updateExplainText('- A role obtains its access through the roles it inherits and the permissions to objects from those roles...')
        elif self.main.animationStep == 1:
            self.updateExplainText('\n- Finding the roles the role inherits:')
            rolename = str(self.lineEdit11.currentText())
            self.rolePermHighlightSpec(rolename)
            if roleChildren:
                self.updateExplainText('\n In the specification, sign means \'>\' inherit. Therefore, role \'%s\' inherits are:'%role)
                self.updateExplainText('\n %s'%role)
                self.updateExplainText(',%s'%(',').join(roleChildren))
            else:
                self.updateExplainText('\n No inheritance is given in the specification.')
#                 self.updateExplainText('\n Role \'%s\' does not inherit any other roles.'%rolename)
        elif self.main.animationStep == 2:
            self.updateExplainText('\n- Getting the permission of the roles:')
            item = self.main.role_res_mat[role]
            for k, v in item.iteritems():
                if v.recursive:
                    self.updateExplainText('\n Role \'%s\': -r %s'%(role, ','.join(v.perms)+' '+k))
                else:
                    self.updateExplainText('\n Role \'%s\': %s'%(role, ','.join(v.perms)+' '+k))
            for c in roleChildren:
                item = self.main.role_res_mat[c]
                for k, v in item.iteritems():
                    if v.recursive:
                        self.updateExplainText('\n Role \'%s\': -r %s'%(c, ','.join(v.perms)+' '+k))
                    else:
                        self.updateExplainText('\n Role \'%s\': %s'%(c, ','.join(v.perms)+' '+k))
        elif self.main.animationStep == 3:
            targetObj = str(self.objDirLineEdit.currentText())
            self.updateExplainText('\n- Conclusion:')
            self.updateExplainText('\n We are examining whether role \'%s\' has %s access to object \'%s\'.'%(role, ','.join(permset), targetObj))
            if not roleperms:
                self.updateExplainText('\n According to the above list, role \'%s\' does not have access to the object.\n Therefore, the answer is \'No\'.'%role)
            else:
                self.updateExplainText('\n According to the above list, role \'%s\' has %s permission to the object.'%(role, ','.join(roleperms)))
                if permset.issubset(roleperms):
                    self.updateExplainText('\n Therefore, the answer is \'Yes\'.')
                else:
                    self.updateExplainText('\n Therefore, the answer is \'No\'.')
        cursor = self.explainTextEdit.textCursor()
        cursor.movePosition(QTextCursor.End, QTextCursor.MoveAnchor)
        self.explainTextEdit.setTextCursor(cursor)       
             
    def onAnimateSelfTest_UserPerm(self, roles, roleAccessObj, roleChildren, roleperms, permset):
        user = str(self.lineEdit11.currentText())
        if self.main.animationStep == 0:
            self.updateExplainText('- A user obtains its access through the roles it assigned to and the roles those roles inherit...')
        elif self.main.animationStep == 1:
            self.updateExplainText('\n- Finding the roles the user belongs to:')
            if roles:
                self.updateExplainText('\n In the specification, the roles are:')
                self.updateExplainText('\n %s'%','.join(roles))
            else:
                self.updateExplainText('\n The user is not assigned to any role. It has no access to any object.')
                self.updateExplainText('\n Therefore, the answer is \'No\'.')
                self.main.animationStep = self.ANIMTESTEPS[self.USERPERM_QUES]
        elif self.main.animationStep == 2:
            self.updateExplainText('\n- Finding the roles the role inherits:')
            self.updateExplainText('\n In the specification, sign means \'>\' inherit.')
            self.userPermHighlightSpec(user)
            if roleChildren:
                self.updateExplainText('\n Therefore, roles involved through inheritance are:')
                self.updateExplainText('\n %s'%(',').join(roleChildren))
            else:
                self.updateExplainText('\n There is no role inherited by the above roles.')
        elif self.main.animationStep == 3:
            self.updateExplainText('\n- Getting the permission of the roles:')
            roleset = roles.union(roleChildren)
            for role in roleset:
                item = self.main.role_res_mat[role]
                for k, v in item.iteritems():
                    if v.recursive:
                        self.updateExplainText('\n Role \'%s\': -r %s'%(role, ','.join(v.perms)+' '+k))
                    else:
                        self.updateExplainText('\n Role \'%s\': %s'%(role, ','.join(v.perms)+' '+k))
        elif self.main.animationStep == 4:
            targetObj = str(self.objDirLineEdit.currentText())
            self.updateExplainText('\n- Conclusion:')
            self.updateExplainText('\n We are examining whether user \'%s\' has %s access to object \'%s\'.'%(user, ','.join(permset), targetObj))
            if not roleperms:
                self.updateExplainText('\n According to the above list, user \'%s\' does not have access to the object.\n Therefore, the answer is \'No\'.'%user)
            else:
                self.updateExplainText('\n According to the above list, user \'%s\' has %s permission to the object.'%(user, ','.join(roleperms)))
                if permset.issubset(roleperms):
                    self.updateExplainText('\n Therefore, the answer is \'Yes\'.')
                else:
                    self.updateExplainText('\n Therefore, the answer is \'No\'.')
        cursor = self.explainTextEdit.textCursor()
        cursor.movePosition(QTextCursor.End, QTextCursor.MoveAnchor)
        self.explainTextEdit.setTextCursor(cursor)  
        
    def setObjUI(self, objDir):
        self.objDir = objDir
        self.objDirLineEdit.lineEdit().setText(objDir)
            
    def addListToComboBox(self, list2Add, comboBox):
        comboBox.blockSignals(True)
        comboBox.clear()
        for i in list2Add:
            comboBox.addItem(i)
        comboBox.blockSignals(False)
        
    def addSpecObjToUI(self):
        self.objDirLineEdit.clear()
        for d in self.scene.dirNodeList:
            self.objDirLineEdit.addItem(d.getFullPath())
        self.objDir = str(self.objDirLineEdit.itemText(0))
        
    def updateUIContents(self):
        if self.main.specFileName:
            if self.questionType.currentIndex() == self.ROLEPERM_QUES:
                self.addListToComboBox(self.main.roleList, self.lineEdit11)
                self.addListToComboBox(self.main.dirList, self.objDirLineEdit)
            elif self.questionType.currentIndex() == self.USERPERM_QUES:
                self.addListToComboBox(self.main.userList, self.lineEdit11)
                self.addListToComboBox(self.main.dirList, self.objDirLineEdit)
            if self.w == None:
                self.w = FileDialog(self.main, 'Select an object', self.main.specDir)
        self.generateChoices()
            
    '''handlers'''        
    def setObjPath(self):
        if not self.main.specFileName:
            QMessageBox.critical(self.main, '', 'Please import a policy or visualization file!')
            return
        self.w.show()
#         
    def showWholePathAsHint(self, dirIndex):
        self.objDirLineEdit.setItemData(dirIndex, str(self.objDirLineEdit.itemText(dirIndex)), Qt.ToolTipRole)
        
    def random11(self):
        if not self.main.specFileName:
            QMessageBox.critical(self.main, '', 'Please import a policy or visualization file!')
            return
        index = random.randrange(self.lineEdit11.count())
        self.lineEdit11.setCurrentIndex(index)
        self.settingChanged()
    
    def randomGetPerm(self):
        if not self.main.specFileName:
            QMessageBox.critical(self.main, '', 'Please import a policy or visualization file!')
            return
        perm = random.randrange(1, 8)
        self.permLineEdit.setCurrentIndex(perm-1)
        self.settingChanged()
        
    def radioButtonSetChecked(self, rbtn, flag):
        rbtn.setAutoExclusive(False)
        rbtn.setChecked(flag)
        rbtn.setAutoExclusive(True)
        
    def rBtn1Clicked(self):
        self.chosenAnswer = 0
        self.radioButtonSetChecked(self.answerRadioBtn2, False)
        self.radioButtonSetChecked(self.answerRadioBtn3, False)
        self.radioButtonSetChecked(self.answerRadioBtn4, False)
        
    def rBtn2Clicked(self):
        self.chosenAnswer = 1
        self.radioButtonSetChecked(self.answerRadioBtn1, False)
        self.radioButtonSetChecked(self.answerRadioBtn3, False)
        self.radioButtonSetChecked(self.answerRadioBtn4, False)

    def rBtn3Clicked(self):
        self.chosenAnswer = 2
        self.radioButtonSetChecked(self.answerRadioBtn1, False)
        self.radioButtonSetChecked(self.answerRadioBtn2, False)
        self.radioButtonSetChecked(self.answerRadioBtn4, False)
        
    def rBtn4Clicked(self):
        self.chosenAnswer = 3
        self.radioButtonSetChecked(self.answerRadioBtn1, False)
        self.radioButtonSetChecked(self.answerRadioBtn2, False)
        self.radioButtonSetChecked(self.answerRadioBtn3, False)
        
    def settingChanged(self):
        self.resetAnimatedItems()
        self.main.animationStep = 0
        self.correctnessTextItem.setHtml("")
        self.explainTextEdit.clear()
        self.settingIsChanged = True
        self.nextExplainPBtn.setText('Explain')
        self.nextExplainPBtn.setStyleSheet('QPushButton {background-color: #328930;}')
        self.generateChoices()          
            
    def checkAnswer(self):
        if not self.main.specFileName:
            QMessageBox.critical(self.main, '', 'Please import a policy or visualization file!')
            return
        if self.chosenAnswer == None:
            QMessageBox.critical(self.main, '', 'Please choose an answer!')
            return
        if self.questionType.currentIndex() == self.ROLEPERM_QUES:
            if self.settingIsChanged:
                roleAccessObj, roleChildren, roleperms, permset = self.getPermForRole(str(self.lineEdit11.currentText()))
                self.answer = [roleAccessObj, roleChildren, roleperms, permset]
                self.settingIsChanged = False
        elif self.questionType.currentIndex() == self.USERPERM_QUES:
            if self.settingIsChanged:
                self.getPermForUser(str(self.lineEdit11.currentText()))
                self.settingIsChanged = False
        if not self.answer[-2]:
            answer = 1
        elif self.answer[-1].issubset(self.answer[-2]):
            answer = 0
        else:
            answer = 1
        if answer == self.chosenAnswer:
            self.correctnessTextItem.setHtml('<font color="green" size="3">Correct</font>')
        else:
            self.correctnessTextItem.setHtml('<font color="red" size="3">Wrong</font>')
            
    def updateExplainText(self, text):
        self.msg += text
        self.explainTextEdit.setText(self.msg)
        
    def explainAnswer(self):
        if str(self.nextExplainPBtn.text()) == 'End':
            self.nextExplainPBtn.setText('Explain')
            self.nextExplainPBtn.setStyleSheet('QPushButton {background-color: #328930;}')
            self.resetAnimatedItems()
            return
        if self.questionType.currentIndex() == self.ROLEPERM_QUES:
            if str(self.nextExplainPBtn.text()) == 'Explain':
                self.nextExplainPBtn.setText('Next')
                self.nextExplainPBtn.setStyleSheet('QPushButton {background-color: yellow;}')
                if not self.main.specFileName:
                    QMessageBox.critical(self.main, '', 'Please import a policy or visualization file!')
                    return
                self.msg = ''
                if self.settingIsChanged:
                    roleAccessObj, roleChildren, roleperms, permset = self.getPermForRole(str(self.lineEdit11.currentText()))
                    self.answer = [roleAccessObj, roleChildren, roleperms, permset]
                    self.settingIsChanged = False
                self.main.animationStep = 0
            self.onAnimateSelfTest_RolePerm(self.answer[0], self.answer[1], self.answer[2], self.answer[3])
            if self.main.animationStep == self.ANIMTESTEPS[self.ROLEPERM_QUES]:
                self.nextExplainPBtn.setText('End')
                self.nextExplainPBtn.setStyleSheet('QPushButton {background-color: red;}')
        elif self.questionType.currentIndex() == self.USERPERM_QUES:
            if str(self.nextExplainPBtn.text()) == 'Explain':
                self.nextExplainPBtn.setText('Next')
                self.nextExplainPBtn.setStyleSheet('QPushButton {background-color: yellow;}')
                self.msg = ''
                if self.settingIsChanged:
                    self.getPermForUser(str(self.lineEdit11.currentText()))
                    self.settingIsChanged = False
                self.main.animationStep = 0
            self.onAnimateSelfTest_UserPerm(self.answer[0], self.answer[1], self.answer[2], self.answer[3], self.answer[4])
            if self.main.animationStep == self.ANIMTESTEPS[self.USERPERM_QUES]:
                self.nextExplainPBtn.setText('End')
                self.nextExplainPBtn.setStyleSheet('QPushButton {background-color: red;}')
        self.main.animationStep += 1