'''
Created on Apr 4, 2014

@author: mandy
'''
from PyQt4.QtCore import *
from PyQt4.QtGui import *
from Ui_MainWindow import Ui_MainWindow
from PolicyManager import PolicyManager
from DiagramIOHelper import DiagramIOHelper
from SpecDialog import SpecDialog
from QueryWindow import QueryWindow, QueryDockWidget
from AutogradingTest import AutogradingTest
from AnswerDecryption import AnswerDecryption
from ToolBox import ToolBox, ToolBoxDockWidget
from RoleHierViewWindow import RoleHierViewDockWidget, RoleHierViewWindow
from DiagramScene import DiagramScene
from DiagramView import DiagramView
from TableView import TableView
from ComputeSpecInfo import ComputeSpecInfo
from RoleNode import RoleNode, RoleCompactNode
from EdgeItem import EdgeItem
from DirNode import DirNode
from UserNode import UserNode
from SelfTestScene import SelfTestScene
from EdgeBundleLabelNode import EdgeBundleLabelNode, BlockingCircleNode
import MyFunctions, math, os, sys, datetime

class MainWindow(QMainWindow):
    '''member variables'''
    NORMAL_MODE = 0
    HIGHLIGHT_MODE = 1
    HIGHLIGHT_NO_HIER_MODE = 2
    HIGHLIGHT_HIER_MODE = 3
    ROLE_HIGHLIGHT_PARENTS = 100
    ROLE_HIGHLIGHT_CHILDREN = 101
    ROLE_HIGHLIGHT_BOTH = 102
    QUERY_MODE = 4
    QUIZ_MODE = 5
    '''font size'''
    FONT_SIZE = 20
    '''floating query widget size'''
    WIDGET_WIDTH = 265
    
    CIRCLELAYOUT_RECTINTVEL = 30
    CIRCLELAYOUT_ANGLEINTVL = 5
    
    TASKBAR_HEIGHT = 20
    currentViewId = 0
    tableView = None
    rHierarchyView = None
    selfTestView = None
    
    numRoles, numUsers, numDirs = 0,0,0
    roleSet = set()
    userSet = set()
    dirSet = set()
    roleList = None
    userList = None
    dirList = None
    '''test spec output'''
    role_adjmat = {}
    user_role_mat = {}
    role_res_mat = {}   
                           
# user_role_mat {'sam': set(['sales']), 
#                 'charles': set(['cust']), 
#                 'dave': set(['cust', 'dev']), 
#                 'quinn': set(['qc']), 
#                 'cathy': set(['cust']), 
#                 'dot': set(['dev']), 
#                 'patty': set(['pres'])}
# 
# role_res_mat {'cust': {'/path/to/db': Permset(perms=set(['x', 'r', 'w']), recursive=False)}, 
#                 'qc': {'/path/to/tests': Permset(perms=set(['x']), recursive=False)}, 
#                 'dev': {'/path/to/tests': Permset(perms=set(['r', 'w']), recursive=False)}, 
#                 'pres': {'/path/to/evidence': Permset(perms=set(['r', 'w']), recursive=False)}, 
#                 'sales': {'/path/to/files': Permset(perms=set(['r', 'w']), recursive=True), 
#                           '/path/to/db': Permset(perms=set(['x', 'r', 'w']), recursive=False)}}
#
# role_adjmat {'cust': RoleNode(parents=set(['sales']), children=set([])), 
#                 'qc': RoleNode(parents=set(['sales', 'dev']), children=set([])), 
#                 'dev': RoleNode(parents=set(['pres']), children=set(['qc'])), 
#                 'pres': RoleNode(parents=set([]), children=set(['sales', 'dev'])), 
#                 'sales': RoleNode(parents=set(['pres']), children=set(['qc', 'cust']))}
                  
    def __init__(self):
        QMainWindow.__init__(self)
        os.chdir(os.path.dirname(os.path.abspath(sys.argv[0])))
        self.savedFileName = None
        self.diagramDir = './policies'
        self.specDir = self.diagramDir
        self.logFile = self.diagramDir+"/RBAC_log"
        self.lastOpenedDirFile = "./.RBACvisual"
        if not os.path.isdir(self.diagramDir):
            MyFunctions.make_sure_path_exists(self.diagramDir)
            
        if os.path.exists(self.lastOpenedDirFile):
            with open(self.lastOpenedDirFile, 'r') as f:
                self.currentFileDir = f.readline()
            f.close()
            self.currentFileDir = self.currentFileDir.replace('\n', '')
        else:
            self.currentFileDir = str(os.path.abspath(self.diagramDir))
            self.writeToFile(self.lastOpenedDirFile, self.currentFileDir)
        
        self.windowUISetup()
        self.initParam()
        self.currentAction = self.ui.actionView_Matrix
        self.ioHelper = DiagramIOHelper(self)
        self.specDialog = SpecDialog(self)
        self.policyManager = PolicyManager(self)
        self.autogradingTest = AutogradingTest(self)
        self.answerDecryption = AnswerDecryption(self)
        self.setupQueryWidget()
        self.setupToolBox()
        self.setupRoleHierViewDockWidget()
        self.setupConnections()
        self.roleUserNodeRadius = (RoleCompactNode.NODE_BOUNDARY_SIZE+UserNode.NODE_BOUNDARY_SIZE)*0.5
        self.extendUserRadius = 2*self.roleUserNodeRadius
        self.computeSpecsInfo()
        self.createAllViews()
        self.selfTestViewScene = SelfTestScene(self.view, self)
        self.selfTestViewScene.setVisibilityOfSceneItems(self.ui.actionView_SelfTest.isChecked())
        
        self.initLog()
#         '''import for test'''
#         self.importSpec(QString('./policies/test.rbac'))
#         self.specFileName = 'test.rbac'
#         self.setWindowTitle(self.specFileName)
#         self.selfTestViewScene.updateLayout()
#         self.selfTestViewScene.updateUIContents()
#         if self.specFileName and self.currentAction==self.ui.actionView_SelfTest:
#                 self.specDialog.show()
#                 self.specDialog.reGenerateSpec()
        self.ui.actionView_SelfTest.setChecked(True)
        self.viewModeChanged(self.ui.actionView_SelfTest)
        
    def closeEvent(self, event):
        self.writeToFile(self.logFile, 20*'-'+"Close RBACvisual   "+self.getCurrentTime()+20*'-'+"\n")
        self.specDialog.close()
        
    def quitApp(self):
        self.writeToFile(self.logFile, 20*'-'+"Close RBACvisual   "+self.getCurrentTime()+20*'-'+"\n")
        QCoreApplication.quit()
        
    def saveLastOpenedPolicyDir(self, filepath):
        self.currentFileDir = filepath[:filepath.rfind('/')]
        with open(self.lastOpenedDirFile, 'w') as f:
            f.write(self.currentFileDir)
        f.close()
        
    '''Set up main widget'''
    def setupConnections(self):
        self.viewActionGroup.triggered.connect(self.viewModeChanged)
        self.ui.actionNew.triggered.connect(self.newDiagram)
        self.ui.actionSave.triggered.connect(self.saveDiagram)
        self.ui.actionSave_As.triggered.connect(self.saveDiagramAs)
        self.ui.actionOpen.triggered.connect(self.openDiagram)
        self.ui.actionImport.triggered.connect(self.importRBCSpec)
        self.ui.actionExport.triggered.connect(self.exportToRBACSpec)
        self.ui.actionExit.triggered.connect(self.quitApp)
        self.ui.actionPan.triggered.connect(self.toggleModeForNodeMovement)
        self.ui.actionToolBox.triggered.connect(self.toggleToolBox)
        self.ui.actionSpecification.triggered.connect(self.showSpecDialog)
        self.ui.actionQuery_Window.toggled.connect(self.toggleQueryWindow)
        self.ui.actionTest.triggered.connect(self.showAutogradingTest)
        self.ui.actionDecrypt.triggered.connect(self.decryptStudentAnswerFile)
