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

@author: mandy
'''
from PyQt4.QtCore import *
from PyQt4.QtGui import *
from commonFunction import Functions
from Ui_MainWindow import Ui_MainWindow
from DiagramScene import DiagramScene
from NewClrcateDialog import NewClrCateDialog
from TypeUserAssignDialog import TypeUserAssignDialog
from AccessControlMain import AccessControlMain
from DiagramIOHelper import DiagramIOHelper
from ClearanceNode import ClearanceNode
from FileNode import FileNode
from EdgeItem import EdgeItem
from UserNode import UserNode
from RadialTreeLayout import RadialTreeLayout
from WholeGraphDialog import WholeGraphDialog
from SpecDialog import SpecDialog
from HelpBrowser import HelpBrowser
from AssignmentDialog import AssignmentDialog
from QueryWindow import QueryWindow
from AutogradingSpec import *
from AutogradingTest import AutogradingTest
from SelfTestScene import SelfTestScene
# from mlspolicy import mlspolicy
from ToolBox import ToolBox, ToolBoxDockWidget
# from MLSForCommandLine import MLSForCommandLine
import sys, os, math, errno

class DiagramView(QGraphicsView):
    
    def __init__(self, scene, parent = None):
        QGraphicsView.__init__(self, scene, parent)
        self.generalGraphScaleX = 1.0
        self.generalGraphScaleY = 1.0
        self.typeGraphScaleX = 1.0
        self.typeGraphScaleY = 1.0
        
    def fitGeneralGraph(self):
        topLeftX = self.viewport().width()
        topLeftY = self.viewport().height()
        bottomRightX = 0
        bottomRightY = 0
        for item in self.scene().items():
            if isinstance(item, ClearanceNode):
                p = item.pos()
                if p.x() < topLeftX:
                    topLeftX = p.x()
                if p.y() < topLeftY:
                    topLeftY = p.y()
                if p.x() > bottomRightX:
                    bottomRightX = p.x()
                if p.y() > bottomRightY:
                    bottomRightY = p.y()
        topLeftX -= self.viewport().width()/100
        topLeftY -= self.viewport().height()/100
        bottomRightX += self.viewport().width()/100
        bottomRightY += self.viewport().height()/100
        self.fitInView(topLeftX, topLeftY, bottomRightX-topLeftX, bottomRightY-topLeftY, mode = Qt.KeepAspectRatio)
        
    def fitTypeGraph(self):
        topLeftX = self.geometry().width()
        topLeftY = self.geometry().height()
        bottomRightX = 0
        bottomRightY = 0
        
        for item in self.scene().items():
            if isinstance(item, FileNode):
                p = item.pos()
                if p.x() < topLeftX:
                    topLeftX = p.x()
                if p.y() < topLeftY:
                    topLeftY = p.y()
                if p.x() > bottomRightX:
                    bottomRightX = p.x()
                if p.y() > bottomRightY:
                    bottomRightY = p.y()
        topLeftX -= self.geometry().width()/100
        topLeftY -= self.geometry().height()/100
        bottomRightX += self.geometry().width()/100
        bottomRightY += self.geometry().height()/100
        self.fitInView(topLeftX, topLeftY, bottomRightX-topLeftX, bottomRightY-topLeftY, mode = Qt.KeepAspectRatio)

class MainWindow(QMainWindow):

    TASKBAR_HEIGHT = 20
    DOCK_TITLEBAR_HEIGHT = 28
    TYPEGRAPH_LABELHEIGHT = 50
    COLORNUM = 20
    
    def __init__(self):
        QMainWindow.__init__(self)
        
#         self.generateAllColors(self.COLORNUM)
        
        self.currentPath = os.path.dirname(os.path.abspath(sys.argv[0]))
        os.chdir(self.currentPath)
        
        self.windowUISetup()
        self.diagramDir = './policies'
        self.lastOpenedDirFile = "./.MLSvisual"
        self.specDir = self.diagramDir
        self.savedMLSVisName = None
        if not os.path.isdir(self.diagramDir):
            self.make_sure_path_exists(self.diagramDir)
            
        self.wholeGraphDialog = WholeGraphDialog(self.scene)
        self.ioHelper = DiagramIOHelper(self.scene)
  
        self.selfTestViewScene = SelfTestScene(self.view, self)
#         self.selfTestViewScene.setVisibilityOfSceneItems(self.ui.actionView_SelfTest.isChecked())
        self.initParam()
        self.radialLayout = RadialTreeLayout(self.scene)
        self.generalGraphLayout = self.scene.layout
        self.generalGraphLayout.showCurrentResult.connect(self.showCurrentLayout)
        self.specDialog = SpecDialog(self.scene)
        self.assignmentDialog = AssignmentDialog(self.scene)
        self.autogradingTest = AutogradingTest(self.scene)
        self.autogradingSpec = AutogradingSpec(self.scene)
        self.helpPanel = None#HelpBrowser(self.scene)
        #self.commandLineFunc = MLSForCommandLine()
        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.selfTestViewScene.updateUIContents()
#         self.selfTestViewScene.updateLayout()
#         '''test'''
#         self.importSpecFile(QString('./policies/exercise.mls'))
        self.ui.actionView_SelfTest.setChecked(True)
        self.viewModeChanged(self.ui.actionView_SelfTest)
                
    def writeToFile(self, filename, message):
        with open(filename, 'a+') as f:
            f.write(message)
        f.close()
        
    def getCurrentTimeString(self):
        return self.getCurrentTime()+': '
    
    def saveLastOpenedPolicyDir(self, filepath):
        self.currentFileDir = filepath[:filepath.rfind('/')]
        with open(self.lastOpenedDirFile, 'w') as f:
            f.write(self.currentFileDir)
        f.close()
         
    def setWindowTitleAsFilename(self, filepath):
        filename = filepath.split('/')[-1]
        self.setWindowTitle(filename)
        
    def make_sure_path_exists(self, path):
        try:
            os.makedirs(path)
        except OSError as exception:
            if exception.errno != errno.EEXIST:
                raise
            
    def windowUISetup(self):
        self.undoStack = QUndoStack()
        self.setupUi()
        
        self.scene = DiagramScene(self)
        self.view = DiagramView(self.scene, self)
        self.view.setScene(self.scene)
        
        self.newClrCateDialog = NewClrCateDialog(self.scene)
        self.typeUserAssignDialog = TypeUserAssignDialog(self.scene)
        self.setupConnections()
        self.view.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
        self.view.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
        
        self.setupQueryWidget()
        self.setupToolBox()
        
    def setupUi(self):
        self.ui = Ui_MainWindow()
        self.ui.setupUi(self)
        self.setupToolbar()
        
    def setupQueryWidget(self):
        self.queryWindowDockWidget = QDockWidget('Query Window', self)
        self.queryWindowDockWidget.setFeatures(QDockWidget.DockWidgetMovable|QDockWidget.DockWidgetFloatable)
        self.queryWindowDockWidget.setAllowedAreas(Qt.RightDockWidgetArea)
        self.queryWindow = QueryWindow(self.scene)
        self.queryWindowDockWidget.setWidget(self.queryWindow)
        self.addDockWidget(Qt.RightDockWidgetArea, self.queryWindowDockWidget)
        self.queryWindowDockWidget.setVisible(False)
        
    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.genGraphButton = QToolButton(self)
        self.genGraphButton.setDefaultAction(self.ui.actionGenerate_Graph)
        self.ui.actionGenerate_Graph.setIcon(QIcon(QPixmap('./icons/genGraph.png')))
        self.ui.toolBar.addWidget(self.genGraphButton)
        self.ui.toolBar.addSeparator()
        self.ui.toolBar.addAction(self.ui.actionAdd_One_Clearance_Node)
        self.ui.actionAdd_One_Clearance_Node.setIcon(QIcon(QPixmap('./icons/clrNd1.png')))
        self.ui.toolBar.addSeparator()
        self.ui.toolBar.addAction(self.ui.actionNormal_Mode)
        self.ui.actionNormal_Mode.setIcon(QIcon(QPixmap('./icons/Nolight.png')))
        self.ui.toolBar.addAction(self.ui.actionEdit_Mode)
        self.ui.actionEdit_Mode.setIcon(QIcon(QPixmap('./icons/Highlight.png')))
        self.ui.toolBar.addSeparator()
        self.ui.toolBar.addAction(self.ui.actionGeneral_Graph)
        self.ui.toolBar.addAction(self.ui.actionType_Graph)
        self.ui.toolBar.addAction(self.ui.actionView_SelfTest)
        self.ui.toolBar.addSeparator()
        
        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.actionZoom_In)
        self.ui.actionZoom_In.setIcon(QIcon(QPixmap('./icons/Zoom-In.png')))
        self.ui.toolBar.addAction(self.ui.actionZoom_Out)
        self.ui.actionZoom_Out.setIcon(QIcon(QPixmap('./icons/Zoom-Out.png')))
        
        self.editActionGroup = QActionGroup(self)
        self.editActionGroup.addAction(self.ui.actionNormal_Mode)
        self.editActionGroup.addAction(self.ui.actionEdit_Mode)
        self.editActionGroup.triggered.connect(self.editModeChanged)
        
        self.viewActionGroup = QActionGroup(self)
        self.viewActionGroup.addAction(self.ui.actionGeneral_Graph)
        self.viewActionGroup.addAction(self.ui.actionType_Graph)
        self.viewActionGroup.addAction(self.ui.actionView_SelfTest)
        
    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.importMLSSpec)
        self.ui.actionExport.triggered.connect(self.exportToMLSSpec)
        self.ui.actionExit.triggered.connect(QCoreApplication.quit)
        
        self.ui.actionGenerate_Graph.triggered.connect(self.scene.growLevelLayout.searchPath)
        self.ui.actionAdd_Successors.triggered.connect(self.scene.addOneLevelSucc)
        self.ui.actionAdd_Predecessors.triggered.connect(self.scene.addOneLevelPred)
        self.ui.actionAdd_One_Clearance_Node.triggered.connect(self.scene.createOneClearanceNode)

        self.ui.actionZoom_In.triggered.connect(self.zoomIn)
        self.ui.actionZoom_Out.triggered.connect(self.zoomOut)

        self.ui.actionSpecification.triggered.connect(self.showSpecDialog)
        self.ui.actionQuery_Window.toggled.connect(self.toggleQueryWindow)
        
        self.ui.actionAssignment_Window.triggered.connect(self.showAssignment)
        self.ui.actionSpecDiagnosis.triggered.connect(self.showAutogradingSpec)
        self.ui.actionTest.triggered.connect(self.showAutogradingTest)
        
        self.ui.actionWhole_General_Graph.triggered.connect(self.showWholeGraph)
        self.ui.actionHelp_Contents.triggered.connect(self.showHelpDialog)
        
    def initParam(self):
        self.scene.initParam()
        self.ioHelper.initParam()
        self.wholeGraphDialog.wholeGraphScene.resetAll()
        self.view.setDragMode(QGraphicsView.NoDrag)
        self.hasInfo = False
        self.computeTypeGraph = 0
        self.longestBtnWidth = 50
        self.hasClr, self.hasCate = False, False
        self.savedMLSVisName = None
#         self.ui.actionGeneral_Graph.setChecked(True)
#         self.viewModeChanged(self.ui.actionGeneral_Graph)
        self.setWindowTitle('MLSvisual')
        
    def resizeEvent(self, event):
        QMainWindow.resizeEvent(self, event)
        top = self.ui.toolBar.height()+self.ui.menubar.height()+self.ui.horizontalGroupBox.height()
        left = self.ui.verticalGroupBox.x()+self.ui.verticalGroupBox.width()
        usableArea = self.geometry()
        usableArea = QRect(usableArea.x(), usableArea.y(), usableArea.width(), usableArea.height()-self.TASKBAR_HEIGHT)
        self.ui.verticalGroupBox.setGeometry(QRect(self.ui.verticalGroupBox.x(), self.ui.verticalGroupBox.y(), self.ui.verticalGroupBox.width(), usableArea.height()-top-2))
        self.ui.verticalLayout.setAlignment(Qt.AlignTop)
        self.ui.verticalLayoutWidget.setGeometry(self.ui.verticalGroupBox.geometry())
        self.ui.verticalGroupBox.setLayout(self.ui.verticalLayout)
        self.ui.horizontalGroupBox.setGeometry(QRect(1, self.ui.horizontalGroupBox.y(), usableArea.width()-2, self.ui.horizontalGroupBox.height()))
        self.ui.horizontalLayoutWidget.setGeometry(self.ui.horizontalGroupBox.geometry())
        self.ui.horizontalGroupBox.setLayout(self.ui.horizontalLayout)
        self.scene.setSceneRect(QRectF(left, top, usableArea.width()-left, usableArea.height()-top))       
        self.view.setGeometry(QRect(left, top, usableArea.width()-left, usableArea.height()-top))
        self.scene.viewWidth = self.view.geometry().width()
        self.scene.viewHeight = self.view.geometry().height()
        self.scene.x = self.view.geometry().x()
        self.scene.y = self.view.geometry().y()
        self.scene.setSceneRect(self.scene.x, self.scene.y, self.scene.viewWidth, self.scene.viewHeight)
        self.scene.resize(event)
        if self.hasInfo:
            self.computeTypeGraph = 0
        if self.ui.actionGeneral_Graph.isChecked():
            self.viewModeChanged(self.ui.actionGeneral_Graph)
        elif self.ui.actionType_Graph.isChecked():
            self.viewModeChanged(self.ui.actionType_Graph)
        elif self.ui.actionView_SelfTest.isChecked():
            self.selfTestViewScene.updateLayout()
            
    def closeEvent(self, evt):
        if self.maybeSave():
            self.queryWindowDockWidget.close()
            #self.writeSettings()
            evt.accept()
        else:
            evt.ignore()
            
    def calculateLevelCircles(self):
        if len(self.scene.typeGraph) > 0:
            rootX, rootY = self.view.viewport().width()/2.0, self.view.viewport().height()/2.0
            d = 0.9*min(self.view.viewport().width(), self.view.viewport().height()) / 2.0  / len(self.scene.typeGraph)
            for level in self.scene.typeGraph.keys():
                radius = d * level
                self.scene.typeGraph[level][1] = QRectF(rootX-radius+self.scene.x, rootY-radius+self.scene.y, 2*radius, 2*radius)
                
    def showGeneralGraph(self):
#         for item in self.scene.items():
#             item.setVisible(False)
        for item in self.generalGraphLayout.V:
            item.setVisible(True)
        for item in self.generalGraphLayout.E:
            item.setVisible(True)
        self.scene.growLevelLayout.equalWidthIntvlOneNodeLayoutNorthSouth(self.scene.growLevelLayout.mergedNdlvlDictionary)
        self.view.fitGeneralGraph()
        self.scene.update()

    def showTypeGraph(self):
        for item in self.scene.items():
#             item.setVisible(False)
            if isinstance(item, FileNode):
                item.setVisible(True)
            elif isinstance(item, EdgeItem):
                if item.type == EdgeItem.FILE_CONN:
                    item.setVisible(True)
        self.view.fitTypeGraph()
        self.scene.update()
        
    def layoutTypeGraph(self):
        self.showTypeGraph()
        if self.scene.typeGraphRoot:
            if self.computeTypeGraph == 0:
                self.radialLayout.buildTreeTable(self.scene.typeGraphRoot)
                self.computeTypeGraph = 1
            self.radialLayout.layout()
            self.radialLayout.mapToScene()
        
            levelNodes = self.scene.typeGraphRoot.children
            level = 1
            while levelNodes:
                self.scene.typeGraph[level] = [levelNodes, None]
                levelNodes = []
                for n in self.scene.typeGraph[level][0]:
                    if n.children:
                        levelNodes.extend(n.children)
                level += 1
            self.calculateLevelCircles()
        self.view.setTransform(QTransform())
        self.view.scale(self.view.typeGraphScaleX, self.view.typeGraphScaleY)
        
    def editModeChanged(self, action):
        if self.ui.actionGeneral_Graph.isChecked():
            if action is self.ui.actionNormal_Mode:
                self.scene.mode = self.scene.Normal
                self.view.setDragMode(QGraphicsView.NoDrag)
            elif action is self.ui.actionEdit_Mode:
                self.scene.mode = self.scene.Edit
                self.view.setDragMode(QGraphicsView.NoDrag)
                
    def viewModeChanged(self, action):
        for item in self.scene.items():
            item.setVisible(False)
        self.view.centerOn(0.5*self.view.viewport().width(), 0.5*self.view.viewport().height())
        self.selfTestViewScene.setVisibilityOfSceneItems(self.ui.actionView_SelfTest.isChecked())
        if action is self.ui.actionGeneral_Graph:
            if self.hasInfo:
                self.showGeneralGraph()
                self.view.setTransform(QTransform())
                self.view.scale(self.view.generalGraphScaleX, self.view.generalGraphScaleY)
        elif action is self.ui.actionType_Graph:
            self.view.setDragMode(QGraphicsView.NoDrag)
            if self.hasInfo:
                self.layoutTypeGraph()
        elif action is self.ui.actionView_SelfTest:
            self.view.setDragMode(QGraphicsView.NoDrag)
            self.selfTestViewScene.updateLayout()
        QApplication.processEvents()
    
    def showSpecDialog(self):
        self.specDialog.reGenerateSpec()
        self.specDialog.show()
        
    def showAutogradingSpec(self):
        self.autogradingSpec.show()
        
    def setMainWindowAllGuiState(self, state):
        self.ui.toolBar.setEnabled(state)
        self.queryWindowDockWidget.setEnabled(state)
        self.toolBoxDockWidget.setEnabled(state)
        self.ui.menubar.setEnabled(state)
        
    def disableAllGui(self):
        self.ui.toolBar.setEnabled(False)
        self.queryWindowDockWidget.setEnabled(False)
#         self.toolBoxDockWidget.setEnabled(False)
        self.ui.menubar.setEnabled(False)
        self.ui.menu_File.setEnabled(False)
        self.ui.menu_Edit.setEnabled(False)
        self.ui.menu_View.setEnabled(False)
        self.ui.menu_Practice.setEnabled(False)
        self.ui.actionNew.setEnabled(False)
        self.ui.actionOpen.setEnabled(False)
        self.ui.actionSave.setEnabled(False)
        self.ui.actionImport.setEnabled(False)
        self.ui.actionExport.setEnabled(False)
        self.ui.actionGeneral_Graph.setEnabled(False)
        self.ui.actionType_Graph.setEnabled(False)
        self.ui.actionGenerate_Graph.setEnabled(False)
        self.ui.actionNormal_Mode.setEnabled(False)
        self.ui.actionEdit_Mode.setEnabled(False)
        self.ui.actionQuery_Window.setEnabled(False)
        self.ui.actionSpecification.setEnabled(False)
        self.ui.actionAdd_One_Clearance_Node.setEnabled(False)
    
    def enableAllGui(self):
        self.ui.toolBar.setEnabled(True)
        self.queryWindowDockWidget.setEnabled(True)
#         self.toolBoxDockWidget.setEnabled(True)
        self.ui.menubar.setEnabled(True)
        self.ui.menu_File.setEnabled(True)
        self.ui.menu_Edit.setEnabled(True)
        self.ui.menu_View.setEnabled(True)
        self.ui.menu_Practice.setEnabled(True)
        self.ui.actionNew.setEnabled(True)
        self.ui.actionOpen.setEnabled(True)
        self.ui.actionSave.setEnabled(True)
        self.ui.actionImport.setEnabled(True)
        self.ui.actionExport.setEnabled(True)
        self.ui.actionGeneral_Graph.setEnabled(True)
        self.ui.actionType_Graph.setEnabled(True)
        self.ui.actionGenerate_Graph.setEnabled(True)
        self.ui.actionNormal_Mode.setEnabled(True)
        self.ui.actionEdit_Mode.setEnabled(True)
        self.ui.actionQuery_Window.setEnabled(True)
        self.ui.actionSpecification.setEnabled(True)
        self.ui.actionAdd_One_Clearance_Node.setEnabled(True)
        
    def showAutogradingTest(self):
        #self.disableAllGui()
        self.autogradingTest.questionDlg.show()
        
    def showAssignment(self):
        self.assignmentDialog.getAssignment()
        self.assignmentDialog.show()
        
    def showWholeGraph(self):
        self.wholeGraphDialog.initialWholeGraph()
        self.wholeGraphDialog.show()
    
    def showHelpDialog(self):
        return
        #self.helpPanel.show()
        
    def toggleQueryWindow(self):
#        QMessageBox.warning(self, '', "The query has been disabled for the take-home exam!")
        if self.queryWindowDockWidget.isVisible():
            self.queryWindowDockWidget.hide()
        else:
            self.queryWindowDockWidget.show()
            
    '''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.RightDockWidgetArea, self.toolBoxDockWidget)
        self.toolBoxDockWidget.setVisible(False)
        
    '''ToolBox window'''
    def toggleToolBox(self):
