################################################################################
#
#       This file is part of Gato (Graph Animation Toolbox) 
#       You can find more information at 
#       http://gato.sf.net
#
#	file:   AnimatedDataStructures.py
#	author: Alexander Schliep (alexander@schliep.org)
#
#       Copyright (C) 1998-2015, Alexander Schliep, Winfried Hochstaettler and 
#       Copyright 1998-2001 ZAIK/ZPR, Universitaet zu Koeln
#                                   
#       Contact: alexander@schliep.org, winfried.hochstaettler@fernuni-hagen.de             
#
#       Information: http://gato.sf.net
#
#       This library is free software; you can redistribute it and/or
#       modify it under the terms of the GNU Library General Public
#       License as published by the Free Software Foundation; either
#       version 2 of the License, or (at your option) any later version.
#
#       This library is distributed in the hope that it will be useful,
#       but WITHOUT ANY WARRANTY; without even the implied warranty of
#       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
#       Library General Public License for more details.
#
#       You should have received a copy of the GNU Library General Public
#       License along with this library; if not, write to the Free
#       Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
#
#
#
#       This file is version $Revision: 670 $ 
#                       from $Date: 2015-01-13 16:04:11 -0500 (Tue, 13 Jan 2015) $
#             last change by $Author: schliep $.
#
################################################################################
from GatoGlobals import AnimationParameters, gInfinity, NoSuchVertexError, NoSuchEdgeError  
from DataStructures import VertexLabeling, Queue, Stack, PriorityQueue
from Graph import SubGraph
import copy
#import sets

g = AnimationParameters

class Animator:
    """ *Debugging* Text only Animator providing animation functions which
        only print to console """
    
    def SetVertexColor(self,v, color):
        print "set color of",v," to ",color
        
    def SetEdgeColor(self, tail, head, color):
        print "set color of edge (",tail,",", head ,") to ",color
        
        
class AnimatedNeighborhood:
    """ Visualizes visiting of neighbors by calling the Neighborhood
        method of graph for v and allowing to iterate over it, while 
        coloring (v,w) cTraversedEdge unless (v,w) is colored with
        one of the colors in ignoreColors.
    
        #Neighborhood = lambda v,a=A,g=G: AnimatedNeighborhood(a,g,v,['red'])
        #
        #for w in Neighborhood(v):
        #    doSomething
        will color all edges cTraversedEdge unless the edge has been colored
        'red' at some point
    
        if a blinkColor is specified the edge will blink
        """
    
    def __init__(self, theAnimator, G, v, ignoreColors = [],
                 blinkColor = None, activeColor = 'yellow',
                 traversedColor = g.cTraversedEdge):	
        """ theAnimator will usually be the GraphDisplay(Frame/Toplevel) """
        self.Animator = theAnimator
        self.nbh = G.Neighborhood(v)[:] # Create a copy so we can delete edges (v,w)
        self.v = v
        self.ignoreColors = ignoreColors
        self.blinkColor = blinkColor
        self.activeColor = activeColor
        self.traversedColor = traversedColor        
        self.lastEdge = None
        self.lastColor = None
        self.Animator.SetVertexFrameWidth(self.v, g.ActiveVertexFrameWidth)

        
    def __getitem__(self, i):
        if self.lastEdge:
            try:
                if self.Animator.GetEdgeColor(self.lastEdge[0],
                                              self.lastEdge[1]) == self.activeColor:
                    if self.lastColor not in self.ignoreColors:
                        col = self.traversedColor
                    else:
                        col = self.lastColor                    
                    self.Animator.SetEdgeColor(self.lastEdge[0],self.lastEdge[1],col)
            except NoSuchEdgeError: # lastEdge was deleted
                pass
        if i < len(self.nbh):
            self.lastEdge = (self.v,self.nbh[i])
            self.lastColor = self.Animator.GetEdgeColor(self.v,self.nbh[i])
            self.Animator.SetEdgeColor(self.v,self.nbh[i],self.activeColor)
            if self.blinkColor != None:
                self.Animator.BlinkEdge(self.v,self.nbh[i],self.blinkColor)
            return self.nbh[i]
        else:
            self.Animator.SetVertexFrameWidth(self.v, g.VertexFrameWidth)
            raise IndexError
            
    def __len__(self):
        return len(self.nbh)
        
        
