#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Created on Wed Jan 30 15:07:27 2019

https://github.com/julienGautier77/visu.git

@author: juliengautier

pip install qdarkstyle (https://github.com/ColinDuquesnoy/QDarkStyleSheet.git)
pip install pyqtgraph (https://github.com/pyqtgraph/pyqtgraph.git)

"""


__author__='julien Gautier'

from PyQt5.QtWidgets import QApplication,QVBoxLayout,QHBoxLayout,QWidget,QPushButton,QGridLayout
from PyQt5.QtWidgets import QInputDialog,QSlider,QCheckBox,QLabel,QSizePolicy,QMenu,QMessageBox
from PyQt5.QtWidgets import QShortcut
from pyqtgraph.Qt import QtCore,QtGui 
from PyQt5.QtCore import Qt
from PyQt5.QtGui import QIcon
import pylab
import sys,time,os
import pyqtgraph as pg # pip install pyqtgraph (https://github.com/pyqtgraph/pyqtgraph.git)
import numpy as np
import qdarkstyle # pip install qdarkstyle https://github.com/ColinDuquesnoy/QDarkStyleSheet  sur conda
from scipy.interpolate import splrep, sproot #
from scipy.ndimage.filters import gaussian_filter,median_filter
from PIL import Image

import pathlib


__version__='2019.07'

__all__=['SEELIGHT']

class SEELIGHT(QWidget) :
    '''open and plot file : 
        SEE(file='nameFile,path=pathFileName)
        Make plot profile ands differents measurements(max,min mean...)
        Can open .spe .SPE .sif .TIFF files
   
    '''
   
    def __init__(self,file=None,path=None,confpath=None):
        
        super(SEELIGHT, self).__init__()
        version=__version__
        p = pathlib.Path(__file__)
        if confpath==None:
            conf=QtCore.QSettings(str(p.parent / 'confVisu.ini'), QtCore.QSettings.IniFormat)
        else:
            conf=QtCore.QSettings(confpath, QtCore.QSettings.IniFormat)
            
        sepa=os.sep
        self.icon=str(p.parent) + sepa+'icons' +sepa
        self.conf = conf
        
        self.nomFichier=''
        self.setStyleSheet(qdarkstyle.load_stylesheet_pyqt5())
        self.path=path
        self.setWindowTitle('Visualization'+'       v.'+ version)
        self.setup()
        self.shortcut()
        self.actionButton()
        self.activateWindow()
        self.raise_()
        self.showNormal()
        self.ite=None
        self.setWindowIcon(QIcon(self.icon+'LOA.png'))
        
        if file==None:
            
            self.dimy=960
            self.dimx=1240
            # Create x and y index
            self.x = np.arange(0,self.dimx)
            self.y = np.arange(0,self.dimy)
            self.y,self.x = np.meshgrid(self.y, self.x)
    
            self.data=(50*np.random.rand(self.dimx,self.dimy)).round() + 150
        else:
            if path==None:
                self.path=self.conf.value('VISU'+"/path")
            
            self.OpenF(fileOpen=self.path+'/'+file)
            
        self.bloqq=1
        
        
    def setup(self):
        
        TogOff=self.icon+'Toggle_Off.svg'
        TogOn=self.icon+'Toggle_On.svg'
        TogOff=pathlib.Path(TogOff)
        TogOff=pathlib.PurePosixPath(TogOff)
        TogOn=pathlib.Path(TogOn)
        TogOn=pathlib.PurePosixPath(TogOn)
        
        self.setStyleSheet("QCheckBox::indicator{width: 30px;height: 30px;}""QCheckBox::indicator:unchecked { image : url(%s);}""QCheckBox::indicator:checked { image:  url(%s);}""QCheckBox{font :10pt;}" % (TogOff,TogOn) )
        
        
        self.vbox1=QVBoxLayout() 
        self.hbox1=QHBoxLayout()
        self.vbox1.addLayout(self.hbox1)
        
        hbox2=QHBoxLayout()
        self.openButton=QPushButton('Open',self)
        self.openButton.setIcon(QtGui.QIcon(self.icon+"Open.svg"))
        self.openButton.setIconSize(QtCore.QSize(50,50))
        self.openButton.setMaximumWidth(200)
        self.openButton.setMaximumHeight(100)
        self.openButton.setShortcut(QtGui.QKeySequence("Ctrl+O"))
        hbox2.addWidget(self.openButton)
        self.openButtonhbox4=QHBoxLayout()
        self.openButton.setStyleSheet("background-color: rgb(0, 0, 0,0) ;border-color: rgb(0, 0, 0,0)")
        
        self.saveButton=QPushButton('Save',self)
        self.saveButton.setMaximumWidth(100)
        self.saveButton.setMinimumHeight(100)
        self.saveButton.setIconSize(QtCore.QSize(50,50))
        hbox2.addWidget(self.saveButton)
        self.saveButton.setIcon(QtGui.QIcon(self.icon+"Saving.svg"))
        self.saveButton.setStyleSheet("background-color: rgb(0, 0, 0,0) ;border-color: rgb(0, 0, 0,0)")
        self.vbox1.addLayout(hbox2)
        
        
        hbox4=QHBoxLayout()
        self.labelFileName=QLabel("File :")
        self.labelFileName.setStyleSheet("font:15pt;")
        self.labelFileName.setMinimumHeight(30)
        self.labelFileName.setMaximumWidth(40)
        hbox4.addWidget(self.labelFileName)
        hbox42=QHBoxLayout()
    
        self.fileName=QLabel()
        self.fileName.setStyleSheet("font:10pt")
        self.fileName.setMaximumHeight(30)
        self.fileName.setMaximumWidth(150)
        hbox42.addWidget(self.fileName)
        self.vbox1.addLayout(hbox4)
        self.vbox1.addLayout(hbox42)
        
        hbox5=QHBoxLayout()
        self.checkBoxPlot=QCheckBox('CROSS',self)
        self.checkBoxPlot.setChecked(False)

        hbox5.addWidget(self.checkBoxPlot)
        hbox6=QHBoxLayout()
        self.label_Cross=QLabel()
        #self.label_Cross.setMaximumHeight(20)
        self.label_Cross.setMaximumWidth(150)
        self.label_Cross. setStyleSheet("font:10pt")
        hbox6.addWidget(self.label_Cross)
        #hbox6.setSpacing(1)
        self.vbox1.addLayout(hbox5)
        self.vbox1.addLayout(hbox6)
        
        self.ZoomLabel=QLabel('Zoom')
        self.vbox1.addWidget(self.ZoomLabel)
        self.checkBoxZoom=QSlider(Qt.Horizontal)
        self.checkBoxZoom.setMaximumWidth(200)
        self.checkBoxZoom.setMinimum(-5)
        self.checkBoxZoom.setMaximum(100)
        self.checkBoxZoom.setValue(-20)
        self.vbox1.addWidget(self.checkBoxZoom)
        
        self.checkBoxScale=QCheckBox('Auto Scale',self)
        self.checkBoxScale.setChecked(True)
        self.checkBoxScale.setMaximumWidth(100)
        
        self.checkBoxColor=QCheckBox('Color',self)
        self.checkBoxColor.setChecked(True)
    
        self.checkBoxHist=QCheckBox('Hist',self)
        self.checkBoxHist.setChecked(False)
        self.maxGraphBox=QCheckBox('Max',self)
        grid_layout = QGridLayout()
        grid_layout.setVerticalSpacing(0)
        grid_layout.setHorizontalSpacing(10)
        grid_layout.addWidget(self.checkBoxScale, 0, 0)
        grid_layout.addWidget(self.checkBoxColor,1,0)
        grid_layout.addWidget(self.checkBoxHist, 0, 1)
        #grid_layout.addWidget(self.checkBoxZoom, 1, 0)
        grid_layout.addWidget(self.maxGraphBox, 1,1)
        
        hbox8=QHBoxLayout()
        hbox8.addLayout(grid_layout)
        
        self.vbox1.addLayout(hbox8)
        
       
        self.vbox1.addStretch(1)
        
        self.winImage = pg.GraphicsLayoutWidget()
        self.winImage.setContentsMargins(0,0,0,0)
        self.winImage.setAspectLocked(True)
        self.winImage.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
        self.winImage.ci.setContentsMargins(0,0,0,0)
        
        vbox2=QVBoxLayout()
        vbox2.addWidget(self.winImage)
        vbox2.setContentsMargins(0,0,0,0)
        
        self.p1=self.winImage.addPlot()
        self.imh=pg.ImageItem()
        self.p1.addItem(self.imh)
        self.p1.setMouseEnabled(x=False,y=False)
        self.p1.setContentsMargins(0,0,0,0)
   
        self.p1.setAspectLocked(True,ratio=1)
        self.p1.showAxis('right',show=False)
        self.p1.showAxis('top',show=False)
        self.p1.showAxis('left',show=False)
        self.p1.showAxis('bottom',show=False)
        
        self.vLine = pg.InfiniteLine(angle=90, movable=False,pen='y')
        self.hLine = pg.InfiniteLine(angle=0, movable=False,pen='y')

        self.xc=10
        self.yc=10
        self.rx=50
        self.ry=50
        self.vLine.setPos(self.xc)
        self.hLine.setPos(self.yc)
        
       
        # text for fwhm on p1
        self.textX = pg.TextItem(angle=-90) 
        self.textY = pg.TextItem()
        
        #histogram
        self.hist = pg.HistogramLUTItem() 
        self.hist.setImageItem(self.imh)
        self.hist.autoHistogramRange()
        self.hist.gradient.loadPreset('flame')
        
        ##  XY  graph
        self.curve2=pg.PlotCurveItem()
        self.curve3=pg.PlotCurveItem()
        
        ## main layout
        hMainLayout=QHBoxLayout()
        hMainLayout.addLayout(vbox2)
        hMainLayout.addLayout(self.vbox1)
        hMainLayout.setContentsMargins(1,1,1,1)
        hMainLayout.setSpacing(1)
        hMainLayout.setStretch(10,1)
        
        self.setLayout(hMainLayout)
        self.setContentsMargins(1,1,1,1)
        
    def actionButton(self):
        
        self.openButton.clicked.connect(self.OpenF)
        self.saveButton.clicked.connect(self.SaveF)
        
        
        self.checkBoxColor.stateChanged.connect(self.Color)
        self.checkBoxPlot.stateChanged.connect(self.PlotXY)
        
        self.checkBoxZoom.valueChanged.connect(self.Zoom)
        #self.checkBoxZoom.stateChanged.connect(self.Zoom)
        
        self.checkBoxHist.stateChanged.connect(self.HIST)
        self.maxGraphBox.stateChanged.connect(self.Coupe)  
        
    def shortcut(self):
        
        self.shortcutPu=QShortcut(QtGui.QKeySequence("+"),self)
        self.shortcutPu.activated.connect(self.paletteup)
        self.shortcutPu.setContext(Qt.ShortcutContext(3))
        #3: The shortcut is active when its parent widget, or any of its children has focus. default O The shortcut is active when its parent widget has focus.
        self.shortcutPd=QtGui.QShortcut(QtGui.QKeySequence("-"),self)
        self.shortcutPd.activated.connect(self.palettedown)
        self.shortcutPd.setContext(Qt.ShortcutContext(3))
        
        self.shortcutOpen=QtGui.QShortcut(QtGui.QKeySequence("Ctrl+o"),self)
        self.shortcutOpen.activated.connect(self.OpenF)
        self.shortcutOpen.setContext(Qt.ShortcutContext(3))
        
        #self.shortcutSave=QtGui.QShortcut(QtGui.QKeySequence("Ctrl+s"),self)
        #self.shortcutSave.activated.connect(self.SaveF)
        #self.shortcutSave.setContext(Qt.ShortcutContext(3))
        
        
        # mousse mvt
        self.proxy=pg.SignalProxy(self.p1.scene().sigMouseMoved, rateLimit=60, slot=self.mouseMoved)
        self.p1.scene().sigMouseClicked.connect(self.mouseClick)
        self.vb=self.p1.vb
           
        
    def Display(self,data):
        
        self.data=data
        
        
        self.dimy=np.shape(self.data)[1]
        self.dimx=np.shape(self.data)[0]
        self.p1.setXRange(0,self.dimx)
        self.p1.setYRange(0,self.dimy)
        
         
        if self.checkBoxScale.isChecked()==1: # autoscale on
            self.imh.setImage(self.data.astype(float),autoLevels=True,autoDownsample=True)
        else :
            self.imh.setImage(self.data.astype(float),autoLevels=False,autoDownsample=True)
        
        self.PlotXY() #graph update
    
        self.Zoom()
    
    def mouseClick(self): # block the cross if mousse button clicked
        if self.bloqq==1:
            self.debloquer()
        else :
            self.bloquer()
            
    def mouseMoved(self,evt):

        ## the cross mouve with the mousse mvt
        if self.bloqq==0: # souris non bloquer
            
            pos = evt[0]  ## using signal proxy turns original arguments into a tuple
            if self.p1.sceneBoundingRect().contains(pos):
                
                mousePoint = self.vb.mapSceneToView(pos)
                self.xMouse = (mousePoint.x())
                self.yMouse= (mousePoint.y())
                if ((self.xMouse>0 and self.xMouse<self.data.shape[0]-1) and (self.yMouse>0 and self.yMouse<self.data.shape[1]-1) ):
                        self.xc = self.xMouse
                        self.yc= self.yMouse  
                        self.vLine.setPos(self.xc)
                        self.hLine.setPos(self.yc) # the cross move only in the graph    
                        #self.ro1.setPos([self.xc-(self.rx/2),self.yc-(self.ry/2)])
                        self.PlotXY()
                
    def fwhm(self,x, y, order=3):
        """
            Determine full-with-half-maximum of a peaked set of points, x and y.
    
        """
        y=gaussian_filter(y,5) # filtre for reducing noise
        half_max = np.amax(y)/2.0
        s = splrep(x, y - half_max,k=order) # F
        roots = sproot(s) # Given the knots .
        if len(roots) > 2:
            pass
           
        elif len(roots) < 2:
            pass
        else:
            return np.around(abs(roots[1] - roots[0]),decimals=2)
        
        
    def Coupe(self):
        
        if self.maxGraphBox.isChecked()==True:
            dataF=gaussian_filter(self.data,5)
            (self.xc,self.yc)=pylab.unravel_index(dataF.argmax(),self.data.shape) #take the max ndimage.measurements.center_of_mass(dataF)#
            self.vLine.setPos(self.xc)
            self.hLine.setPos(self.yc)
            
        xxx=np.arange(0,int(self.dimx),1)#
        yyy=np.arange(0,int(self.dimy),1)#
        coupeX=self.data[int(self.xc),:]
        coupeXMax=np.max(coupeX)
        dataCross=self.data[int(self.xc),int(self.yc)] 
        self.label_Cross.setText('x='+ str(int(self.xc)) + ' y=' + str(int(self.yc)) + ' value=' + str(dataCross))
        
        if coupeXMax==0: # evite la div par zero
            coupeXMax=1
            
        coupeXnorm=(self.data.shape[0]/10)*(coupeX/coupeXMax) # normalize the curves
        self.curve2.setData(30+coupeXnorm,yyy,clear=True)
        
        coupeY=self.data[:,int(self.yc)]
        coupeYMax=np.max(coupeY)
        if coupeYMax==0:
            coupeYMax=1
            
        coupeYnorm=(self.data.shape[1]/10)*(coupeY/coupeYMax)
        self.curve3.setData(xxx,20+coupeYnorm,clear=True)
        
        ### print fwhm on the  X et Y curves if max  >20 counts
        xCXmax=np.amax(coupeXnorm) # max
        if xCXmax>20:
            fwhmX=self.fwhm(yyy, coupeXnorm, order=3)
            if fwhmX==None:
                self.textX.setText('')
            else:
                self.textX.setText('fwhm='+str(fwhmX))
            #yCXmax=yyy[coupeXnorm.argmax()]
            #self.textX.setPos(xCXmax-3,yCXmax+3)
        yCYmax=np.amax(coupeYnorm) # max
        if yCYmax>20:
            fwhmY=self.fwhm(xxx, coupeYnorm, order=3)
            #xCYmax=xxx[coupeYnorm.argmax()]
            if fwhmY==None:
                self.textY.setText('',color='w')
            else:
                self.textY.setText('fwhm='+str(fwhmY),color='w')
            #self.textY.setPos(xCYmax-3,yCYmax-3)   
    
 
    def PlotXY(self): # plot curves on the  graph
        
        if self.checkBoxPlot.isChecked()==1:
            
            self.p1.addItem(self.vLine, ignoreBounds=False)
            self.p1.addItem(self.hLine, ignoreBounds=False)
            self.p1.addItem(self.curve2)
            self.p1.addItem(self.curve3)
            self.p1.showAxis('left',show=True)
            self.p1.showAxis('bottom',show=True)
            self.Coupe()
        else:
            self.p1.removeItem(self.vLine)
            self.p1.removeItem(self.hLine)
            self.p1.removeItem(self.curve2)
            self.p1.removeItem(self.curve3)
            self.p1.removeItem(self.textX)
            self.p1.removeItem(self.textY)
            self.p1.showAxis('left',show=False)
            self.p1.showAxis('bottom',show=False)
            
    def paletteup(self):
        
        levels=self.imh.getLevels()
        if levels[0]==None:
            xmax =self.data.max()
            xmin=self.data.min()
        else :
            xmax=levels[1]
            xmin=levels[0]
            
        self.imh.setLevels([xmin, xmax-(xmax- xmin) / 10])
        #hist.setImageItem(imh,clear=True)
        self.hist.setHistogramRange(xmin,xmax)

    def palettedown(self):
        
        levels=self.imh.getLevels()
        if levels[0]==None:
            xmax=self.data.max()
            xmin=self.data.min()
        else :
            xmax=levels[1]
            xmin=levels[0]
            
        self.imh.setLevels([xmin, xmax+ (xmax- xmin) / 10])
        #hist.setImageItem(imh,clear=True)
        self.hist.setHistogramRange(xmin,xmax)
    
    def Color(self):
        """ image in colour
        """
        if self.checkBoxColor.isChecked()==1:
            self.hist.gradient.loadPreset('flame')
        else:
            self.hist.gradient.loadPreset('grey')
            
    def Zoom(self):
        
        """Zoom function
        """
        self.zo=self.checkBoxZoom.value()
        
        if self.checkBoxPlot.isChecked()==0:
            self.xc=self.dimx/2
            self.yc=self.dimy/2
        
       
        if self.zo<=0:
            self.p1.setXRange(0,self.dimx)
            self.p1.setYRange(0,self.dimy)
        
        else:
            xmin=self.xc-10*(101-self.zo)
            xmax=self.xc+10*(101-self.zo)
            ymin=self.yc-10*(101-self.zo)
            ymax=self.yc+10*(101-self.zo)
            
            if xmin<0:
                xmin=0
            if xmax>self.dimx:
                xmax=self.dimx   
                
            if ymin<0:
                ymin=0
            if ymax>self.dimy:
                ymax=self.dimy 
                
            self.p1.setXRange(xmin,xmax)
            self.p1.setYRange(ymin,ymax)
    
        
    def bloquer(self): # block the cross
        
        self.bloqq=1
        self.conf.setValue('VISU'+"/xc",int(self.xc)) # save cross postion in ini file
        self.conf.setValue('VISU'+"/yc",int(self.yc))
         
    def debloquer(self): # unblock the cross
        self.bloqq=0
    
    def HIST(self):
        
        if self.checkBoxHist.isChecked()==1:
            self.winImage.addItem(self.hist)
        else:
            self.winImage.removeItem(self.hist)
    

        
    def OpenF(self,fileOpen=None):

        if fileOpen==False:
            chemin=self.conf.value('VISU'+"/path")
            fname=QtGui.QFileDialog.getOpenFileName(self,"Open File",chemin,"Images (*.txt *.spe *.TIFF *.sif *.tif);;Text File(*.txt);;Ropper File (*.SPE);;Andor File(*.sif);; TIFF file(*.TIFF)")
            fichier=fname[0]
        else:
            fichier=str(fileOpen)
            
        ext=os.path.splitext(fichier)[1]
        
        if ext=='.txt': # text file
            self.data=np.loadtxt(str(fichier))
        elif ext=='.spe' or ext=='.SPE': # SPE file
            dataSPE=SpeFile(fichier)
            data1=dataSPE.data[0]#.transpose() # first frame
            self.data=data1#np.flipud(data1)
        elif ext=='.TIFF' or ext=='.tif':# tiff File
            dat=Image.open(fichier)
            self.data=np.array(dat)
        elif ext=='.sif': 
            sifop=SifFile()
            im=sifop.openA(fichier)
            
            self.data=np.rot90(im,3)
#            self.data=self.data[250:495,:]
        else :
            msg = QMessageBox()
            msg.setIcon(QMessageBox.Critical)
            msg.setText("Wrong file format !")
            msg.setInformativeText("The format of the file must be : .SPE  .TIFF .sif or .txt ")
            msg.setWindowTitle("Warning ...")
            msg.setWindowFlags(QtCore.Qt.WindowStaysOnTopHint)
            msg.exec_()
            
        chemin=os.path.dirname(fichier)
        self.conf.setValue("VISU"+"/path",chemin)
        self.conf.setValue("VISU"+"/lastFichier",os.path.split(fichier)[1])
        self.fileName.setText(os.path.split(fichier)[1])
        self.nomFichier=os.path.split(fichier)[1]
        self.dataOrg=self.data
        self.Display(self.data)
    

    def SaveF (self):
        
        fname=QtGui.QFileDialog.getSaveFileName(self,"Save data as tiff ",self.path)
        self.path=os.path.dirname(str(fname[0]))
        fichier=fname[0]
        print(fichier,' is saved')
        self.conf.setValue("VISU"+"/path",self.path)
        time.sleep(0.1)
#        img_PIL = PIL.Image.fromarray(self.data)
#        img_PIL.save(str(fname[0])+'.TIFF',format='TIFF') 
        np.savetxt(str(fichier)+'.txt',self.data)
        self.fileName.setText(fname[0]+'.TIFF') 

  
    def newDataReceived(self,data):
        self.data=data
        self.dataOrg=self.data
        self.Display(self.data)
        
        
    def open_widget(self,fene):
        """ open new widget 
        """

        if fene.isWinOpen==False:
            fene.setup
            fene.isWinOpen=True
            
            #fene.Display(self.data)
            fene.show()
        else:
            #fene.activateWindow()
            fene.raise_()
            fene.showNormal()


    def closeEvent(self,event):

        exit  
        
def runVisuLIGHT() :
        
    from PyQt5.QtWidgets import QApplication
    import sys
    import qdarkstyle
    import visu
    
    appli = QApplication(sys.argv)   
    appli.setStyleSheet(qdarkstyle.load_stylesheet_pyqt5())
    e = visu.visualLIGHT.SEELIGHT()
    e.show()
    appli.exec_() 



        
if __name__ == "__main__":
    
    appli = QApplication(sys.argv) 
    appli.setStyleSheet(qdarkstyle.load_stylesheet_pyqt5())
    e = SEELIGHT()
    e.show()
    appli.exec_() 