
from Tkinter import *
import math
from Cantera.num import *

def plotLimits(ypts, f=0.0, ndiv=5, logscale=0):
    """Return plot limits that"""
    if logscale:
        threshold = 1.0e-19
    else:
        threshold = -1.0e20
    ymax = -1.e20
    ymin = 1.e20
    for y in ypts:
        if y > ymax: ymax = y
        if y < ymin and y > threshold: ymin = y

    dy = abs(ymax - ymin)

    if logscale:
        ymin = math.floor(math.log10(ymin))
        ymax = math.floor(math.log10(ymax))+1
        fctr = 1.0

##         if dy < 0.2*ymin:
##             ymin = ymin*.9
##             ymax = ymax*1.1
##             dy = abs(ymax - ymin)
##         else:
    else:
        ymin = ymin - f*dy
        ymax = ymax + f*dy
        dy = abs(ymax - ymin)

        try:
            p10 = math.floor(math.log10(0.1*dy))
            fctr = math.pow(10.0, p10)
        except:
            return (ymin -1.0, ymax + 1.0, 1.0)
        mm = [2.0, 2.5, 2.0]
        i = 0
        while dy/fctr > ndiv:
            fctr = mm[i % 3]*fctr
            i = i + 1
        ymin = fctr*math.floor(ymin/fctr)
        ymax = fctr*(math.floor(ymax/fctr+0.999))

    return (ymin, ymax, fctr)


