'''
Created on Apr 8, 2014

@author: mandy
'''

from PyQt4.QtCore import QRect, QRectF, Qt, QPointF, QLineF, QString, pyqtSignal, QTimer
from PyQt4.QtGui import QGraphicsScene, QGraphicsView, QPainter, QPen, QBrush, QColor, QTransform, QPainterPath, QMenu, \
                        QGraphicsEllipseItem
from RoleNode import *
from DirNode import DirNode
from UserNode import UserNode
from ToolBoxContextHandler import *
import math, os, socket, datetime

class DiagramScene(QGraphicsScene):
    '''
    viewids
    '''
    MAIN_VIEW = 0
    SPLIT_VIEW_LEFT = 1
    SPLIT_VIEW_RIGHT = 2
    '''
    flags for context menu
    '''
    ADD_PARENT_ROLE = 0
    DELETE_PARENT_ROLE = 1
    ADD_CHILD_ROLE = 2
    DELETE_CHILD_ROLE = 3
    
    ADD_USER_2ROLE = 4
    DELETE_USER_2ROLE = 5
    ADD_DIR_2ROLE = 6
    DELETE_DIR_2ROLE = 7
    
    ADD_ROLE_2USER = 8
    DELETE_ROLE_2USER = 9
    
    ADD_ROLE_2DIR = 10
    DELETE_ROLE_2DIR = 11
    
    CREATE_ROLENODE = 12
    DELETE_ROLENODE = 13
    
    CREATE_USERNODE = 14
    DELETE_USERNODE = 15
    
    CREATE_DIRNODE = 16
    DELETE_DIRNODE = 17
    
    '''
    member variables
    '''
    parentWindow = None 
    nodesContextMenuResponce = pyqtSignal(QGraphicsItem, int)
    animationStarted = pyqtSignal()
    animationStopped = pyqtSignal()
    
    def __init__(self, mainWindow):
        QGraphicsScene.__init__(self, mainWindow)
        self.hostname = socket.gethostname() 
        self.pid = os.getpid()
        self.date = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
        self.stuInfo = self.hostname+'.'+str(self.pid)+'.'+self.date
        self.main = mainWindow
        self.toolBoxContextHandler = ToolBoxContextHandler(self.main, None)
        self.toolBoxContextHandler.hide()
        self.initParam()
        self.nodesContextMenuResponce.connect(self.toolBoxContextHandler.modifyPolicy)
        
