'''
Created on Apr 17, 2014

@author: mandy
'''

from PyQt4.QtGui import QGraphicsItem, QGraphicsEllipseItem, QColor, QBrush, QPen, QPainter, QFont
from PyQt4.QtCore import QObject, Qt, QRectF, QRect, QPointF
import math
import MyFunctions

class nodeComponent(QGraphicsEllipseItem):
    components = []
    
    ROLE_ITEM = 0
    USER_ITEM = 1
    DIR_ITEM = 2
    def __init__(self, node, index):
        QObject.__init__(self)
        QGraphicsEllipseItem.__init__(self, node)
        self.parent = node
        self.index = index  
        if self.index == self.ROLE_ITEM:
            self.setStartAngle(0)
            self.setSpanAngle(180*16)
            self.color = Qt.red
        elif self.index == self.USER_ITEM:
            self.setStartAngle(180*16)
            self.setSpanAngle(90*16)
            self.color = Qt.yellow
        elif self.index == self.DIR_ITEM:
            self.setStartAngle(0)
            self.setSpanAngle(-90*16)
            self.color = Qt.green
        self.setRect(node.rectContent)
        self.setFlag(QGraphicsItem.ItemIsMovable, True)
        self.setFlag(QGraphicsItem.ItemIsSelectable, True)
        self.setAcceptHoverEvents(True)
        self.setVisible(False)
        self.paintColor = self.color
        self.highlightColor = Qt.cyan
        self.highlight = False
        
    def paint(self, painter, option, widget):
        self.setPen(self.paintColor)
        self.setBrush(self.paintColor)
        painter.setRenderHint(QPainter.Antialiasing, True)
        QGraphicsEllipseItem.paint(self, painter, option, widget)
        
    def mouseMoveEvent(self, event):
        self.parent.mouseMoveEvent(event)

    def mousePressEvent(self, event):
        if self.index != self.ROLE_ITEM:
            if self.paintColor == self.color:
                self.paintColor = self.highlightColor
                self.highlight = True
            else:
                self.paintColor = self.color
                self.highlight = False
            
        if self.index == self.USER_ITEM:
            self.parent.main.toggleRoleUserWindow(self.parent)
        elif self.index == self.DIR_ITEM:
            self.parent.main.toggleRolePermWindow(self.parent)
            