#         self.ui.actionHelp_Contents.triggered.connect(self.showHelpDialog)

        self.animationControl.clicked.connect(self.onAnimationButtonClicked)
        self.stopAnimationButton.clicked.connect(self.onAnimationStopped)
        self.scene.animationStarted.connect(self.onAnimationStarted)
        self.scene.animationStopped.connect(self.onAnimationStopped)
        self.queryWindow.animateQuery0.connect(self.scene.animateQuery0)
        self.queryWindow.animateQuery1.connect(self.scene.animateQuery1)
        self.queryWindow.animateQuery2.connect(self.scene.animateQuery2)
        self.queryWindow.animateQuery3.connect(self.scene.animateQuery3)
        self.queryWindow.animateQuery4.connect(self.scene.animateQuery4)
        self.queryWindow.animateQuery5.connect(self.scene.animateQuery5)
        self.queryWindow.animateQuery6.connect(self.scene.animateQuery6)
        self.queryWindow.animateQuery7.connect(self.scene.animateQuery7)
        self.queryWindow.animateQuery8.connect(self.scene.animateQuery8)
        self.queryWindow.animateQuery9.connect(self.scene.animateQuery9)
        
    def setupToolbar(self):
        self.ui.toolBar.addAction(self.ui.actionNew)
        self.ui.actionNew.setIcon(QIcon(QPixmap('./icons/NewFile.png')))
        self.ui.toolBar.addAction(self.ui.actionOpen)
        self.ui.actionOpen.setIcon(QIcon(QPixmap('./icons/OpenFile.png')))
        self.ui.toolBar.addAction(self.ui.actionSave)
        self.ui.actionSave.setIcon(QIcon(QPixmap('./icons/savefile.png')))
        self.ui.toolBar.addAction(self.ui.actionImport)
        self.ui.actionImport.setIcon(QIcon(QPixmap('./icons/Importfile.png')))
        self.ui.toolBar.addAction(self.ui.actionExport)
        self.ui.actionExport.setIcon(QIcon(QPixmap('./icons/Exportfile.png')))

        self.ui.toolBar.addSeparator()
        self.ui.toolBar.addAction(self.ui.actionToolBox)
        self.ui.actionToolBox.setIcon(QIcon(QPixmap('./icons/toolbox.png')))
        
        self.ui.toolBar.addAction(self.ui.actionSpecification)
        self.ui.actionSpecification.setIcon(QIcon(QPixmap('./icons/spec.png')))

        self.ui.toolBar.addAction(self.ui.actionQuery_Window)
        self.ui.actionQuery_Window.setIcon(QIcon(QPixmap('./icons/query.png')))
        self.ui.toolBar.addSeparator()
        self.ui.toolBar.addAction(self.ui.actionView_Matrix)
        self.ui.actionView_Matrix.setIcon(QIcon(QPixmap('./icons/matrixView.png')))

        self.ui.toolBar.addAction(self.ui.actionView_Separate)
        self.ui.actionView_Separate.setIcon(QIcon(QPixmap('./icons/hierView.png')))
        
        self.ui.toolBar.addAction(self.ui.actionView_SelfTest)
         
        self.ui.toolBar.addSeparator()
        self.ui.toolBar.addAction(self.ui.actionPan)
        self.ui.actionPan.setIcon(QIcon(QPixmap('./icons/pan.png')))
         
        self.viewActionGroup = QActionGroup(self)
        self.viewActionGroup.addAction(self.ui.actionView_Matrix)
        self.viewActionGroup.addAction(self.ui.actionView_rHierarchy)
        self.viewActionGroup.addAction(self.ui.actionView_Separate)
        self.viewActionGroup.addAction(self.ui.actionView_SelfTest)
                
        self.ui.toolBar.addSeparator()
        self.animationControl = QToolButton()
        self.animationControl.setIcon(QIcon(QPixmap('./icons/images/pause.png')))
        self.animationControl.setDisabled(True)
        self.stopAnimationButton = QToolButton()
        self.stopAnimationButton.setIcon(QIcon(QPixmap('./icons/images/stop.png')))
        self.stopAnimationButton.setDisabled(True)
        self.ui.toolBar.addWidget(self.animationControl)
        self.ui.toolBar.addWidget(self.stopAnimationButton)
        
    def setupUi(self):
        self.ui = Ui_MainWindow()
        self.ui.setupUi(self)
        self.setupToolbar()
        
    def windowUISetup(self):
        startX = 0.5*(QApplication.desktop().availableGeometry().width()-self.geometry().width())
        startY = 0.5*(QApplication.desktop().availableGeometry().height()-self.geometry().height())
        self.move(QPoint(startX, startY))
        self.setupUi()
        self.setWindowTitle(str('RBACvisual'))
        
        '''VIEW SPLITTER'''
        self.ui.viewSplitter = QSplitter(Qt.Horizontal, self.centralWidget())
        self.scene = DiagramScene(self)
        self.view = DiagramView(self.scene, self.ui.viewSplitter)
        self.view.setScene(self.scene)
        self.view.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
        self.view.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
        self.center = QPointF(0.5*self.geometry().width(), 0.5*self.geometry().height()-30-4)
        
        self.sceneRight = DiagramScene(self)
        self.sceneRight.viewId = DiagramScene.SPLIT_VIEW_RIGHT
        self.childrenViewRight = DiagramView(self.sceneRight, self.ui.viewSplitter)
        self.childrenViewRight.setScene(self.sceneRight)
        self.childrenViewRight.setBackgroundBrush(QBrush(QColor(255, 240, 240), Qt.SolidPattern))
        self.childrenViewRight.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
        self.childrenViewRight.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
        self.childrenViewRight.hide()
        self.ui.viewSplitter.addWidget(self.view)
        self.ui.viewSplitter.addWidget(self.childrenViewRight)
                           
    def setupQueryWidget(self):
        self.queryWindowDockWidget = QueryDockWidget(self)
        self.queryWindow = QueryWindow(self.scene, self)
        self.queryWindowDockWidget.setWidget(self.queryWindow)
        self.addDockWidget(Qt.RightDockWidgetArea, self.queryWindowDockWidget)
        self.queryWindowDockWidget.setVisible(False)
        
    '''Separate view Leftside ToolBox'''
    def setupToolBox(self):
        self.toolBoxDockWidget = ToolBoxDockWidget(self)
        self.toolBox = ToolBox(self, self.toolBoxDockWidget)
        self.toolBoxDockWidget.setWidget(self.toolBox)
        self.addDockWidget(Qt.LeftDockWidgetArea, self.toolBoxDockWidget)
        self.toolBoxDockWidget.setVisible(False)

    '''Role Hierarchy View Rightside widget'''
    def setupRoleHierViewDockWidget(self):
        self.roleHierViewDockWidget = RoleHierViewDockWidget(self)
        self.roleHierViewWindow = RoleHierViewWindow(self.scene, self)
        self.roleHierViewDockWidget.setWidget(self.roleHierViewWindow)
        self.roleUserWindow = self.roleHierViewWindow.ui.roleUserGroupBox
        self.rolePermWindow = self.roleHierViewWindow.ui.rolePermGroupBox
        self.addDockWidget(Qt.RightDockWidgetArea, self.roleHierViewDockWidget)
        self.roleHierViewDockWidget.setVisible(False)
    
    '''Animation'''
    def toggleAnimation(self, state):
        if state == Qt.Checked:
            self.queryWindow.animationEnabled = True
        else:
            self.queryWindow.animationEnabled = False
            
    def setAnimationInterval(self):
        interval, accept = QInputDialog.getInt(self, 'Set Interval', '', value=self.scene.timerInterval/1000, min=1, max=10, step=1)
        if accept:
            self.scene.timerInterval = interval * 1000
            
    def onAnimationStarted(self):
        self.queryWindow.ui.runQueryButton.setDisabled(True)
        self.animationControl.setEnabled(True)
        self.stopAnimationButton.setEnabled(True)
    
    def onAnimationStopped(self):
        self.queryWindow.ui.runQueryButton.setEnabled(True)
        self.animationControl.setDisabled(True)
        self.stopAnimationButton.setDisabled(True)
        self.animationControl.setIcon(QIcon(QPixmap('./icons/images/pause.png')))
        if self.scene.animationTimer.isActive():
            self.scene.animationStep = 0
            self.scene.animationTimer.setInterval(5000)
            self.scene.message = ''
            self.scene.animationTimer.stop()
            for item in self.scene.items():
                if item.highlighted:
                    item.highlighted = False
            self.scene.update()
            
    def onAnimationButtonClicked(self):
        if self.scene.animationTimer.interval() == 9000000:
            self.animationControl.setIcon(QIcon(QPixmap('./icons/images/pause.png')))
            self.scene.animationTimer.setInterval(self.scene.timerInterval)
        else:
            self.animationControl.setIcon(QIcon(QPixmap('./icons/images/start.png')))
            self.scene.animationTimer.setInterval(9000000)
            
    ''' User statistics'''
    def getCurrentTime(self):
        return str(datetime.datetime.now())
    
    def initLog(self):
        self.writeToFile(self.logFile, '\n'+20*'-'+"Start RBACvisual"+self.getCurrentTime()+20*'-'+"\n")
        message = self.scene.stuInfo+"\n"
        self.writeToFile(self.logFile, message)
    
    def writeToFile(self, filename, message):
        with open(filename, 'a+') as f:
            f.write(message)
        f.close()
        
    def getCurrentTimeString(self):
        return self.getCurrentTime()+': '
    
    '''I/O functions'''
    def maybeSave(self):