class DataGraph(Frame):
    def __init__(self,master,
                 data, ix=0, iy=0,
                 title='',
                 label = ('x-axis','y-axis'),
                 logscale = (0,0),
                 pixelX=500,
                 pixelY=500):
        self.logscale = logscale
        self.data = data
        self.ix = ix
        self.iy = iy
        self.minX, self.maxX, self.dx = plotLimits(data[ix,:],
                                                   logscale=self.logscale[0])
        self.minY, self.maxY, self.dy = plotLimits(data[iy,:],
                                                   logscale=self.logscale[1])

        Frame.__init__(self,master, relief=RIDGE, bd=2)
        self.title = Label(self,text=' ')
        self.title.grid(row=0,column=1,sticky=W+E)
        self.graph_w, self.graph_h = pixelX - 120, pixelY - 70
        self.origin = (100, 20)
        self.canvas = Canvas(self,
                             width=pixelX,
                             height=pixelY,
                             relief=SUNKEN,bd=1)
        id = self.canvas.create_rectangle(self.origin[0],self.origin[1],
                                          pixelX-20,pixelY-50)
        self.canvas.grid(row=1,column=1,rowspan=2,sticky=N+S+E+W)
        self.last_points=[]
        self.ticks(self.minX, self.maxX, self.dx,
                   self.minY, self.maxY, self.dy, 10)
        self.screendata()
        self.draw()
        self.canvas.create_text(self.origin[0] + self.graph_w/2,
                                self.origin[1] + self.graph_h + 30,
                                text=label[0],anchor=N)
        self.canvas.create_text(self.origin[0] - 50,
                                self.origin[1] + self.graph_h/2,
                                text=label[1],anchor=E)


    def writeValue(self, y):
        yval = '%15.4f' % (y)
        self.title.config(text = yval)

    def delete(self, ids):
        for id in ids:
            self.canvas.delete(id)

    def screendata(self):
        self.xdata = array(self.data[self.ix,:])
        self.ydata = array(self.data[self.iy,:])
        npts = len(self.ydata)
        if self.logscale[0] > 0:
            self.xdata = log10(self.xdata)
        if self.logscale[1] > 0:
            self.ydata = log10(self.ydata)
        f = float(self.graph_w)/(self.maxX-self.minX)
        self.xdata = (self.xdata - self.minX)*f + self.origin[0]
        f = float(self.graph_h)/(self.maxY-self.minY)
        self.ydata = (self.maxY - self.ydata)*f + self.origin[1]

    def toscreen(self,x,y):
        if self.logscale[0] > 0:
            x = log10(x)
        if self.logscale[1] > 0:
            y = log10(y)
        f = float(self.graph_w)/(self.maxX-self.minX)
        xx = (x - self.minX)*f + self.origin[0]
        f = float(self.graph_h)/(self.maxY-self.minY)
        yy = (self.maxY - y)*f + self.origin[1]
        return (xx, yy)

    def move(self, id, newpos, oldpos):
        dxpt = (newpos[0] - oldpos[0])/(self.maxX-self.minX)*self.graph_w
        dypt = -(newpos[1] - oldpos[1])/(self.maxY-self.minY)*self.graph_h
        self.canvas.move(id, dxpt, dypt)
        self.writeValue(newpos[1])

    def plot(self,n,color='black'):
        xpt, ypt = self.toscreen(self.data[self.ix,n],
                                 self.data[self.iy,n])
        #xpt = (x-self.minX)/(self.maxX-self.minX)*float(self.graph_w) + self.origin[0]
        #ypt = (self.maxY-y)/(self.maxY-self.minY)*float(self.graph_h) + self.origin[1]
        id_ycross = self.canvas.create_line(xpt,self.graph_h+self.origin[1],xpt,self.origin[1],fill = 'gray')
        id_xcross = self.canvas.create_line(self.origin[0],ypt,self.graph_w+self.origin[0],ypt,fill = 'gray')
        id = self.canvas.create_oval(xpt-2,ypt-2,xpt+2,ypt+2,fill=color)
        #self.writeValue(y)
        s = '(%g, %g)' % (self.data[self.ix,n],self.data[self.iy,n])
        if n > 0 and self.data[self.iy,n] > self.data[self.iy,n-1]:
            idt = self.canvas.create_text(xpt+5,ypt+5,text=s,anchor=NW)
        else:
            idt = self.canvas.create_text(xpt+5,ypt-5,text=s,anchor=SW)

        return [id,id_xcross,id_ycross, idt]

    def draw(self,color='red'):
        npts = len(self.xdata)
        for n in range(1,npts):
            self.canvas.create_line(self.xdata[n-1],self.ydata[n-1],
                            self.xdata[n],self.ydata[n],fill=color)

    def addLabel(self, y, orient=0):
        if orient==0:
            xpt, ypt = self.toscreen(y, 1.0)
            ypt = self.origin[1] + self.graph_h + 5
            self.canvas.create_text(xpt,ypt,text=y,anchor=N)
        else:
            xpt, ypt = self.toscreen(self.minX, y)
            xpt = self.origin[0] - 5
            self.canvas.create_text(xpt,ypt,text=y,anchor=E)
    def addLegend(self,text,color=None):
        m=Message(self,text=text,width=self.graph_w-10)
        m.pack(side=BOTTOM)
        if color:
            m.config(fg=color)

    def pauseWhenFinished(self):
        self.wait_window()

    def minorTicks(self, x0, x1, y, n, size, orient=0):
        xtick = x0
        dx = (x1 - x0)/float(n)
        if orient == 0:
            while xtick <= x1:
                xx, yy = self.toscreen(xtick, y)
                self.canvas.create_line(xx,yy,
                                        xx,yy-size)
                xtick += dx
        else:
            while xtick <= x1:
                xx, yy = self.toscreen(y, xtick)
                self.canvas.create_line(xx,yy,
                                        xx+size,yy)
                xtick += dx


    def ticks(self, xmin, xmax, dx, ymin, ymax, dy, size):

        if self.logscale[0]:
            xmin = math.pow(10.0,xmin)
            xmax = math.pow(10.0,xmax)
        if self.logscale[1]:
            ymin = math.pow(10.0,ymin)
            ymax = math.pow(10.0,ymax)

        n = 5
        ytick = ymin
        while ytick <= ymax:
            xx, yy = self.toscreen(xmin, ytick)
            self.canvas.create_line(xx, yy, xx + size,yy)
            self.addLabel(ytick,1)
            xx, yy = self.toscreen(xmax, ytick)
            self.canvas.create_line(xx, yy, xx - size,yy)
            ytick0 = ytick
            if self.logscale[1]:
                ytick *= 10.0
                n = 10
            else: ytick = ytick + dy
            if ytick <= ymax:
                self.minorTicks(ytick0, ytick, xmin, n, 5, 1)
                self.minorTicks(ytick0, ytick, xmax, n, -5, 1)

        n = 5
        xtick = xmin
        while xtick <= xmax:
            xx, yy = self.toscreen(xtick, ymin)
            self.canvas.create_line(xx, yy, xx, yy - size)
            self.addLabel(xtick,0)
            xx, yy = self.toscreen(xtick, ymax)
            self.canvas.create_line(xx, yy, xx, yy + size)
            if self.logscale[0]:
                xtick *= 10.0
                n = 10
            else: xtick = xtick + dx
            if xtick <= xmax:
                self.minorTicks(xtick - dx, xtick, ymin, n, 5, 0)
                self.minorTicks(xtick - dx, xtick, ymax, n, -5, 0)