class BlinkingNeighborhood:
    """ Visualizes visiting blinking (v,w) for all w when iterating over
        the Neighborhood
    
        #Neighborhood = lambda v,a=A,g=G: BlinkingNeighborhood(a,g,v,c)
        #
        #for w in Neighborhood(v):
        #    doSomething
        will blink all edges"""
    
    def __init__(self,theAnimator,G,v,c):	
        """ theAnimator will usually be the GraphDisplay(Frame/Toplevel) """
        self.Animator = theAnimator
        self.nbh = G.Neighborhood(v)
        self.v = v
        self.color = c
        
    def __getitem__(self, i):
        if i < len(self.nbh):
            self.Animator.BlinkEdge(self.v, self.nbh[i], self.color)
            return self.nbh[i]
        else:
            raise IndexError
            
    def __len__(self):
        return len(self.nbh)
        
class BlinkingTrackLastNeighborhood(BlinkingNeighborhood):
    """ Visualizes visiting blinking (v,w) for all w when iterating over
        the Neighborhood. It also temporarily keeps the the last blinked
        edge grey
    
        #Neighborhood = lambda v,a=A,g=G: BlinkingTrackLastNeighborhood(a,g,v,c,track)
        #
        #for w in Neighborhood(v):
        #    doSomething
        will blink all edges with color c, the last blinked is tracked with color 
        track """
    old = None
    
    
    def __init__(self,theAnimator,G,v,c,track="grey"):
        BlinkingNeighborhood.__init__(self,theAnimator,G,v,c)
        self.trackColor = track
        
    def __getitem__(self, i):
        if BlinkingTrackLastNeighborhood.old != None and i < len(self.nbh): 
            old = BlinkingTrackLastNeighborhood.old
            self.Animator.SetEdgeColor(old[0],old[1],old[2])
            
        BlinkingTrackLastNeighborhood.old = (self.v,self.nbh[i],
                                             self.Animator.GetEdgeColor(self.v,self.nbh[i]))
        retVal = BlinkingNeighborhood.__getitem__(self,i)
        self.Animator.SetEdgeColor(self.v,self.nbh[i],self.trackColor)
        
        return retVal
        
        
class BlinkingContainerWrapper:
    """ Visualizes iterating over a list of vertices and/or edges by
        blinking.
    
        #List = lambda l, a=A: BlinkingContainerWrapper(a,l,color)
        #
        #for w in List:
        #    doSomething
        """
    
    def __init__(self, theAnimator, l, color=g.cOnQueue):	
        self.Animator = theAnimator
        self.list = copy.copy(l)
        self.color = color
        
    def __getitem__(self, i):
        if i < len(self.list):
            item = self.list[i]
            if type(item) == type(2): # vertex
                self.Animator.BlinkVertex(item,self.color)
            else:
                self.Animator.BlinkEdge(item[0],item[1],self.color)
            return item
        else:
            raise IndexError
            
    def __len__(self):
        return len(self.list)
        
        