#         if not self.undoStack.isClean():
#             ret = QMessageBox.warning(self, '', 'The diagram has been modified. Do you want to save your changes', 
#                                       buttons=QMessageBox.Save|QMessageBox.Discard|QMessageBox.Cancel, 
#                                       defaultButton=QMessageBox.Save)
#             if ret == QMessageBox.Save:
#                 return self.saveDiagram()
#             elif ret == QMessageBox.Discard:
#                 self.undoStack.setClean()
#                 return True
#             elif ret == QMessageBox.Cancel:
#                 return False
        return True
    
    def newDiagram(self):
        self.maybeSave()
        self.initParam()
        self.tableView.tableViewRoleUser.model().clear()
        self.tableView.tableViewRolePerm.model().clear()
        self.scene.clear()
        self.sceneRight.clear()
        self.updateAllScenes()
        self.currentAction = self.ui.actionView_Matrix
        self.dirNodesHierarchy, self.dirNodes = self.computeSpec.getDirHierarchy(self.dirList)
        self.numLeafDirs = len(self.dirNodesHierarchy[-1])
        self.createRHierarchyView()
        self.createSeparateView()
        self.toolBox.ui.getContentForComboBox()
        self.resizeViews()
        self.initInterface()
        self.ui.actionView_Matrix.setChecked(True)
        self.currentAction = self.ui.actionView_Matrix
        '''Collect user operation data'''
        self.writeToFile(self.logFile, 50*'-'+'\n')
        self.writeToFile(self.logFile, self.getCurrentTimeString()+"New diagram\n")
        
    def importSpec(self, filename):
        if not filename.isEmpty():
            self.specDir = QFileInfo(filename).absolutePath()
            self.initParam()
            try:
                self.user_role_mat, self.role_res_mat, self.role_adjmat = self.ioHelper.import_(str(filename))
#                 print self.user_role_mat
#                 print self.role_res_mat
#                 print self.role_adjmat
                self.saveLastOpenedPolicyDir(str(filename))
                '''Collect user operation data'''
                message = self.getCurrentTimeString()+"Import RBAC spec file: "+str(filename)+"\n"+50*'*'+'\n'
                lines = []
                with open(str(filename), 'r') as f:
                    lines = f.readlines()
                f.close()
                message+='\n'.join(lines)
                self.writeToFile(self.logFile, message+"\n"+50*'*'+"\n")
                self.computeSpecsInfo()
                self.createAllViews()
            except Exception as e:
                self.writeToFile(self.logFile, "Import Failed!\n")
                QMessageBox.critical(self, 'Error', str(e))
                return
            self.writeToFile(self.logFile, "Import Succeeded!\n")
            self.updateAllScenes()
            self.initInterface()   
            
    def importRBCSpec(self):
        self.maybeSave()
        filename = QFileDialog.getOpenFileName(self, 'Import from RBAC Spec', directory=self.currentFileDir, filter='(*.rbac);;All Files(*.*)')
        self.importSpec(filename)
        self.specFileName = str(filename).split('/')[-1]
        self.setWindowTitle(self.specFileName)
        self.selfTestViewScene.updateLayout()
        self.selfTestViewScene.updateUIContents()
        if self.specFileName and self.currentAction==self.ui.actionView_SelfTest:
                self.specDialog.show()
                self.specDialog.reGenerateSpec()
        
    def exportToRBACSpec(self):
        self.emptyHintContent()
        filename = QFileDialog.getSaveFileName(self, 'Export to RBAC Specification file', directory=self.currentFileDir, filter='(*.rbac);;All Files(*.*)')
        if not filename.isEmpty():
            self.specDir = QFileInfo(filename).absolutePath()
            self.specFileName = str(filename).split('/')[-1]
            message = self.getCurrentTimeString()+"Export RBAC spec to file "+str(filename)+'\n'
            self.writeToFile(self.logFile, message)
            try:
                self.ioHelper.export(str(filename))
            except Exception as e:
                self.writeToFile(self.logFile, "Export Failed!\n")
                QMessageBox.critical(self, 'Error', str(e))
                return
            self.writeToFile(self.logFile, "Export Succeeded!\n")
            self.saveLastOpenedPolicyDir(str(filename))
    
    def saveDiagram(self):
        self.emptyHintContent()
        filename = QFileDialog.getSaveFileName(self, 'Save to RBAC Visualization File', directory=self.currentFileDir, filter='(*.rbacvis);;All Files(*.*)')
        if not filename.isEmpty():
            self.diagramDir = QFileInfo(filename).absolutePath()
            '''Collect user operation data'''
            self.writeToFile(self.logFile, self.getCurrentTimeString()+"Save RBAC vis file\n")
            try:
                if self.savedFileName is not None:
                    self.ioHelper.write(str(filename))
                    self.writeToFile(self.logFile, 'Save Succeeded!\n')
                    self.writeToFile(self.logFile, 50*'-'+'\n')
                    self.saveLastOpenedPolicyDir(str(self.savedFileName))
                else:
                    self.saveDiagramAs()
            except Exception as e:
                self.writeToFile(self.logFile, 'Save Failed!\n')
                self.writeToFile(self.logFile, 50*'-'+'\n')
                QMessageBox.critical(self, 'Error', str(e))
                return
            
    def setWindowTitleAsFilename(self, filepath):
        filename = filepath.split('/')[-1]
        self.setWindowTitle(filename)
        
    def saveDiagramAs(self):
        filename = QFileDialog.getSaveFileName(self, 'Save Diagram As...', directory=self.currentFileDir, filter='(*.rbacvis)')
        if not filename.isEmpty():
            self.diagramDir = QFileInfo(filename).absolutePath()
            self.ioHelper.write(str(filename))
            self.savedFileName = str(filename)
            self.setWindowTitleAsFilename(str(filename))
            '''Collect user operation data'''
            self.writeToFile(self.logFile, self.getCurrentTimeString()+"Save RBAC vis file\n")
            self.writeToFile(self.logFile, 50*'-'+'\n')
            '''Store last spec/vis file location'''
            self.saveLastOpenedPolicyDir(str(filename))
    
    def openDiagram(self):
        #self.maybeSave()
        self.emptyHintContent()
        filename = QFileDialog.getOpenFileName(self, 'Open Diagram', directory=self.currentFileDir, filter='(*.rbacvis);;All Files(*.*)')
        if not filename.isEmpty():
            self.diagramDir = QFileInfo(filename).absolutePath()
            self.initParam()
            try:
                self.ioHelper.read(str(filename))
            except Exception as e:
                QMessageBox.critical(self, 'Error', str(e))
                return
            self.specFileName = str(filename).split('/')[-1]
            self.setWindowTitle(self.specFileName)
            self.updateAllScenes()
            self.initInterface()
            self.saveLastOpenedPolicyDir(str(filename))
            message = self.getCurrentTimeString()+"Open RBAC vis file: "+str(filename)+"\n"+50*'*'+'\n'
            lines = []
            with open(str(filename), 'r') as f:
                lines = f.readlines()
            f.close()
            message+='\n'.join(lines)
            self.writeToFile(self.logFile, message+"\n"+50*'*'+"\n")
            
    
    def setMainWindowAllGuiState(self, state):
        self.ui.toolBar.setEnabled(state)
        self.queryWindowDockWidget.setEnabled(state)
        self.toolBoxDockWidget.setEnabled(state)
        self.ui.menubar.setEnabled(state)
        
    '''View functions'''
    def resizeEvent(self, event):
        QMainWindow.resizeEvent(self, event)
        self.roleHierViewWindow.resizeEvent(event)
        self.resizeViews()
        
    def toggleModeForNodeMovement(self):
        if self.ui.actionPan.isChecked():
            self.writeToFile(self.logFile, self.getCurrentTimeString()+"Pan for Node Movement on\n")
            self.nodeMove = True
            if self.mode == self.NORMAL_MODE:
                self.policyManager.highlightAllNodes()
        else:
            self.writeToFile(self.logFile, self.getCurrentTimeString()+"Pan for Node Movement off\n")
            self.nodeMove = False
        if self.specDialog.isVisible():
            self.specDialog.reGenerateSpec()
        self.updateAllScenes()
        self.hintForMoveNode()
        
    def changeViewSizeForSeparateView(self):
        self.view.setGeometry(0,0,0.5*self.ui.viewSplitter.geometry().width(), self.ui.viewSplitter.geometry().height())
        self.childrenViewRight.setGeometry(0.5*self.ui.viewSplitter.geometry().width(),0,0.5*self.ui.viewSplitter.geometry().width(), self.ui.viewSplitter.geometry().height())
        self.scene.setSceneRect(QRectF(self.view.geometry()))
        self.sceneRight.setSceneRect(QRectF(self.childrenViewRight.geometry()))
        currentSizes = self.ui.viewSplitter.sizes()
        currentSizes[0] = 0.5*self.ui.viewSplitter.geometry().width()
        currentSizes[1] = 0.5*self.ui.viewSplitter.geometry().width()
        self.ui.viewSplitter.setSizes(currentSizes)

    def changeViewSizeForMainView(self):
        self.view.setGeometry(0,0,self.centralWidget().geometry().width(), self.centralWidget().geometry().height())
        self.scene.setSceneRect(0, 0, self.view.geometry().width(), self.view.geometry().height())
        
    def resizeViews(self):
        self.ui.viewSplitter.setGeometry(0, 0, self.centralWidget().geometry().width(), self.centralWidget().geometry().height())
        if self.scene.displaySeparate:
            self.changeViewSizeForSeparateView()
        else:
            self.changeViewSizeForMainView()
        self.view.centerOn(0.5*self.view.viewport().width(), 0.5*self.view.viewport().height())
        self.updateAllItemPos()
        if self.scene.displayMatrixView:
            if self.tableView:
                self.tableView.resize(self.view.geometry())
        elif self.scene.displaySelfTest:
            self.selfTestViewScene.updateLayout()
        elif self.scene.displaySeparate:
            if isinstance(self.clickedNode, UserNode):
                self.updateAllUserNodesConsiderClickRelated()
            else:
                self.updateUserNodePositionsCircular()
        self.updateEdgePositions()
        self.updateAllScenes()
        
    def updateAllItemPos(self): 
        for i in self.scene.items():
            if isinstance(i, RoleNode) or isinstance(i, RoleCompactNode):
                i.setPos(QPointF(i.relativeX*self.scene.sceneRect().width(), i.relativeY*self.scene.sceneRect().height()))
        for i in self.sceneRight.items():
            if isinstance(i, DirNode):
                i.setPos(QPointF(i.relativeX*self.sceneRight.sceneRect().width()+self.scene.sceneRect().width(), i.relativeY*self.sceneRight.sceneRect().height()))
                
    def setVisibilitySeparateView(self, flag):
        for i in self.scene.items():
            if isinstance(i, RoleCompactNode):
                i.setVisible(flag)
            elif isinstance(i, UserNode):
                i.setVisible(flag)
            elif isinstance(i, EdgeItem) and (i.type == EdgeItem.SEPARATE_ROLE_CONN or\
                                               i.type == EdgeItem.SEPARATE_ROLEUSER_CONN or\
                                               (i.type == EdgeItem.IMPLICIT_ROLE_CONN)):# and self.mode == self.NORMAL_MODE)):
                i.setVisible(flag)
        for i in self.sceneRight.items():
            if isinstance(i, DirNode):
                i.setVisible(flag)
            elif isinstance(i, EdgeItem) and i.type == EdgeItem.SEPARATE_DIR_CONN:
                i.setVisible(flag)
    
    def checkImplicitEnableFlag(self):
        self.hasSolidEdgeFlag = False
        if self.role_adjmat != {}:
            self.hasSolidEdgeFlag = True
                      
    def viewModeChanged(self, action):
        self.updateToolbarEdit(action)
        self.currentAction = action
        self.selfTestViewScene.setVisibilityOfSceneItems(self.ui.actionView_SelfTest.isChecked())
        if action is self.ui.actionView_Matrix:
            self.writeToFile(self.logFile, self.getCurrentTimeString()+"Switch to Matrix View\n")
            self.scene.enableView(0)
            self.setVisibilitySeparateView(False)
            self.specDialog.hide()
        elif action is self.ui.actionView_Separate:
            self.writeToFile(self.logFile, self.getCurrentTimeString()+"Switch to Hierarchy View\n")
            self.scene.enableView(3)
            self.setVisibilitySeparateView(True)
            self.specDialog.hide()
        elif action is self.ui.actionView_SelfTest:
            self.scene.enableView(1)
            self.setVisibilitySeparateView(False)
            if self.specFileName:
                self.specDialog.show()
                self.specDialog.reGenerateSpec()
        self.resizeViews()
        self.hintForViewStatus()
        
    def updateMatrixView(self):
        self.tableView.updateRoleUserTableView()
        self.tableView.updateRolePermTableView()
            
    def createMatrixView(self):
        if self.tableView:
            self.updateMatrixView()
        else:
            self.tableView = TableView(self.view, self)

    def createRHierarchyView(self):
        self.checkImplicitEnableFlag()
        for r in self.roleList:
            self.policyManager.createRoleNode(r)
            self.policyManager.createRoleCompactNode(r)
             
        for r in self.roleNodes:
            for c in self.roleNodes:
                if c.name in r.children:
                    self.policyManager.createEdgeForRoleHier(r, c)
                if r.parents == set([]):
                    MyFunctions.addItemToDict(self.roleHier, 0, r)
                     
        for r in self.roleCompactNodes:
            for c in self.roleCompactNodes:
                if c.name in r.children:
                    self.policyManager.createEdgeForRoleCompactHier(r, c)
                if r.parents == set([]):
                    MyFunctions.addItemToDict(self.roleCompactHier, 0, r)
                    
    def removeAllImplicitEdges(self):
        for e in self.scene.items():
            if isinstance(e, EdgeItem) and e.type == EdgeItem.IMPLICIT_ROLE_CONN:
                self.scene.removeItem(e)
                del e
                
    def constructImplicitRoleRelation(self, nodeList):
