# -*- coding: cp1252 -*-
import numpy as np
import matplotlib.pyplot as plt
from os import mkdir, listdir
from matplotlib.widgets import  RectangleSelector
from matplotlib.widgets import Button
from matplotlib.widgets import Slider
from mpl_toolkits.mplot3d import Axes3D
from numpy.random import rand
from PIL import Image
import shutil
import os
from pylab import *
from decimal import *
from scipy import ndimage
#import mayavi.mlab as ml
import matplotlib.animation as animation


info=np.dtype([('xdim','int'),('ydim','int'),('zdim','int'),('t','int'),('xp','float64'),('yp','float64'),('zp','float64'),('f','float64'),('venc','float64'),('slope','float64')])

def load_data(f1,f2):
    """
    Global loading function
    INPUT
    f1 -- file data.txt
    f2 -- file data.dat
    OUTPUT
    xp,yp,zp,f,slope,venc,matrix
    """
    dataInfo=load_data_info(f1)
    matrix=load_data_dat(f2,dataInfo)
    print ""
    print "------>>>>>Loading data completed successfully<<<<<------"
    return matrix,dataInfo
    
def load_data_dat(filename,dataInfo,path ='.'):
	"""
	Loading file data.dat
	OUTPUT
	matrix -- Image matrix
	"""
	try:
	    f=open(os.path.join(path,filename))
	    print "Reading current file: ", os.path.join(path,filename)
	    matrix=np.loadtxt(filename)
	    #print matrix
	    matrix=matrix.reshape((dataInfo['xdim'],dataInfo['ydim'],dataInfo['zdim'],dataInfo['t']))
	    return matrix
	except IOError:
		print "No such file or directory: ", filename
		exit

def load_data_info(filename, path='.'):
    """
    Loading file info.txt
    INPUT
    filename
    OUTPUT
    xdim,ydim,zdim,tdim,xp,yp,zp,f,venc,slope
    """
    try:
        f=open(os.path.join(path,filename),'r')
        print "Reading current file: ", os.path.join(path,filename)
        dataInfo=np.loadtxt(filename,dtype=info)
        return dataInfo
        
    except IOError:
        print "No such file or directory: ",  filename
        exit

def sscale(matrix,venc,slope):
    matrix=venc*(matrix)-slope
    d=ravel(matrix)
    dd=where(abs(d)==slope)
    for el in dd[0]:
	d[el]=0.0
    matrix=reshape(d,shape(matrix))
    return matrix

def cross_corr(matrix,v_r):
    x=shape(matrix)[0]
    y=shape(matrix)[1]
    t=shape(matrix)[2]
    Pxy=zeros((x,y),float)
    F1xy=zeros((t),float)
    F2xy=zeros((x,y,t),float)
    F1xy=v_r-mean(v_r)
    for i in xrange(x):
        for j in xrange(y):
            for z in xrange(t):
               F2xy[i,j,z]=matrix[i,j,z]-mean(matrix[i,j,:])
    Nxy=F1xy*F2xy
    for i in xrange(x):
        for j in xrange(y):
            Pxy[i,j]=sum(Nxy[i,j,:])/sqrt(sum(pow(F1xy,2))*sum(F2xy[i,j,:]**2))
    return Pxy
class FrameIndex:
    def __init__(self,matrix,dataInfo,index):
            self.ind = 0
            self.dataInfo=dataInfo
            self.matrix=matrix
            self.index=index
            self.f=plt.figure()
            self.ax = self.f.add_subplot(111)
            self.f.subplots_adjust(bottom=0.2)
            self.ax.set_title('Instant 0')
            self.l=self.ax.imshow(matrix[:,:,0])
            self.axprev = plt.axes([0.6, 0.05, 0.1, 0.075])
            self.axnext = plt.axes([0.71, 0.05, 0.1, 0.075])
            self.axok = plt.axes([0.82, 0.05, 0.1, 0.075])
    def next(self, event):
                if(self.ind<self.dataInfo['t']-1):
                    self.ind += 1
                    self.ax.set_title('Instant %d'%(self.ind))
                    self.l.set_data(self.matrix[:,:,self.ind])
                    plt.draw()
    def prev(self, event):
                if(self.ind>0):
                    self.ind -= 1
                    self.ax.set_title('Instant %d'%self.ind)
                    self.l.set_data(self.matrix[:,:,self.ind])
                    plt.draw()
    def select(self,event):
                self.index[0]=self.ind
                close(self.f)
                return self.ind
                
    def run(self):
        bnext = Button(self.axnext, 'Next')
        bnext.on_clicked(self.next)
        bprev = Button(self.axprev, 'Previous')
        bprev.on_clicked(self.prev)
        bOk = Button(self.axok, 'Ok')
        bOk.on_clicked(self.select)
        plt.show()
        
	