#         self.animationTimer = QTimer(self)
#         self.timerInterval = 5000
#         self.animationTimer.setInterval(self.timerInterval)
#         self.animationTimer.timeout.connect(self.animateQuery)
#         self.animationType = None
#         self.animationStep = 0
        self.message = ''
        
    def initParam(self):
        self.viewId = self.MAIN_VIEW
        self.displayMatrixView = False
        self.displaySelfTest = False
        self.displaySeparate = False
            
    def enableView(self, viewId):
        self.displayMatrixView = False
        self.displaySelfTest = False
        self.displaySeparate = False
        self.main.childrenViewRight.hide()
        self.main.view.setBackgroundBrush(QBrush(QColor(255, 255, 255), Qt.SolidPattern))
        self.viewId = self.MAIN_VIEW
        if viewId == 0: 
            self.displayMatrixView = True
        elif viewId == 1: 
            self.displaySelfTest = True
        elif viewId == 3: 
            self.displaySeparate = True
            self.viewId = self.SPLIT_VIEW_LEFT
            self.main.view.setBackgroundBrush(QBrush(QColor(240, 255, 240), Qt.SolidPattern))
            self.main.childrenViewRight.show()
        if self.main.tableView:
            if self.displayMatrixView:
                self.main.tableView.show()
            else:
                self.main.tableView.hide()
            
    def drawForeground(self, painter, rect):
        if self.viewId == self.SPLIT_VIEW_RIGHT:
            painter.save()
            font = self.font()
            font.setPixelSize(self.main.FONT_SIZE)
            painter.setFont(font)
            x = int(self.sceneRect().x()+5)
            y = int(self.sceneRect().y())
            painter.drawText(QRectF(x,y, self.sceneRect().width(), self.sceneRect().height()), self.main.roleHierRightPerm)
            painter.restore()
            
        if self.message and self.viewId == self.SPLIT_VIEW_LEFT:
            painter.save()
            transform = painter.transform()
            transform.scale(1.0/painter.transform().m11(), 1.0/painter.transform().m22())
            painter.setTransform(transform)

            painter.setFont(QFont('Helvetica', 20))
            xStart = self.views()[0].horizontalScrollBar().value()+80
            yStart = self.views()[0].verticalScrollBar().value()+self.views()[0].viewport().height()-100
            painter.drawText(QRectF(xStart, yStart, self.views()[0].viewport().width()-200, self.views()[0].viewport().height()), self.message)
            painter.restore()
        
        QGraphicsScene.drawForeground(self, painter, rect)
        
    def contextMenuEvent(self, evt):
        item = self.itemAt(evt.scenePos())
        self.rightClickedItem = item
        menu = QMenu()
        
        if item is not None:
            item.setSelected(True)
        if self.main.scene.displaySeparate:
            if self == self.main.scene:
                if isinstance(item, RoleCompactNode):
                    addParentRoleAction = menu.addAction('Assign Parent Role')
                    deleteParentRoleAction = menu.addAction('Remove Parent Role')
                    addChildRoleAction = menu.addAction('Assign Child Role')
                    deleteChildRoleAction = menu.addAction('Remove Child Role')
                    menu.addSeparator()
                    addUserToRoleAction = menu.addAction('Assign User')
                    deleteUserFromRoleAction = menu.addAction('Remove User')
                    addDirToRoleAction = menu.addAction('Assign Object')
                    deleteDirFromRoleAction = menu.addAction('Remove Object')
                    menu.addSeparator()
                    deleteRoleAction = menu.addAction('Delete')
                    addParentRoleAction.triggered.connect(self.contextAddParentToRole)
                    deleteParentRoleAction.triggered.connect(self.contextDeleteParentFromRole)
                    addChildRoleAction.triggered.connect(self.contextAddChildToRole)
                    deleteChildRoleAction.triggered.connect(self.contextDeleteChildFromRole)
                    addUserToRoleAction.triggered.connect(self.contextAddUserToRole)
                    deleteUserFromRoleAction.triggered.connect(self.contextDeleteUserFromRole)
                    addDirToRoleAction.triggered.connect(self.contextAddDirToRole)
                    deleteDirFromRoleAction.triggered.connect(self.contextDeleteDirFromRole)
                    deleteRoleAction.triggered.connect(self.contextDeleteRoleNode)
                elif isinstance(item, UserNode):
                    addRoleToUserAction = menu.addAction('Assign Role')
                    deleteRoleFromUserAction = menu.addAction('Remove Role')
                    menu.addSeparator()
                    deleteUserAction = menu.addAction('Delete')
                    addRoleToUserAction.triggered.connect(self.contextAddRoleToUser)
                    deleteRoleFromUserAction.triggered.connect(self.contextDeleteRoleFromUser)
                    deleteUserAction.triggered.connect(self.contextDeleteUserNode)
                else:
                    createRoleAction = menu.addAction('Create Role')
                    createUserAction = menu.addAction('Create User')
                    createDirAction = menu.addAction('Create Object')
                    menu.addSeparator()
                    menu.addAction(self.main.ui.actionQuery_Window)
                    createRoleAction.triggered.connect(self.contextCreateRoleNode)
                    createUserAction.triggered.connect(self.contextCreateUserNode)
                    createDirAction.triggered.connect(self.contextCreateDirNode)
            else:
                if isinstance(item, DirNode):
                    addRoleToDirAction = menu.addAction('Assign Role')
                    deleteRoleFromDirAction = menu.addAction('Remove Role')
                    menu.addSeparator()
                    deleteDirAction = menu.addAction('Delete')
                    addRoleToDirAction.triggered.connect(self.contextAddRoleToDir)
                    deleteRoleFromDirAction.triggered.connect(self.contextDeleteRoleFromDir)
                    deleteDirAction.triggered.connect(self.contextDeleteDirNode)
                else:
                    createRoleAction = menu.addAction('Create Role')
                    createUserAction = menu.addAction('Create User')
                    createDirAction = menu.addAction('Create Object')
                    menu.addSeparator()
                    menu.addAction(self.main.ui.actionQuery_Window)
                    createRoleAction.triggered.connect(self.contextCreateRoleNode)
                    createUserAction.triggered.connect(self.contextCreateUserNode)
                    createDirAction.triggered.connect(self.contextCreateDirNode)
            menu.exec_(evt.screenPos())
        
    def drawLabelNodesEdges(self, painter, roleNodes, userNods, dirNodes):
        #Ending edges
        painter.drawLine(roleNodes[0].pointRightTop, roleNodes[-1].pointRightBottom)
        painter.drawLine(userNods[0].pointRightTop, userNods[-1].pointRightBottom)
        painter.drawLine(dirNodes[0].pointRightTop, dirNodes[-1].pointRightBottom)

    def contextAddParentToRole(self):
        self.nodesContextMenuResponce.emit(self.rightClickedItem, self.ADD_PARENT_ROLE)
        
    def contextDeleteParentFromRole(self):
        self.nodesContextMenuResponce.emit(self.rightClickedItem, self.DELETE_PARENT_ROLE)
        
    def contextAddChildToRole(self):
        self.nodesContextMenuResponce.emit(self.rightClickedItem, self.ADD_CHILD_ROLE)
        
    def contextDeleteChildFromRole(self):
        self.nodesContextMenuResponce.emit(self.rightClickedItem, self.DELETE_CHILD_ROLE)
        
    def contextAddUserToRole(self):
        self.nodesContextMenuResponce.emit(self.rightClickedItem, self.ADD_USER_2ROLE)
        
    def contextDeleteUserFromRole(self):
        self.nodesContextMenuResponce.emit(self.rightClickedItem, self.DELETE_USER_2ROLE)
        
    def contextAddDirToRole(self):
        self.nodesContextMenuResponce.emit(self.rightClickedItem, self.ADD_DIR_2ROLE)
        
    def contextDeleteDirFromRole(self):
        self.nodesContextMenuResponce.emit(self.rightClickedItem, self.DELETE_DIR_2ROLE)
        
    def contextDeleteRoleNode(self):
        self.nodesContextMenuResponce.emit(self.rightClickedItem, self.DELETE_ROLENODE)
    
    '''for user node'''
    def contextAddRoleToUser(self):
        self.nodesContextMenuResponce.emit(self.rightClickedItem, self.ADD_ROLE_2USER)
        
    def contextDeleteRoleFromUser(self):
        self.nodesContextMenuResponce.emit(self.rightClickedItem, self.DELETE_ROLE_2USER)
        
    def contextDeleteUserNode(self):
        self.nodesContextMenuResponce.emit(self.rightClickedItem, self.DELETE_USERNODE)
        
    '''for dir ndoe'''
    def contextAddRoleToDir(self):
        self.nodesContextMenuResponce.emit(self.rightClickedItem, self.ADD_ROLE_2DIR)
        
    def contextDeleteRoleFromDir(self):
        self.nodesContextMenuResponce.emit(self.rightClickedItem, self.DELETE_ROLE_2DIR)
        
    def contextDeleteDirNode(self):
        self.nodesContextMenuResponce.emit(self.rightClickedItem, self.DELETE_DIRNODE)

    '''create nodes'''
    def contextCreateRoleNode(self):
        self.rightClickedItem = QGraphicsEllipseItem()
        self.nodesContextMenuResponce.emit(self.rightClickedItem, self.CREATE_ROLENODE)

    def contextCreateUserNode(self):
        self.rightClickedItem = QGraphicsEllipseItem()
        self.nodesContextMenuResponce.emit(self.rightClickedItem, self.CREATE_USERNODE)
        
    def contextCreateDirNode(self):
        self.rightClickedItem = QGraphicsEllipseItem()
        self.nodesContextMenuResponce.emit(self.rightClickedItem, self.CREATE_DIRNODE)
        
    '''Animation'''
    def findRoleUserNodeInList(self, name, nodelist):
        for e in nodelist:
            if e.name == name:
                return e
            
    def findObjNodeInList(self, name, nodelist):
        for e in nodelist:
            if e.dir == name:
                return e
        
    def stopAnimationTimer(self):
        self.animationTimer.stop()
        self.animationStopped.emit()
        self.parentWindow.actionPan.setEnabled(True)
        self.parentWindow.actionToolBox.setEnabeld(True)
        self.parentWindow.actionSpecification.setEnabeld(True)
        self.parentWindow.actionTest.setEnabeld(True)

    def startAnimationTimer(self):
        self.animationTimer.start()
        self.animationStarted.emit()
        self.parentWindow.ui.actionPan.setEnabled(False)
        self.parentWindow.actionToolBox.setEnabeld(False)
        self.parentWindow.actionSpecification.setEnabeld(False)
        self.parentWindow.actionTest.setEnabeld(False)

    def exitAnimation(self):
        self.message = ''
        self.animationStep = 0
        
    def animateQuery0(self, rolename, username, objname):
        '''Does the specified role allow user access to object'''
        self.animationType = 0
        self.animationParameters = [rolename, username, objname]
        self.message = 'Whether role of %s allows user %s access to object %s' % \
            (rolename, username, objname)
        self.update()
        self.startAnimationTimer()
     
    def animateQuery1(self, rnode, rnodeset, objnode):
        '''What objects can role read/write/execute'''
        self.animationType = 1
        self.animationParameters = [rnode, rnodeset, objnode]
        self.update()
        self.startAnimationTimer()
    
    def animateQuery2(self, username):
        '''What roles does certain user occupy'''
        self.animationType = 2
        self.animationParameters = [username]
        self.update()
        self.startAnimationTimer()
    
    def animateQuery3(self, rolename):
        '''Which users occupy the specified role'''
        self.animationType = 3
        self.animationParameters = [rolename]
        self.update()
        self.startAnimationTimer()
    
    def animateQuery4(self, rolename):
        '''What roles does the specified role inherit'''
        self.animationType = 4
        self.animationParameters = [rolename]
        self.update()
        self.startAnimationTimer()
    
    def animateQuery5(self, rolename):
        '''What roles inherit the specified role'''
        self.animationType = 5
        self.animationParameters = [rolename]
        self.update()
        self.startAnimationTimer()
        
    def animateQuery6(self, rolename1, rolename2):
        '''Is role X >= role Y'''
        self.animationType = 6
        self.animationParameters = [rolename1, rolename2]
        self.update()
        self.startAnimationTimer()
    
    def animateQuery7(self, rolename1, rolename2):
        '''Are the users of role X '+u"\u2286"+' the users of role Y'''
        self.animationType = 7
        self.animationParameters = [rolename1, rolename2]
        #self.message = 'The type of %s is %s' % (str(filename), str(typeNode.name))
        self.update()
        self.startAnimationTimer()
    
    def animateQuery8(self, rolename1, rolename2):
        '''Are the permissions of role X '+u"\u2286"+' the permissions of role Y'''
        self.animationType = 8
        self.animationParameters = [rolename1, rolename2]
        self.update()
        self.startAnimationTimer()
    
    def animateQuery9(self, rolenode, dirnode, permset):
        '''Does the specified role allow access to a certain object'''
        self.animationType = 9
        self.animationParameters = [rolenode, dirnode, permset]
        self.update()
        self.startAnimationTimer()
    
    def animateQuery(self):
        if self.animationType == 0:
            rolename = self.animationParameters[0]
            username = self.animationParameters[1]
            objname = self.animationParameters[2]
            rnode = self.findRoleUserNodeInList(rolename, self.main.roleNodes)
            unode = self.findRoleUserNodeInList(username, self.main.userNodes)
            onode = self.findObjNodeInList(objname, self.main.dirNodes)
            self.stopAnimationTimer()
        elif self.animationType == 1:
            rnode = self.animationParameters[0]
            rnodeset = self.animationParameters[1]
            onode = self.animationParameters[2]
            self.stopAnimationTimer()
        elif self.animationType == 2:
            username = self.animationParameters[0]
            unode = self.findRoleUserNodeInList(username, self.main.userNodes)
            self.stopAnimationTimer()
        elif self.animationType == 3:
            rolename = self.animationParameters[0]
            rnode = self.findRoleUserNodeInList(rolename, self.main.roleNodes)
            self.stopAnimationTimer()
        elif self.animationType == 4:
            rolename = self.animationParameters[0]
            rnode = self.findRoleUserNodeInList(rolename, self.main.roleNodes)
            self.stopAnimationTimer()
        elif self.animationType == 5:
            rolename = self.animationParameters[0]
            rnode = self.findRoleUserNodeInList(rolename, self.main.roleNodes)
            self.stopAnimationTimer()
        elif self.animationType == 6:
            rolename1 = self.animationParameters[0]
            rolename2 = self.animationParameters[1]
            rnode1 = self.findRoleUserNodeInList(rolename1, self.main.roleNodes)
            rnode2 = self.findRoleUserNodeInList(rolename2, self.main.roleNodes)
            self.stopAnimationTimer()
        elif self.animationType == 7:
            rolename1 = self.animationParameters[0]
            rolename2 = self.animationParameters[1]
            rnode1 = self.findRoleUserNodeInList(rolename1, self.main.roleNodes)
            rnode2 = self.findRoleUserNodeInList(rolename2, self.main.roleNodes)
            self.stopAnimationTimer()
        elif self.animationType == 8:
            rolename1 = self.animationParameters[0]
            rolename2 = self.animationParameters[1]
            rnode1 = self.findRoleUserNodeInList(rolename1, self.main.roleNodes)
            rnode2 = self.findRoleUserNodeInList(rolename2, self.main.roleNodes)
            self.stopAnimationTimer()
        elif self.animationType == 9:
            rolenode = self.animationParameters[0]
            dirnode = self.animationParameters[1]
            permset = self.animationParameters[2]
            self.stopAnimationTimer()
            