class ContainerWrapper(BlinkingContainerWrapper):
    """ Visualizes iterating over a list of vertices and/or edges by
        coloring. If color has changed in the meantime the original
        color will not be set again.
    
        #List = lambda l, a=A: ContainerWrapper(a,l,color)
        #
        #for w in List:
        #    doSomething
        """
    
    def __init__(self, theAnimator, l, color=g.cOnQueue):
        BlinkingContainerWrapper.__init__(self,theAnimator,l,color)	
        self.lastitem  = None
        self.lastcolor = None
        
    def __getitem__(self, i):
        if i < len(self.list):
            item = self.list[i]
            if type(item) == type(2): # vertex
                dummy = self.Animator.GetVertexColor(item)
                if (self.lastitem != None) and \
                       (self.Animator.GetVertexColor(self.lastitem) == self.color):
                    self.Animator.SetVertexColor(self.lastitem,self.lastcolor)
                self.Animator.SetVertexColor(item,self.color)
                self.lastcolor = dummy
            else:
                dummy = self.Animator.GetEdgeColor(item[0],item[1])
                if (self.lastitem != None) and \
                       (self.Animator.GetEdgeColor(self.lastitem[0],self.lastitem[1]) == self.color):
                    self.Animator.SetEdgeColor(self.lastitem[0],self.lastitem[1],self.lastcolor)
                self.Animator.SetEdgeColor(item[0],item[1],self.color)
                self.lastcolor = dummy
            self.lastitem = item
            return item
        else:
            if type(self.lastitem) == type(2): # vertex
                if (self.lastitem != None) and \
                       (self.Animator.GetVertexColor(self.lastitem) == self.color):
                    self.Animator.SetVertexColor(self.lastitem,self.lastcolor)
            else:
                if (self.lastitem != None) and \
                       (self.Animator.GetEdgeColor(self.lastitem[0],self.lastitem[1]) == self.color):
                    self.Animator.SetEdgeColor(self.lastitem[0],self.lastitem[1],self.lastcolor)                
            raise IndexError
            
class VisibleVertexLabeling(VertexLabeling):
    def __init__(self, theAnimator):
        VertexLabeling.__init__(self)
        self.A = theAnimator
        
    def __setitem__(self, v, val):
        VertexLabeling.__setitem__(self, v, val)
        if val == gInfinity:
            val = "Infinity"
        elif val == -gInfinity:
            val = "-Infinity"
        self.A.SetVertexAnnotation(v,val)
        
        
class AnimatedVertexLabeling(VertexLabeling):
    """ Visualizes changes of values of the VertexLabeling
        by changing vertex colors appropriately.
    
        E.g.,
        #d = AnimatedVertexLabeling(A) 
        #d[v] = 0
        will color v cInitial.
    
        The coloring used for d[v] = val 
        - cInitial if val = 0,None,gInfinity
        - "blue" else """
    
    def __init__(self, theAnimator, initial=0, color="blue"):
        """ theAnimator will usually be the GraphDisplay(Frame/Toplevel) 
            initial is the value to cause coloring in cInitial """
        VertexLabeling.__init__(self)
        self.Animator = theAnimator
        self.initial=initial
        self.color = color
        
    def __setitem__(self, v, val):
        VertexLabeling.__setitem__(self, v, val)
        if val == self.initial or val == None or val == gInfinity:
            self.Animator.SetVertexColor(v,g.cInitial)
        else:
            self.Animator.SetVertexColor(v,self.color)
            
            
class AnimatedSignIndicator:
    """ Visualizes sign of vertex or edge:
        weight > 0 : green
               = 0 : grey
               < 0 : red """
    
    def __init__(self,theAnimator):
        self.Animator = theAnimator
        self.weight   = {}
        
    def __setitem__(self, i, val):
        self.weight[i] = val
        if type(i) == type(2): # vertex
            if val>0:
                self.Animator.SetVertexColor(i,"green")
            elif val<0:
                self.Animator.SetVertexColor(i,"red")
            else:
                self.Animator.SetVertexColor(i,"grey")
        else:
            if val>0:
                self.Animator.SetEdgeColor(i,"green")
            elif val<0:
                self.Animator.SetEdgeColor(i,"red")
            else:
                self.Animator.SetEdgeColor(i,"grey")
                
    def __getitem__(self, i):
        return self.weight[i]
        
        
        
