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

# Program is used to select correct exafs curves from the canberra 30 elements
# The user can see all the curves from the canberra detector and can unselected
# the bad curves. Then the sum of the selected curves is shown in black
#
#Description of variables
#self.scans{"title","","data_array",""}:    C'est un dictionnaire contenant tous les scans contenu dans le fichier .canb
#	- "title": 		Contient la ligne #S: Ex 49 exafs 12.1297 12.1441
#	- "data_array": 	Contient les valeurs: A1 .... A30, I0, T (counting time), Energy
#self.scanActif{"title","","data_array",""}: C'est un dictionnaire contenant les valeurs du n° de scan selectionné
#self.numscan: 			Contient une liste de tous les numeros de scan: Ex [49,52,53,89]
#self.date: 			Contient la date de tous les scans: Ex [Wed Jun 30 11:56:41 2010, Wed Jun 30 12:16:33 2010,...]
#self.removed_element: 		C'est une liste des elements enleves: Ex [A1, A5, D2, C7]
#self:labels			Contient la liste de la ligne #L Ex:A1   A2   ...  D7   D8   I0 T Energy
#self.labels.index("Energy"):	C'est l'index des valeurs de l'Energy: Ca doit etre a 32
#self.labels.index("T"):	C'est l'index des valeurs du T (Counting Time): Ca doit etre a 31
#self.labels.index("I0"): 	C'est l'index des valeurs de I0: Ca doit etre a 30
#
#self.Xdata:			C'est les valeur de l'energy pour un n° de scan: Ex [12.1297, 12.1322, 12.1345, 12.1367,...]
#self.Ydata_I0:			C'est les valeur des 30 Elements / I0 pour un n° de scan
#self.Ydata_Ct:			C'est les valeur des 30 Elements / T (Counting Time) pour un n° de scan
#self.Xdata_sum:		C'est les coordonnées pour tracé la somme. C'est la meme chose que self.Xdata
#self.Ydata_sum:		C'est la somme de Y (en Noir)
#

import sys, os
import pdb
import cStringIO
import numpy
from PyQt4 import QtCore, QtGui, Qt
from PyQt4 import Qwt5 as qwt# module pour afficher des graphs
from datetime import datetime
try:
    _fromUtf8 = QtCore.QString.fromUtf8
except AttributeError:
    _fromUtf8 = lambda s: s


