# import the needed modules
from __future__ import absolute_import
from __future__ import print_function
try:
#  import sys
  import numpy
  try:
    from astropy.io import fits as pyfits
  except:
    import pyfits

  import wx
  import matplotlib
  import pipeline_product
  import xsh_plot_widgets

  from reflex import parseSofJson,RecipeParameter
  from reflex_interactive_app import PipelineInteractiveApp
  from pipeline_product import PipelineProduct
  from pipeline_display import SpectrumDisplay, ImageDisplay, ScatterDisplay

  import xsh_parameters_common

#  matplotlib.use('WXAgg')
  import_sucess = 'true'
  import warnings
  warnings.simplefilter('ignore',UserWarning)

#NOTE for developers: 
# -If you want to modify the current script to cope
#  with different parameters, this is the function to modify:
#  setInteractiveParameters()
# -If you want to modify the current script to read different data from
#  the input FITS, these are the functions (class DataPlotterManager) to modify:
#  readFitsData()    to indicate what are the FITS input to plot
#  plotSpectrum()    to control 1D image product layout
#  plotImage()       to control 2D image product layout
#  plotTable()       to control 1D table product layout
#  oplotTable()      to control 1D table product overplots
#  getSN()           to access 1D spectrum S/N FITS header info
#  setInsMode()      to access ins mode FITS header info
#  setObjType()      to access obj type FITS header info
#  setRecId()        to set rec id (used in parameter prefix)
#  getArmId()        to get arm id FITS header info
#
# -If you want to modify the current script to modify the plots (using the same
#  data),  this is the function to modify:
#  plotProductsGraphics()          (from class DataPlotterManager)
# -If you want to modify the text that appears in the "Help" button,
#  this is the function to modify:
#  setWindowHelp()
# -If you want to modify the title of the window, modify this function:
#  setWindowTitle()


  #This class deals with the specific details of data reading and final plotting.
  class DataPlotterManager:

    def paragraph(self,text, width=None):
       """ wrap text string into paragraph
           text:  text to format, removes leading space and newlines
           width: if not None, wraps text, not recommended for tooltips as
                  they are wrapped by wxWidgets by default
       """
       import textwrap
       #print 'width=',width,'Text=',text
       if width is None:
           return textwrap.dedent(text).replace('\n', ' ').strip()
       else:
           return textwrap.fill(textwrap.dedent(text), width=width) 


    #1D spectrum plots
    def plotSpectrum(self,data,errs,qual,bpcode,subplot,title,tooltip):
        data.readSpectrum(0)
        errs.readSpectrum(1)
        nwave = len(data.flux)
        minlimwave = int(nwave*0.25)
        maxlimwave = int(nwave*0.75)

        spectrum = SpectrumDisplay()
        spectrum.setLabels('Wavelength [nm]','Total Flux ['+data.bunit+']')

        spectrum.display(subplot,title,self.paragraph(tooltip),data.wave,data.flux,errs.flux, autolimits = True) 
        #matplotlib.pyplot.tight_layout()
        if self.response_found is True and self.rec_id[16:19] != "nod":
           #in case response is available we need to reduce fonts
           subplot.set_title(title, fontsize=7)
        try:
            pass
            #subplot.figure.tight_layout()
        except AttributeError:
            pass

        #Flag BP as errors
        qual.readSpectrum(2)
        bpm_flag = numpy.bitwise_and(qual.flux,int(bpcode) ) == 0 
        mask_f_data=numpy.ma.MaskedArray(data.flux, mask=bpm_flag).compressed()
        mask_f_wave=numpy.ma.MaskedArray(data.wave,mask=bpm_flag).compressed()
        size_f_err=numpy.ma.MaskedArray(errs.flux,mask=bpm_flag).compressed()

        bpm_all = (qual.flux == 0 ) 
        mask_a_data=numpy.ma.MaskedArray(data.flux, mask=bpm_all).compressed()
        mask_a_wave=numpy.ma.MaskedArray(data.wave,mask=bpm_all).compressed()
        size_a_err=numpy.ma.MaskedArray(errs.flux,mask=bpm_all).compressed()
        #print "size all", mask_a_data.size
        if mask_a_data.size > 0 :
           subplot.errorbar(mask_a_wave, mask_a_data, xerr=None, yerr=size_a_err, color='k', linestyle='', capsize=0)
        #print "size masked", mask_f_data.size
        #print "size spectrum", data.flux.size
        if mask_f_data.size > 0 :
           subplot.errorbar(mask_f_wave, mask_f_data, xerr=None, yerr=size_f_err, color='r', linestyle='', capsize=0)
        subplot.set_xlim(spectrum.wave_lim)
        subplot.set_ylim(spectrum.flux_lim)
       

    #2D image display
    def plotImage(self,obj,bpm,subplot,title,tooltip):

          obj.readImage(fits_extension=0)
          obj.read2DLinearWCS(fits_extension=0)
          img_obj = ImageDisplay()

          bpm.readImage(fits_extension=2)
          img_bpm = ImageDisplay()

          img_obj.setLabels('Wavelength [nm]','Position Along Slit \n [arcsec]')
          y_size, x_size = obj.image.shape
          #print 'x_size=',x_size , 'y_size=',y_size
          #print 'crval1=',obj.crval1,'crpix1=',obj.crpix1,'cdelt1=',obj.cdelt1 
          
          img_obj.setXLinearWCSAxis(obj.crval1,obj.cdelt1,obj.crpix1)
          img_obj.setYLinearWCSAxis(obj.crval2,obj.cdelt2,obj.crpix2)

          #img_obj.setLimits((0,x_size),(0,y_size))
          img_obj.display(subplot, title, self.paragraph(tooltip),obj.image,bpm.image)
          if self.response_found is True and self.rec_id[16:19] != "nod":
             #in case response is available we need to reduce fonts
             subplot.set_title(title, fontsize=7)



    #3D cube slices display
    def plotCubeSlice(self,obj,bpm,slice,subplot,title,tooltip):
          obj.readImage(fits_extension=0)
          obj.read2DLinearWCS(fits_extension=0)
          img_obj = ImageDisplay()
          image = obj.image[slice,:,:]

          bpm.readImage(fits_extension=2)
          img_bpm = ImageDisplay()
          error = obj.image[slice,:,:]

          #img_obj.setLabels('IFU slice [arcsec]','Position Along Slit \n [arcsec]')
          img_obj.setLabels('IFU slice [arcsec]','Position Along Slit \n [pixel]')
          y_size, x_size = image.shape
          print('x_size=',x_size , 'y_size=',y_size)
          #print 'crval1=',obj.crval1,'crpix1=',obj.crpix1,'cdelt1=',obj.cdelt1 
          #print 'crval2=',obj.crval2,'crpix2=',obj.crpix2,'cdelt2=',obj.cdelt2 
          
          #img_obj.setXLinearWCSAxis(self.crval1,self.cdelt1,self.crpix1)
          #img_obj.setYLinearWCSAxis(self.crval1,self.cdelt1,self.crpix1)
          img_obj.setXLinearWCSAxis(-2,2,1)
          #img_obj.setYLinearWCSAxis(self.crval1,self.cdelt1,self.crpix1)

          #img_obj.setLimits((0,x_size),(0,y_size))
          img_obj.display(subplot, title, self.paragraph(tooltip),image)
          if self.response_found is True and self.rec_id[16:19] != "nod":
             #in case response is available we need to reduce fonts
             subplot.set_title(title, fontsize=7)


    #1D spectrum table plots
    def plotTable(self,tab,Xcol,Ycol,Xlab,Ylab,subplot,title,tooltip,
    wave = None):

        tab.readTableXYColumns(fits_extension=1,xcolname=Xcol, ycolname=Ycol)
        spectrum = SpectrumDisplay()
        plotmax = numpy.nanmax(tab.y_column)
        plotmin = numpy.nanmin(tab.y_column)
    

        flux_plotmax = plotmax + 0.2 * plotmax
        flux_plotmin = plotmin - 0.2 * plotmax
      
        spectrum.setLabels(Xlab,Ylab)
        spectrum.flux_lim = flux_plotmin, flux_plotmax
        if wave is not None:
           spectrum.setWaveLimits((wave[0], wave[len(wave)-1]))

        spectrum.display(subplot,title,self.paragraph(tooltip),tab.x_column,tab.y_column) 
        if self.response_found is True and self.rec_id[16:19] != "nod":
           #in case response is available we need to reduce fonts
           subplot.set_title(title, fontsize=7)

    #1D spectrum table over-plots
    def oplotTable(self,tab,Xcol,Ycol,Xlab,Ylab,subplot,color):

        tab.readTableXYColumns(fits_extension=1,xcolname=Xcol, ycolname=Ycol)
        wave_lim = subplot.get_xlim()
        flux_lim = subplot.get_ylim()
        spectrum = SpectrumDisplay()
        spectrum.overplot(subplot,tab.x_column,tab.y_column,color)
        subplot.set_xlim(wave_lim)
        subplot.set_ylim(flux_lim)

    def scatterPlotScatter(self, subplot, x, y,color=None):
        if color == None :
           subplot.scatter(x, y, s=0.4, color='blue')
        else:
           subplot.scatter(x, y, s=0.4, color=color)

        subplot.ticklabel_format(style='sci',scilimits=(0,3))

    def scatterPlotLabels(self, subplot, x_label, y_label):
        subplot.set_xlabel(x_label, fontsize=12)
        subplot.set_ylabel(y_label, fontsize=12)

    def finalSetup(self, subplot, title, tooltip):
        subplot.grid(True)
        subplot.set_title(title, fontsize=12)
        subplot.tooltip = self.paragraph(tooltip)

    def scatterPlot(self, subplot, x, y, x_label, y_label, title, tooltip):

        self.scatterPlotScatter(subplot, x, y)
        self.scatterPlotLabels(subplot, x_label, y_label)
        self.scatterPlotLimits(subplot, x, y)
        self.finalSetup(subplot, title, self.paragraph(tooltip))

    def scatterPlotLimits(self, subplot, x, y):
        subplot.set_xlim(numpy.nanmin(x)-1, numpy.nanmax(x) + 1.)
        subplot.set_ylim(1.05 * numpy.nanmin(y), 1.05 * numpy.nanmax(y))


    #1D table scatter plots
    def plotTableScatter(self,tab,Xcol,Ycol,Xlab,Ylab,subplot,title,tooltip,ext_no=None):
        extno=1
        if ext_no != None :
           extno=ext_no

        tab.readTableXYColumns(fits_extension=extno,xcolname=Xcol,ycolname=Ycol)
        self.scatterPlotScatter(subplot, tab.x_column, tab.y_column)
        self.scatterPlotLabels(subplot, Xlab, Ylab)
        self.scatterPlotLimits(subplot, tab.x_column, tab.y_column)
        self.finalSetup(subplot, title, self.paragraph(tooltip))
        self.scatterPlot(subplot, tab.x_column, tab.y_column, Xlab, Ylab, title, tooltip)


    def oplotTableScatter(self,tab,Xcol,Ycol,subplot,ext_no=None,color=None):
        extno=1
        if ext_no != None :
           extno=ext_no

        tab.readTableXYColumns(fits_extension=extno,xcolname=Xcol,ycolname=Ycol)
        self.scatterPlotScatter(subplot, tab.x_column, tab.y_column,color=color)

        #subplot.scatter(tab.x_column, tab.y_column,color)

    def getDecodeBP(self, fitsfile):
        hdulist = pyfits.open(fitsfile.name)
        self.decode_bp = hdulist[0].header['ESO PRO REC1 PARAM4 VALUE']

    #Get NAXIS info (Xshooter and arm specific)
    def getNAXIS3(self, fitsfile):
      hdulist = pyfits.open(fitsfile.name)
      self.NAXIS3 = hdulist[0].header['NAXIS3']

    def getWCS(self, fitsfile):
      hdulist = pyfits.open(fitsfile.name)
      self.NAXIS1 = hdulist[0].header['NAXIS1']
      self.NAXIS2 = hdulist[0].header['NAXIS2']
      self.NAXIS3 = hdulist[0].header['NAXIS3']

      self.crpix1 = hdulist[0].header['CRPIX1']
      self.crval1 = hdulist[0].header['CRVAL1']
      self.cdelt1 = hdulist[0].header['CDELT1']

      self.crpix2 = hdulist[0].header['CRPIX2']
      self.crval2 = hdulist[0].header['CRVAL2']
      self.cdelt2 = hdulist[0].header['CDELT2']

      self.crpix3 = hdulist[0].header['CRPIX3']
      self.crval3 = hdulist[0].header['CRVAL3']
      self.cdelt3 = hdulist[0].header['CDELT3']
      self.wmax= self.crval3+(self.NAXIS3-1)*self.cdelt3
    #Get S/N info (Xshooter and arm specific)
    def getSN(self, fitsfile):
      hdulist = pyfits.open(fitsfile.name)
      self.SN1 = hdulist[0].header['ESO QC FLUX1 SN']
      if self.arm_uvb_found  == True :
        self.SN2 = hdulist[0].header['ESO QC FLUX2 SN']
        self.RN1 = "450-470 nm"
        self.RN2 = "510-530 nm"
      if self.arm_vis_found  == True :
        self.SN2 = hdulist[0].header['ESO QC FLUX2 SN']
        self.SN3 = hdulist[0].header['ESO QC FLUX3 SN']
        self.RN1 = "672-680 nm"
        self.RN2 = "745-756 nm"
        self.RN3 = "992-999 nm"
      if self.arm_nir_found  == True :
        self.RN1 = "1514-1548 nm"
        self.OPTI5_NAME = hdulist[0].header['ESO INS OPTI5 NAME']
        if "JH" in self.OPTI5_NAME :
          self.arm_nir_jh_found = True
          print("Found NIR JH filter")
        else :
          self.SN2 = hdulist[0].header['ESO QC FLUX2 SN']
          self.RN2 = "2214-2243 nm"
     
    # This function will read all the columns, images and whatever is needed
    # from the products. The variables , self.plot_x, self.plot_y, etc...
    # are used later in function plotProductsGraphics().
    # Add/delete these variables as you need (only that plotProductsGraphics()
    # has to use the same names).
    # You can also create some additional variables (like statistics) after
    # reading the files.
    # If you use a control variable (self.xxx_found), you can modify 
    # later on the layout of the plotting window based on the presence of 
    # given input files. 
    # sof contains all the set of frames
    def readFitsData(self, fitsFiles):
      #Control variable to check if the interesting files where at the input
      prefix = "SCI_IFU_"
      self.spectrum3D_found   = False
      self.traces_ifu_slices_found   = False
      self.spectrum1D_found   = False
      self.flux_spectrum1D_found   = False
      self.lineguess_found = False
      self.spectrum2D_found      = False
      self.response_found      = False
      self.mresponse_found      = False
      self.sky_spectrum2D_found      = False
      self.sky2D_found   = False
      self.obj_sky2D_found   = False
      self.bpm_found   = False
      self.arm_uvb_found      = False
      self.arm_vis_found      = False
      self.arm_nir_found      = False
      self.arm_nir_jh_found   = False
      self.nima = 0
      self.NAXIS3=100

      #Read all the products
      frames = dict()
      for frame in fitsFiles:
        if frame == '' :
          continue
        #hdulist = pyfits.open(frame)
        #hdulist = frame.hdulist()
        header = pyfits.open(frame.name)
        #Make sure to have only products from the same recipe
        #that used this (common) script 
        if 'ESO PRO REC1 ID' in header[0].header :
           rec_id = header[0].header['ESO PRO REC1 ID']
           if rec_id == self.rec_id :
              #print rec_id, self.rec_id
              category = frame.category
              frames[category] = frame
              print(frame)
      #Note that you have to take care that no other input to this py script
      #the same prefix as SCI_IFU, TELL_IFU, FLUX_IFU
 
      prefixes = [k.split('_')[0]+"_"+k.split('_')[1] for k in frames.keys()]
      print("prefixes=",prefixes)
      if "SCI_IFU" in prefixes :
        prefix = "SCI_IFU_"
      elif "TELL_IFU" in prefixes:
        prefix = "TELL_IFU_"
      elif "FLUX_IFU" in prefixes:
        prefix = "FLUX_IFU_"
      elif "CAL_IFU" in prefixes:
        prefix = "CAL_IFU_"
      elif "SKY_IFU" in prefixes:
        prefix = "SKY_IFU_"

      arm=self.seq_arm

      if arm == "UVB":
         self.arm_uvb_found = True
      if arm == "VIS":
         self.arm_vis_found = True
      if arm == "NIR":
         self.arm_nir_found = True
      print("prefix=",prefix)