class AnimatedPotential:
    """ Visualizes the potential from 0 (green) to
         max (brown) of a vertex. """
    def __init__(self,max,theAnimator1,theAnimator2=None):
        self.pot      = {}
        self.max      = max
        self.colors   = ['#00FF00','#11EE00','#22DD00','#33CC00','#44BB00',
                         '#55AA00','#669900','#778800','#887700','#996600',
                         '#AA5500','#BB4400','#CC3300']
        self.Animator1 = theAnimator1
        if theAnimator2 == None:
            self.Animator2 = theAnimator1
        else:
            self.Animator2 = theAnimator2 
            
    def __setitem__(self,v,val):
        self.pot[v] = val
        if val == gInfinity:
            self.Animator2.SetVertexAnnotation(v,"Inf")
        elif val == -gInfinity:
            self.Animator2.SetVertexAnnotation(v,"-Inf")
        else:
            self.Animator2.SetVertexAnnotation(v,"%d"%val)
        if val > self.max:
            val = self.max
        self.Animator1.SetVertexColor(v,self.colors[(val*(len(self.colors)-1))/self.max])
        
    def __getitem__(self,v):
        return self.pot[v]
        
        
        
class BlinkingVertexLabeling(VertexLabeling):
    """ Visualizes changes of values of the VertexLabeling
        by blinking vertices """
    
    def __init__(self, theAnimator):
        """ theAnimator will usually be the GraphDisplay(Frame/Toplevel) """
        VertexLabeling.__init__(self)
        self.Animator = theAnimator
        
    def __setitem__(self, v, val):
        VertexLabeling.__setitem__(self, v, val)
        if val == 0:
            self.Animator.BlinkVertex(v)
        else:
            self.Animator.BlinkVertex(v)
            
            
class AnimatedVertexQueue(Queue):
    """ Visualizes status of vertices in relation to the Queue by
        coloring them
    
        - cOnQueue if they are in the queue
        - cRemovedFromQueue if they have been on the queue and were
          removed """
    
    def __init__(self, theAnimator, colorOn=g.cOnQueue, colorOff=g.cRemovedFromQueue):
        """ theAnimator will usually be the GraphDisplay(Frame/Toplevel) """
        Queue.__init__(self)
        self.Animator = theAnimator
        self.ColorOn = colorOn
        self.ColorOff = colorOff
        self.lastRemoved = None
        
    def Append(self,v):
        Queue.Append(self,v)
        self.Animator.SetVertexColor(v, self.ColorOn)
        
    def Top(self):
        v = Queue.Top(self)
        self.Animator.SetVertexColor(v, self.ColorOff)
        if self.lastRemoved is not None:
            self.Animator.SetVertexFrameWidth(self.lastRemoved, g.VertexFrameWidth)
        self.Animator.SetVertexFrameWidth(v, g.ActiveVertexFrameWidth)
        self.lastRemoved = v 
        return v
        
    def Clear(self):
        for v in self.contents:
            self.Animator.SetVertexColor(v, self.ColorOff)
        Queue.Clear(self) 
        if self.lastRemoved is not None:
            self.Animator.SetVertexFrameWidth(self.lastRemoved,g.VertexFrameWidth)
            self.lastRemoved = None
            
class AnimatedVertexPriorityQueue(PriorityQueue):    
    """ Visualizes status of vertices in relation to the PriorityQueue by
        coloring them
    
        - cOnQueue if they are in the queue
        - cRemovedFromQueue if they have been on the queue and were
          removed """
    
    def __init__(self, theAnimator, colorOn=g.cOnQueue, colorOff=g.cRemovedFromQueue):
        """ theAnimator will usually be the GraphDisplay(Frame/Toplevel) """
        PriorityQueue.__init__(self)
        self.Animator = theAnimator
        self.ColorOn = colorOn
        self.ColorOff = colorOff
        self.lastRemoved = None
        
    def Insert(self,value,sortKey):
        PriorityQueue.Insert(self,value,sortKey)
        self.Animator.SetVertexColor(value, self.ColorOn)
        
    def DecreaseKey(self,value,newSortKey):
        PriorityQueue.DecreaseKey(self,value,newSortKey)
        self.Animator.BlinkVertex(value)
        
    def DeleteMin(self):
        v = PriorityQueue.DeleteMin(self)
        self.Animator.SetVertexColor(v, self.ColorOff)
        if self.lastRemoved is not None:
            self.Animator.SetVertexFrameWidth(self.lastRemoved, g.VertexFrameWidth)
        self.Animator.SetVertexFrameWidth(v, g.ActiveVertexFrameWidth)
        self.lastRemoved = v 
        return v
        
        
