#!/usr/bin/env python
# -*- coding: utf-8 -*-

from Tkinter import *
import tkFont
from graph_SBC import MultiGraph
from wskrand import RNG



RCSID="$Id: murdoch.pyw,v 1.1 2009/04/10 15:47:57 wilfrid Exp wilfrid $"
shortRCSID=RCSID[5:-1].replace("Wilfrid ","")

GEOMETRY="+10+10"

class Animation(MultiGraph):
    def __init__(self,master,rng=None):
        self.stopgovar=StringVar()
        self.smallvar=StringVar()
        MultiGraph.__init__(self,master,
                            actions=[("Increment",self.increment),
                                     ("RUN","PAUSE",self.stopgovar,self.stopgo),
                                     ("SmallSet","Remove",self.smallvar,self.small),
                                     ("Single",self.animate1),
                                     #("Mult (1)",self.animate2),
                                     #("Mult (2)",self.animate3),
                                     ("Couple",self.animate4)                        
                                    # ("CFTP",self.animate5),
                                     ])
        self.x0=self.graph[0].x0
        self.y0=self.graph[0].y1
        self.x1=self.graph[0].x1
        self.y1=self.graph[0].y0
        
        self.alpha=3  # this controls the transition kernel - larger value means walk takes smaller steps
        self.smallsetlow=(self.x0+self.x1)*0.5-(self.x1-self.x0)/(2*self.alpha)
        self.smallsethigh=(self.x0+self.x1)*0.5+(self.x1-self.x0)/(2*self.alpha)

        self.t=self.x0
        self.tinc=16
        self.tstore=self.t
        self.tincstore=self.tinc
        
        self.animation=None
        self.current_animation=None
        self.hold=500
        if rng:
            self.rng=rng
        else:
            self.rng=RNG()

        self.c=["firebrick","blue"] # ["firebrick","chocolate","salmon","saddlebrown","coral"]
            
    def increment(self):
        animation=self.after(400,self.current_animation)        
    
    def stopgo(self):
        if self.stopgovar.get()=="RUN":
            self.after_cancel(self.animation)
        else:
            self.animation=self.after(400,self.current_animation)

    def animate1(self):
        self.restart()
        self.x=self.rng.uniform(0,1)
        self.current_animation=self.animate1_run
        self.animation=self.after(500,self.current_animation)

    def animate1_run(self):
        self.clean()
        if self.t>self.x1: self.rescale1()
        self.small()  # get small set to redraw itself, in case of rescaling of right hand graph
        self.triangle1(self.x,fillcol=self.c[0])
        self.graph[0].tag_raise("small")
        u=self.kernel(self.x)
        self.transit1((self.x,0),(u,0),fg=self.c[0])
        self.transitg((self.x,0),(u,0),fg=self.c[0])
        self.x=u
        self.t=self.t+self.tinc
        if self.stopgovar.get()=="PAUSE":
            self.animation=self.after(self.hold,self.animate1_run)
        #self.animation=self.after(self.hold,self.animate1_run)

    def triangle1(self,x,fillcol):
        self.graph[0].create_polygon(self.x0*(1-x)-(self.x1-self.x0)/self.alpha+self.x1*x,self.y0,
                                     self.x0*(1-x)-(self.x1-self.x0)/self.alpha+self.x1*x,0.1*self.y0,
                                     self.x0*(1-x)+(self.x1-self.x0)/self.alpha+self.x1*x,0.1*self.y0,
                                     self.x0*(1-x)+(self.x1-self.x0)/self.alpha+self.x1*x,self.y0,
                                     fill=fillcol,
                                     stipple="gray25",tag="move")
        self.graph[0].create_line(self.x0*(1-x)+self.x1*x,self.y0,
                                  self.x0*(1-x)+self.x1*x,0.1*self.y0,
                                  width=3,
                                  fill="gray45",tag="move")

    def transit1(self,p0,p1,fg="firebrick",blip=0.1): # this controls the arrow in the left panel
        x,y=p0  # y=0
        u,v=p1  # v=0
        w=(x+u)/2  # w=x/2
        ww=(y+v)/2+blip  # ww=0.1
        self.graph[0].create_line(self.x0*(1-x)+self.x1*x,self.y0*(1-y)+self.y1*y,
                                  self.x0*(1-w)+self.x1*w,self.y0*(1-ww)+self.y1*ww,
                                  self.x0*(1-u)+self.x1*u,self.y0*(1-v)+self.y1*v,
                                  arrow="last",
                                  smooth=1,
                                  width=3,
                                  fill=fg,
                                  tag="move")
        
    def transitg(self,p0,p1,fg="firebrick",blip=0.1): # this controls the graph in the right panel
        x=p0[0]
        u=p1[0]
        self.graph[1].create_line(self.t,
                                  self.y0*(1-x)+self.y1*x,
                                  self.t+self.tinc,
                                  self.y0*(1-u)+self.y1*u,
                                  width=3,
                                  fill=fg)

    def triangle2(self,x,fillcol):
        self.graph[0].create_polygon(self.x0*(1-x)-(self.x1-self.x0)/self.alpha+self.x1*x,self.y0,
                                     self.x0*(1-x)-(self.x1-self.x0)/self.alpha+self.x1*x,0.1*self.y0,
                                     self.x0*(1-x)+(self.x1-self.x0)/self.alpha+self.x1*x,0.1*self.y0,
                                     self.x0*(1-x)+(self.x1-self.x0)/self.alpha+self.x1*x,self.y0,
                                  fill=fillcol,stipple="gray50",
                                  tag="move")
        self.graph[0].create_line(self.x0*(1-x)+self.x1*x,self.y0,
                                  self.x0*(1-x)+self.x1*x,0.1*self.y0,
                                  width=3,
                                  fill="gray45",tag="move")

    def small(self):
        if self.smallvar.get()=="Remove":
            self.graph[0].lower(self.graph[0].create_polygon(self.smallsetlow,self.y0,
                                     self.smallsetlow,0.1*self.y0,
                                     self.smallsethigh,0.1*self.y0,
                                     self.smallsethigh,self.y0,
                                     fill="darkolivegreen",tags="small",stipple="gray50"))
            self.graph[1].lower(self.graph[1].create_polygon(self.x0,0.5*self.y0-(self.y1-self.y0)/(2*self.alpha),
                                     self.x0,0.5*self.y0+(self.y1-self.y0)/(2*self.alpha),
                                     self.x1,0.5*self.y0+(self.y1-self.y0)/(2*self.alpha),
                                     self.x1,0.5*self.y0-(self.y1-self.y0)/(2*self.alpha),
                                     fill="darkolivegreen",tags="smallright",stipple="gray50")) 
        else:
            self.graph[0].delete("small")
            self.graph[1].delete("smallright")


    def animate4(self):
        self.restart()
        self.couple=0
        self.x=self.rng.uniform(0,1)
        self.y=self.rng.uniform(0,1)
        self.current_animation=self.animate4_run
        self.animation=self.after(500,self.current_animation)


    def animate4_run(self):
        self.clean()
        if self.t>self.x1: self.rescale1()
        self.small()  # get small set to redraw itself, in case of rescaling of right hand graph
        self.graph[0].tag_raise("small")
        if self.couple:
            col="purple"
            self.triangle2(self.x,fillcol=col)
            u=self.kernel(self.x)
            v=u
            self.transit1((self.x,0),(u,0),fg=col)
            self.transitg((self.x,0),(u,0),fg=col)            
        else:
            if 0.5-1/(2.0*self.alpha)<self.x<0.5+1/(2.0*self.alpha) and 0.5-1/(2.0*self.alpha)<self.y<0.5+1/(2.0*self.alpha):
                u,v=self.smalltransition(self.x,self.y)
            else:
                u=self.kernel(self.x)
                v=self.kernel(self.y)
            self.triangle2(self.x,fillcol=self.c[0])
            self.triangle2(self.y,fillcol=self.c[1])                      
            self.transit1((self.x,0),(u,0),fg=self.c[0])
            self.transitg((self.x,0),(u,0),fg=self.c[0])
            self.transit1((self.y,0),(v,0),fg=self.c[1])
            self.transitg((self.y,0),(v,0),fg=self.c[1])
        self.x=u
        self.y=v
        self.t=self.t+self.tinc
        if self.stopgovar.get()=="PAUSE":
            self.animation=self.after(self.hold,self.animate4_run)