class RoleNode(QGraphicsEllipseItem):
    NODESIZE = 60
    NODE_BOUNDARY_SIZE = 63
    def __init__(self, role, scene, main):
        QGraphicsEllipseItem.__init__(self)
        self.rectContent = QRectF(-0.5*self.NODESIZE, -0.5*self.NODESIZE, self.NODESIZE, self.NODESIZE)
        self.rectbound = QRectF(-0.5*self.NODE_BOUNDARY_SIZE, -0.5*self.NODE_BOUNDARY_SIZE, self.NODE_BOUNDARY_SIZE, self.NODE_BOUNDARY_SIZE)
        self.setRect(self.rectContent)
        self.roleItem = nodeComponent(self, 0)
        self.roleUserItem = nodeComponent(self, 1)
        self.roleObjItem = nodeComponent(self, 2)
        self.roleItem.components = [self.roleUserItem, self.roleObjItem, self]
        self.roleUserItem.components = [self.roleItem, self.roleObjItem, self]
        self.roleObjItem.components = [self.roleItem, self.roleUserItem, self]
        
        self.edgeList = []
        self.level = 0
        self.main = main
        self.name = role
        
        if role in self.main.role_adjmat.keys():
            self.parents = self.main.role_adjmat[role].parents
            self.children = self.main.role_adjmat[role].children
        else:
            self.parents = set()
            self.children = set()
            
        self.parentNodes = set()
        self.childrenNodes = set()

        self.scene = scene
        self.highlighted = False
        
        self.relativeX, self.relativeY = 0, 0

        self.label = self.name
        self.font = QFont("Calibri")
        self.font.setPixelSize(self.main.FONT_SIZE)
        self.pen = QPen()
        
        self.setFlag(QGraphicsItem.ItemIsMovable, True)
        self.setFlag(QGraphicsItem.ItemIsSelectable, True)
        self.setVisible(False)
    
    def setAllVisible(self, flag):
        self.setVisible(flag)
        self.roleItem.setVisible(flag)
        self.roleUserItem.setVisible(flag)
        self.roleObjItem.setVisible(flag)
        
    def mouseMoveEvent(self, event):
        QGraphicsEllipseItem.mouseMoveEvent(self, event)
        offset = QPointF(0,0)
        self.roleItem.setPos(offset)
        self.roleUserItem.setPos(offset)
        self.roleObjItem.setPos(offset)
        self.scene.update()
        
    def mouseReleaseEvent(self, event):
        QGraphicsEllipseItem.mouseMoveEvent(self, event)
        self.relativeX = self.pos().x()/self.scene.sceneRect().width()
        self.relativeY = self.pos().y()/self.scene.sceneRect().height()
        self.scene.update()

    def paint(self, painter, option, widget=None):
        '''
        draw outline
        '''
        self.pen.setColor(Qt.black)
        self.pen.setWidth(5.0)
        self.setPen(self.pen)
        painter.setRenderHint(QPainter.Antialiasing, True)
        QGraphicsEllipseItem.paint(self, painter, option, widget)
        '''
        display name as label
        '''
        self.pen.setColor(Qt.black)
        painter.setPen(self.pen)
        painter.setFont(self.font)
        self.labelRect = painter.fontMetrics().boundingRect(self.name)
        x = int(self.rect().bottomLeft().x()-(self.labelRect.width()))
        y = int(self.rect().topLeft().y()-0.5*self.labelRect.height())
        self.paintLabel(painter, self.brush, x, y)
                
    def paintLabel(self, painter, oldbrush, x, y):
        rect = self.labelRect
        rect.moveTo(x, y)
        painter.drawText(rect, Qt.AlignLeft, self.label)
        
    def itemChange(self, change, value):
        if change == QGraphicsItem.ItemPositionChange:
            for edge in self.edgeList:
                edge.updatePosition()
        return value             

class RoleCompactNode(QGraphicsEllipseItem):
    NODESIZE = 50
    NODE_BOUNDARY_SIZE = 53
    
    def __init__(self, role, scene, main):
        QGraphicsEllipseItem.__init__(self)
        #self.setAcceptHoverEvents(True)
        self.rectContent = QRectF(-0.5*self.NODESIZE, -0.5*self.NODESIZE, self.NODESIZE, self.NODESIZE)
        self.rectbound = QRectF(-0.5*self.NODE_BOUNDARY_SIZE, -0.5*self.NODE_BOUNDARY_SIZE, self.NODE_BOUNDARY_SIZE, self.NODE_BOUNDARY_SIZE)
        self.setRect(self.rectContent)
        '''for roles edges'''
        self.roleEdgeList = []
        self.level = 0
        self.main = main
        self.name = role
        if role in self.main.role_adjmat.keys():
            self.parents = self.main.role_adjmat[role].parents
            self.children = self.main.role_adjmat[role].children
        else:
            self.parents = set()
            self.children = set()
            
        self.parentNodes = set()
        self.childrenNodes = set()
        self.allParentNodes = set()
        self.allChildrenNodes = set()
        
        self.possibleParentNodes = set()
        self.possibleChildrenNodes = set()
        
        self.userNodes = []
        self.dirNodes = []

        self.scene = scene
        self.highlighted = False
        self.color = QColor(127, 255, 127)
        self.penColor = QColor(0,127, 0)
        self.labelColor = Qt.black
        self.label = self.name
        '''for boder'''
        self.inheritHighlight = False
        self.boderColor = Qt.red
        self.inheritColor = Qt.darkBlue
        self.pen = QPen(self.boderColor)
        self.pen.setWidth(3.0)
        self.font = QFont("Calibri")
        self.font.setPixelSize(self.main.FONT_SIZE)
        
        self.relativeX, self.relativeY = 0, 0

        self.setFlag(QGraphicsItem.ItemIsMovable, True)
        self.setFlag(QGraphicsItem.ItemIsSelectable, True)
        self.setVisible(False)
                       
    def setUserNodesPosition(self, flag):
        if flag:
            radius = self.main.extendUserRadius
        else:
            radius = self.main.roleUserNodeRadius
        for u in self.userNodes:
            u.setPos(self.pos().x()+radius*math.cos(u.angle2Rolenode), self.pos().y()+radius*math.sin(u.angle2Rolenode))

    def toggleUserNodes(self):
        for u in self.userNodes:
            if self.main.mode == self.main.HIGHLIGHT_MODE:
                if self.highlighted:
                    u.highlighted = True
                    radius = self.main.extendUserRadius
                else:
                    u.highlighted = False
                    radius = self.main.roleUserNodeRadius
            else:
                radius = self.main.roleUserNodeRadius
            u.setPos(self.pos().x()+radius*math.cos(u.angle2Rolenode), self.pos().y()+radius*math.sin(u.angle2Rolenode))
                
    def mouseMoveEvent(self, event):
        QGraphicsEllipseItem.mouseMoveEvent(self, event)
    
    def mouseReleaseEvent(self, event):
        QGraphicsEllipseItem.mouseReleaseEvent(self, event)
        self.relativeX = self.pos().x()/self.scene.sceneRect().width()
        self.relativeY = self.pos().y()/self.scene.sceneRect().height()
        self.toggleUserNodes()
        self.main.updateClickRelatedUserNodes()
        self.main.checkMainMode()
        self.main.updateEdgePositions()
        self.main.updateAllScenes()