#         if self.mode == self.QUIZ_MODE:
#             return
        self.removeAllImplicitEdges()
        for r in nodeList:
            r.possibleParentNodes = set()
            r.possibleChildrenNodes = set()
        for r in nodeList:
            for ar in nodeList:
                if ar != r:
                    if ar.userNodes==[] and r.userNodes==[] and ar.dirNodes==[] and r.dirNodes==[]:
                        continue 
                    userIsSubset = self.queryWindow.queryRoleUsersSubset(r.name, ar.name)
                    permissionIsSubset = self.queryWindow.queryRolePermSubset(ar.name, r.name)
                    #r inherits ar, so in graph r is the parent of ar
                    if (userIsSubset and permissionIsSubset) \
                        and ar not in r.allChildrenNodes \
                        and r not in ar.allParentNodes:
                        ar.possibleParentNodes.add(r)
                        r.possibleChildrenNodes.add(ar)
                        edge = EdgeItem(EdgeItem.IMPLICIT_ROLE_CONN, r, ar, self)
                        self.scene.addItem(edge)
            self.policyManager.removeTransitiveEdges(self.roleCompactNodes, True)
            
                        
    def constructHierarchyForRoleNodes(self, nodeList, hierarchyDict):      
        visited = []
        for r in nodeList:
            group = self.computeSpec.breadthFirstSearch(self.role_adjmat, r)
            if group not in visited:
                visited.append(group)
        self.getHier(visited, hierarchyDict)
        for r in self.roleCompactNodes:
            self.computeSpec.getAllParentNodesForRoleNode(r)
            self.computeSpec.getAllChildrenNodesForRoleNode(r)
    #else:
        self.constructImplicitRoleRelation(self.roleCompactNodes)
        self.constructHierarchyOnHierAndImplicitHier()
        
    def getHier(self, visited, hierarchyDict):
        currentLevel = 0
        '''construct node hierarchy based on groups'''
        for g in visited:
            start = list(g)[0]
            frontier = [start]
            newvisited = set([start])
            hier = [set([start])]
            hierDict = {}
            nodesinhier = set([start])
            while frontier:
                r = frontier.pop(0)
                newvisited.add(r)
                
                index = MyFunctions.indexofSetInListcontainItem(r, hier)
                if r.parentNodes!=set():
                    parentset = r.parentNodes-nodesinhier
                    if index == 0:
                        hier.insert(0, parentset)
                        index+=1
                    else:
                        hier[index-1] = hier[index-1].union(parentset)
                if r.childrenNodes!=set():
                    childrenset = r.childrenNodes-nodesinhier
                    if index == len(hier)-1:
                        hier.append(childrenset)
                    else:
                        hier[index+1] = hier[index+1].union(childrenset)#r.childrenNodes)
                frontier.extend(r.parentNodes.union(r.childrenNodes)-newvisited)
                for item in hier:
                    nodesinhier = nodesinhier.union(item)
            for i in hier:
                if i == set():
                    hier.remove(i)
            for i in xrange(len(hier)):
                #hier[i] = sorted(hier[i], key=lambda r: r.name) 
                hierDict[i] = list(hier[i])
            hierarchyDict[currentLevel] = hierDict
            currentLevel += 1
        '''find all cycles in graph'''
