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

@author: yifli
'''

from PyQt4.QtGui import QGraphicsLineItem, QMessageBox, QPen, QBrush, QInputDialog, QGraphicsItem, \
                        QPolygonF, QPainter, QPainterPath, QColor, QFontMetricsF, QFontMetrics, QTransform
from PyQt4.QtCore import Qt,QLineF, QPointF, QRectF
from TypeNode import TypeNode
from FileNode import FileNode
from DomainNode import DomainNode
import math
import re
import string

EDGE_WIDTH = 2

class EdgeItem(QGraphicsLineItem):

    AUTO_CONN = 0
    EXEC_CONN = 1
    TYPE_CONN = 2
    FILE_CONN = 3

    def __init__(self, type, start, end):
        QGraphicsLineItem.__init__(self)
        self.selectionOffset = 20
        self.arrowSize = 20
        self.setFlag(QGraphicsItem.ItemIsSelectable)
        self.type = type
        self.startItem = start
        self.endItem = end
        self.description = ''
        self.setZValue((-1000.0))
        self.highlighted = False   
        self.selectionPolygon = None
       
#     def __setattr__(self, name, value):
#         self.__dict__[name] = value
#         if name == 'name':
#             width = QFontMetrics(self.scene().font()).boundingRect(self.name).width()
#             if width > self.boundingRect().width():
#                 self.setToolTip(self.name)
                
    def createSelectionPolygon(self):
        pi = 3.141592653589793238463
        angle = self.line().angle()
        radAngle = angle*pi/180
        dx = self.selectionOffset * math.sin(radAngle)
        dy = self.selectionOffset * math.cos(radAngle)
        halfoffset = 0.5*self.selectionOffset
        if dx == 0 or dy == 0:
            dx, dy = halfoffset, halfoffset 
        offset1 = QPointF(dx, dy)
        offset2 = QPointF(-dx, -dy)
        nPolygon = QPolygonF([self.line().p1() + offset1, self.line().p1() + offset2, \
                             self.line().p2() + offset2, self.line().p2() + offset1])
        self.selectionPolygon = nPolygon
        self.update()
       
    def boundingRect(self):
        return self.selectionPolygon.boundingRect()

    def shape(self):                 
        angle = self.line().angle()
        if angle < 0:
            angle += 360
        angle -= 90
        angle = math.pi * angle / 180.0
#         adjustment = 4
#         xTrans = adjustment * math.cos(angle)
#         yTrans = adjustment * math.sin(angle)
#         lower_line = self.line().translated(-xTrans,-yTrans)
#         upper_line = self.line().translated(xTrans, yTrans)
#         path = QPainterPath(upper_line.p1())
#             #         path.lineTo(upper_line.p1())
#         pointList = [upper_line.p1(), lower_line.p1(), lower_line.p2(), upper_line.p2(), upper_line.p1()]
#         boundingRect = QPolygonF(pointList)
#         path.addPolygon(boundingRect)
 
        adjustment = 10
        xTrans = adjustment * math.cos(angle)
        yTrans = adjustment * math.sin(angle)
        p1 = QPointF(self.line().p1().x()-xTrans, self.line().p1().y()+yTrans)
        rect = QRectF(p1.x(), p1.y(), self.line().length(), 2*adjustment)
        t = QTransform()
        t.translate(p1.x(), p1.y())
        t.rotate(-self.line().angle())
        t.translate(-p1.x(), -p1.y())
        path = QPainterPath()
        path.addRect(rect)
        newPath = QPainterPath(t.map(path))
#         path.lineTo(lower_line.p1())
#         path.lineTo(lower_line.p2())
#         path.lineTo(upper_line.p2())
#         path.lineTo(upper_line.p1())
#         boundingRect = QPolygonF(upper_line.p1(), lower_line.p1(), lower_line.p2(), upper_line.p2(), upper_line.p1())
#         path.addRect(boundingRect.boundingRect())
        #path.addRect(self.boundingRect())
#         if not isinstance(self.endItem, TypeNode) and not isinstance(self.endItem, FileNode):
        if isinstance(self.endItem, DomainNode):
            newPath.addPolygon(self.arrowHead)
        newPath = QPainterPath()
        newPath.addPolygon(self.selectionPolygon)
        return newPath
    
    def paint(self, painter, option, widget=None):
        if self.startItem.collidesWithItem(self.endItem):
            return
        
        if self.scene().domainGraphOnly and self.type == self.TYPE_CONN:
            return
        
        painter.setRenderHint(QPainter.HighQualityAntialiasing)
        
        
        if self.type == self.AUTO_CONN or self.type == self.TYPE_CONN or self.type == self.FILE_CONN:
            pen = QPen(Qt.SolidLine)
            if self.type == self.AUTO_CONN:
                pen.setWidth(2.0)
        else:
            pen = QPen(Qt.DashLine)
            pen.setWidth(2.0)
            
        if self.highlighted:
            pen.setColor(QColor(0, 0, 255))
        painter.setPen(pen)
        painter.setBrush(QBrush(Qt.black))
        
        if isinstance(self.endItem, DomainNode) or isinstance(self.endItem, TypeNode):
            centerline = QLineF(self.startItem.pos(), self.endItem.pos())
            startRect = self.endItem.boundingRect()
            endRect = self.endItem.boundingRect()
            
            # test the intersection between centerline and startRect
            p1 = startRect.topLeft() + self.startItem.pos()
            p2 = startRect.bottomLeft() + self.startItem.pos()
            intersection1 = QPointF()
            intersectType = QLineF(p1,p2).intersect(centerline, intersection1)
            if intersectType != QLineF.BoundedIntersection:
                p1 = p2
                p2 = startRect.bottomRight() + self.startItem.pos()
                intersectType = QLineF(p1,p2).intersect(centerline, intersection1)
                if intersectType != QLineF.BoundedIntersection:
                    p1 = p2
                    p2 = startRect.topRight() + self.startItem.pos()
                    intersectType = QLineF(p1, p2).intersect(centerline, intersection1)
                    if intersectType != QLineF.BoundedIntersection:
                        p1 = p2
                        p2 = startRect.topLeft() + self.startItem.pos()
                        intersectType = QLineF(p1, p2).intersect(centerline, intersection1)
                        if intersectType != QLineF.BoundedIntersection:
                            return
             
            intersection1 = (p1+p2) / 2.0  

            
            
            # test the intersection between centerline and endRect
            p1 = endRect.topLeft() + self.endItem.pos()
            p2 = endRect.bottomLeft() + self.endItem.pos()
            intersection2 = QPointF()
            intersectType = QLineF(p1,p2).intersect(centerline, intersection2)
            if intersectType != QLineF.BoundedIntersection:
                p1 = p2
                p2 = endRect.bottomRight() + self.endItem.pos()
                intersectType = QLineF(p1,p2).intersect(centerline, intersection2)
                if intersectType != QLineF.BoundedIntersection:
                    p1 = p2
                    p2 = endRect.topRight() + self.endItem.pos()
                    intersectType = QLineF(p1, p2).intersect(centerline, intersection2)
                    if intersectType != QLineF.BoundedIntersection:
                        p1 = p2
                        p2 = endRect.topLeft() + self.endItem.pos()
                        intersectType = QLineF(p1, p2).intersect(centerline, intersection2)
                        if intersectType != QLineF.BoundedIntersection:
                            return
            
            
            intersection2 = (p1+p2) / 2.0  
            self.setLine(QLineF(self.startItem.pos(), intersection2))
            
            if isinstance(self.endItem, DomainNode):
                verts = []
                verts.append(intersection2)
                angle = math.acos(self.line().dx() / self.line().length())
                if self.line().dy() >= 0:
                    angle = 2*math.pi - angle
                    
                verts.append( self.line().p2() +   QPointF(-math.cos(angle + math.pi / 12) * self.arrowSize,
                                                         math.sin(angle + math.pi / 12) * self.arrowSize)
                             )
                verts.append( self.line().p2() + QPointF(-math.cos(angle - math.pi / 12) * self.arrowSize,
                                                         math.sin(angle - math.pi / 12) * self.arrowSize)
                             )
    
                self.arrowHead = QPolygonF(verts)
                painter.drawPolygon(self.arrowHead)        

        else:
            self.setLine(QLineF(self.startItem.pos(), self.endItem.pos()))

        
#         angle = self.line().angle()
#         if angle < 0:
#             angle += 360
#         angle -= 90
#         angle = math.pi * angle / 180.0
#          
#  
#         adjustment = 8
#         xTrans = adjustment * math.cos(angle)
#         yTrans = adjustment * math.sin(angle)
#         painter.setBrush(QBrush(Qt.red))
#         p1 = QPointF(self.line().p1().x()-xTrans, self.line().p1().y()+yTrans)
#         rect = QRectF(p1.x(), p1.y(), self.line().length(), 16)
#         t = QTransform()
#         t.translate(p1.x(), p1.y())
#         t.rotate(-self.line().angle())
#         t.translate(-p1.x(), -p1.y())
#          
#         path = QPainterPath()
#         path.addRect(rect)
#         newPath= QPainterPath(t.map(path))
#         painter.drawPath(newPath)
        
        # drawing
        painter.drawLine(self.line())

        if self.isSelected():
            painter.save()
            painter.setPen(QPen(QColor(0, 255, 0, 128), 1, Qt.SolidLine))
            painter.setBrush(QBrush(QColor(0, 255, 0, 128)))
            painter.drawPolygon(self.selectionPolygon)
            painter.restore()
        if self.description:
            if ( self.scene().showDomainDomainLabels and (self.type == self.AUTO_CONN or self.type == self.EXEC_CONN) or
                 self.scene().showDomainTypeLabels and self.type == self.TYPE_CONN ):
                
                fm = QFontMetricsF(self.scene().font())
                width = fm.boundingRect(self.description).width()
                space = math.sqrt( (intersection1.x() - intersection2.x())**2 + (intersection1.y() - intersection2.y())**2 )

                angle = self.line().angle()
                
                if angle > 90 and angle <= 270:
                    if space >= 2.0 * width:
                        painter.translate(intersection1*0.5 + self.line().p2()*0.5)
                    else:
                        painter.translate(intersection1*0.1 + self.line().p2()*0.9)
                    '''
                    if self.type == EdgeItem.AUTO_CONN or self.type == EdgeItem.EXEC_CONN:
                        #painter.translate(self.line().p1()*0.2 + self.line().p2()*0.8)
                        painter.translate(intersection1*0.2 + self.line().p2()*0.8)
                    else:
                        #painter.translate(self.line().p1()*0.4 + self.line().p2()*0.6)
                        painter.translate(intersection1*0.6 + self.line().p2()*0.4)
                    '''
                    painter.rotate(180-angle)

                else:
                    if space >= 2.0 * width:
                        painter.translate(intersection1*0.5 + self.line().p2()*0.5)
                    else:
                        painter.translate(intersection1*0.9 + self.line().p2()*0.1)
 
                    '''
                    if self.type == EdgeItem.AUTO_CONN or self.type == EdgeItem.EXEC_CONN:
                        #painter.translate(self.line().p1()*0.8 + self.line().p2()*0.2)
                        painter.translate(intersection1*0.8 + self.line().p2()*0.2)
                    else:
                        #painter.translate(self.line().p1()*0.5 + self.line().p2()*0.5)
                        painter.translate(intersection1*0.6 + self.line().p2()*0.4)
                    '''
                    painter.rotate(-self.line().angle())

                painter.drawText(0, -5, self.description)
        
    def updatePosition(self):
        line = QLineF(self.mapFromItem(self.startItem, QPointF(0, 0)), self.mapFromItem(self.endItem, QPointF(0, 0)))
        self.setLine(line)
        self.createSelectionPolygon()
        if self.type == self.AUTO_CONN or self.type == self.EXEC_CONN:
            self.setToolTip(self.description)
        
        