#Definition of the Main frame
class MainFrame(QtGui.QMainWindow):
    def __init__(self,parent=None):
	QtGui.QMainWindow.__init__(self, parent)
	self.scans = {}
        self.create_main_frame()
        QtGui.QApplication.setStyle(QtGui.QStyleFactory.create('cleanlooks'))

    def FormClose(self):
	print "You decided to quit. Then Bye bye !!"
	self.close() #Close the main frame

    # Set by default all checkboxes to True (selected)
    def true_chkbox(self):
        for i in range(30):
	  if not self.checkboxes[i].isChecked():
		self.checkboxes[i].setChecked(True)
		
    # Set by default all checkboxes to False (unselected)
    def false_chkbox(self):
        for i in range(30):
	  if self.checkboxes[i].isChecked():
		self.checkboxes[i].setChecked(False)
    # Reset all curves
    def resetcurves(self):
	self.label_FileCanb.setText("")
	self.Xdata=[]
	self.Xdata_sum=[]
	self.Ydata_I0=[]
	self.Ydata_Ct=[]
	self.Ydata_sum=[]
	self.Combo_ScanList.clear()
	for i in range(6):
	  plot = getattr(self, "plot_%d" % (i+1))
	  plot.setTitle('No title') #set plot title
	  for j in range(6):# for 6 curves (curve1 -> curve5 curve6=sum)
               curve = getattr(plot, "curve%d" % (j+1))               
	       curve.setData(self.Xdata,self.Ydata_I0)# give data
	  plot.setAxisAutoScale(qwt.QwtPlot.xBottom)
	  plot.setAxisAutoScale(qwt.QwtPlot.yLeft) 
	  plot.setAxisAutoScale(qwt.QwtPlot.yRight) 	    	
          plot.replot()

    # Initialization of the Curves
    def plot_init(self): 
	colorpen=[Qt.QPen(Qt.Qt.magenta,2),Qt.QPen(Qt.Qt.red,2),Qt.QPen(Qt.Qt.blue,2),
                  Qt.QPen(Qt.Qt.green,2),Qt.QPen(Qt.Qt.darkYellow,2),Qt.QPen(Qt.Qt.black,2)]
	legend=['A1','A2','A3','A4','A5','A6','A7',
		'B1','B2','B3','B4','B5','B6','B7','B8',
		'C1','C2','C3','C4','C5','C6','C7',
		'D1','D2','D3','D4','D5','D6','D7','D8',
		'Result']
	for i in range(6):
	  plot = getattr(self, "plot_%d" % (i+1))
	  plot.setTitle('No title') #set plot title
	  plot.setCanvasBackground(Qt.Qt.white) #set plot background
	  plot.insertLegend(qwt.QwtLegend(), qwt.QwtPlot.RightLegend)# add legend 
	  plot.grid = qwt.QwtPlotGrid()# add a grid
          plot.grid.attach(plot)#attach grid to the plot
          plot.grid.setPen(Qt.QPen(Qt.Qt.gray, 0, Qt.Qt.DotLine))# set grid properties
	  plot.enableAxis(qwt.QwtPlot.yRight)
          plot.setAxisTitle(qwt.QwtPlot.xBottom, 'Energy (KeV)')# X axis title
          plot.setAxisTitle(qwt.QwtPlot.yLeft, 'Counts')# Y left axis title
          plot.setAxisTitle(qwt.QwtPlot.yRight, 'Sum Counts')# Y right axis title	  
	  #Affichage valeur curseur
	  plot.picker = qwt.QwtPlotPicker(qwt.QwtPlot.xBottom, 
					qwt.QwtPlot.yLeft, 
					qwt.QwtPicker.PointSelection | qwt.QwtPicker.DragSelection, 
					qwt.QwtPlotPicker.CrossRubberBand, 
					qwt.QwtPicker.AlwaysOn, plot.canvas())	  
	  #Affichage rectangle pour zoom
          plot.zoomer = qwt.QwtPlotZoomer(qwt.QwtPlot.xBottom,
					qwt.QwtPlot.yLeft,
          				qwt.QwtPicker.DragSelection,
					qwt.QwtPicker.AlwaysOff,plot.canvas())
	  for j in range(6):
	    if j==5:
	       new_legend=legend[30]#add legend Result
	       new_curve = qwt.QwtPlotCurve(new_legend) #add a new curve with legend
	       new_curve.setYAxis(qwt.QwtPlot.yRight)
	    else:
	       new_legend=legend[i*5+j]#add a new legend
	       new_curve = qwt.QwtPlotCurve(new_legend) #add a new curve with legend	       
	       new_curve.setYAxis(qwt.QwtPlot.yLeft)
	    new_curve.setPen(colorpen[j])# define a curve color
            new_curve.attach(plot)#attach curve to plot
	    setattr(plot, 'curve%d' % (j+1), new_curve)	

    #Get the X data for the plots    
    def get_Xdata(self,scan_data):
	Xdata = scan_data[self.labels.index("Energy")]#Abcsisse (Energy)
	self.Xdata=Xdata
	return Xdata

    #Get the Y data for the plots
    def get_Ydata(self,scan_data):
        dCt=[]
	dI0=[]
	for i in range(len(scan_data)-3): # pour les 30 elements 
           dCt.append((scan_data[i])/(scan_data[self.labels.index("T")]))
	   dI0.append((scan_data[i])/(scan_data[self.labels.index("I0")]))
	self.Ydata_Ct=dCt
	self.Ydata_I0=dI0
	if self.rb_I0.isChecked() == True:#Normalization by I0, Y=Y/I0	
	   return dI0
        elif self.rb_Ct.isChecked() == True:#Normalization by Counting Time, Y=Y/T
	   return dCt

    #plot scans from A1 to D8
    def plot_scans(self,Xd,Yd):
	self.removed_element=[]
        for i in range(6):#for 6 tabs (1-5|6-10|11-15|16-20|21-25|26-30)
	    plot = getattr(self, "plot_%d" % (i+1))
	    plot.setTitle(self.Combo_ScanList.currentText())# set plot title
            for j in range(5):# for 5 curves (curve1 -> curve5)
               curve = getattr(plot, "curve%d" % (j+1))
               if self.checkboxes[i*5+j].isChecked():#checkboxe is checked
                  curve.show()#display the curve
               else:
                  curve.hide()#No curve displayed		
	          self.removed_element.append(str(self.checkboxes[i*5+j].text()))
	       curve.setData(Xd, Yd[i*5+j])# give data
	    #plot.zoomer.setZoomBase(plot.zoomer.scaleRect())
	    #print dir(plot.zoomer.scaleRect)
	    plot.setAxisAutoScale(qwt.QwtPlot.xBottom)
	    plot.setAxisAutoScale(qwt.QwtPlot.yLeft) 
	    plot.setAxisAutoScale(qwt.QwtPlot.yRight) 	    	
            plot.replot()	    
	    plot.zoomer.setZoomBase(plot.zoomer.scaleRect())	
        self.plot_sum(Xd,Yd)

    #Plot the sum of all the scans
    def plot_sum(self, Xsum, Ysum): 
	Y_data=[] 
        for i in range(30):
	  if self.checkboxes[i].isChecked():
	     if Y_data == []:#first time
		Y_data = numpy.array(Ysum[i])# first data
	     else:
		Y_data = Y_data + numpy.array(Ysum[i])#sum the data
	for i in range(6):#for 6 tabs (1-5|6-10|11-15|16-20|21-25|26-30)
	  plot = getattr(self, "plot_%d" % (i+1))
	  curve = getattr(plot, "curve6")#curve sum
	  curve.setData(Xsum, Y_data)
	  self.Ydata_sum=Y_data	 	  
	  plot.replot()

    #replot when click checkboxes
    def replot_scans(self,ignored=None):  
	if self.rb_I0.isChecked() == True:#Normalization by I0, Y=Y/I0	
	   self.plot_scans(self.Xdata,self.Ydata_I0)
        elif self.rb_Ct.isChecked() == True:#Normalization by Counting Time, Y=Y/T
	   self.plot_scans(self.Xdata, self.Ydata_Ct)

    #Plot curves in Counting Time mode
    def plot_scan_ct(self):
	self.plot_scans(self.Xdata, self.Ydata_Ct)

    #Plot curves in I0 mode
    def plot_scan_I0(self):
	self.plot_scans(self.Xdata, self.Ydata_I0)

    #Zoom 
    def zoom(self, onnn):		
        for i in range(6):
	   plot = getattr(self, "plot_%d" % (i+1))	  
 	   plot.zoomer.setEnabled(onnn)	
	   plot.zoomer.zoom(0)#-> zoom out to zoombase
	   if onnn:
		plot.picker.setRubberBand(qwt.QwtPicker.NoRubberBand)
	  
	   else:
		plot.picker.setRubberBand(qwt.QwtPicker.CrossRubberBand)

    #Selection of the scan number. Called by clicking on the listbox
    def scan_selected(self, numero_index_scan):
	#print "numero_index_scan = %s" %numero_index_scan
        if numero_index_scan == 0:
          print 'There is no scan. Please select an another scan'
        else:
	  self.NormalisationGroup.setEnabled(True)
	  self.DetectorGroup.setEnabled(True)
	  self.btnZoom.setEnabled(True)
	  self.btnSave.setEnabled(True)
	  self.btnReset.setEnabled(True)
	  self.scanActif=self.scans[self.numscan[numero_index_scan - 1]]
          X_data = self.get_Xdata(self.scanActif["data_array"])#get Xdata
	  Y_data =self.get_Ydata(self.scanActif["data_array"])#get Ydata
	  self.plot_scans(X_data,Y_data)
	  self.zoom(False)

    #Dialogbox to open and threat a canb file. Called by clicking on Open
    def OpenCanbFile(self): 
	self.path_org = os.getcwd()
	filename = str(QtGui.QFileDialog.getOpenFileName(self,'Open file',self.path_org,("Canb files (*.canb);;All Files (*)"),""))#open
	if filename:
	   self.path_working=os.path.dirname(filename)
	else:
	  return
    	f=open(filename,"r")
	#self.resetcurves()
	#mettre ici une initialisation des graphes:
	#	-effacer les courbes
	#	-mettre les axes au mini
	#	-effacer les titres scan
	self.label_FileCanb.setText(filename)#label of file's name in Tab1
	self.Combo_ScanList.clear()
	self.Combo_ScanList.addItem('---')
        data=[]
        scan_arrays={}
        self.numscan=[]
	self.date=[]
        self.removed_element=[]
        for line in f:
           if line.startswith("#S"):
              a=line.split()
              scan_number=a[1]
              command=a[2] + " " + a[3] + " " + a[4]
              title= scan_number + " " + command
              data_array = []
	      data.append({"title":title, "data_array": data_array})
              scan_arrays[int(scan_number)]=data[-1]
              self.numscan.append(int(scan_number))
              self.Combo_ScanList.addItem(title)
           elif line.startswith("#D"):
		self.date.append(line[3:])
           elif line.startswith("#L"):
	     self.labels=line[3:-2].split()	     
           elif line.startswith("#"):	 
              pass # passe les autres commentaires
           elif line.startswith("\n"):
	      pass #si new line   
	   elif line.startswith("\r"):  
	      pass # si retour chariot
           else:
	      if line!="\n" or line!="\r":
                 data_array.append(line)           
        for scan in data:
	   if scan["data_array"]!=[]:
                scan_data = "".join(scan["data_array"])
                scan["data_array"]=numpy.genfromtxt(cStringIO.StringIO(scan_data))	
	   else:		
		self.numscan.remove(int(scan["title"].split()[0]))
		self.Combo_ScanList.removeItem(self.Combo_ScanList.findText(scan["title"]))
        self.scans=scan_arrays	
        self.ScanSelectionGroup.setEnabled(True)
	for i in self.numscan:
	   a=numpy.transpose(self.scans[i]["data_array"])
	   self.scans[i]["data_array"]=a     
        f.close()

    #Dialogbox to save the result
    def saveDialog(self):
	numero_index_scan=self.Combo_ScanList.currentIndex()
	numero_scan=self.numscan[self.Combo_ScanList.currentIndex()-1]
        data=self.scans[numero_scan]["data_array"]
	t = datetime.now()
	Modification_date=t.strftime("%Y-%m-%d %H:%M:%S")
	#header
	line_S="#S %s\n" %(self.scans[numero_scan]["title"])
	line_D="#D %s" %self.date[numero_index_scan-1]
	line_C1="#C Modified by canb.py the: %s\n" %Modification_date
	line_C2="#C Removed elements: %s\n" %self.removed_element
	line_L="#L Energy I0 Canb Canb/I0\n"
	#I0
	I0=data[self.labels.index("I0")]
	#Canb
	if self.rb_I0.isChecked() == True:
	   canb=self.Ydata_sum*data[self.labels.index("I0")]
	else: 
	   canb=self.Ydata_sum*data[self.labels.index("T")] 
	fich = str(QtGui.QFileDialog.getSaveFileName(self, 'Save file',self.path_working,("Data files (*.dat);;All Files (*)"),""))
	if fich != "":
	   if fich.find(".dat")==-1:  
	      filename = "%s%s" %(fich,".dat")
	   else:
	      filename=fich	   
	   f = open(filename, 'w')	
	   f.write(line_S)
	   f.write(line_D)
	   f.write(line_C1)
	   f.write(line_C2)
	   f.write(line_L)
	   for i in range(len(self.Ydata_sum)):
	      line_data="%s %s %s %s\n" %(self.Xdata[i], I0[i], canb[i], self.Ydata_sum[i])
	      f.write(line_data)
	   f.close()
        else:
	   print "Canceled"