#         for g in visited:
#             for r in list(g):
#                 initial_path = []
#                 initial_path.append(r)
#                 self.computeSpec.find_paths_with_cycles(initial_path)
#         print self.cycles
#         '''
#         construct hierarchy
#         '''
#         currentLevel = 0
#         nodecount = 0
#         while nodecount < len(nodeList):
#             for r in hierarchyDict[currentLevel]:
#                 nodecount += 1
#                 for c in r.childrenNodes:
#                     MyFunctions.addItemToDict(hierarchyDict, currentLevel+1, c)
#             currentLevel += 1

    def getImplicitHier(self, visited, hierarchyDict):
        currentLevel = 0
        '''construct node hierarchy based on groups'''
        for g in visited:
            start = list(g)[0]
            frontier = [start]
            newvisited = set([start])
            hier = [set([start])]
            hierDict = {}
            nodesinhier = set([start])
            while frontier:
                r = frontier.pop(0)
                newvisited.add(r)
                
                index = MyFunctions.indexofSetInListcontainItem(r, hier)
                if r.possibleParentNodes!=set():
                    parentset = r.possibleParentNodes-nodesinhier
                    if index == 0:
                        hier.insert(0, parentset)
                        index+=1
                    else:
                        hier[index-1] = hier[index-1].union(parentset)
                if r.possibleChildrenNodes!=set():
                    childrenset = r.possibleChildrenNodes-nodesinhier
                    if index == len(hier)-1:
                        hier.append(childrenset)
                    else:
                        hier[index+1] = hier[index+1].union(childrenset)#r.childrenNodes)
                frontier.extend(r.possibleParentNodes.union(r.possibleChildrenNodes)-newvisited)
                for item in hier:
                    nodesinhier = nodesinhier.union(item)
            for i in hier:
                if i == set():
                    hier.remove(i)
            for i in xrange(len(hier)):
                #hier[i] = sorted(hier[i], key=lambda r: r.name) 
                hierDict[i] = list(hier[i])
            if hierDict not in hierarchyDict.values():
                hierarchyDict[currentLevel] = hierDict
                currentLevel += 1
            
    def constructHierarchyOnHierAndImplicitHier(self):
        self.roleCompactCompleteHier = {}
        roots = set()
        if not self.hasSolidEdgeFlag:
            for r in self.roleCompactNodes:
                if not r.possibleParentNodes:
                    roots.add(r)
            visited = []
            for r in roots:
                group, queue = set(), [r]
                while queue:
                    vertex = queue.pop(0)
                    if vertex not in group:
                        group.add(vertex)
                        connected = vertex.possibleChildrenNodes
                        queue.extend(connected-group)
                if group not in visited:
                    visited.append(group)
            self.getImplicitHier(visited, self.roleCompactCompleteHier)
            
    def updateEdgePositions(self):
        for e in self.scene.items():
            if isinstance(e, EdgeItem):
                e.updatePosition()
        for e in self.sceneRight.items():
            if isinstance(e, EdgeItem):
                e.updatePosition()
                
    def updateUserNodesPosOfRoleNode(self, r):
        if r.userNodes:
                angle = 0
                intervalAngle = 2*math.pi/len(r.userNodes)
                for u in r.userNodes:
                    if u.highlighted and self.mode == self.HIGHLIGHT_MODE:
                        radius = self.extendUserRadius
                    else:
                        radius = self.roleUserNodeRadius
                    u.angle2Rolenode = angle
                    u.setPos(r.pos().x()+radius*math.cos(angle), r.pos().y()+radius*math.sin(angle))
                    angle+=intervalAngle
                    
    def updateUserNodePositionsCircular(self):
        for r in self.roleCompactNodes:
            self.updateUserNodesPosOfRoleNode(r)
    
    def setPermInfoInRoleHierView(self):
        rolenodes = []
        tempClickedNodes = self.clickedRelatedNodes
        tempClickedNodes.append(self.clickedNode)
        for r in self.roleCompactNodes:
            if r not in tempClickedNodes:
                if r.highlighted:
                    rolenodes.append(r)
        for r in rolenodes:
            for d in r.dirNodes:
                d.highlighted = True
                if self.role_res_mat[r.name][d.dir][1]:
                    if d not in tempClickedNodes:
                        d.recursive = True
                        for dd in d.allchildren:
                            dd.highlighted = True
                            if dd not in tempClickedNodes:
                                dd.recursive = True
        self.setPermText()
                        
    def setPermText(self):            
        rolenodes = []
        lines = []
        if isinstance(self.clickedNode, RoleCompactNode) or isinstance(self.clickedNode, RoleNode):
            rolenodes.append(self.clickedNode)
        for item in self.clickedRelatedNodes:
            if isinstance(item, RoleCompactNode):
                rolenodes.append(item)
        for r in self.role_res_mat.keys():
            objList, permIter, permissions, permissionStrings, completePermStringList = self.computeSpec.getObjPermForRole(r)
            for i in xrange(len(objList)):
                flag, rnode = self.specDialog.checkNodeWithNameInList(r, rolenodes)
                if flag:
                    lines.append(r+": "+permissionStrings[i]+" "+completePermStringList[0][i])       
        if isinstance(self.clickedNode, DirNode):
            temp = []
            for e in lines:
                if e.find(self.clickedNode.dir)!=-1:
                    temp.append(e)
            lines=temp
        self.roleHierRightPerm = "\n".join(lines)
                
    def evenlyLayout(self, scene, hierarchyDict):
        direction = 1
        numGraphs = len(hierarchyDict)
        if numGraphs>0:
            view_w, view_h = scene.sceneRect().width()/numGraphs, scene.sceneRect().height()
            for k, h in hierarchyDict.iteritems():
                intvl_h = (view_h-30)/(len(h)+1)
                height = 0.2*view_h
                for key, value in h.iteritems():
                    startX = k*view_w
                    intvl_w = view_w/(len(h[key])+1)
                    if len(h[key]) == 1:
                        intvl_w = 0.5*view_w
                    if len(h[key]) > 3:
                        flucY = 20
                    else:
                        flucY = 0
                    for r in h[key]:
                        startX += intvl_w
                        r.setPos(QPointF(startX, height+direction*flucY))
                        r.relativeX = startX/self.scene.sceneRect().width()
                        r.relativeY = r.pos().y()/self.scene.sceneRect().height()
                        direction *= -1
                    height += intvl_h

    def evenlyLayoutNestedList(self, scene, hierarchyList):
        direction = -1
        view_w, view_h = scene.sceneRect().width(), scene.sceneRect().height()
        intvl_h = (view_h-30)/(len(hierarchyList)+1)
        height = 0.2*view_h
        for key in xrange(len(hierarchyList)):
            width = scene.sceneRect().width()
            intvl_w = view_w/(len(hierarchyList[key])+1)
            if len(hierarchyList[key]) == 1:
                intvl_w = 0.5*view_w
            if len(hierarchyList[key]) > 3:
                flucY = 16
            else:
                flucY = 0
            for r in hierarchyList[key]:
                width += intvl_w
                r.setPos(QPointF(width, height+direction*flucY))
                r.relativeX = (width-scene.sceneRect().width())/self.sceneRight.sceneRect().width()
                r.relativeY = r.pos().y()/self.sceneRight.sceneRect().height()
                direction *= -1
            height += intvl_h
                
    def createCoterieView(self):
        '''create the pi'''
        numUnits = self.numLeafDirs+self.numRoles+self.numUsers
        #print numUnits, self.numLeafDirs,self.numRoles,self.numUsers
        self.angleInterval = (360-3*self.CIRCLELAYOUT_ANGLEINTVL)/numUnits  
        #self.angleInterval = (360*16-3*self.CIRCLELAYOUT_ANGLEINTVL)/numUnits     
        labelNode = EdgeBundleLabelNode(self.scene, 'Users', None)
        #if center.x() > center.y():
        radius = self.center.y()
        rect = QRectF(self.center.x()-radius, 2, 2*radius, 2*radius)
#         else:
#             radius = center.x()-4
#             rect = QRectF(2, 2, 2*radius, 2*radius)
  
        #user nodes
        angleStart = 0
        angleSpan = self.numUsers*self.angleInterval
        labelNode.setPosition(rect, angleStart, angleSpan)
        #self.labelNode = labelNode
        self.scene.addItem(labelNode)
        self.labelUserNodes.append(labelNode)
        
        innerrect = QRectF(rect.x()+self.CIRCLELAYOUT_RECTINTVEL, rect.y()+self.CIRCLELAYOUT_RECTINTVEL, rect.width()-2*self.CIRCLELAYOUT_RECTINTVEL, rect.height()-2*self.CIRCLELAYOUT_RECTINTVEL)
        for i in xrange(len(self.userList)):
            labelNode = EdgeBundleLabelNode(self.scene, self.userList[i], None)
            labelNode.setPosition(innerrect, angleStart+i*self.angleInterval, self.angleInterval)
            self.scene.addItem(labelNode)
            self.labelUserNodes.append(labelNode)