class RectangularSelection:
    def __init__(self,matrix,ist,coord):
        self.matrix=matrix
        self.ist=ist
        self.coord=coord
        xb = np.arange(int(matrix.shape[0]))
	yb = np.arange(int(matrix.shape[1]))
        self.f=figure()
	self.ax=self.f.add_subplot(1,1,1)
        self.f.subplots_adjust(bottom=0.2)
	self.ax.matshow(np.transpose(matrix[:,:,ist]),extent=[min(xb),max(xb),min(yb),max(yb)],animated=True)
	self.ax.grid()
	self.ax.set_title("Choose Rectangular Selection for selected frame "+str(ist))
        
    def closeFig(self,event):
        close(self.f)
    def onselect(self,eclick, erelease):
        'eclick and erelease are the press and release events'
        x1, y1 = eclick.xdata, eclick.ydata
        x2, y2 = erelease.xdata, erelease.ydata
        if y1>y2:
            y1,y2=y2,y1
        if x1>x2:
            x1,x2=x2,x1
        self.ax.set_ylim(y1,y2)
        self.ax.set_xlim(x1,x2)
        plt.draw()
        self.coord[0]=x1
        self.coord[1]=x2
        self.coord[2]=y1
        self.coord[3]=y2
        print ("(%3.2f, %3.2f) --> (%3.2f, %3.2f)" % (x1, y1, x2, y2))
    def run(self):
        self.axOk = plt.axes([0.6, 0.05, 0.1, 0.075])
        self.bOk = Button(self.axOk, 'Ok')
        self.bOk.on_clicked(self.closeFig)
        self.RS = RectangleSelector(self.ax, self.onselect,
                                           drawtype='box', useblit=True,
                                           button=[1,3], # don't use middle button
                                           minspanx=5, minspany=5,
                                           spancoords='pixels')
        plt.show()

class SelectPixel:
    def __init__(self,w_matrix,coord,ts,pixel):
        self.matrix=w_matrix
        self.coord=coord
        self.ts=ts
        self.pixel=pixel
        self.fig=plt.figure()
        self.fig2=plt.figure()
        self.ax=self.fig.add_subplot(1,1,1)
        self.sub_matrix=self.matrix[coord[0]:coord[1],coord[2]:coord[3],:]
        xb = np.arange(int(self.sub_matrix.shape[0]))
	yb = np.arange(int(self.sub_matrix.shape[1]))
        im=self.ax.matshow(np.transpose(self.sub_matrix[:,:,ts]),extent=[min(xb),max(xb),min(yb),max(yb)],picker=True,animated=True)
        self.ax.set_picker(5)
        self.ax.set_title("Choose a Central Reference Pixel")
	self.ax.grid()
    def closeFig(self,event):
            close(self.fig2)
            close(self.fig)
    def onpick(self,event):
            artist = event.artist
            if isinstance(artist, matplotlib.axes.Axes):
                x=event.mouseevent.ydata
                y=event.mouseevent.xdata
                self.pixel[0]=int(x)
                self.pixel[1]=int(y)
                self.update(x,y)
                plt.draw()
    def update(self,x,y):
            x=int(x)
            y=int(y)
            n=1
            hold(False)
            for i in [1,0,-1]:
                for j in (-1,0,1):
                    ax=self.fig2.add_subplot(3,3,n)
                    a=self.sub_matrix[x+j,y+i,:]
                    l=np.arange(len(a))
                    ax.plot(l,a,color='r')
                    xc=x+j
                    yc=y+i
                    stringa="Pixel "+str(xc)+ " " +str(yc) 
                    xx=ax.set_xlabel('Time Istant')
                    t=ax.set_title(stringa)
                    t.set_size('7')
                    xx.set_size('7')
                    n+=1
                    self.fig2.canvas.draw()
    def run(self):
        axOk = self.fig2.add_axes([0.9, 0.025, 0.08, 0.04])
        bOk = Button(axOk, 'Ok')
        bOk.on_clicked(self.closeFig)
        self.fig.canvas.mpl_connect('pick_event', self.onpick)
        plt.show()
        