class AnimatedVertexStack(Stack):
    """ Visualizes status of vertices in relation to the Stack by
        coloring them
    
        - cOnQueue if they are in the queue
        - cRemovedFromQueue if they have been on the queue and were
          removed """
    
    def __init__(self, theAnimator, colorOn=g.cOnQueue, colorOff=g.cRemovedFromQueue):
        """ theAnimator will usually be the GraphDisplay(Frame/Toplevel) """
        Stack.__init__(self)
        self.Animator = theAnimator
        self.ColorOn = colorOn
        self.ColorOff = colorOff
        self.lastRemoved = None
        
    def Push(self,v):
        Stack.Push(self,v)
        self.Animator.SetVertexColor(v, self.ColorOn)
        
    def Pop(self):
        v = Stack.Pop(self)
        self.Animator.SetVertexColor(v, self.ColorOff)
        if self.lastRemoved is not None:
            self.Animator.SetVertexFrameWidth(self.lastRemoved, g.VertexFrameWidth)
        self.Animator.SetVertexFrameWidth(v, g.ActiveVertexFrameWidth)
        self.lastRemoved = v 
        return v
        
    def Clear(self):
        for v in self.contents:
            self.Animator.SetVertexColor(v, self.ColorOff)
        Stack.Clear(self)
        if self.lastRemoved is not None:
            self.Animator.SetVertexFrameWidth(self.lastRemoved, g.VertexFrameWidth)
            self.lastRemoved = None
            
            
            ##class AnimatedPriorityQueue(PriorityQueue):
            ##    def __init__(self, theAnimator, color=cVisited):
            ##	""" theAnimator will usually be the GraphDisplay(Frame/Toplevel) """
            ##	self.Animator = theAnimator
            ##        self.color = color        
            ##        PriorityQueue.__init__(self)
            
            ##    def Insert(self,value,sortKey):
            ##        # XXX For compat. to AnimatedVertexSet (yuk)
            ##        PriorityQueue.Insert(self,value,sortKey)
            
            ##    def DeleteMin(self):
            ##        """ Return and delete minimal value with minimal sortKey from queue. """
            ##	v = PriorityQueue.DeleteMin(self)
            ## 	self.Animator.SetVertexColor(v,self.color)
            ##        return v
            
            
            
            
class AnimatedVertexSet:
    """ Visualizes status of vertices in relation to the Set by
        coloring them

        - addcolor when they are added to the set
        - color if they have been in the set and were
          removed

        
    """
    
    def __init__(self, theAnimator, vertexSet=None, color=g.cVisited, addcolor='red',
                 trackLast=None):
        """ theAnimator will usually be the GraphDisplay(Frame/Toplevel) """
        if vertexSet == None:
            self.vertices = []
        else:
            self.vertices = vertexSet
        self.Animator = theAnimator
        self.color = color
        self.addcolor = addcolor
        self.trackLast = trackLast
        self.last = None
        
    def Set(self, vertexSet):
        """ Sets the set equal to a copy of vertexSet """
        self.vertices = vertexSet[:]
        
    def Remove(self, v):
        self.Animator.SetVertexColor(v,self.color)
        self.vertices.remove(v)
        if self.trackLast:
            if self.last:
                self.Animator.SetVertexFrameWidth(self.last,
                                                  g.VertexFrameWidth)
            self.Animator.SetVertexFrameWidth(v,
                                              g.ActiveVertexFrameWidth)
            self.last = v
            
    def Add(self,v):
        """ Add a single vertex v """
        self.Animator.SetVertexColor(v,self.addcolor)
        self.vertices.append(v)
        
    def IsNotEmpty(self):
        return len(self.vertices) > 0
        
    def IsEmpty(self):
        return len(self.vertices) == 0
        
    def Contains(self,v):
        return v in self.vertices
        
        