#         innerrect = QRectF(innerrect.x()+self.CIRCLELAYOUT_RECTINTVEL, innerrect.y()+self.CIRCLELAYOUT_RECTINTVEL, innerrect.width()-2*self.CIRCLELAYOUT_RECTINTVEL, innerrect.height()-2*self.CIRCLELAYOUT_RECTINTVEL)
#         blockNode = BlockingCircleNode(innerrect, angleStart, angleSpan)
#         self.scene.addItem(blockNode)

        #role nodes
        labelNode = EdgeBundleLabelNode(self.scene, 'Roles', None)
        angleStart += angleSpan+self.CIRCLELAYOUT_ANGLEINTVL
        angleSpan = self.numRoles*self.angleInterval
        labelNode.setPosition(rect, angleStart, angleSpan)
        self.scene.addItem(labelNode)
        self.labelRoleNodes.append(labelNode)
        
        for i in xrange(len(self.roleList)):
            labelNode = EdgeBundleLabelNode(self.scene, self.roleList[i], None)
            labelNode.setPosition(innerrect, angleStart+i*self.angleInterval, self.angleInterval)
            self.scene.addItem(labelNode)
            self.labelRoleNodes.append(labelNode)
            
        #dir nodes
        labelNode = EdgeBundleLabelNode(self.scene, 'Directories', None)
        angleStart += angleSpan+self.CIRCLELAYOUT_ANGLEINTVL
        angleSpan = -angleStart+355
        angleInter = angleSpan/self.numLeafDirs
        labelNode.setPosition(rect, angleStart, angleSpan)
        self.scene.addItem(labelNode)
        self.labelDirNodes.append(labelNode)
        
        self.dirNodesChildrenNumList = [[0]*len(self.dirNodesHierarchy[-1])]
        for i in xrange(len(self.dirNodesHierarchy)-2, -1, -1):
            tempList = []
            for d in self.dirNodesHierarchy[i]:
                num = 0
                for p in d.children:
                    if p.children == []:
                        num += 1
                for m in xrange(len(self.dirNodesHierarchy[i+1])):
                    c = self.dirNodesHierarchy[i+1][m]
                    if c in d.children:
                        num += self.dirNodesChildrenNumList[0][m]
                tempList.append(num)
            self.dirNodesChildrenNumList.insert(0, tempList)

        for i in xrange(len(self.dirNodesHierarchy)):
            innerrect = QRectF(rect.x()+(i+1)*self.CIRCLELAYOUT_RECTINTVEL, rect.y()+(i+1)*self.CIRCLELAYOUT_RECTINTVEL, rect.width()-2*(i+1)*self.CIRCLELAYOUT_RECTINTVEL, rect.height()-2*(i+1)*self.CIRCLELAYOUT_RECTINTVEL)
            angleS = angleStart
            for j in xrange(len(self.dirNodesHierarchy[i])):
                if self.dirNodesChildrenNumList[i][j] == 0:
                    angleInterval = angleInter
                else:
                    angleInterval = self.dirNodesChildrenNumList[i][j]*angleInter
                labelNode = EdgeBundleLabelNode(self.scene, self.dirNodesHierarchy[i][j].dir, self.dirNodesHierarchy[i][j].dir)
                labelNode.setPosition(innerrect, angleS, angleInterval)
                angleS += angleInterval
                self.scene.addItem(labelNode)
                self.labelDirNodes.append(labelNode)
                
        innerrect = QRectF(innerrect.x()+self.CIRCLELAYOUT_RECTINTVEL, innerrect.y()+self.CIRCLELAYOUT_RECTINTVEL, innerrect.width()-2*self.CIRCLELAYOUT_RECTINTVEL, innerrect.height()-2*self.CIRCLELAYOUT_RECTINTVEL)
        blockNode = BlockingCircleNode(innerrect, angleStart, angleSpan)
        self.scene.addItem(blockNode)
        
        innerrect = QRectF(rect.x()+2*self.CIRCLELAYOUT_RECTINTVEL, rect.y()+2*self.CIRCLELAYOUT_RECTINTVEL, rect.width()-4*self.CIRCLELAYOUT_RECTINTVEL, rect.height()-4*self.CIRCLELAYOUT_RECTINTVEL)
        angleStart = 0
        angleSpan = self.numUsers*self.angleInterval
        blockNode = BlockingCircleNode(innerrect, angleStart, angleSpan)
        self.scene.addItem(blockNode)
        
        angleStart += angleSpan+self.CIRCLELAYOUT_ANGLEINTVL
        angleSpan = self.numRoles*self.angleInterval
        blockNode = BlockingCircleNode(innerrect, angleStart, angleSpan)
        self.scene.addItem(blockNode)
        
        '''for edges to show assigned relationship'''
        for keys, values in self.user_role_mat.iteritems():
            user, role = None, None
            for u in self.labelUserNodes:
                if keys == u.text:
                    user = u
            for r in self.labelRoleNodes:
                if r.text in values:
                    role = r
                    edge = EdgeItem(EdgeItem.COTERIE_CONN, user, role, self)
                    edge.color = Qt.blue
                    self.scene.addItem(edge)
    
        for keys, values in self.role_res_mat.iteritems():
            direc, role = None, None
            for r in self.labelRoleNodes:
                if keys == r.text:
                    role = r
            for d in self.labelDirNodes:
                for k in values.iterkeys():
                    if d.fullPath == k:
                        direc = d
                        edge = EdgeItem(EdgeItem.COTERIE_CONN, role, direc, self)
                        self.scene.addItem(edge)
        self.scene.update()
        
    def createSeparateView(self):
        self.childrenViewRight.setGeometry(0.5*self.centralWidget().geometry().width()-2,0,0.5*self.centralWidget().geometry().width()+2, self.centralWidget().geometry().height())
        self.sceneRight.setSceneRect(QRectF(self.childrenViewRight.geometry()))
        for r in self.roleCompactNodes:
            rolenode = None
            users = set()
            for key, value in self.user_role_mat.iteritems():
                if r.name in value:
                    rolenode = r
                    users.add(key)
            for u in users:
                usernode = UserNode(u, self)
                self.userNodes.append(usernode)
                self.scene.addItem(usernode)
                
                if rolenode:
                    rolenode.userNodes.append(usernode)
                    usernode.roleNode = rolenode
                    edge = EdgeItem(EdgeItem.SEPARATE_ROLEUSER_CONN, rolenode, usernode, self)
                    usernode.edgeList.append(edge)
                    self.scene.addItem(edge)
                else:
                    x, y = MyFunctions.generateRandomCoordinates(0.4*self.scene.sceneRect().width(), 0.5*self.scene.sceneRect().height())
                    usernode.setPos(x, y)
                    usernode.relativeX = x/self.scene.sceneRect().width()
                    usernode.relativeY = y/self.scene.sceneRect().height()
        for key, value in self.user_role_mat.iteritems():
            if value == set():
                self.policyManager.createUserNode(key)
                
        for key, value in self.role_res_mat.iteritems():
            if key != 'None':
                for r in self.roleCompactNodes:
                    if key == r.name:
                        rolenode = r
                        break
                for d in value.keys():
                    for dirnode in self.dirNodes:
                        if d == dirnode.dir:
                            rolenode.dirNodes.append(dirnode)
                            dirnode.roleNodes.append(rolenode)
        for i in xrange(len(self.dirNodesHierarchy)):
            for j in self.dirNodesHierarchy[i]:
                self.sceneRight.addItem(j)
                for c in j.children:
                    edge = EdgeItem(EdgeItem.SEPARATE_DIR_CONN, j, c, self)
                    self.sceneRight.addItem(edge)
        self.constructHierarchyForRoleNodes(self.roleCompactNodes, self.roleCompactHier)
        if self.hasSolidEdgeFlag:
            self.evenlyLayout(self.scene, self.roleCompactHier)
        else:
            self.evenlyLayout(self.scene, self.roleCompactCompleteHier)
        
        self.evenlyLayoutNestedList(self.sceneRight, self.dirNodesHierarchy)
        
    ''''''''''set qgraphicsItem highlight information'''''''''
    def initiateItemsHightlightState(self):
        self.mode = self.NORMAL_MODE
        for i in self.scene.items():
            if (isinstance(i, RoleCompactNode) or isinstance(i, UserNode)) and not i.highlighted:
                self.mode = self.HIGHLIGHT_MODE
        for i in self.sceneRight.items():
            if  isinstance(i, DirNode) and not i.highlighted:
                self.mode = self.HIGHLIGHT_MODE
        if self.clickedNode or self.clickedRelatedNodes!=[]:
            self.mode = self.HIGHLIGHT_MODE