#         toolBoxWidth = self.toolBoxDockWidget.geometry().width()+5
#         if self.toolBoxDockWidget.isVisible():
#             self.toolBoxDockWidget.hide()
#             self.centralWX = 0
#             self.centralDeductW -= toolBoxWidth
#         else:
#             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()
        if self.toolBoxDockWidget.isVisible():
            self.toolBoxDockWidget.hide()
        else:
            self.toolBoxDockWidget.show()
        
    def zoomIn(self):
        self.view.scale(1.25, 1.25)
        if self.ui.actionGeneral_Graph.isChecked():
            self.view.generalGraphScaleX = self.view.transform().m11()
            self.view.generalGraphScaleY = self.view.transform().m22()
        else:
            self.view.typeGraphScaleX = self.view.transform().m11()
            self.view.typeGraphScaleY = self.view.transform().m22()
    
    def zoomOut(self):
        self.view.scale(0.75, 0.75) 
        if self.ui.actionGeneral_Graph.isChecked():
            self.view.generalGraphScaleX = self.view.transform().m11()
            self.view.generalGraphScaleY = self.view.transform().m22()
        else:
            self.view.typeGraphScaleX = self.view.transform().m11()
            self.view.typeGraphScaleY = self.view.transform().m22()
    
    def resetGraphSize(self):
        if self.ui.actionGeneral_Graph.isChecked():
            xratio, yratio = 1.0/self.view.generalGraphScaleX, 1.0/self.view.generalGraphScaleY
            self.view.generalGraphScaleX = 1.0
            self.view.generalGraphScaleY = 1.0
        else:
            xratio, yratio = 1.0/self.view.typeGraphScaleX, 1.0/self.view.typeGraphScaleY
            self.view.typeGraphScaleX = 1.0
            self.view.typeGraphScaleY = 1.0
        self.view.scale(xratio, yratio) 
            
    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 eraseClrcatelayout(self):
        for i in range(self.ui.verticalLayout.count()): self.ui.verticalLayout.itemAt(i).widget().close()
        for i in range(self.ui.horizontalLayout.count()): self.ui.horizontalLayout.itemAt(i).widget().close()
        
    def newDiagram(self):  
        if self.maybeSave() or self.scene.mode == self.scene.Test:
            self.hasInfo = False
            self.initParam()
            self.eraseClrcatelayout()
    
    def showCurrentLayout(self):
        self.generalGraphLayout.mapToScene()
        self.scene.update()
    
    def setupClrCateUI(self):
        usableArea = self.geometry()
        usableArea = QRect(usableArea.x(), usableArea.y(), usableArea.width(), usableArea.height()-self.TASKBAR_HEIGHT)
        self.eraseClrcatelayout()
        self.setupClrradiobtns(usableArea)
        self.setupCateCheckBox(usableArea)
    
    def setUserNodeAroundClrNode(self, clrNode, r):
        if clrNode and clrNode.userNodes:
            intvl = 2*math.pi/len(clrNode.userNodes)
            angle = 0
            for u in clrNode.userNodes:
                if u not in self.scene.items():
                    self.scene.addItem(u)
                u.setPos(clrNode.pos().x()-0.5*self.scene.USERNODESIZE+r*math.cos(angle),\
                         clrNode.pos().y()-0.5*self.scene.USERNODESIZE+r*math.sin(angle))
                u.setVisible(True)
                angle-=intvl
            
    def arrangeAllUserNodePos(self):
        for c in self.scene.items():
            if isinstance(c, ClearanceNode):
                self.setUserNodeAroundClrNode(c, self.scene.USERCLRDISTANCE)
                
    def updateSecuritySpec(self):
        clr = 'clearances:'
        cate = 'categories:'
        for c in self.scene.clearances:
            clr +=c
            if c != self.scene.clearances[-1]:
                clr+='<'
        for c in self.scene.categories:
            cate+= c
            if c != self.scene.categories[-1]:
                cate+=','
        self.scene.securitySpec=clr+'\n'+cate
    
    def delClrCateInfo(self, isClrDel, index):
        if isClrDel:
            clr = self.scene.clearances[index]
            self.scene.newClearance = [clr]
            self.scene.newcategoryCombination = self.scene.categoryCombination
            self.scene.clearances.remove(clr)
            for n in self.ioHelper.latticeNodes:
                n.flgClr=self.ioHelper.getClearanceFlg(n)
            for n in self.ioHelper.wholelatticeNodes:
                n.flgClr=self.ioHelper.getClearanceFlg(n)
        else:
            cate = self.scene.categories[index]
            self.scene.newClearance = self.scene.clearances
            self.scene.newcategoryCombination = Functions.allNewCateCombination(self.scene.categories, cate)
            for n in self.scene.newcategoryCombination:
                self.scene.categoryCombination.remove(n)
            self.scene.categories.remove(cate)
        self.updateSecuritySpec()
        self.setupClrCateUI()
        self.hasInfo = True
        self.ioHelper.setupSecurityHierarchyForDel()
        
    def createClrCateInfo(self, name, isClr, step):
        if self.hasInfo:
            if len(self.scene.clearances)>0:
                self.hasClr = True
            if len(self.scene.categories)>0:
                self.hasCate = True
                
        info = str(name).replace(' ', '')
        if info.find('#') != -1:
            info = info[:info.find('#')]
        if isClr:
            self.hasClr = True
            clr = str(name)
            self.scene.clearances.insert(step, clr)
            self.scene.newClearance = [clr]
            self.scene.newcategoryCombination = self.scene.categoryCombination
            for n in self.ioHelper.latticeNodes:
                n.flgClr=self.ioHelper.getClearanceFlg(n)
            for n in self.ioHelper.wholelatticeNodes:
                n.flgClr=self.ioHelper.getClearanceFlg(n)
        else:
            cate = str(name)
            self.scene.newClearance = self.scene.clearances
            self.scene.categories.append(cate)
            self.scene.newcategoryCombination = Functions.allNewCateCombination(self.scene.categories, cate)
            if not self.hasCate:
                self.scene.newcategoryCombination.append([])
                self.hasCate = True
            for n in self.scene.newcategoryCombination:
                self.scene.categoryCombination.append(n)
        self.updateSecuritySpec()
        self.setupClrCateUI()
        if self.hasClr and self.hasCate:
            self.hasInfo = True
            self.ioHelper.setupSecurityHierarchy()
        