############################################################
########                 main frame                 ########
############################################################
    def create_main_frame(self): 
	self.setWindowTitle("Traitement des spectres du detecteur Canbera ")#Add window title
	self.label_FileCanb = QtGui.QLabel("", self)#label chemin et nom de fichier canb
	#Toolbars & icon
        self.toolBar = QtGui.QToolBar(self)
        self.addToolBar(self.toolBar)	
	#----icon Open
	self.btnOpen = QtGui.QToolButton(self)
	self.btnOpen.setText("Open")
	self.btnOpen.setToolButtonStyle(Qt.Qt.ToolButtonTextUnderIcon)
	#self.btnOpen.setIcon(QtGui.QIcon.fromTheme(("document-open")))
	self.btnOpen.setIcon(QtGui.QIcon("/usr/share/icons/oxygen/48x48/actions/document-open.png"))
        self.toolBar.addWidget(self.btnOpen)
	#----icon Save
	self.btnSave = QtGui.QToolButton(self)
	self.btnSave.setText("Save")
	self.btnSave.setEnabled(False)
	self.btnSave.setToolButtonStyle(Qt.Qt.ToolButtonTextUnderIcon)
	#self.btnSave.setIcon(QtGui.QIcon.fromTheme(("document-save")))
	self.btnSave.setIcon(QtGui.QIcon("/usr/share/icons/oxygen/48x48/actions/document-save.png"))
        self.toolBar.addWidget(self.btnSave)
	#----icon Zoom
	self.btnZoom = QtGui.QToolButton(self)
        self.btnZoom.setText("Zoom")
        self.btnZoom.setCheckable(True)
	self.btnZoom.setEnabled(False)
	self.btnZoom.setToolButtonStyle(Qt.Qt.ToolButtonTextUnderIcon)
	#self.btnZoom.setIcon(QtGui.QIcon.fromTheme(("zoom-in")))
	self.btnZoom.setIcon(QtGui.QIcon("/usr/share/icons/gnome/48x48/actions/zoom-in.png"))
        self.toolBar.addWidget(self.btnZoom)
	#----icon Reset
	self.btnReset = QtGui.QToolButton(self)
	self.btnReset.setText("Reset")
	self.btnReset.setToolButtonStyle(Qt.Qt.ToolButtonTextUnderIcon)
	self.btnReset.setEnabled(False)
	#self.btnOpen.setIcon(QtGui.QIcon.fromTheme(("document-open")))
	self.btnReset.setIcon(QtGui.QIcon("/usr/share/icons/oxygen/48x48/actions/edit-undo.png"))
        self.toolBar.addWidget(self.btnReset)
	#----icon Quit
	self.btnQuit = QtGui.QToolButton(self)
	self.btnQuit.setText("Quit")
	self.btnQuit.setToolButtonStyle(Qt.Qt.ToolButtonTextUnderIcon)	
	#self.btnQuit.setIcon(QtGui.QIcon.fromTheme(("exit")))
	self.btnQuit.setIcon(QtGui.QIcon("/usr/share/icons/gnome/48x48/actions/exit.png"))
        self.toolBar.addWidget(self.btnQuit)

	#------button connexion------
	QtCore.QObject.connect(self.btnOpen, QtCore.SIGNAL('clicked()'), self.OpenCanbFile)
	QtCore.QObject.connect(self.btnSave, QtCore.SIGNAL('clicked()'), self.saveDialog)
	QtCore.QObject.connect(self.btnZoom, QtCore.SIGNAL('toggled(bool)'), self.zoom)
	QtCore.QObject.connect(self.btnReset, QtCore.SIGNAL('clicked()'), self.resetcurves)
	QtCore.QObject.connect(self.btnQuit, QtCore.SIGNAL('clicked()'), self.FormClose)

	#Creation tabwidget
	self.TabWidget = QtGui.QTabWidget(self)
	self.TabWidget.setMinimumSize(800,300)# size(width, height)
	#Creation Scan selection
        self.ScanSelectionGroup = QtGui.QGroupBox("Scan selection", self)
	self.ScanSelectionGroup.setEnabled(False)
	self.Combo_ScanList =QtGui.QComboBox(self)
	QtGui.QGridLayout(self.ScanSelectionGroup)
	self.ScanSelectionGroup.layout().addWidget(self.Combo_ScanList)
	#------button connexion------
	QtCore.QObject.connect(self.Combo_ScanList, QtCore.SIGNAL('activated(int)'), self.scan_selected)
	#Creation Normalisation
        self.NormalisationGroup = QtGui.QGroupBox("Normalization", self)
	self.NormalisationGroup.setEnabled(False)
        self.rb_Ct = QtGui.QRadioButton("Counting Time", self)	
        self.rb_I0 = QtGui.QRadioButton("I0", self)
	self.rb_I0.setChecked(True) #set radiobutton 'selected'
	QtGui.QGridLayout(self.NormalisationGroup)
        self.NormalisationGroup.layout().addWidget(self.rb_Ct,0,0)
        self.NormalisationGroup.layout().addWidget(self.rb_I0,0,1)
	#------radiobutton connexion------
	QtCore.QObject.connect(self.rb_Ct, QtCore.SIGNAL('clicked()'), self.plot_scan_ct)
	QtCore.QObject.connect(self.rb_I0, QtCore.SIGNAL('clicked()'), self.plot_scan_I0)	
	#Creation Dectector
	self.DetectorGroup=QtGui.QGroupBox("Detector 30 elements", self)#Creation Groupbox
	self.DetectorGroup.setEnabled(False)
	#self.button_Close = QtGui.QDialogButtonBox(QtGui.QDialogButtonBox.Close)#Creation Button 
	self.grp = QtGui.QWidget(self)
        self.setCentralWidget(self.grp)	
	QtGui.QGridLayout(self.grp)
	self.grp.layout().addWidget(self.label_FileCanb,1,0,1,0)
	self.grp.layout().addWidget(self.TabWidget,2,0,1,0)
	self.grp.layout().addWidget(self.ScanSelectionGroup,3,0,1,1)#4,0,1,1
	self.grp.layout().addWidget(self.NormalisationGroup,4,0,1,1)#4,1,1,1
        self.grp.layout().addWidget(self.DetectorGroup,3,1,2,2)#5,0,1,2

	#################################
	#configuration des tab
	#################################
        self.checkboxes = []# list checkboxes object checked (all by default)
	self.button_AllOn = QtGui.QPushButton("All on", self )
	self.button_AllOff = QtGui.QPushButton("All off", self )
	QtGui.QGridLayout(self.DetectorGroup)
	#------------------------------------------------------------------------------------
	def add_chkbox(new_chkbox_name, coor={'j':0}): #display the 30 checkboxes in a correct order
	  j = coor['j']
	  new_chkbox = QtGui.QCheckBox(new_chkbox_name, self.DetectorGroup)
	  new_chkbox.setChecked(True)	  	  
          self.checkboxes.append(new_chkbox)# add checkboxe to the list
	  self.DetectorGroup.layout().addWidget(new_chkbox, j%6, j/6)
	  coor['j']=j+1
	  #------checkbox connexion------
	  QtCore.QObject.connect(new_chkbox, QtCore.SIGNAL('stateChanged(int)'), self.replot_scans)
	#------------------------------------------------------------------------------------
	for i in range(7):
          chkbox_name = 'A%d' % (i+1)
	  add_chkbox(chkbox_name)
	for i in range(8):
          chkbox_name = 'B%d' % (i+1)
	  add_chkbox(chkbox_name)
	for i in range(7):
          chkbox_name = 'C%d' % (i+1)
	  add_chkbox(chkbox_name)
	for i in range(8):
          chkbox_name = 'D%d' % (i+1)
	  add_chkbox(chkbox_name)	
        self.DetectorGroup.layout().addWidget(self.button_AllOn)
        self.DetectorGroup.layout().addWidget(self.button_AllOff)
	#------checkbox connexion------
	QtCore.QObject.connect(self.button_AllOn, QtCore.SIGNAL('clicked()'), self.true_chkbox)
	QtCore.QObject.connect(self.button_AllOff, QtCore.SIGNAL('clicked()'), self.false_chkbox)
        titles = ['1-5','6-10','11-15','16-20','21-25','26-30']
        self.plot_pages = []
        for i in range(6):
            new_page = QtGui.QWidget(self)
            QtGui.QVBoxLayout(new_page)
            self.plot_pages.append(new_page)
            new_plot = qwt.QwtPlot(new_page)
            new_page.layout().addWidget(new_plot)        
            setattr(self, 'plot_%d' % (i+1), new_plot)
            self.TabWidget.addTab(new_page, titles[i])	  
        self.plot_init()

if __name__ == "__main__":

    app = QtGui.QApplication(sys.argv)
    form = MainFrame()
    form.show()
    app.exec_()