#         if self.mode == self.HIGHLIGHT_MODE:
#             if self.toolBox.ui.noRHierRBtn.isChecked():
#                 self.highlightmode = self.HIGHLIGHT_NO_HIER_MODE
#             else:
#                 self.highlightmode = self.HIGHLIGHT_HIER_MODE
            #self.main.toolBox.ui.withRHierRBtn.setChecked(True)
#         if self.mode == self.NORMAL_MODE:
#             self.mode = self.HIGHLIGHT_MODE
#             self.policyManager.disableAllNodes()
    
    def checkMainMode(self):
        allDisabled = True
        for i in self.scene.items():
            if ((isinstance(i, RoleCompactNode) or isinstance(i, UserNode))) and i.highlighted:
                allDisabled = False
        for i in self.sceneRight.items():
            if  isinstance(i, DirNode) and i.highlighted:
                allDisabled = False 
        if allDisabled:
            self.mode = self.NORMAL_MODE
            self.policyManager.highlightAllNodes()
            self.policyManager.disableAllNodes()
            
    def setEdgeHighlightState(self, e, state):
        if state:
            if e.type == e.SEPARATE_ROLEUSER_CONN:
                e.color = QColor(0,127, 0)
            else:
                e.color = Qt.black
            e.lineWidth = 2.0
        else:
            e.color = Qt.gray
            e.lineWidth = 1.0
            
    def updateAllUserNodes(self):
        for r in self.roleCompactNodes:
                r.toggleUserNodes()
                
    def updateClickRelatedUserNodes(self):
        for r in self.clickedRelatedNodes:
            if isinstance(r, RoleCompactNode):
                r.toggleUserNodes()
                
    def updateAllUserNodesConsiderClickRelated(self):
        for r in self.roleCompactNodes:
            for u in r.userNodes:
                if r in self.clickedRelatedNodes:
                    radius = self.extendUserRadius
                    if u == self.clickedNode or u in self.clickedRelatedNodes:
                        u.highlighted = True
                    else:
                        u.highlighted = False
                else:
                    u.highlighted = False
                    radius = self.roleUserNodeRadius
                u.setPos(r.pos().x()+radius*math.cos(u.angle2Rolenode), r.pos().y()+radius*math.sin(u.angle2Rolenode))
                        
    def updateAllDirNodesForRoleClicked(self):
        for r in self.roleCompactNodes:
            if r.highlighted:
                for d in r.dirNodes:
                    d.highlighted = True
                    if self.role_res_mat[r.name][d.dir][1]:
                        for dd in d.allchildren:
                            dd.highlighted = True
                            dd.recursive = True
                  
    def updateAllEdges(self):
        if self.mode == self.HIGHLIGHT_MODE:
            for e in self.scene.items():
                if isinstance(e, EdgeItem):
                    if e.startItem.highlighted and e.endItem.highlighted:
                        self.setEdgeHighlightState(e, True)
                    else:
                        self.setEdgeHighlightState(e, False)
            for e in self.sceneRight.items():
                if isinstance(e, EdgeItem):
                    if e.startItem.highlighted and e.endItem.highlighted:
                        self.setEdgeHighlightState(e, True)
                    else:
                        self.setEdgeHighlightState(e, False)
        else:
            for e in self.scene.items():
                if isinstance(e, EdgeItem):
                    self.setEdgeHighlightState(e, True)
            for e in self.sceneRight.items():
                if isinstance(e, EdgeItem):
                    self.setEdgeHighlightState(e, True)
    
    def updateAllScenes(self): 
        self.updateAllEdges()
        self.scene.update()
        self.sceneRight.update()
        
    def clearAllScenes(self):
#         self.scene.clear()
        for i in self.scene.items():
            if i not in self.selfTestViewScene.interfaceQuesItems and \
            i not in self.selfTestViewScene.interfaceTableItems:
                self.scene.removeItem(i)
                del i
        self.sceneRight.clear()
        
    '''Parameter setting'''
    def emptyClickedNodeInfo(self):
        self.clickedNode = None
        self.clickedRelatedNodes = []
        
    def initParam(self):
        '''clear specification'''
        self.spec = QString()
        self.specFileName = None
        self.hasSolidEdgeFlag = False
        #self.prevSpec = ''
        '''central widget size'''
        self.centralWX = 0
        self.centralDeductW = 0
        '''separate view'''
        self.emptyClickedNodeInfo()
        self.dirNodes = []
        self.userNodes = []
        self.allowUsernodeHighlight = True
        '''role hierarchy view'''
        self.roleNodes = []
        self.roleCompactNodes = []
        self.roleHier = {}
        self.roleCompactHier = {}
        self.roleHierRightPerm = ''
        '''coterie view'''
        self.labelUserNodes = []
        self.labelRoleNodes = []
        self.labelDirNodes = []
        '''clean screen'''
        self.clearAllScenes()
        self.nodeMove = False
        self.mode = self.NORMAL_MODE
        self.highlightmode= self.HIGHLIGHT_NO_HIER_MODE
        self.roleHighlightScheme = self.ROLE_HIGHLIGHT_CHILDREN
        self.scene.displayMatrixView = True
        
        '''policy information'''
        self.roleSet = set()
        self.userSet = set()
        self.dirSet = set()
        self.numRoles = 0
        self.numUsers = 0
        self.numDirs = 0
        self.roleList = []
        self.userList = []
        self.dirList = []
        self.dirNodesHierarchy = []
        self.dirNodes = []
        self.numLeafDirs = 0
        self.cycles = []
        self.role_res_mat, self.user_role_mat, self.role_adjmat = {}, {}, {}
    
    def initInterface(self):
        self.mode = self.NORMAL_MODE
        self.highlightmode = self.HIGHLIGHT_NO_HIER_MODE
        self.roleHighlightScheme = self.ROLE_HIGHLIGHT_CHILDREN
        self.toolBox.ui.noRHierRBtn.setEnabled(True)
        self.toolBox.ui.withRHierRBtn.setEnabled(True)
        self.toolBox.ui.noRHierRBtn.setChecked(True)
        self.policyManager.enableHighlightNoRHier()
        
        self.specDialog.close()
        self.toolBox.ui.initToolBoxUISelection()
        self.queryWindow.setQueryForQuestion(0)
        self.emptyHintContent()
        self.viewModeChanged(self.currentAction)
                    
    def computeSpecsInfo(self):
        self.computeSpec = ComputeSpecInfo(self)
        self.roleSet = self.computeSpec.getRoleSet()
        self.userSet = self.computeSpec.getUserSet()
        self.dirSet = self.computeSpec.getDirSet()
        self.numRoles = self.computeSpec.getNumRoles()
        self.numUsers = self.computeSpec.getNumUsers()
        self.numDirs = self.computeSpec.getNumDirs()
        self.roleList = list(self.roleSet)
        self.roleList.sort()
        self.userList = list(self.userSet)
        self.userList.sort()
        self.dirList = list(self.dirSet)
        self.dirList.sort()
        self.dirNodesHierarchy, self.dirNodes = self.computeSpec.getDirHierarchy(self.dirList)
        self.numLeafDirs = len(self.dirNodesHierarchy[-1])
        
    def createAllViews(self):
        self.createMatrixView()
        self.createRHierarchyView()
        self.createSeparateView()
        self.ui.actionInsertUser.triggered.connect(self.tableView.insertNewUser)
        self.ui.actionInsertRole.triggered.connect(self.tableView.insertNewRole)
        self.ui.actionInsertDir.triggered.connect(self.tableView.insertNewDir)
        
        self.ui.actionDeleteUser.triggered.connect(self.tableView.deleteSelectedUser)
        self.ui.actionDeleteRole.triggered.connect(self.tableView.deleteSelectedRole)
        self.ui.actionDeleteDir.triggered.connect(self.tableView.deleteSelectedDir)
        self.toolBox.ui.getContentForComboBox()
        self.resizeViews()
        
    '''Toolbar update'''
    def updateToolbarEdit(self, action):
        self.ui.actionInsertUser.setEnabled(False)
        self.ui.actionDeleteUser.setEnabled(False)
        self.ui.actionInsertRole.setEnabled(False)
        self.ui.actionDeleteRole.setEnabled(False)
        self.ui.actionInsertDir.setEnabled(False)
        self.ui.actionDeleteDir.setEnabled(False)
        if action == self.ui.actionView_Matrix:
            self.ui.actionInsertUser.setEnabled(True)
            self.ui.actionDeleteUser.setEnabled(True)
            self.ui.actionInsertRole.setEnabled(True)
            self.ui.actionDeleteRole.setEnabled(True)
            self.ui.actionInsertDir.setEnabled(True)
            self.ui.actionDeleteDir.setEnabled(True)
    
    def toggleRoleHierViewDockWidget(self, state):
        roleHierViewDockWidgetWidth = self.roleHierViewDockWidget.geometry().width()
        if self.roleHierViewDockWidget.isVisible():
            self.centralDeductW -= roleHierViewDockWidgetWidth#self.WIDGET_WIDTH
            self.centralWidget().setGeometry(self.centralWX, self.centralWidget().geometry().y(), self.geometry().width()-self.centralDeductW, self.centralWidget().geometry().height())
        else:
            self.centralDeductW += roleHierViewDockWidgetWidth#self.WIDGET_WIDTH
            self.centralWidget().setGeometry(self.centralWX, self.centralWidget().geometry().y(), self.geometry().width()-self.centralDeductW, self.centralWidget().geometry().height())
        MyFunctions.setWidgetVisibility(self.roleHierViewDockWidget, state)
        
    '''Role User window'''
    def toggleRoleUserWindow(self, roleNode):
        '''
        add/remove user lists
        '''
        users = set()
        for key, value in self.user_role_mat.iteritems():
            if roleNode.name in value:
                users.add(key)
        if roleNode.roleUserItem.highlight:
            self.roleHierViewWindow.ui.addRoleUserList(roleNode.name, list(users))
        else:
            self.roleHierViewWindow.ui.removeRoleUserList(roleNode.name)
               
    '''Role Perm window'''
    def toggleRolePermWindow(self, roleNode):
        '''
        add/remove user lists
        '''
        if roleNode.roleObjItem.highlight:
            permList = [[], []]
            if roleNode.name in self.role_res_mat.keys():
                item = self.role_res_mat[roleNode.name]
                accessList = []
                for v in item.values():
                    accessStr = ','.join(v.perms)
                    accessList.append(accessStr)
                permList = [item.keys(), accessList]
            self.roleHierViewWindow.ui.addRolePermList(roleNode.name, permList)
        else:
            self.roleHierViewWindow.ui.removeRolePermList(roleNode.name)
    
    '''ToolBox window'''
    def toggleToolBox(self):
        toolBoxWidth = self.toolBoxDockWidget.geometry().width()+5
        if self.toolBoxDockWidget.isVisible():
            self.writeToFile(self.logFile, self.getCurrentTimeString()+"Toolbox off\n")
            self.toolBoxDockWidget.hide()
            self.centralWX = 0
            self.centralDeductW -= toolBoxWidth
        else:
            self.writeToFile(self.logFile, self.getCurrentTimeString()+"Toolbox on\n")
            self.toolBoxDockWidget.show()
            self.centralWX = toolBoxWidth
            self.centralDeductW += toolBoxWidth#self.WIDGET_WIDTH
        self.centralWidget().setGeometry(self.centralWX, self.centralWidget().geometry().y(), self.geometry().width()-self.centralDeductW, self.centralWidget().geometry().height())
        self.resizeViews()
        self.hintForToolBox()
    
    '''Query window'''
    def toggleQueryWindow(self):