class DiscreteSlider(Slider):
    """A matplotlib slider widget with discrete steps."""
    def __init__(self, *args, **kwargs):
        self.inc = kwargs.pop('increment', 0.5)
        Slider.__init__(self, *args, **kwargs)
    def set_val(self, val):
        discrete_val = int(val / self.inc) * self.inc
        xy = self.poly.xy
        xy[2] = discrete_val, 1
        xy[3] = discrete_val, 0
        self.poly.xy = xy
        self.valtext.set_text(self.valfmt % discrete_val)
        if self.drawon: 
            self.ax.figure.canvas.draw()
        self.val = val
        if not self.eventson: 
            return
        for cid, func in self.observers.iteritems():
            func(discrete_val)
class TreshHold:
    def __init__(self,sub_matrix,pixel,cc,tr):
        self.matrix=sub_matrix
        self.pixel=pixel
        self.cc=cc
        self.tr=tr
        value=arange(0,1,0.01)
        self.inc=0.01
	count=0
	c=[]
	self.f=figure()
	#Reference pixel velocity profile
	print "Reference Pixel time profile"	
	self.ax=self.f.add_subplot(2,1,1)
	x=np.arange(len(self.matrix[pixel[0],pixel[1],:]))
	self.ax.plot(x,self.matrix[pixel[0],pixel[1],:],color='r')
	self.ax.set_title('Reference pixel velocity value across time v(t)',size='12')
	#Tresh hold value
	for v in value:
	    count=0
 	    for i in xrange(cc.shape[0]):
			for j in xrange(cc.shape[1]):
				if(cc[i][j]>=v):
					count+=1
	    c.append(count)
	self.ax=self.f.add_subplot(2,1,2)
        self.bar=self.ax.bar(value,c, width=0.02, color='r')
	#plot(value,c,color='r')
	self.ax.set_title('Number of pixel vs Thresh_hold',size='12')
        axcolor = 'lightgoldenrodyellow'
	self.axslide = plt.axes([0.25, 0.02, 0.35, 0.03], axisbg=axcolor)
        self.sslide= DiscreteSlider(self.axslide, 'TreshHold', 0.0, 1.0,increment=self.inc, valinit=self.inc)
    def update(self,val):
            self.ax.hold(True)
            for el in self.bar:
                if el.get_x()==val:
                    el.set_facecolor('g')
                else:
                    el.set_facecolor('r')
            self.tr[0]=val
    def closeFig(self,event):
        close(self.f)
    def run(self):
        self.sslide.on_changed(self.update)
        axok = plt.axes([0.8, 0.01, 0.1, 0.04])
        axcolor = 'lightgoldenrodyellow'
        button = Button(axok, 'Ok', color=axcolor, hovercolor='0.975')
        button.on_clicked(self.closeFig)    
        plt.show() 


def morpho(matrix):
    """
    Applicazione degli operatori morfologici
    per determinare il contorno del vaso
    """		
    F=ndimage.binary_opening(matrix)
    f1=ndimage.binary_fill_holes(F)
    f2=ndimage.binary_erosion(f1)
    f3=ndimage.binary_dilation(f2)
    out=zeros_like(matrix)
    out=where(f3==True,matrix,0)
    return out
    