class AnimatedEdgeSet:
    """ Visualizes status of edges in relation to the Set by
        coloring them
    
        - 'blue' if they are added to the set
        - cVisited  if they have been in the set and were
          removed """
    
    def __init__(self, theAnimator, edgeSet=None, color='blue'):
        """ theAnimator will usually be the GraphDisplay(Frame/Toplevel) """
        if edgeSet == None:
            self.edges = []
        else:
            self.edges = edgeSet	    
        self.Animator = theAnimator
        self.color = color
        
    def __len__(self):
        return len(self.edges)
        
    def __getitem__(self,key):
        return self.edges[key]
        
    def Set(self, edgeSet):
        """ Sets the set equal to a copy of edgeSet """
        self.edges = edgeSet[:]
        
    def AddEdge(self, e):
        self.Animator.SetEdgeColor(e[0],e[1], self.color)
        self.edges.append(e)
        
    def Remove(self, e):
        self.Animator.BlinkEdge(e[0], e[1], g.cVisited)
        self.Animator.SetEdgeColor(e[0], e[1], g.cVisited)
        self.edges.remove(e) 
        
    def IsNotEmpty(self):
        return len(self.edges) > 0
        
    def Contains(self,e):
        return e in self.edges
        
        
class AnimatedSubGraph(SubGraph):
    """ Visualizes status of vertices and edges in relation to the SubGraph by
        coloring them
        - color (default is 'blue') if they are added to the SubGraph """
    
    def __init__(self, G, theAnimator, color="blue"):
        """ color is used to color vertices and edges in the subgraph.
            theAnimator will usually be the GraphDisplay(Frame/Toplevel) """
        SubGraph.__init__(self, G)
        self.Animator = theAnimator
        self.Color = color
        
    def AddVertex(self,v):
        try:
            SubGraph.AddVertex(self,v)
            self.Animator.SetVertexColor(v,self.Color)
            self.Animator.DefaultInfo()
        except NoSuchVertexError:
            return
            
    def AddEdge(self,edge,head=None):
        # Poor mans function overload
        if head == None and len(edge) == 2:
            t = edge[0]
            h = edge[1]
        else:
            t = edge
            h = head
        try:
            tt, hh = SubGraph.AddEdge(self,t,h)
            self.Animator.SetEdgeColor(tt,hh,self.Color)
            # Raise edges above other
            self.Animator.RaiseEdge(tt,hh)
            self.Animator.DefaultInfo()
            return tt,hh
        except NoSuchVertexError, NoSuchEdgeError:
            return

    def AddSubGraph(self, G):
        """ Add subgraph G to self. Will do nothing if self and G 
            have distinct supergraphs """
        if self.superGraph != G.superGraph:
            log.error("AddSubGraph: distinct superGraphs")
            return
        
        for v in G.Vertices():
            if G.QIsolated(v):
                SubGraph.AddVertex(self,v)
                
        for t,h in G.Edges():
            SubGraph.AddEdge(self, t, h)
        self.Animator.SetEdgesColor(G.Edges(),self.Color) 
        #print "Just called setEdgesColor animator is ", self.Animator.__class__.__name__
        self.Animator.SetAllVerticesColor(self.Color, graph=G)
        self.RaiseEdges()
        self.Animator.DefaultInfo()


    def RaiseEdges(self):
        for (t,h) in self.Edges():
            tt, hh = self.superGraph.Edge(t,h)
            self.Animator.RaiseEdge(tt,hh)
            
            
    def DeleteEdge(self,edge,head=None):
        if head == None and len(edge) == 2:
            t = edge[0]
            h = edge[1]
        else:
            t = edge
            h = head
        try:
            SubGraph.DeleteEdge(self,t,h)
            self.Animator.SetEdgeColor(t,h,"black")
        except NoSuchVertexError, NoSuchEdgeError:
            return
            
    def Clear(self, color="grey"):
        """ Delete all vertices and edges from the animated subgraph. 
            and color them with 'color' (grey is default) """
        
        # GraphDisplay functions save several update()'s
        self.Animator.SetAllVerticesColor(color, self)
        self.Animator.SetAllEdgesColor(color, self)
        
        self.vertices         = [] 
        self.adjLists         = {}
        self.invAdjLists      = {}   # Inverse Adjazenzlisten
        self.size = 0
        self.totalWeight   = 0
        
        
    def AddEdgeByVertices(self,tail,head):
        try:
            SubGraph.AddEdge(self,tail,head)
            self.Animator.SetEdgeColor(tail,head,self.Color)
            self.Animator.DefaultInfo()
        except NoSuchVertexError, NoSuchEdgeError:
            return
            
            
            