#     def generateAllColors(self, num):
#         import random, colorsys
#         self.clearanceColors = []
#         self.currentColorIndex = 0
#         intvl = 360 / num
#         for i in xrange(0, num):
#             hue = i*intvl
#             print 'hue', hue
#             saturation = 90 + random.random() * 10;
#             lightness = 50 + random.random() * 10;
#             color = colorsys.hls_to_rgb(hue/360.0, lightness/100.0, saturation/100.0)
#             color0 = color[0]*255
#             color1 = color[1]*255
#             color2 = color[2]*255
#             color = 'rgba('+str(color0)+','+str(color1)+','+str(color2)+','+'127)'
#             self.clearanceColors.append(color)
#             print color
        
    def setClrbtnColor(self, radiobutton):
#         if self.currentColorIndex%2==0:
#             color = self.clearanceColors[self.currentColorIndex]
#         else:
#             color = self.clearanceColors[self.COLORNUM-1-self.currentColorIndex]
#         self.currentColorIndex+=1
        color0, color1, color2 = Functions.colorMapping(radiobutton.text(), self.scene.clearances)
        color = 'rgba('+str(color0)+','+str(color1)+','+str(color2)+','+'127)'
        radiobutton.setStyleSheet(QString("font: bold; font-size:18px"))#background:"+color))
        rLabel = QLabel(radiobutton)
        rLabel.setStyleSheet("background-color :"+color)
        #rLabel.setFixedWidth(30)
        rLabel.setGeometry(QRect(0,4,18,20))
        
    def setupClrradiobtns(self, usableArea):
        self.scene.radioBtnList = []
        for i in xrange(len(self.scene.clearances)):
            radiobutton = QRadioButton(QString(self.scene.clearances[i]))
            radiobutton.setChecked(False)
            self.ui.verticalLayout.addWidget(radiobutton)
            if i==0:
                radiobutton.setChecked(True)
            self.setClrbtnColor(radiobutton)
            radiobutton.show()
            self.scene.radioBtnList.append(radiobutton)
            width = radiobutton.fontMetrics().boundingRect(radiobutton.text())
            if self.longestBtnWidth < width.width():
                self.longestBtnWidth = width.width()
        self.ui.verticalGroupBox.setGeometry(QRect(self.ui.verticalGroupBox.x(), self.ui.verticalGroupBox.y(), self.longestBtnWidth+25, usableArea.height()))
        radioYIntvl = 0.8*self.geometry().height()/(len(self.scene.clearances)+1)
        self.ui.verticalLayout.setSpacing(radioYIntvl)
        self.ui.verticalLayoutWidget.setGeometry(self.ui.verticalGroupBox.geometry().x(), self.ui.verticalGroupBox.geometry().y(), self.ui.verticalGroupBox.geometry().width(), 0.8*self.geometry().height())
        sceneWidth = self.geometry().width()-self.longestBtnWidth-25
        self.scene.setSceneRect(QRectF(self.ui.verticalGroupBox.x()+self.longestBtnWidth+25, self.scene.sceneRect().y(), sceneWidth, self.scene.sceneRect().height()))       
        self.view.setGeometry(QRect(self.scene.sceneRect().x(), self.scene.sceneRect().y(), self.scene.sceneRect().width(), self.scene.sceneRect().height()))
 
    def setupCateCheckBox(self, usableArea):
        self.scene.checkBoxList = []
        for i in xrange(len(self.scene.categories)):
            checkBox = QCheckBox(" "+str(i+1)+": "+self.scene.categories[i])
            checkBox.setChecked(False)
            self.ui.horizontalLayout.addWidget(checkBox)
            if i==0:
                checkBox.setChecked(True)
            checkBox.setStyleSheet(QString("font: bold;font-size:16px;"))
            checkBox.show()
            self.scene.checkBoxList.append(checkBox)
                
    def connectClrCateButtons(self):
        for e in self.scene.radioBtnList:
            e.clicked.connect(self.scene.updateClrLevel)
        for e in self.scene.checkBoxList:
            e.clicked.connect(self.scene.updateCateCombination)
    
    def clrCateWinConfig(self):
        usableArea = self.geometry()
        usableArea = QRect(usableArea.x(), usableArea.y(), usableArea.width(), usableArea.height()-self.TASKBAR_HEIGHT)
        self.eraseClrcatelayout()
        self.setupClrradiobtns(usableArea)
        self.setupCateCheckBox(usableArea)
        self.connectClrCateButtons()
            
    def importSpecFile(self, filename):
        if not filename.isEmpty():
            self.initParam()
            self.hasInfo = True
            self.specDir = QFileInfo(filename).absolutePath()
            specFile = str(filename)
            try:
                AccessControlMain(str(filename), './parsedfile.txt')
                self.ioHelper.import_(filename, './parsedfile.txt')
                self.saveLastOpenedPolicyDir(str(filename))
                self.setWindowTitleAsFilename(str(filename))
                self.clrCateWinConfig()
            except Exception as e:
                QMessageBox.critical(self, 'Error', str(e))
                return
            self.activateWindow()
            self.setFocus()
            if self.scene.typeGraphRoot:
                self.ui.actionType_Graph.setEnabled(True)
            else:
                self.ui.actionType_Graph.setDisabled(True)
            self.selfTestViewScene.updateUIContents()
            self.selfTestViewScene.updateLayout()
            self.resizeEvent(None)
            self.scene.update()
            self.showSpecDialog()
            
    def importMLSSpec(self):
        self.maybeSave()
        filename = QFileDialog.getOpenFileName(self, 'Import from MLS Spec', directory=self.specDir, filter='(*.mls);;All Files(*.*)')
        self.importSpecFile(filename)
        
    def exportToMLSSpec(self):
        filename = QFileDialog.getSaveFileName(self, 'Export to MLS Spec', directory=self.specDir, filter='(*.mls)')
        if not filename.isEmpty():
            try:
                self.ioHelper.export(str(filename))  
                self.undoStack.setClean() 
                self.setWindowTitleAsFilename(str(filename))
                self.saveLastOpenedPolicyDir(str(filename))
            except Exception as e:
                QMessageBox.critical(self, 'Error', str(e))
                if QFile.exists(filename):
                    QFile.remove(filename)
                    
    def saveDiagram(self):
        if self.savedMLSVisName is not None:
            self.ioHelper.write(self.savedMLSVisName)                                                                                                                                                                                                                                                      
            self.undoStack.setClean()
            self.saveLastOpenedPolicyDir(str(self.savedMLSVisName))
            self.setWindowTitleAsFilename(self.savedMLSVisName)
        else:
            self.saveDiagramAs()
    
    def saveDiagramAs(self):
        filename = QFileDialog.getSaveFileName(self, 'Save Diagram As...', directory=self.diagramDir, filter='(*.mlsvis)')
        if not filename.isEmpty():
            self.diagramDir = QFileInfo(filename).absolutePath()
            self.ioHelper.write(str(filename))
            self.savedMLSVisName = str(filename)
            self.undoStack.setClean()
            '''Store last spec/vis file location'''
            self.saveLastOpenedPolicyDir(str(filename))
            self.setWindowTitleAsFilename(str(filename))
            
    def openDiagram(self):
        self.maybeSave() 
        filename = QFileDialog.getOpenFileName(self, 'Open Diagram', directory=self.diagramDir, filter='(*.mlsvis);;All Files(*.*)')
        if not filename.isEmpty():
            self.diagramDir = QFileInfo(filename).absolutePath()
            self.ioHelper.read(str(filename))
            self.hasInfo = True
#             self.ui.actionGeneral_Graph.setChecked(True)
#             self.viewModeChanged(self.ui.actionGeneral_Graph)
            self.undoStack.setClean()
            self.setWindowTitleAsFilename(str(filename))
            self.saveLastOpenedPolicyDir(str(filename))
        self.scene.update()