#         if fabs(self.oldPos.x()-)
#         message = "Role("+self.name+"): Moved\n"
#         self.main.writeToFile(self.main.logFile, self.main.getCurrentTimeString()+message)

    def mousePressEvent(self, event):
        self.main.roleHierRightPerm = ''
        self.oldPos = self.pos()
        if self.main.nodeMove and self.isSelected:
            for item in self.main.roleCompactNodes:
                if item != self:
                    item.setSelected(False)
            for item in self.main.userNodes:
                    item.setSelected(False)
        if event.button() == Qt.LeftButton and (not self.main.nodeMove):
            for d in self.main.dirNodes:
                d.highlighted = False
                d.recursive = False

            self.retrieveHighlightUI()
            QGraphicsEllipseItem.mousePressEvent(self, event)
            self.main.initiateItemsHightlightState()
            if self.main.mode == self.main.HIGHLIGHT_MODE and event.button() == Qt.LeftButton:
                if self.highlighted:
                    if self.main.clickedNode and (self.main.clickedNode == self or self.main.clickedNode not in self.main.roleCompactNodes):
                        self.highlighted = False
                        self.main.clickedNode = None
                        self.main.clickedRelatedNodes = []
                    else:
                        self.main.policyManager.highlightNodeWithBorderRoleNode(self)
                else:
                    self.main.policyManager.highlightNodeWithBorderRoleNode(self)
                self.main.policyManager.setUnclickedNodesGrey()
                self.main.setPermInfoInRoleHierView()
            self.main.showHintContent()
            if self.main.specDialog.isVisible():
                self.main.specDialog.reGenerateSpec()
            self.setHighlightUI()
            '''Collect user operation data'''
            if self.highlighted:
                message = "HView: Role("+ self.name+ "): Clicked: Apply highlighting\n"
            else:
                message = "HView: Role("+ self.name+ "): Clicked: Remove highlighting\n"
            self.main.writeToFile(self.main.logFile, self.main.getCurrentTimeString()+message)
            
    def setHighlightUI(self):
        if self.main.toolBox.ui.noRHierRBtn.isChecked():
            self.main.highlightmode = self.main.HIGHLIGHT_NO_HIER_MODE
        else:
            self.main.highlightmode = self.main.HIGHLIGHT_HIER_MODE
            if self.main.toolBox.ui.roleChildHighlightRBtn.isChecked():
                self.main.roleHighlightScheme = self.main.ROLE_HIGHLIGHT_CHILDREN
            elif self.main.toolBox.ui.roleParentHighlightRBtn.isChecked():
                self.main.roleHighlightScheme = self.main.ROLE_HIGHLIGHT_PARENTS
            elif self.main.toolBox.ui.roleBothHighlightRBtn.isChecked():
                self.main.roleHighlightScheme = self.main.ROLE_HIGHLIGHT_BOTH
        
    def retrieveHighlightUI(self):
            self.main.toolBox.ui.noRHierRBtn.setEnabled(True)
            self.main.toolBox.ui.withRHierRBtn.setEnabled(True)
            if self.main.highlightmode == self.main.HIGHLIGHT_NO_HIER_MODE:
                self.main.toolBox.ui.noRHierRBtn.setChecked(True)
                self.main.policyManager.enableHighlightNoRHier()
            else:
                self.main.toolBox.ui.withRHierRBtn.setChecked(True)
                self.main.policyManager.enableHighlightWithRHier()
                if self.main.roleHighlightScheme == self.main.ROLE_HIGHLIGHT_CHILDREN:
                    self.main.toolBox.ui.roleChildHighlightRBtn.setChecked(True)
                elif self.main.roleHighlightScheme == self.main.ROLE_HIGHLIGHT_PARENTS:
                    self.main.toolBox.ui.roleParentHighlightRBtn.setChecked(True)
                elif self.main.roleHighlightScheme == self.main.ROLE_HIGHLIGHT_BOTH:
                    self.main.toolBox.ui.roleBothHighlightRBtn.setChecked(True)
            
    def paint(self, painter, option, widget=None):
        if self.main.mode == self.main.HIGHLIGHT_MODE:
            if self.highlighted:
                self.color = QColor(127, 255, 127)
                self.penColor = QColor(0,127, 0)
                self.labelColor = Qt.black
            else:
                self.color = Qt.gray
                self.penColor = Qt.darkGray
                self.labelColor = Qt.gray
        else:
            self.color = QColor(127, 255, 127)
            self.penColor = QColor(0,127, 0)
            self.labelColor = Qt.black
        self.paintBorder(painter)
        '''
        draw outline
        '''
        self.pen.setColor(self.penColor)
        self.pen.setWidth(3.0)
        self.setPen(self.pen)
        self.setBrush(self.color)
        painter.setRenderHint(QPainter.Antialiasing, True)
        QGraphicsEllipseItem.paint(self, painter, option, widget)
        '''
        display name as label
        '''
        self.pen.setColor(self.labelColor)
        painter.setPen(self.pen)
        painter.setFont(self.font)
        self.labelRect = painter.fontMetrics().boundingRect(self.name)
        self.labelRect = QRect(self.labelRect.x(), self.labelRect.y(), self.labelRect.width()+3, self.labelRect.height())
        x = int(self.rect().bottomLeft().x()-(self.labelRect.width())+5)
        y = int(self.rect().topLeft().y()-0.6*self.labelRect.height())
        self.paintLabel(painter, self.brush, x, y)
        
    def paintBorder(self, painter):
        if self.main.clickedNode == self or self in self.main.clickedRelatedNodes:
            if self.inheritHighlight:
                self.pen.setColor(self.inheritColor)
            else:
                self.pen.setColor(self.boderColor)
            painter.setPen(self.pen)
            r = self.boundingRect()
            #painter.drawRect(QRect(r.x()-0.12*r.width(), r.y()-0.12*r.height(), 1.2*r.width(), 1.2*r.height()))
            painter.drawRect(QRect(r.x()-0.04*r.width(), r.y()-0.04*r.height(), 1.03*r.width(), 1.03*r.height()))

    def paintLabel(self, painter, oldbrush, x, y):
        rect = self.labelRect
        rect.moveTo(x, y)
        painter.drawText(rect, Qt.AlignLeft, self.label)
        
    def itemChange(self, change, value):
        if change == QGraphicsItem.ItemPositionChange:
            for e in self.edgeList:
                e.updatePosition()
        return value  