class AnimatedPredecessor(VertexLabeling):
    """ Animates a predecessor array by 
    
        - coloring edges (pred[v],v) 'red' 
        - coloring edges (pred[v],v) 'grey' if the value of
          pred[v] is changed """
    
    def __init__(self, theAnimator, ignoreColors = [], predColor='red'):
        VertexLabeling.__init__(self)
        self.Animator = theAnimator
        self.ignoreColors = ignoreColors
        self.predColor = predColor
        
    def __setitem__(self, v, val):
        try:
            oldVal = VertexLabeling.__getitem__(self, v)
            if oldVal != None:
                if not self.Animator.GetEdgeColor(oldVal, v) in self.ignoreColors:
                    self.Animator.SetEdgeColor(oldVal, v, 'grey')
        except:
            pass 
        if val != None:
            try:
                if not self.Animator.GetEdgeColor(val, v) in self.ignoreColors:
                    self.Animator.SetEdgeColor(val, v, self.predColor)
            except:
                pass
        VertexLabeling.__setitem__(self, v, val)
        
        
    def SetPredColor(self, color):
        """ NOTE: This does not recolor assigned (pred[v],v) edges """
        self.predColor = color
        
    def AppendLeaveColor(self,color):
        if self.ignoreColors == None:
            self.ignoreColors = [color]
        else:
            self.ignoreColors.append(color)
            
class ComponentMaker:
    """ Subsequent calls of method NewComponent() will return differently
        colored subgraphs of G """
    colors = ['#FF0000','#00FF00','#0000FF',
              '#009999','#990099','#999900',
              '#996666','#669966','#666699',
              '#0066CC','#6600CC','#66CC00',
              '#00CC66','#CC0066','#CC6600']

    def __init__(self, graph, animator, forbidden_colors=None):
        self.G = graph
        self.A = animator
        self.lastColor = 0
        self.firstCall = True
        self.colors = copy.copy(self.colors)
        if forbidden_colors:
            for color in forbidden_colors:
                if color in self.colors:
                    self.colors.remove(color)
        
    def NewComponent(self):
        self.firstCall = False
        comp = AnimatedSubGraph(self.G, self.A, self.colors[self.lastColor])
        self.lastColor = self.lastColor + 1
        if self.lastColor == len(self.colors):
            self.lastColor = 0
        return comp
        
    def LastComponentColor(self):
        if self.firstCall:
            return None
        if self.lastColor > 0:
            return self.colors[self.lastColor -1]
        else:
            return self.colors[-1]
  
        
################################################################################
#
# Functions
#
################################################################################
        
def showPathByPredecessorArray(source,sink,pred,A,color="red"):
    """ Visualizes a path from source to sink in a graph G
        displayed in A. The path is specified in terms of the
        predecessor array pred and will be colored with color
        (default is 'red') """
    
    v = sink
    
    seen = [v] # avoid getting stuck in cycles
    
    while (pred[v] != None) and (pred[v] != v):
        A.SetVertexColor(v,color)
        A.SetEdgeColor(pred[v],v,color)
        v = pred[v]
        if v in seen:
            return
        else:
            seen.append(v)
            
    A.SetVertexColor(v,color)
    
    ################################################################################
    #
    # Wrapper
    #
    ################################################################################
    