# For any arm search a list of input frames
      key = prefix+"MERGE3D_DATA_OBJ_"+arm
      if key in frames :
        self.spectrum3D_found = True
        hdulist = frames[prefix+"MERGE3D_DATA_OBJ_"+arm]
        self.hdu3D = hdulist
        self.spectrum3D = PipelineProduct(hdulist)
        self.error3D = PipelineProduct(hdulist)
        self.qual3D = PipelineProduct(hdulist)
        self.getSN(hdulist)
        self.getNAXIS3(hdulist)
        self.getWCS(hdulist)
        #print "SN=",self.SN1
        self.getDecodeBP(hdulist)
        #print "Decode BP=",self.decode_bp
        self.nima += 1
        #print "found MERGED3D spectrum"

      key = prefix+"MERGE3D_TRACE_OBJ_"+arm
      if key in frames :
        self.traces_ifu_slices_found = True
        hdulist = frames[prefix+"MERGE3D_TRACE_OBJ_"+arm]
        self.traces_ifu_slices = PipelineProduct(hdulist)
        self.nima += 1
        #print "found MERGED3D Trace"

      key = prefix+"MERGE1D_"+arm
      if key in frames :
        self.spectrum1D_found = True
        hdulist = frames[prefix+"MERGE1D_"+arm]
        #hdulist = hdulist[prefix+"MERGE1D_"+arm]
        self.spectrum1D = PipelineProduct(hdulist)
        self.error1D = PipelineProduct(hdulist)
        self.qual1D = PipelineProduct(hdulist)
        self.getSN(hdulist)
        #print "SN=",self.SN1
        self.getDecodeBP(hdulist)
        #print "Decode BP=",self.decode_bp
        self.nima += 1
        #print "found MERGED1D spectrum"
      
      key = prefix+"FLUX_MERGE1D_"+arm
      if key in frames :
        self.flux_spectrum1D_found = True
        hdulist = frames[prefix+"FLUX_MERGE1D_"+arm]
        self.flux_spectrum1D = PipelineProduct(hdulist)
        self.flux_error1D = PipelineProduct(hdulist)
        self.flux_qual1D = PipelineProduct(hdulist)
        self.nima += 1
        #print "found FLUX_MERGED1D spectrum"
        
      key = prefix+"MERGE2D_"+arm
      if key in frames :
        self.spectrum2D_found = True
        hdulist = frames[prefix+"MERGE2D_"+arm]
        self.bpm = PipelineProduct(hdulist)
        self.spectrum2D = PipelineProduct(hdulist)
        self.nima += 1
        #print "found MERGED2D spectrum"
        header = pyfits.open(hdulist.name)
        self.key_object = header[0].header['OBJECT']
        #print prefix
        #print object
        if 'CAL_IFU_' in prefix and 'SKY' in self.key_object and 'stare' in self.rec_id :
            self.obj_type = "Sky"

      key = "SKY_IFU_MERGE2D_"+arm
      if key in frames and self.rec_id[16:19] != "nod":
        self.sky_spectrum2D_found = True
        hdulist = frames["SKY_IFU_MERGE2D_"+arm]
        self.sky_spectrum2D = PipelineProduct(hdulist)
        self.nima += 1
        #print "found SKY_IFU_MERGED2D spectrum"

      key = prefix+"SKY_"+arm
      if key in frames :
        self.sky2D_found = True
        hdulist = frames[prefix+"SKY_"+arm]
        self.sky2D = PipelineProduct(hdulist)
        #print "found SKY_2D spectrum"

      key = prefix+"SUB_SKY_"+arm
      if key in frames :
        self.obj_sky2D_found = True
        hdulist = frames[prefix+"SUB_SKY_"+arm]
        self.obj_sky2D = PipelineProduct(hdulist)
        #print "found SUB_SKY spectrum"

      if self.rec_id[0:10] == "xsh_respon":

         key = "RESPONSE_MERGE1D_IFU_"+arm
         if key in frames : 
            self.response_found = True
            hdulist = frames["RESPONSE_MERGE1D_IFU_"+arm]
            self.response = PipelineProduct(hdulist)
            self.nima += 1
            #print "found RESPONSE_MERGE1D_IFU_ spectrum"

         key = "MRESPONSE_MERGE1D_IFU_"+arm
         if key in frames : 
            self.mresponse_found = True
            hdulist = frames["MRESPONSE_MERGE1D_IFU_"+arm]
            self.mresponse = PipelineProduct(hdulist)
            #print "found MRESPONSE_MERGE1D_IFU_ spectrum"

    #get ins mode (Slit/IFU and Stare/Offset/Nodding)
    def setInsMode(self, rec_id):
      #Recipe ID variable to properly define params
      self.rec_id = rec_id

      if self.rec_id[16:21] == "stare" :
         self.ins_mode = "Slit-Stare"
      elif self.rec_id[16:22] == "offset" :
         self.ins_mode = "Slit-Offset"

      elif self.rec_id[16:19] == "nod" :
         self.ins_mode = "Slit-Nodding"
      elif self.rec_id == "xsh_scired_ifu_stare" :
         self.ins_mode = "ifu-stare"
      elif self.rec_id == "xsh_scired_ifu_offset" :
         self.ins_mode = "ifu-offset"

    #Set Object type (Object/Std star) to display proper info
    def setObjType(self, rec_id):
      #Recipe ID variable to properly define params
      self.rec_id = rec_id

      if self.rec_id[0:10] == "xsh_scired":
         self.obj_type = "Object"
      
      if self.rec_id[0:10] == "xsh_respon":
         self.obj_type = "Std Star"



    #Set rec id (to have proper recipe parameters prefix)
    def setRecId(self, rec_id):
      #Recipe ID variable to properly define params
      self.rec_id = rec_id
      self.setInsMode(rec_id)
      self.setObjType(rec_id)

    #Get arm setting
    def getArmId(self, sof):
      #Recipe ID variable to properly define params
      self.rec_id = "xsh_respon_slit_stare"
      self.seq_arm = "UVB"
      nf = 0

      frames = dict()
      files = sof.files
      for f in files:
      #for frame in fitsFiles:
        file_name=f.name
        if file_name == '' :
          continue
        else :
           nf += 1
           hdulist = pyfits.open(file_name)
           rec_id_list = hdulist[0].header['ESO PRO REC1 ID']
           arm_list = hdulist[0].header['ESO SEQ ARM']
      if nf != 0 :
         self.rec_id = rec_id_list[0:]
         self.seq_arm = arm_list[0:]

      if self.seq_arm == "UVB":
         self.arm_uvb_found = True

      if self.seq_arm == "VIS":
         self.arm_uvb_found = True

      if self.seq_arm == "NIR":
         self.arm_uvb_found = True

      if self.rec_id[16:21] == "stare" :
         self.ins_mode = "Slit-Stare"
      elif self.rec_id[16:22] == "offset" :
         self.ins_mode = "Slit-Offset"

      elif self.rec_id[16:19] == "nod" :
         self.ins_mode = "Slit-Nodding"
      elif self.rec_id == "xsh_scired_ifu_stare" :
         self.ins_mode = "ifu-stare"
      elif self.rec_id == "xsh_scired_ifu_offset" :
         self.ins_mode = "ifu-offset"

      if self.rec_id[0:10] == "xsh_scired":
         self.obj_type = "Object"
      
      if self.rec_id[0:10] == "xsh_respon":
         self.obj_type = "Std Star"


    def plotWidgets(self) :
        widgets = list()
        min=0
        max=100
        title_slider="Select plane id by clicking with mouse left button"
        if self.spectrum3D_found == True :
           max=self.NAXIS3 
           val=numpy.floor(self.NAXIS3/2+0.5)
           # Cube plane selector 
           self.slider =xsh_plot_widgets.InteractiveSlider(self.cube_plane_selector,self.setPlaneSelectCallBack,min,max,val,0, title=title_slider)
           widgets.append(self.slider)

        return widgets

    def setPlaneSelectCallBack(self, plane_id) :
        plane_id = int(plane_id)
        self.subplot_cube.cla()
        self.setDisplayCubeSlice(plane_id)

    def setDisplayCubeSlice(self, plane_id) :
        self.wcen= self.crval3+(plane_id-1)*self.cdelt3
        self.title_cube_obj   = 'IFU slices plane id: %#6.5g wavelength: %#6.5g [nm]'% (plane_id,self.wcen) 

        self.plotCubeSlice(self.spectrum3D,self.spectrum3D,plane_id,self.subplot_cube,self.title_cube_obj,self.tooltip_cube_obj)



    # This function creates all the subplots. It is responsible for the plotting 
    # layouts. 
    # There can different layouts, depending on the availability of data
    # Note that subplot(I,J,K) means the Kth plot in a IxJ grid 
    # Note also that the last one is actually a box with text, no graphs.
    def addSubplots(self, figure):
      nrows=self.nima
      row=1;
      #print "self.spectrum1D_found",self.spectrum1D_found
      #print "self.spectrum2D_found",self.spectrum2D_found
      #print "self.flux_spectrum1D_found",self.flux_spectrum1D_found
      #print "self.response_found",self.response_found
      #print "self.spectrum2D_found",self.spectrum2D_found
      #print "self.sky_spectrum2D_found",self.sky_spectrum2D_found

      if self.spectrum1D_found == True and self.spectrum2D_found == True:
        self.subplot_spectrum  = figure.add_subplot(nrows,1,row)
        row +=1

        if self.flux_spectrum1D_found == True :
           self.subplot_flux_spectrum = figure.add_subplot(nrows,1,row)
           row +=1

        if self.response_found == True:
           self.subplot_response    = figure.add_subplot(nrows,1,row)
           row +=1

        if self.spectrum2D_found == True :
           self.subplot_image_obj = figure.add_subplot(nrows,1,row)
           row +=1

        if self.rec_id[17:19] != "nod" :
          if self.sky_spectrum2D_found == True :
             self.subplot_image_sky = figure.add_subplot(nrows,1,row)
             row +=1
      elif self.spectrum3D_found == True and self.traces_ifu_slices_found == True:
        self.subplot_cube   = figure.add_subplot(nrows,1,row)
        row +=1
        self.subplot_traces_ifu_slices  = figure.add_subplot(nrows,1,row)
        row +=1
        self.cube_plane_selector = figure.add_axes([0.1, 0.505, 0.83, 0.01])
        self.cube_plane_pix_range = figure.add_axes([0.1, 0.495, 0.83, 0.01])
        self.cube_plane_wav_range = figure.add_axes([0.1, 0.465, 0.83, 0.01])

        # Set the colormap and norm to correspond to the data for which
        # the colorbar will be used.

        cmap = matplotlib.cm.afmhot
        norm1 = matplotlib.colors.Normalize(vmin=0, vmax=self.NAXIS3)
        norm2 = matplotlib.colors.Normalize(vmin=self.crval3, vmax=self.wmax)

        #add colorbar
        cb1 = matplotlib.colorbar.ColorbarBase(self.cube_plane_pix_range, cmap=cmap,
                                   norm=norm1,orientation='horizontal')
        cb2 = matplotlib.colorbar.ColorbarBase(self.cube_plane_wav_range, cmap=cmap,
                                   norm=norm2,orientation='horizontal')

      else : 
        self.subtext_nodata    = figure.add_subplot(1,1,1)
        print("found no spectrum data")


 
    # This is the function that makes the plots.
    # Add new plots or delete them using the given scheme.
    # The data has been already stored in self.plot_x, self.plot_xdif, etc ...
    # It is mandatory to add a tooltip variable to each subplot.
    # One might be tempted to merge addSubplots() and plotProductsGraphics().
    # There is a reason not to do it: addSubplots() is called only once at
    # startup, while plotProductsGraphics() is called always there is a resize.
    def plotProductsGraphics(self):
      if self.spectrum1D_found == True and self.spectrum2D_found == True: 
        #and self.lineguess_found == True 
        title_pref = 'Standard-extracted and Merged Spectrum.'        
        title_flux_spectrum = 'Standard Extracted, Merged, and Flux Calibrated Spectrum.'
        tooltip_spectrum ="""\
                          Plot of the standard-extracted and merged spectrum of the object (blue line) as total flux (ADU) versus wavelength (nm). The +-1 sigma uncertainties are plotted as the light blue region encompassing the object spectrum (and bounded by the light grey spectra). Flagged pixels are marked with a dark-grey vertical bar stretching between the +- 1 sigma limits. Flagged bad pixels that are decoded as "bad pixels" are marked by a red vertical bar stretching between the +- 1 sigma limits. Note that this spectrum is not flux calibrated."""

        tooltip_flux_spectrum ="""\
                              Plot of the standard-extracted, merged,
                              and flux calibrated spectrum of the
                              object (blue line) as total flux (10^-16
                              erg/s/cm^2/A) versus wavelength
                              (nm). The +-1 sigma uncertainties are
                              plotted as the light blue region
                              encompassing the object spectrum (and
                              bounded by the light grey
                              spectra). Flagged pixels are marked with
                              a dark-grey vertical bar stretching
                              between the +- 1 sigma limits. Flagged
                              bad pixels that are decoded as "bad
                              pixels" are marked by a red vertical bar
                              stretching between the +- 1 sigma
                              limits. The reference standard star
                              spectrum from the catalog is overplotted for
                              comparison purposes as a green line."""

        if self.arm_uvb_found == True:
          title_spectrum   = title_pref+' \n SN: %#.2f (%#s); %#.2f (%#s) '% (self.SN1,self.RN1,self.SN2,self.RN2)

        if self.arm_vis_found == True:
          title_spectrum   = title_pref+' \n SN: %#.2f (%#s); %#.2f (%#s); %#.2f (%#s) '% (self.SN1,self.RN1,self.SN2,self.RN2,self.SN3,self.RN3)

        if self.arm_nir_found == True and self.arm_nir_found == True:
             title_spectrum   = title_pref+' \n SN: %#.2f (%#s); '% (self.SN1,self.RN1)
        elif self.arm_nir_found == True :
             title_spectrum   = title_pref+' \n SN: %#.2f (%#s); %#.2f (%#s); '% (self.SN1,self.RN1,self.SN2,self.RN2)
           
           
        #Spectrum plot

        self.plotSpectrum(self.spectrum1D,self.error1D,self.qual1D,self.decode_bp,self.subplot_spectrum,title_spectrum,tooltip_spectrum)

        #Flux calibrated Spectrum plot

        if self.flux_spectrum1D_found == True:

           self.plotSpectrum(self.flux_spectrum1D,self.flux_error1D,self.flux_qual1D,self.decode_bp,self.subplot_flux_spectrum,title_flux_spectrum,tooltip_flux_spectrum)
        if self.response_found == True :
           self.oplotTable(self.response,'LAMBDA','REF','Wavelength [nm]','Reference flux [erg/e-/cm^2]',self.subplot_flux_spectrum,'green')



        #Image
        title_image_obj   = '2D Merged ' + self.obj_type + ' Spectrum' 
        tooltip_image_obj ="""\
                           Image of the 2D merged spectrum of the
        object in ADU. A red hue corresponds to flagged pixels, which
        may be good or bad. Note that this spectrum is not flux calibrated."""


        title_image_sky   = '2D Merged Sky Spectrum ' 
        tooltip_image_sky ="""\
                           Image of the 2D merged spectrum of the sky
        in ADU. A red hue corresponds to flagged pixels, which
        may be good or bad. Note that this spectrum is not flux calibrated."""
        #Object merged 2D
        if self.spectrum2D_found  == True:
           self.plotImage(self.spectrum2D,self.bpm,self.subplot_image_obj,title_image_obj,tooltip_image_obj)


        #sky merged 2D
        if self.sky_spectrum2D_found  == True and self.rec_id != "xsh_respon_slit_nod" and self.rec_id != "xsh_scired_slit_nod" :

           self.plotImage(self.sky_spectrum2D,self.bpm,self.subplot_image_sky,title_image_sky,tooltip_image_sky)


        #Scatter plot
        if self.response_found == True :
           title_response   = 'Instrument response curve' 
           tooltip_response ="""\
                             Plot of the instrument response curve
        (erg/e-/cm^2) as determined from the standard star observation
        (green). The raw response is overplotted for comparison
        purposes (blue). If the master response curve is available, then it is overplotted for comparison purposes (yellow)."""
           if self.spectrum1D_found == True:
              self.plotTable(self.response,'LAMBDA','REF_DIV_OBS','Wavelength [nm]','Raw Response \n[erg/e-/cm^2]',self.subplot_response,title_response,tooltip_response,self.spectrum1D.wave)
              self.oplotTable(self.response,'LAMBDA','RESPONSE','Wavelength [nm]','Response [erg/e-/cm^2]',self.subplot_response,'green')

           else:
              #print "self.response_found"
              self.plotTable(self.response,'LAMBDA','RESPONSE','Wavelength [nm]','Response [erg/e-/cm^2]',self.subplot_response,title_response,tooltip_response)
           if self.mresponse_found == True :
              self.oplotTable(self.mresponse,'LAMBDA','RESPONSE','Wavelength [nm]','Response [erg/e-/cm^2]',self.subplot_response,'yellow')

      if self.spectrum3D_found == True and self.traces_ifu_slices_found :


        plane_id=numpy.floor(self.NAXIS3/2+0.5)
        #self.wcen= self.crval3+(plane_id-1)*self.cdelt3

        #self.title_cube_obj   = 'IFU slices plane %#6.0g %#6.3g'% (plane_id,self.wcen) 
        self.tooltip_cube_obj ="""\
                            The displayed image corresponds to the
        plane id indicated by the slider below. To view a different
        plane of the science reconstructed cube, the user should select
        the desired plane id with the mouse left button, using the
        slider shown below the image.  
                                      """
        title_traces_ifu_slices   = 'IFU slices traces' 
        tooltip_traces_ifu_slices ="""\
                          Traces of the IFU object central position
        observed by slicer number 1,2,3 are displayed respectively in
        colors blue, green, red. If the cube has been perfectly 
        reconstructed the three traces should overlap. Traces are well
        defined only for point-like and high SNR objects. Low SNR pr
        extended objects may present a not aggregated point distribution.
                                      """
        plane_id=int(numpy.floor(self.NAXIS3/2+0.5))
        self.setDisplayCubeSlice(plane_id)

        self.plotTableScatter(self.traces_ifu_slices,'WAVELENGTH','POS_1', 'Wavelength [nm]','Slit position [pix]',self.subplot_traces_ifu_slices,title_traces_ifu_slices,tooltip_traces_ifu_slices)
        self.oplotTableScatter(self.traces_ifu_slices,'WAVELENGTH','POS_2', self.subplot_traces_ifu_slices,color='green')
        self.oplotTableScatter(self.traces_ifu_slices,'WAVELENGTH','POS_3', self.subplot_traces_ifu_slices,color='red')


        #self.plotTable(self.traces_ifu_slices,'WAVELENGTH','POS_1','Wavelength [nm]','Slit position [pix]',self.subplot_traces_ifu_slices,title_traces_ifu_slices,tooltip_traces_ifu_slices)
        #self.oplotTable(self.traces_ifu_slices,'WAVELENGTH','POS_2','Wavelength [nm]','Slit position [pix]',self.subplot_traces_ifu_slices,'yellow')
        #self.oplotTable(self.traces_ifu_slices,'WAVELENGTH','POS_3','Wavelength [nm]','Slit position [pix]',self.subplot_traces_ifu_slices,'green')

      else :
        #Data not found info
        self.subtext_nodata.set_axis_off()
        self.text_nodata = """Merged spectrum
       (PRO.CATG=PREF_MERGE3D_DATA_OBJ_ARM,PREF_TRACE3D_DATA_OBJ_ARM, 
       where PREF=FLUX_IFU, TELL_IFU or SCI_IFU, 
       ARM=UVB,VIS or NIR) not found in the products. 
       This may be due to a recipe failure. 
      Check your input parameter values, 
      correct possibly typos and
      press 'Re-run recipe' button."""
        self.subtext_nodata.text(0.1, 0.6, self.text_nodata, color='#11557c', 
                                 fontsize=18, ha='left', va='center', alpha=1.0)
        self.subtext_nodata.tooltip="""\
                                    Merged spectrum not found in the products"""
        print("found no spectrum data")
 
  
    # This function specifies which are the parameters that should be presented
    # in the window to be edited.
    # Note that the parameter has to be also in the in_sop port (otherwise it 
    # won't appear in the window) 
    # The descriptions are used to show a tooltip. They should match one to one
    # with the parameter list 
    # Note also that parameters have to be prefixed by the 'recipe name:'
        
    def setInteractiveParameters(self):
      paramList = list()

      rec_id=self.rec_id
      self.par = xsh_parameters_common.Parameters()

      self.par.setGeneralObjectParameters(paramList,rec_id)

      print(rec_id)
      if ("stare" in rec_id) or ("nod" in rec_id) :
         print("entered")
         self.par.setStackParameters(paramList,rec_id)
      if self.rec_id != "xsh_scired_ifu_stare" :
         self.par.setCrhSingleParameters(paramList,rec_id)

      if rec_id[16:21] == "stare" :
         print("background")
         self.par.setBackgroundParameters(paramList,rec_id)

      if self.rec_id != "xsh_scired_ifu_stare" :
         self.par.setLocalizeParameters(paramList,rec_id)
      self.par.setRectifyParameters(paramList,rec_id)

      return paramList

    def setWindowHelp(self):
      help_text = """
This is an interactive window which help asses the quality of the execution of a recipe.
"""
      return help_text

    def setWindowTitle(self):
      title = 'X-shooter Interactive ' + self.obj_type + ' Spectrum Extraction. ' + self.seq_arm + ' Arm. ' + self.ins_mode
      return title

except ImportError:
  import_sucess = 'false'
  print("Error importing modules pyfits, wx, matplotlib, numpy")
  raise

