from __future__ import absolute_import
from __future__ import print_function
def log_invocation(fn='/tmp/reflex_invoc.log'):
    """ log invocation of actor for easy reexecution with:
        eval $(cat /tmp/reflex_invoc.log)
    """
    import os, sys
    #if 'REFLEX_DEBUG' not in os.environ:
    #    return
    try:
        with open(fn, 'w') as f:
            path = ""
            s = " ".join(['"%s"' % x for x in sys.argv])
            try:
                import reflex
                path = '"%s:"' % os.path.dirname(reflex.__file__)
            except ImportError:
                pass
            f.write('PYTHONPATH=%s$PYTHONPATH python %s\n' % (path, s)) 
    except:
        pass

# import the needed modules
try:
  import reflex
  import_sucess = True
  import reflex_plot_widgets
  import pipeline_product 
  from pipeline_display import ImageDisplay

#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, this is the function to modify:
#  readFitsData()                  (from class DataPlotterManager) 
# -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:
    # 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
      self.fibff_all_found = False
      self.slitff_found = False

      #Read all the products
      frames = dict()
      for frame in fitsFiles:
        if frame == '' :
          continue
        category = frame.category
        frames[category] = frame
        #print (frame.name)
      if "FIB_FF_DTC_REDL" in frames and \
         "FIB_FF_DTC_REDU" in frames :  
        self.fibff_all_found = True  

      if "SLIT_FF_DTC_REDL" in frames and \
         "SLIT_FF_DTC_REDU" in frames :  
        self.slitff_found = True  
 
      if self.fibff_all_found == True :
        frame_redl = frames["FIB_FF_DTC_REDL"]
        frame_redu = frames["FIB_FF_DTC_REDU"]

        self.fibreff_redl = pipeline_product.PipelineProduct(frame_redl)
        self.fibreff_redu = pipeline_product.PipelineProduct(frame_redu)
        self.fibreff_next = self.fibreff_redl.all_hdu[0].header['NAXIS3']

      if self.slitff_found == True :
        frame_redl = frames["SLIT_FF_DTC_REDL"]
        frame_redu = frames["SLIT_FF_DTC_REDU"]

        self.slitff_redl = pipeline_product.PipelineProduct(frame_redl)
        self.slitff_redu = pipeline_product.PipelineProduct(frame_redu)

        self.wlen = self.slitff_redl.all_hdu[0].header['ESO INS GRAT2 WLEN']
        self.slitff_redl_next = self.slitff_redl.all_hdu[0].header['NAXIS3']
        self.slitff_redu_next = self.slitff_redu.all_hdu[0].header['NAXIS3']
        self.is_simcal = self.slitff_redl.all_hdu[0].header['ESO OCS SIMCAL']

      self.list_slitff_redl_fid = []
      for i in range(self.slitff_redl_next):
         self.list_slitff_redl_fid.append(i)

      self.list_slitff_redu_fid = []
      for i in range(self.slitff_redu_next):
         self.list_slitff_redu_fid.append(i)

      self.list_fibff_fid = []
      for i in range(self.fibreff_next):
         self.list_fibff_fid.append(i)

      #read first all input image to save time later in case of update 
      self.list_slitff_redl = []
      self.list_slitff_redu = []
      self.list_slitff_redl=self.readAllImages(self.slitff_redl,self.slitff_redl_next)
      self.list_slitff_redu=self.readAllImages(self.slitff_redu,self.slitff_redu_next)

      self.list_fibff_redl = []
      self.list_fibff_redu = []
      self.list_fibff_redl=self.readAllImages(self.fibreff_redl,self.fibreff_next)
      self.list_fibff_redu=self.readAllImages(self.fibreff_redu,self.fibreff_next)


    def plotWidgets(self) :
        widgets = list()

        # Files Selector radiobutton
        labels_fib_ff = self.list_fibff_fid
        labels_slit_ff = self.list_slitff_redl_fid

        self.radiobutton1 = reflex_plot_widgets.InteractiveRadioButtons(self.fibre_flat_selector, self.setFibreSelectCallBack, labels_fib_ff, 0, 
                title="")
        self.radiobutton2 = reflex_plot_widgets.InteractiveRadioButtons(self.slit_flat_selector, self.setSlitSelectCallBack, labels_slit_ff, 0, 
                title="")
        widgets.append(self.radiobutton1)
        widgets.append(self.radiobutton2)

        return widgets

    def setFibreSelectCallBack(self, ext_id) :
        ext_id = int(ext_id)
        self.subplot_allff_redu.cla()
        self.subplot_allff_redl.cla()

        self.displayFibreImages(ext_id)

    def setSlitSelectCallBack(self, ext_id) :
        ext_id = int(ext_id)

        if ext_id < self.slitff_redu_next :
           self.subplot_slitff_redu.cla()
        self.subplot_slitff_redl.cla()

        self.displaySlitImages(ext_id)

    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) 

    #Read all images
    def readAllImages(self,obj,next):
        return_list = []
        mylist = list(range(next))
        for i in mylist:
          obj.readImage(fits_extension=0)
          obj.read2DLinearWCS(fits_extension=0)
          return_list.append(obj.image[i])
        return return_list

    #2D image display
    def plotImage(self,obj,subplot,title,tooltip,ext_id):
          #The following commands are done by readAllImages()
          #before calling plotImage in an initial call to save time
          #in case the user ask to update the plots interactively
          #
          #obj.readImage(fits_extension=0)
          #obj.read2DLinearWCS(fits_extension=0)
          #print obj.image[ext_id].shape

          img_obj = ImageDisplay()
          image = obj.image[ext_id]
          y_size, x_size = image.shape

          img_obj.setLabels('X [pix]','Y [pix]')
          img_obj.setXLinearWCSAxis(obj.crval1,obj.cdelt1,obj.crpix1)
          img_obj.setYLinearWCSAxis(obj.crval2,obj.cdelt2,obj.crpix2)

          img_obj.display(subplot, title, self.paragraph(tooltip),image)

    def displayFibreImages(self,fid):
        tooltip=self.setWindowFibreHelp()
        tit_redl=self.setWindowFibreTitle("REDL")
        tit_redu=self.setWindowFibreTitle("REDU")

        self.plotImage(self.fibreff_redu,self.subplot_allff_redu,tit_redu,tooltip,fid)
        self.plotImage(self.fibreff_redl,self.subplot_allff_redl,tit_redl,tooltip,fid)

    def displaySlitImages(self,fid):
        tooltip=self.setWindowSlitHelp()
        tit_redl=self.setWindowSlitTitle("REDL")
        tit_redu=self.setWindowSlitTitle("REDU")
        if fid < self.slitff_redu_next :
           self.plotImage(self.slitff_redu,self.subplot_slitff_redu,tit_redu,tooltip,fid)
        self.plotImage(self.slitff_redl,self.subplot_slitff_redl,tit_redl,tooltip,fid)


    # 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):
      if self.fibff_all_found == True:

        ncols=2
        nraws=2
        self.subplot_allff_redu  = figure.add_subplot(nraws,ncols,1)
        self.subplot_slitff_redu = figure.add_subplot(nraws,ncols,2)
        self.subplot_allff_redl  = figure.add_subplot(nraws,ncols,3)
        self.subplot_slitff_redl = figure.add_subplot(nraws,ncols,4)

      else : 
        self.subtext_nodata    = figure.add_subplot(1,1,1)

      self.fibre_flat_selector = figure.add_axes([0.10, 0.46, 0.26, 0.05])
      self.slit_flat_selector = figure.add_axes([0.60, 0.46, 0.26, 0.05])
      tip="Frame Id: (Mouse \n left button)"
      self.fibre_flat_selector.text(0.34, 0.50, tip, color='black', fontsize=10, ha='left', va='center', alpha=1.0)
      self.slit_flat_selector.text(0.34, 0.50, tip, color='black', fontsize=10, ha='left', va='center', alpha=1.0)

    def displayDataNotFound(self):
      #Data not found info
      self.subtext_nodata.set_axis_off()
      self.text_nodata = 'Line prediction not found in the products (PRO.CATG=FIB_FF_DTC_REDL or FIB_FF_DTC_REDU or SLIT_FF_DTC_REDL or SLIT_FF_DTC_REDU)' 
      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='Images not found in the products'


    # 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.fibff_all_found == True :
     
         #self.imageTooltips()
         slitff_id=self.list_slitff_redl_fid[0]
         fibreff_id=self.list_fibff_fid[0]
         self.displayFibreImages(fibreff_id)
         self.displaySlitImages(slitff_id)
  

    # 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()
      paramList.append(reflex.RecipeParameter(recipe='flames_cal_prep_sff_ofpos',displayName='ext_method',group='ofpos',description='Extraction method. <std | opt | fst | fop>'))
      paramList.append(reflex.RecipeParameter(recipe='flames_cal_prep_sff_ofpos',displayName='filter_switch',group='ofpos',description='Filter switch. <none | median>'))
      paramList.append(reflex.RecipeParameter('flames_cal_prep_sff_ofpos',displayName='sat_thr',group='ofpos',description='Saturation threshold'))
      paramList.append(reflex.RecipeParameter(recipe='flames_cal_prep_sff_ofpos',displayName='fileprep',group='ofpos',description='Slitff* and Fibreff* file preparation. If fast extraction method is used it should be set to FALSE.'))
      paramList.append(reflex.RecipeParameter(recipe='flames_cal_prep_sff_ofpos',displayName='save_flat_size',group='ofpos',description='To be sure to use the flat part of a slit flatsone may need to subtract this bit. The default value -1, is used for automatic setting: if WCEN=520 save_flat_size=0, else save_flat_size=2. Values explicitly set by user overwrite this rule. [-1]'))

      return paramList

    def setWindowFibreHelp(self):
      help_text = """
In this window, the user may check the quality of the synthetic fibre
      all-flat which is critical to determine the extraction quality
      of science spectra. The fibres should appear smooth without any
      artefacts. The save_flat_size parameter value may affect quality."""
      return help_text

    def setWindowFibreTitle(self,chip):
      title = 'FLAMES-UVES all fibre flat '+chip
      return title


    def setWindowSlitHelp(self):
      help_text = """
In this window, the user may check the quality of the echelle-slit flats which is critical to determine the extraction quality of science spectra. The images should appear smooth without any artefacts. The save_flat_size parameter value may affect quality."""
      return help_text

    def setWindowSlitTitle(self,chip):
      title = 'FLAMES-UVES slit flat '+chip
      return title

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

#This is the 'main' function
if __name__ == '__main__':
  log_invocation()

  # import reflex modules
  import reflex_interactive_app
  import sys

  # import UVES reflex modules
  import flames_plot_common

  # Create interactive application
  interactive_app = reflex_interactive_app.PipelineInteractiveApp(enable_init_sop=True)

  #Check if import failed or not
  if import_sucess == 'false' :
    interactive_app.setEnableGUI('false')

  #Open the interactive window if enabled
  if interactive_app.isGUIEnabled() :
    #Get the specific functions for this window
    dataPlotManager = DataPlotterManager()
    interactive_app.setPlotManager(dataPlotManager)
    interactive_app.showGUI()
  else :
    interactive_app.passProductsThrough()

  # print outputs
  interactive_app.print_outputs()

  sys.exit()