class FlowWrapper:
    """ This class visualizes the flow in a directed graph G
        with animator GA and it's residual network R with
        animator RA.
    
        flow = FlowWrapper(G,A,R,RA,G.edgeWeights[0],R.edgeWeights[0])
    
        or
    
        flow = FlowWrapper(G,A,R,RA,G.edgeWeights[0],R.edgeWeights[0],G.vertexWeights[0])
    """
    def __init__(self,  G, GA, R, RA, flow, res, excess=None):
        self.zeroEdgeColor = g.cEdgeDefault
        self.G      = G
        self.GA     = GA
        self.R      = R
        self.RA     = RA
        self.flow   = flow
        self.cap    = copy.deepcopy(res)
        self.res    = res
        self.excess = excess
        if self.excess == None:        ## if no startup excess set all to zero
            self.excess = {}
            for v in self.G.vertices:
                self.excess[v] = 0
        for e in self.G.Edges():
            self.flow[e] = 0 
            
    def __setitem__(self, e, val):
        if (self.excess[e[0]] != gInfinity) and (self.excess[e[0]] != -gInfinity):
            self.excess[e[0]] = self.excess[e[0]] + self.flow[e] - val
        if (self.excess[e[1]] != gInfinity) and (self.excess[e[1]] != -gInfinity):
            self.excess[e[1]] = self.excess[e[1]] - self.flow[e] + val  
        if self.excess[e[0]] > 0:
            self.RA.SetVertexColor(e[0],"green")
        elif self.excess[e[0]] < 0:
            self.RA.SetVertexColor(e[0],"red")
        else:
            self.RA.SetVertexColor(e[0],"gray")
        if self.excess[e[1]] > 0:
            self.RA.SetVertexColor(e[1],"green")
        elif self.excess[e[1]] < 0:
            self.RA.SetVertexColor(e[1],"red")
        else:
            self.RA.SetVertexColor(e[1],"gray")
        self.flow[e] = val
        if val == self.cap[e]:     
            self.GA.SetEdgeColor(e[0],e[1],"blue")
            self.GA.SetEdgeAnnotation(e[0],e[1],"%d/%d" % (val,self.cap[e]),"black")
            try:
                self.RA.DeleteEdge(e[0],e[1])
            except:
                None
            if not self.R.QEdge(e[1],e[0]):
                self.RA.AddEdge(e[1],e[0])
        elif val == 0: 
            self.GA.SetEdgeColor(e[0],e[1],self.zeroEdgeColor)
            #self.GA.SetEdgeAnnotation(e[0],e[1],"%d/%d" % (val, self.cap[e]),"gray")
            self.GA.SetEdgeAnnotation(e[0],e[1],"","gray")
            try:
                self.RA.DeleteEdge(e[1],e[0])
            except:
                None
            if not self.R.QEdge(e[0],e[1]):
                self.RA.AddEdge(e[0],e[1])
        else:                      
            self.GA.SetEdgeColor(e[0],e[1],"#9999FF")
            self.GA.SetEdgeAnnotation(e[0],e[1],"%d/%d" % (val,self.cap[e]),"black")
            if not self.R.QEdge(e[1],e[0]):
                self.RA.AddEdge(e[1],e[0])
            if not self.R.QEdge(e[0],e[1]):
                self.RA.AddEdge(e[0],e[1])
        if self.G.QEdge(e[0],e[1]):
            self.res[(e[1],e[0])]  = val
            self.res[(e[0],e[1])]  = self.cap[(e[0],e[1])] - val
        else:
            self.res[(e[0],e[1])]  = val
            self.res[(e[1],e[0])]  = self.cap[(e[1],e[0])] - val
        
    def __getitem__(self, e):
        return self.flow[e]
        
        
class ReducedCostsWrapper:
    """ Visualizes the reduced costs of the edge
        >0 green
        =0 grey
        <0 red 
    """
    def __init__(self, A, cost, pot):
        self.cost = cost
        self.pot = pot
        self.A = A
        
    def __setitem__(self, e, val):
        self.cost[e] = val
        rc = self.cost[e] + self.pot[e[0]] - self.pot[e[1]]
        try:
            if rc > 0:
                self.A.SetEdgeColor(e[0],e[1],"red")
            elif rc == 0:
                self.A.SetEdgeColor(e[0],e[1],"grey")
            else:
                self.A.SetEdgeColor(e[0],e[1],"green")
        except:
            None
            
    def __getitem__(self, e):
        return self.cost[e]
