'''
Created on May 10, 2016

@author: manwang
'''
from PyQt4.QtCore import *
from PyQt4.QtGui import *
import random, commonFunction
    
class SelfTestScene(QWidget):
    SLPERM_QUES = 0
    USERPERM_QUES = 1
    QUES_INFO = [['Can the users with the specified security level access the object with the specified permission?', 'Yes', 'No'],\
                 ['Can the user access the object with the specified permission?', 'Yes', 'No'],\
                ]
    
    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.interfaceQuesItems = set()
        self.interfaceTableItems = set()
        self.objDir = None
        self.subSL = None
        self.objSL = None
        self.settingIsChanged = True
        self.chosenAnswer = None
        self.answer = None
        
    def createGraphicsTextItem(self, scene, text, fontsize=20, isQuesItem = True):
        item = QGraphicsTextItem(text)
        commonFunction.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('Security Level Permission')
        self.questionType.addItem('User Permission')
        commonFunction.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(3)
        self.tableViewQuestionConf.setColumnCount(5)
        self.tableViewQuestionConf.verticalHeader().setVisible(False)
        self.tableViewQuestionConf.horizontalHeader().setVisible(False)
        '''1'''
        self.tableViewQuestionConf.clear()
        self.setCellText(1, 0, 'Security Level', QFont('Courier', 20))
        self.setCellText(2, 0, '', 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.setCellText(2,2, 'Security Level', QFont('Courier', 20))
        '''set up cell content 0,1'''
        widget = QWidget()
        hlayout = QHBoxLayout(widget)
        self.sltextItem = QLabel('Subject')
        commonFunction.setFontForUI(self.sltextItem, 20)
        self.slConfirmPBtn = QPushButton('Confirm')
        hlayout.addWidget(self.sltextItem)
        hlayout.addWidget(self.slConfirmPBtn)
        hlayout.setContentsMargins(0, 0, 0, 0)
        widget.setLayout(hlayout)
        self.tableViewQuestionConf.setCellWidget(0,1,widget)
        
        self.lineEdit11, self.randomPBtn11 = self.createLineEditAndButtonCombo(1,1)
        
        widget = QWidget()
        hlayout = QHBoxLayout(widget)
        self.objDirLineEdit = QComboBox()
        self.objDirLineEdit.setSizeAdjustPolicy(QComboBox.AdjustToContents)
        self.objDirLineEdit.setEditable(True)
        self.objDirLineEdit.completer().setCompletionMode(QCompleter.PopupCompletion)
        hlayout.addWidget(self.objDirLineEdit)
        hlayout.setContentsMargins(0, 0, 0, 0)
        widget.setLayout(hlayout)
        self.tableViewQuestionConf.setCellWidget(1,3, widget)
            
        self.permLineEdit, self.permRandomPBtn = self.createLineEditAndButtonCombo(1,4)
        '''only allow r,w'''
        for i in xrange(1, 4):
            self.permLineEdit.addItem(commonFunction.convertOctToRWXString(i))
            
        self.objDirLineEdit.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.objDirLineEdit.highlighted.connect(lambda dirIndex: self.showWholePathAsHint(dirIndex))
        self.randomPBtn11.clicked.connect(self.random11)
        self.permRandomPBtn.clicked.connect(self.randomGetPerm)
        self.slConfirmPBtn.clicked.connect(self.confirmSubSL)
        
        self.lineEdit11.editTextChanged.connect(self.settingChanged)
        self.lineEdit11.currentIndexChanged.connect(self.getSLForUser)
        self.permLineEdit.currentIndexChanged.connect(self.settingChanged)
        self.objDirLineEdit.editTextChanged.connect(self.updateFileInfo)
        
    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: ')
        commonFunction.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.SLPERM_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")
            commonFunction.setFontForUI(self.answerRadioBtn1, 25)
            self.answerRadioBtn2 = QRadioButton('No')
            self.answerRadioBtn2.setStyleSheet("background-color: white")
            commonFunction.setFontForUI(self.answerRadioBtn2, 25)
            self.answerRadioBtn3 = QRadioButton()
            self.answerRadioBtn3.setStyleSheet("background-color: white")
            commonFunction.setFontForUI(self.answerRadioBtn3, 25)
            self.answerRadioBtn4 = QRadioButton()
            self.answerRadioBtn4.setStyleSheet("background-color: white")
            commonFunction.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')
            commonFunction.setFontForUI(self.nextExplainPBtn, 25)
            self.createUIInScene(self.nextExplainPBtn)
            self.nextExplainPBtn.setStyleSheet("background-color: #328930")

            self.nextSkipPBtn = QPushButton('Check')
            commonFunction.setFontForUI(self.nextSkipPBtn, 25)
            self.createUIInScene(self.nextSkipPBtn)
            
            self.correctnessTextItem = self.createGraphicsTextItem(self.scene,'', 25)
                    
            self.explainTextEdit = QTextEdit()
            commonFunction.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.35
        self.tableViewQuestionConf.setGeometry(0, 0, self.scene.sceneRect().width(), ratio*self.scene.sceneRect().height())
        self.labelQuestion.setPos(self.scene.sceneRect().x()+10,\
                                  self.scene.sceneRect().y()+(ratio+0.01)*(self.scene.sceneRect().height()))#self.main.ui.horizontalGroupBox.geometry().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(self.scene.sceneRect().x()+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().x()+self.scene.sceneRect().width()-10-xinter, \
                                         self.scene.sceneRect().y()+self.scene.sceneRect().height()-10-yinter, \
                                         xinter, yinter)
        xinter = self.nextSkipPBtn.geometry().width()
        self.nextSkipPBtn.setGeometry(self.nextExplainPBtn.geometry().x()-xinter-10, self.nextExplainPBtn.geometry().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(), \
                                      self.scene.sceneRect().y()+(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.SLPERM_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.SLPERM_QUES:
            self.securityLevelPermUIsetting()
        elif qtype == self.USERPERM_QUES:
            self.userPermUIsetting()
        self.updateUIContents()
        self.updateLayout()
        self.settingChanged()
        
    def generateChoices(self):
        if self.questionType.currentIndex() == self.SLPERM_QUES:
            self.generateChoicesForRolePermQues()
        elif self.questionType.currentIndex() == self.USERPERM_QUES:
            self.generateChoicesForUserPermQues()
        
    def generateChoicesForRolePermQues(self):
        self.answerRadioBtn1.setText(self.QUES_INFO[self.SLPERM_QUES][1])
        self.answerRadioBtn2.setText(self.QUES_INFO[self.SLPERM_QUES][2])
    
    def generateChoicesForUserPermQues(self):
        self.answerRadioBtn1.setText(self.QUES_INFO[self.SLPERM_QUES][1])
        self.answerRadioBtn2.setText(self.QUES_INFO[self.SLPERM_QUES][2])
        
    def securityLevelPermUIsetting(self):
        '''
        0 |     1            | 2 |  3             |     4
        0 | Subject    1     | 2 | obj            | perm
        1 | SecurityLevel    |   | dir            | p
        2 |                  |   | securityLevel  | 
        '''
        self.slConfirmPBtn.setVisible(True)
        self.sltextItem.setVisible(True)
        self.tableViewQuestionConf.item(0,1).setText('')
        self.tableViewQuestionConf.item(1,0).setText('Security Level')
        self.tableViewQuestionConf.item(2,0).setText('')
        self.tableViewQuestionConf.item(0,3).setText('Object')
        self.tableViewQuestionConf.item(0,4).setText('Permission')
        self.tableViewQuestionConf.item(1,2).setText('Directory')
        self.tableViewQuestionConf.item(2,2).setText('Security Level')
        self.tableViewQuestionConf.item(2,3).setText('')
        
        self.objDirLineEdit.setVisible(True)
        self.permLineEdit.setVisible(True)
        self.permRandomPBtn.setVisible(True)
        self.labelQuestionText.setPlainText(self.QUES_INFO[self.SLPERM_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 |   security level|   | security level | 
        '''
        self.slConfirmPBtn.setVisible(False)
        self.sltextItem.setVisible(False)
        self.tableViewQuestionConf.item(0,1).setText('User')
        self.tableViewQuestionConf.item(1,0).setText('Name')
        self.tableViewQuestionConf.item(2,0).setText('Security Level')
        self.tableViewQuestionConf.item(0,3).setText('Object')
        self.tableViewQuestionConf.item(1,2).setText('Directory')
        self.tableViewQuestionConf.item(2,2).setText('Security Level')
        self.tableViewQuestionConf.item(2,3).setText('')
        self.tableViewQuestionConf.item(0,4).setText('Permission')
        self.objDirLineEdit.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()

    def resetAnimatedItems(self):
        self.main.animationStep = 0
        self.explainTextEdit.clear()
        
    def getSLForUser(self, user):
        node = None
        user = str(self.lineEdit11.currentText())
        for u in self.main.ioHelper.userNodes:
            if u.name == user:
                node = u
                if u.clrNode:
                    node = u.clrNode
        if node:
            clearance = node.clearance
            category = node.category
            if '' in category:
                category.remove('')
            flgClr = self.scene.clearances.index(clearance)
            cateNumSetStr = '('
            cateNumSet = set()
            for c in category:
                    cateNumSet.add(self.scene.categories.index(c)+1)
            cateNumSetStr += ','.join(str(c) for c in cateNumSet)
            cateNumSetStr += ')'
            self.subSL = commonFunction.SecurityLevel(flgClr, set(category))
            subSLStr = clearance+','+cateNumSetStr
            self.tableViewQuestionConf.item(2,1).setText(subSLStr)
        else:
            self.tableViewQuestionConf.item(2,1).setText('')
        self.settingChanged()
            
    def onAnimateSelfTest(self):
        if self.main.animationStep == 0:
            self.updateExplainText(self.msgAnalysis[0])
        elif self.main.animationStep < len(self.msgAnalysis):
            for i in self.msgAnalysis[self.main.animationStep]:
                self.updateExplainText(i)
        cursor = self.explainTextEdit.textCursor()
        cursor.movePosition(QTextCursor.End, QTextCursor.MoveAnchor)
        self.explainTextEdit.setTextCursor(cursor)       
    
    def updateFileInfo(self):
        '''file type'''
        self.objDir = str(self.objDirLineEdit.currentText())
        dirComponents = self.objDir.split('/')
        path = ''
        if self.objDir:
            objnode = None
            '''get object security level'''
            for d in dirComponents:
                if path != '/':
                    path += '/'
                path += d
                for f in self.main.ioHelper.add2Scene.fileNodes:
                    if path == f.fullPath:
                        objnode = f
                        break
            if objnode:
                typenode = objnode.type
                if typenode:
                    clearance = typenode.clearance
                    category = typenode.category
                    if '' in category:
                        category.remove('')
                    flgClr = self.scene.clearances.index(clearance)
                    cateNumSetStr = typenode.categoryNumStr
                    self.objSL = commonFunction.SecurityLevel(flgClr, set(category))
                    objSLStr = clearance+','+cateNumSetStr
                    self.tableViewQuestionConf.item(2,3).setText(objSLStr)
                else:
                    self.tableViewQuestionConf.item(2,3).setText('None') 
            else:
                self.tableViewQuestionConf.item(2,3).setText('None')
        self.settingChanged()
            
    def addListToComboBox(self, list2Add, comboBox):
        comboBox.blockSignals(True)
        comboBox.clear()
        for i in list2Add:
            comboBox.addItem(i)
        comboBox.blockSignals(False)
        
    def updateUIContents(self):
        if self.main.hasInfo:
            if self.questionType.currentIndex() == self.SLPERM_QUES:
                self.objDirLineEdit.blockSignals(True)
                self.objDirLineEdit.clear()
                for f in self.main.ioHelper.add2Scene.fileNodes:
                    self.objDirLineEdit.addItem(f.fullPath)
                self.objDirLineEdit.blockSignals(False)
            elif self.questionType.currentIndex() == self.USERPERM_QUES:
                for u in self.main.ioHelper.userNodes:
                    self.lineEdit11.addItem(u.name)
                self.getSLForUser(str(self.lineEdit11.currentText()))
                self.objDirLineEdit.blockSignals(True)
                self.objDirLineEdit.clear()
                for f in self.main.ioHelper.add2Scene.fileNodes:
                    self.objDirLineEdit.addItem(f.fullPath)
                self.objDirLineEdit.blockSignals(False)
            self.updateFileInfo()
        self.generateChoices()
            
    '''handlers'''        
    def showWholePathAsHint(self, dirIndex):
        self.objDirLineEdit.setItemData(dirIndex, str(self.objDirLineEdit.itemText(dirIndex)), Qt.ToolTipRole)
        
    def confirmSubSL(self):
        '''allow selection from GUI'''
        if not self.main.hasInfo:
            QMessageBox.critical(self.main, '', 'Please import a policy or visualization file!')
            return
        flgClr = self.scene.updateClrLevel()
        self.scene.updateCateCombination()
        '''flgClr, self.scene.cateClicked'''
        cateIndxSet = set()
        for c in self.scene.cateClicked:
            cateIndxSet.add(self.scene.categories.index(c))
        self.subSL = commonFunction.SecurityLevel(flgClr, set(self.scene.cateClicked))
        subSLStr = self.scene.clrClicked+',('+','.join(str(c+1) for c in cateIndxSet)+')'
        self.lineEdit11.lineEdit().setText(subSLStr)
        
    def random11(self):
        if not self.main.hasInfo:
            QMessageBox.critical(self.main, '', 'Please import a policy or visualization file!')
            return
        if self.questionType.currentIndex() == self.SLPERM_QUES:
            '''get clearance'''
            flgClr = random.randrange(len(self.scene.radioBtnList))
            self.scene.radioBtnList[flgClr].setChecked(True)
            self.scene.clrClicked = self.scene.radioBtnList[flgClr].text().remove(' ')
            ''' get cate set'''
            self.scene.cateClicked = []
            numCates = len(self.scene.categories)
            randnumOfCate = random.randint(0,numCates)
            cateIndxSet = set()
            for p in xrange(0,randnumOfCate):
                num = random.randint(0,numCates-1)
                cateIndxSet.add(num)
            for i in xrange(len(self.scene.checkBoxList)):
                if i in cateIndxSet:
                    item = self.scene.checkBoxList[i]
                    item.setChecked(True)
                    string = str(item.text().section(': ', 1))
                    self.scene.cateClicked.append(string)
                else:
                    self.scene.checkBoxList[i].setChecked(False)
            self.subSL = commonFunction.SecurityLevel(flgClr, set(self.scene.cateClicked))
            subSLStr = self.scene.clrClicked+',('+','.join(str(c+1) for c in cateIndxSet)+')'
            self.lineEdit11.lineEdit().setText(subSLStr)
        elif self.questionType.currentIndex() == self.USERPERM_QUES:
            index = random.randrange(len(self.main.ioHelper.userNodes))
            user = self.main.ioHelper.userNodes[index].name
            self.lineEdit11.lineEdit().setText(user)
            self.getSLForUser(user)
        self.settingChanged()
    
    def randomGetPerm(self):
        if not self.main.hasInfo:
            QMessageBox.critical(self.main, '', 'Please import a policy or visualization file!')
            return
        perm = random.randrange(1, 4)
        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 reanalyze(self):
        answer = set()
        self.msgAnalysis = ['- The access a subject security level has to objects is determined by the relationship of the security levels of the subject and the object...']
        if self.questionType.currentIndex() == self.USERPERM_QUES:
            temp = ['\n- The user is \'%s\'.'%str(self.lineEdit11.currentText())]
            temp.append('\n Its security level is \'%s\'.'%str(self.tableViewQuestionConf.item(2,1).text()))
        elif self.questionType.currentIndex() == self.SLPERM_QUES:
            temp = ['\n- The subject security level is:\n %s'%str(self.lineEdit11.currentText())]
        temp.append('\n- The object security level is:\n %s'%str(self.tableViewQuestionConf.item(2,3).text()))
        self.msgAnalysis.append(temp)
        
        permtxt = []
        clrDiff = self.subSL.clearance - self.objSL.clearance
        if clrDiff>0:
            permtxt.append('\n The clearance of the subject is higher than that of the object.')
        elif clrDiff == 0:
            permtxt.append('\n The clearance of the subject is the same as that of the object.')
        else:
            permtxt.append('\n The clearance of the subject is lower than that of the object.')
        if self.subSL.categoryset==self.objSL.categoryset:
            permtxt.append('\n The category of the subject is the same as that of the object.')
            if clrDiff >= 0:
                answer.add('r')
            if  clrDiff <= 0:
                answer.add('w')
        elif self.subSL.categoryset.issuperset(self.objSL.categoryset):
            permtxt.append('\n The category of the subject is a superset of that of the object.')
            if clrDiff >= 0:
                answer.add('r')
        elif self.subSL.categoryset.issubset(self.objSL.categoryset):
            permtxt.append('\n The category of the subject is a subset of that of the object.')
            if clrDiff <= 0:
                answer.add('w')
        else:
            permtxt.append('\n The category of the subject does not have inclusion relation with that of the object.')
        permstr = str(self.permLineEdit.currentText())
        perms = set(permstr)
        perms.discard('-')
        if perms.issubset(answer):
            self.answer = 0
            answertxt = 'Yes' 
        else:
            self.answer = 1
            answertxt = 'No' 
            
        self.msgAnalysis.append(permtxt)
        
        temp = []
        temp.append('\n- Conclusion:')
        temp.append('\n Given the following rules for Security level (L, C):')
        temp.append('\n  1. L_sub == L_obj and C_sub == C_obj -> The subject can read and write to the object.')
        temp.append('\n  2. L_sub >= L_obj and C_sub is a superset of C_obj -> The subject can read the object.')
        temp.append('\n  3. L_sub <= L_obj and C_sub is a subset of C_obj -> The subject can write to the object.')
        self.msgAnalysis.append(temp)
        temp = []
        permission = []
        if 'r' in answer:
            permission.append('read')
        if 'w' in answer:
            permission.append('write')
        if permission == []:
            temp.append('\n The subject has no permission to the object.')
        else:
            temp.append('\n The subject has \'%s\' permission to the object.'%(' and '.join(permission)))
        temp.append('\n Since the permission in question is %s.\n Therefore, the answer is \'%s\'.'%(permstr, answertxt))
        self.msgAnalysis.append(temp)
    
    def checkAnswer(self):
        if not self.main.hasInfo:
            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.settingIsChanged:
            self.reanalyze()
            self.settingIsChanged = False
        if self.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 str(self.nextExplainPBtn.text()) == 'Explain':
            self.nextExplainPBtn.setText('Next')
            self.nextExplainPBtn.setStyleSheet('QPushButton {background-color: yellow;}')
            if not self.main.hasInfo:
                QMessageBox.critical(self.main, '', 'Please import a policy or visualization file!')
                return
            self.msg = ''
            if self.settingIsChanged:
                self.reanalyze()
                self.settingIsChanged = False
            self.main.animationStep = 0
        self.onAnimateSelfTest()
        if self.main.animationStep == len(self.msgAnalysis):
            self.nextExplainPBtn.setText('End')
            self.nextExplainPBtn.setStyleSheet('QPushButton {background-color: red;}')
        self.main.animationStep += 1