def ShowSegmentation(M1,M2,M3,ist):
    xp=1.0;yp=1.0
    x1=arange(0,xp*(shape(M1)[1]),xp)
    y1=arange(0,yp*(shape(M1)[0]),yp)

    ### ContourF plot base
    f=plt.figure()
    ax=f.add_subplot(221)
    cf1=ax.contourf(x1,y1,M1[:,:,ist])
    f.colorbar(cf1)
    ax.grid()
    ax.set_title('matrix velocity filled contours at TS='+str(ist))
    plt.draw()
    ### ContourF plot tresh-hold matrix
    ax=f.add_subplot(222)
    cf2=ax.contourf(x1,y1,M2[:,:,ist])
    f.colorbar(cf2)
    ax.grid()
    ax.set_title('tresh-hold matrix velocity filled contours at TS='+str(ist))
    plt.draw()
    ### ContourF plot of morph-matrix 
    ax=f.add_subplot(223)
    cf3=ax.contourf(x1,y1,M3[:,:,ist])
    f.colorbar(cf3)
    ax.grid()
    ax.set_title('morph-matrix velocity filled contours masked at TS='+str(ist))
    f.savefig('outProcessing.png')
    plt.show()
   
   
def mask(matrix, trs, cc):
	"""
	Maschera sulla matrice
	INPUT
	matrix -- input matrix
	trs -- tresh hold value
	cc -- cross correlation matrix
	OUTPUT
	fmatrix -- matrice filtrata
	"""
	fmatrix=zeros_like(matrix)
	num=0
	for i in xrange(cc.shape[0]):
		for j in xrange(cc.shape[1]):
			if(cc[i,j]>=trs):
				fmatrix[i,j,:]=matrix[i,j,:]	
				num+=1
	print "Founded ", num, "value over threshold value ", trs
        '''
        print cc.shape
        print matrix.shape
        
        f=where(cc>trs,matrix,0)
        print f.shape
        return f
        '''
	return fmatrix
        

def Image3d(matrix,ts):
    fig=plt.figure()
    ax2 = fig.add_subplot(1,1,1,projection='3d')
    x,y = np.mgrid[:matrix.shape[0],:matrix.shape[1]]
    pl=ax2.plot_surface(x,y,matrix[:,:,ts],cmap=plt.cm.jet,rstride=1,cstride=1,linewidth=0.,antialiased=False)
    ax2.set_title('3D for frame=%d'%ts)
    ax2.set_zlim3d(0,100)
    plt.show()


def Animation3d(matrix_morpho):
        fig=plt.figure()
        ax2 = fig.add_subplot(1,1,1,projection='3d')
        x,y = np.mgrid[:matrix_morpho.shape[0],:matrix_morpho.shape[1]]
        pl=ax2.plot_surface(x,y,matrix_morpho[:,:,0],cmap=plt.cm.jet,rstride=1,cstride=1,linewidth=0.,antialiased=False)
        ax2.set_title('3D')
        ax2.set_zlim3d(0,100)
        def update(i, ax2, fig,x2,y2,matrix_morpho):
            ax2.cla()
            wframe = ax2.plot_surface(x2, y2, matrix_morpho[:,:,i], cmap=plt.cm.jet,rstride=1,cstride=1,linewidth=0.,antialiased=False)
            ax2.set_zlim3d(0,100)
            return wframe,
        ani = animation.FuncAnimation(fig, update, 
                frames=xrange(0,12), 
                fargs=(ax2, fig,x,y,matrix_morpho), interval=30)
        
        plt.show()
	
   
class Animation3d:
    def __init__(self,matrix):
        self.matrix=matrix
        self.f=plt.figure()
        self.ax=self.f.add_subplot(1,1,1,projection='3d')
        self.x,self.y=np.mgrid[:matrix.shape[0],:matrix.shape[1]]
        self.surf=self.ax.plot_surface(self.x,self.y,matrix[:,:,0],cmap=plt.cm.jet,rstride=1,cstride=1,linewidth=0.,antialiased=False)
        self.ax.set_title('3D')
        self.ax.set_zlim3d(0,100)

        
    def update(self,num,ax,fig) :
            self.ax.cla()
            wframe = self.ax.plot_surface(self.x, self.y, matrix[:,:,num], cmap=plt.cm.jet,rstride=1,cstride=1,linewidth=0.,antialiased=False)
            self.ax.set_zlim3d(0,100)
            return wframe,
   
    def run(self):
        line_ani = animation.FuncAnimation(self.f, self.update, frames=np.arange(0,12),fargs=(self.ax, self.f),
                              interval=30, blit=False)
        plt.show()