#        self.animation=self.after(self.hold,self.animate4_run)

        

    def transitg0(self,fg="gray25"):
        t=self.t
        tinc=self.tinc
        self.graph[1].create_polygon(t,self.y0,
                                     t+tinc,self.y0,
                                     t+tinc,self.y1,
                                     t,self.y1,
                                     fill="red",
                                     tags="block")

    def transitg1(self,x,u):
        self.graph[1].create_line(self.t,
                                  self.y0*(1-x)+self.y1*x,
                                  self.t+self.tinc,
                                  self.y0*(1-u)+self.y1*u,
                                  width=3,
                                  fill="purple",
                                  tags="move")

    def kernel(self,x):
#        u,v = (self.rng.uniform(0,1),self.rng.uniform(0,1))
        w = self.rng.uniform(-1,1)/self.alpha
        return min(max(x+w,0),1)
#        return min(max(x+u,self.x0),self.x1/440)
#        if x*v>u:
#            return x-u,1-v
#        elif (1-x)*v>1-u:
#            return x+1-u,1-v
#        else:
#            return u,v
#    def smalltransition(self,x,y):
#        w = self.rng.uniform(-1,1)/self.alpha
#        newx = min(max(x+w,0),1)
#        if max(0,y-1/self.alpha)<newx<min(1,y+1/self.alpha):
#            self.couple=1
#            return newx,newx
#        else:
#            if x<y:
#                ww = self.rng.uniform(x+1/self.alpha,y+1/self.alpha)
#            else:
#                ww = self.rng.uniform(y-1/self.alpha,x-1/self.alpha)
#            newy = min(max(ww,0),1)
#            return newx,newy         
    def smalltransition(self,x,y):
        newx = self.kernel(self.x)
        if 0.5-1/(2.0*self.alpha)<newx<0.5+1/(2.0*self.alpha):
            self.couple=1
            return newx,newx
        else:
            newy = self.kernel(self.y)
            while 0.5-1/(2.0*self.alpha)<newy<0.5+1/(2.0*self.alpha):
                newy = self.kernel(self.y)
            return newx,newy     

    def restart(self):
        self.clean()
        self.t=self.tstore
        self.tinc=self.tincstore
        self.graph[1].delete(ALL)

    def clean(self):
        if self.animation:
            self.after_cancel(self.animation)
        self.graph[0].delete("move")

    def rescale1(self):
        self.t=self.t/2
        self.tinc=self.tinc/2
        self.graph[1].scale(ALL,self.x0,self.y0,0.5,1)

    def rescale2(self):
        self.tinc=self.tinc/2
        self.graph[1].scale(ALL,self.x1,self.y0,0.5,1)

if __name__ == "__main__":
    master=Tk()

    rng=RNG()
    rng.seed(13)

    mg=Animation(master,rng=rng)

    mg.animate1()

    font=tkFont.Font(family="Helvetica",size=8,weight="bold")
#    Label(master,text=QUOTE,font=font).grid(column=0,row=10,columnspan=16)
#    Label(master,text=shortRCSID,font=font,fg="darkslategray").grid(row=11,column=1,columnspan=16)

    master.geometry(GEOMETRY)
    master.mainloop()

    raise SystemExit
