'''
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
'''
"""
             ThreadMentor: Thread Visualization System
           (c)2012-2014 Michigan Technological University

@author: Man Wang
@date: Oct. 21, 2013
"""
import math
from FileNode import FileNode

class RadialTreeLayout(object):

    def __init__(self, scene):
        self.scene = scene
        self.sceneWidth = scene.width()
        self.sceneHeight = scene.height()
        
    
    def calculateLeaveNumber(self, root):
        nodesToVisit = [root]
        while nodesToVisit:
            n = nodesToVisit[-1]
            if n.children:
                if n.children[0].visited:
                    n.leaves = 0
                    for c in n.children:
                        n.leaves += c.leaves
                    n.visited = True
                    nodesToVisit.pop()
                else: 
                    for c in n.children:
                        nodesToVisit.append(c)
            else:
                n.visited = True
                n.leaves = 1
                nodesToVisit.pop()
                
        
        
        
    def buildTreeTable(self, root, extraSpacing = 0):
        root.leftBisectorLimit = 2*math.pi
        self.nodeTable = {}
        self.nodeTable[0]=[root]
        level=1
        levelNodes = root.children
        #print root.name, root.type.name, root.fullPath
#        for c in root.children:
#            print 'root c', c.name, c.type.name, c.fullPath
        while levelNodes:
            self.nodeTable[level] = levelNodes
            #print levelNodes
            for n in levelNodes:
                n.level = level
            levelNodes = []
            for n in self.nodeTable[level]:
                n.visited = False
                n.leftBisectorLimit = 2*math.pi
                if n.children:
                    levelNodes.extend(n.children)