#        QMessageBox.warning(self, '', "The query has been disabled for the take-home exam!")
        if self.queryWindowDockWidget.isVisible():
            self.writeToFile(self.logFile, self.getCurrentTimeString()+"Query Window off\n")
            self.queryWindowDockWidget.hide()
            self.centralDeductW -= self.WIDGET_WIDTH
            #MyFunctions.setWidgetWidth(self.centralWidget(), self.centralWidget().geometry(), self.geometry().width())#+self.queryWindowDockWidget.geometry().width()+5)
        else:
            self.writeToFile(self.logFile, self.getCurrentTimeString()+"Query Window on\n")
            self.queryWindowDockWidget.show()
            self.queryWindow.changeQueryInput()
            self.centralDeductW += self.WIDGET_WIDTH
            #MyFunctions.setWidgetWidth(self.centralWidget(), self.centralWidget().geometry(), self.geometry().width()-self.queryWindowDockWidget.geometry().width()-5)
        self.centralWidget().setGeometry(self.centralWX, self.centralWidget().geometry().y(), self.geometry().width()-self.centralDeductW, self.centralWidget().geometry().height())
        self.resizeViews()
        self.hintForQueryWindow()
        
    '''Spec window'''
    def showSpecDialog(self):
        self.specDialog.reGenerateSpec()
        self.specDialog.show()
        self.hintForSpecWindow()
        self.writeToFile(self.logFile, self.getCurrentTimeString()+"Specification Window on\n")
        
    '''Test window'''
    def showAutogradingTest(self):
        #self.disableAllGui()
        self.mode = self.QUIZ_MODE
        self.autogradingTest.questionDlg.show()
        self.hintForTest()
        
    '''Decrypt studnet answer file'''
    def decryptStudentAnswerFile(self):
        self.answerDecryption.answerFileLoadDlg.show()
        self.hintForDecryption()
    
    def hintForHighlightClickedNode(self):
        if self.clickedNode:
            if isinstance(self.clickedNode, RoleCompactNode):
                if self.highlightmode == self.HIGHLIGHT_NO_HIER_MODE:
                    self.ui.introLabel.setText('A role node is clicked and users assigned and the accessible objects are framed.')
                elif self.roleHighlightScheme == self.ROLE_HIGHLIGHT_CHILDREN:
                    self.ui.introLabel.setText('Clicked role node and roles it inherits from are framed. The blue framed nodes are related via inheritance.')
                elif self.roleHighlightScheme == self.ROLE_HIGHLIGHT_PARENTS:
                    self.ui.introLabel.setText('Clicked role node and roles inheriting it are framed. The blue framed nodes are related via inheritance.')
                elif self.roleHighlightScheme == self.ROLE_HIGHLIGHT_BOTH:
                    self.ui.introLabel.setText('Clicked role node and roles it inherits and inherits it are framed. The blue framed nodes are related via inheritance.')
            elif isinstance(self.clickedNode, UserNode):
                self.ui.introLabel.setText('An user node is clicked. Its role, roles its role inherits from and other nodes related to the roles are framed.')
            elif isinstance(self.clickedNode, DirNode):
                self.ui.introLabel.setText('An object node is clicked. All roles and users that have access to it are framed.')

    def hintForViewStatus(self):
        if self.scene.displayMatrixView:
            self.ui.introLabel.setText('This is the "Matrix View". It consists of tables of role-to-user assignment and role-to-object permission.')
        elif self.scene.displaySeparate:
            self.ui.introLabel.setText('This is the "Hierarchy View". It consists of graphs of role hierarchy with user assignment and object hierarchy.')
            
    def hintForQueryWindow(self):
        if self.queryWindowDockWidget.isVisible():
            self.ui.introLabel.setText('Please choose a question and configure the parameters via combo boxes.')
        else:
            self.ui.introLabel.setText('')
        
    def hintForSpecWindow(self, regen = False):
        if regen:
            self.ui.introLabel.setText('The policy is synchronized with the visualization.')
        else:
            if self.specDialog.isVisible():
                self.ui.introLabel.setText('Edits to policy may be applied via textual edits in this window or operations on visualization. Click "Re-generate" to synchronize the policy and the visualization.')
            else:
                self.ui.introLabel.setText('')
    
    def hintForTest(self):
        if self.autogradingTest.questionDlg.isVisible():
            self.ui.introLabel.setText('The test mode has been initiated.')
        else:
            self.ui.introLabel.setText('')
            
    def hintForDecryption(self):
        if self.answerDecryption.answerFileLoadDlg.isVisible():
            self.ui.introLabel.setText('Please choose the answer file to be decrypted.')
        else:
            self.ui.introLabel.setText('')
            
    def hintForToolBox(self):
        if self.toolBoxDockWidget.isVisible():
            self.ui.introLabel.setText('This toolbox can be used to adjust the highlight scheme for Hierarchy View and apply edits to policy.')
        else:
            self.ui.introLabel.setText('')
            
    def hintForMoveNode(self):
        if self.ui.actionPan.isChecked():
            self.ui.introLabel.setText('This mode is used to move nodes in Hierarcy View without affecting the current highlighting.')
        else:
            self.ui.introLabel.setText('')
        
    def emptyHintContent(self):
        self.ui.introLabel.setText('')
           
    def showHintContent(self):
        self.ui.introLabel.setText('')
        self.hintForHighlightClickedNode()
        