#            for c in levelNodes:
#                print 'levelNodes', level, c.name, c.type.name, c.fullPath
            level += 1
            
        self.calculateLeaveNumber(root)
        root.wedgeAngle = 2 * math.pi 
    
        self.numLevels = len(self.nodeTable)
        self.viewportWidth = self.scene.views()[0].viewport().width()
        self.viewportHeight = self.scene.views()[0].viewport().height()
        self.radius = min(self.viewportWidth, self.viewportHeight) / 2.0
        if self.numLevels >1:
            self.d =  self.radius / (self.numLevels-1)

    def mapToScene(self):
        edges = set()
        for nodes in self.nodeTable.values():
            for n in nodes:
                for e in n.edgeList:
                    edges.add(e)
                n.setPos(n.relativeX+self.sceneWidth/2.0, -n.relativeY+self.sceneHeight/2.0)
                #n.setPos(n.relativeX, -n.relativeY)
                
        for e in edges:
            e.updatePosition()

    
    def layout(self):
        rootX = 0.0
        rootY = 0.0
        
        for level in xrange(self.numLevels):
            if level == 0:
                rootNode = self.nodeTable[0][0]
                rootNode.relativeX = rootX
                rootNode.relativeY = rootY
            elif level == 1:
                node = self.nodeTable[1][0]
                parent = node.parent
                node.wedgeAngle = min(float(node.leaves)/float(parent.leaves)*parent.wedgeAngle, 2.0*math.pi/3.0)
                node.rightLimit = -node.wedgeAngle/2.0
                node.leftLimit = node.wedgeAngle/2.0
                prevLeftLimit = node.leftLimit
                node.relativeX = self.d
                node.relativeY = 0
                for i in xrange(1, len(self.nodeTable[1])):
                    node = self.nodeTable[1][i]
                    node.wedgeAngle = min(float(node.leaves)/float(parent.leaves)*parent.wedgeAngle, 2.0*math.pi/3.0)
                    node.angle = prevLeftLimit + node.wedgeAngle/2.0
                    node.rightLimit = prevLeftLimit
                    node.leftLimit = node.angle + node.wedgeAngle/2.0
                    prevLeftLimit = node.leftLimit
                    node.relativeX = self.d * math.cos(node.angle)
                    node.relativeY = self.d * math.sin(node.angle)
            else:
                curParent = self.nodeTable[level][0].parent
                prevLeftLimit = curParent.rightLimit
                for node in self.nodeTable[level]:
                    parent = node.parent
                    if parent is not curParent:
                        prevLeftLimit = parent.rightLimit
                        curParent = parent
                    node.wedgeAngle = min(float(node.leaves)/float(parent.leaves)*parent.wedgeAngle, 2.0*math.pi/3.0)
                    node.angle = prevLeftLimit + node.wedgeAngle/2.0
                    node.rightLimit = prevLeftLimit
                    node.leftLimit = node.angle + node.wedgeAngle/2.0
                    prevLeftLimit = node.leftLimit
                    node.relativeX = level*self.d*math.cos(node.angle)
                    node.relativeY = level*self.d*math.sin(node.angle)
                    
                     
         
        '''   
        for level in xrange(self.numLevels):
            if level == 0:
                rootNode = self.nodeTable[0][0]
                rootNode.relativeX = rootX
                rootNode.relativeY = rootY
            elif level == 1:
                currentNode = self.nodeTable[1][0]
                numNodes = len(self.nodeTable[1])
                
                angleSpace = 2*math.pi / numNodes
                
                firstDirectoryFound = False
                lastDirectoryAngle = 0.0
                hadPreviousDirectory = False
                degsToPrevDirectory = 0.0
                prevDirectory = None
                
                for index, currentNode in enumerate(self.nodeTable[1]):
                    currentNode.relativeX = rootX+self.d * math.cos(angleSpace * index)
                    currentNode.relativeY = rootY+self.d * math.sin(angleSpace * index)
                    currentNode.angle = angleSpace * index
                    
                    if currentNode.children:
                        if not firstDirectoryFound:
                            firstDirectoryFound = True
                            firstDirectory = currentNode
                    
                        degsToPrevDirectory = currentNode.angle - lastDirectoryAngle 
                        currentNode.rightBisectorLimit = currentNode.angle - degsToPrevDirectory/2.0
                        
                        if hadPreviousDirectory:
                            prevDirectory.degsToNextDir = degsToPrevDirectory
                            prevDirectory.leftBisectorLimit = currentNode.rightBisectorLimit
                            
                
                        currentNode.leftTangentLimit = currentNode.angle +math.pi/3.0
                        currentNode.rightTangentLimit = currentNode.angle - math.pi/3.0
                        
                        currentNode.leftLimit = min(currentNode.leftBisectorLimit, 
                                                    currentNode.leftTangentLimit)
                        currentNode.rightLimit = max(currentNode.rightBisectorLimit,
                                                     currentNode.rightTangentLimit)
                        
                        lastDirectoryAngle = currentNode.angle
                        prevDirectory = currentNode
                        hadPreviousDirectory = True
                
                if firstDirectoryFound:
                    remainingAngles = 2*math.pi - prevDirectory.angle
                    degsToFirstDirectory = remainingAngles + firstDirectory.angle
                    firstDirectory.rightBisectorLimit = firstDirectory.angle - degsToFirstDirectory/2.0
                    if firstDirectory.rightBisectorLimit < 0:
                        leftLimit = firstDirectory.rightBisectorLimit + 2*math.pi;
                    else:
                        leftLimit = firstDirectory.rightBisectorLimit
                    prevDirectory.leftBisectorLimit = leftLimit + 2*math.pi
#                    firstDirectory.leftLimit = min(firstDirectory.leftBisectorLimit, firstDirectory.leftTangentLimit)
                    firstDirectory.rightLimit = max(firstDirectory.rightBisectorLimit, firstDirectory.rightTangentLimit)
                    
                    prevDirectory.leftLimit = min(prevDirectory.leftBisectorLimit, prevDirectory.leftTangentLimit)
#                    prevDirectory.rightLimit = max(prevDirectory.rightBisectorLimit, prevDirectory.rightTangentLimit)      
            elif level >= 2:                
                # loop through all nodes at this level to get list of parents
                parents = set()
                for currentNode in self.nodeTable[level]:
                    if currentNode.parent:
                        parents.add(currentNode.parent)
                
                for parent in parents:
                    firstDirectoryFound = False
                    lastDirectoryAngle = 0.0
                    hadPreviousDirectory = False

                    numChildren = len(parent.children)
                    leftLimit = parent.leftLimit
                    rightLimit = parent.rightLimit
                    
                    angleSpace = (leftLimit - rightLimit) / numChildren
                    
                    for index, currentNode in enumerate(parent.children):
                        currentNode.relativeX = rootX+level*self.d* math.cos(angleSpace*index + rightLimit)
                        currentNode.relativeY = rootY+level*self.d* math.sin(angleSpace*index + rightLimit)
                        currentNode.angle = (angleSpace * index) + rightLimit

                        
                        if currentNode.children:
                            if not firstDirectoryFound:
                                firstDirectory = currentNode
                                firstDirectoryFound = True
                        
                            degsToPrevDirectory = currentNode.angle - lastDirectoryAngle
                            currentNode.rightBisectorLimit = currentNode.angle - degsToPrevDirectory/2.0
                            
                            if hadPreviousDirectory:
                                prevDirectory.degsToNextDir = degsToPrevDirectory
                                prevDirectory.leftBisectorLimit = currentNode.rightBisectorLimit
                            
                            arc = math.acos(float(level)/float(level+1))
                            currentNode.leftTangentLimit = currentNode.angle + arc
                            currentNode.rightTangentLimit = currentNode.angle - arc
                            
                            currentNode.leftLimit = min(currentNode.leftBisectorLimit, currentNode.leftTangentLimit)
                            currentNode.rightLimit = max(currentNode.rightBisectorLimit, currentNode.rightTangentLimit)
                            
                            lastDirectoryAngle = currentNode.angle
                            prevDirectory = currentNode
                            hadPreviousDirectory = True
                            
                    if firstDirectoryFound:
                        remainingDegrees = 2*math.pi - prevDirectory.angle
                        degsToFirstDirectory = remainingDegrees +firstDirectory.angle
                        firstDirectory.rightBisectorLimit = firstDirectory.angle - degsToFirstDirectory/2.0
                        
                        if firstDirectory.rightBisectorLimit < 0:
                            leftLimit = firstDirectory.rightBisectorLimit + 2*math.pi
                        else:
                            leftLimit = firstDirectory.rightBisectorLimit
                        
                        prevDirectory.leftBisectorLimit = leftLimit + 2*math.pi
                        
#                        firstDirectory.leftLimit = min(firstDirectory.leftBisectorLimit, firstDirectory.leftTangentLimit)
                        firstDirectory.rightLimit = max(firstDirectory.rightBisectorLimit, firstDirectory.rightTangentLimit)

                        prevDirectory.leftLimit = min(prevDirectory.leftBisectorLimit, prevDirectory.leftTangentLimit)

#                        prevDirectory.rightLimit = max(prevDirectory.rightBisectorLimit, prevDirectory.rightTangentLimit)      
        '''
