# import the needed modules
from __future__ import absolute_import
from __future__ import print_function
try:
  import reflex
  import pipeline_product
  import_sucess = True

#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.line_guess_tab_blue_found = False
      self.line_guess_tab_red_found = False
      #Read all the products
      frames = dict()
      for frame in fitsFiles:
        if frame == '': continue
        try:
          pp = pipeline_product.PipelineProduct(frame)
          pro_rec1_id = pp.readKeyword('ESO PRO REC1 ID')
        except KeyError:
          pro_rec1_id = '<missing>'
        if pro_rec1_id == 'uves_cal_predict':
          print('Keeping {} with PRO.REC1.ID={}'.format(frame.category, pro_rec1_id))
        else:
          print('Tossing {} with PRO.REC1.ID={}'.format(frame.category, pro_rec1_id))
          continue
        category = frame.category
        frames[category] = frame

      if "LINE_GUESS_TAB_BLUE" in frames : 
        self.line_guess_tab_blue_found = True
        frame = frames["LINE_GUESS_TAB_BLUE"]
        self.line_guess         = uves_plot_common.PlotableBlueLineGuessTable(frame)

      if "LINE_GUESS_TAB_REDL" in frames and \
         "LINE_GUESS_TAB_REDU" in frames :  
        self.line_guess_tab_red_found = True
        frame_redl = frames["LINE_GUESS_TAB_REDL"]
        frame_redu = frames["LINE_GUESS_TAB_REDU"]
        self.line_guess         = uves_plot_common.PlotableRedLineGuessTable(frame_redl,
                                                            frame_redu)

    # 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.line_guess_tab_blue_found == True or self.line_guess_tab_red_found == True :
        self.subplot_xdif_x    = figure.add_subplot(3,2,1)
        self.subplot_ydif_x    = figure.add_subplot(3,2,2)
        self.subplot_xdif_y    = figure.add_subplot(3,2,3)
        self.subplot_ydif_y    = figure.add_subplot(3,2,4)
        self.subplot_ydif_xdif = figure.add_subplot(3,2,5)
        self.subplot_y_x       = figure.add_subplot(3,2,6)
      else : 
        self.subtext_nodata    = figure.add_subplot(1,1,1)
          
    # 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.line_guess_tab_blue_found == True or self.line_guess_tab_red_found == True :
        #XDIF vs X plot
        tooltip_xdif_x ="""Plot of the difference between the measured and predicted line X coordinate (pix) versus the measured line X coordinate (pix). 
The solid and dashed horizontal lines represent the median value and the +-1 sigma range respectively."""
        if self.line_guess_tab_blue_found == True :
          title_xdif_x   = 'XDIF: Mean=%#.3g Med=%#.3g RMS=%#.3g'% (self.line_guess.mean_xdif,self.line_guess.median_xdif,self.line_guess.std_xdif) 
        elif self.line_guess_tab_red_found == True:
          title_xdif_x   = 'XDIF: Mean=%#.3g Med=%#.3g RMS=%#.3g'% (self.line_guess.mean_all_xdif,self.line_guess.median_all_xdif,self.line_guess.std_all_xdif) 
        self.line_guess.plotXDIFvsX(self.subplot_xdif_x, title_xdif_x, tooltip_xdif_x)

        #YDIF vs X plot
        tooltip_ydif_x ="""Plot of the difference between the measured and predicted line Y coordinate (pix) versus the measured line X coordinate (pix). 
The solid and dashed horizontal lines represent the median value and the +-1 sigma range respectively."""
        if self.line_guess_tab_blue_found == True :
          title_ydif_x   = 'YDIF: Mean=%#.3g Med=%#.3g RMS=%#.3g'% (self.line_guess.mean_ydif,self.line_guess.median_ydif,self.line_guess.std_ydif) 
        elif self.line_guess_tab_red_found == True:
          title_ydif_x   = 'YDIF: Mean=%#.3g Med=%#.3g RMS=%#.3g'% (self.line_guess.mean_all_ydif,self.line_guess.median_all_ydif,self.line_guess.std_all_ydif) 
        self.line_guess.plotYDIFvsX(self.subplot_ydif_x, title_ydif_x, tooltip_ydif_x)

        #XDIF vs Y plot
        tooltip_xdif_y ="""Plot of the difference between the measured and predicted line X coordinate (pix) versus the measured line Y coordinate (pix). 
The solid and dashed horizontal lines represent the median value and the +-1 sigma range respectively."""
        if self.line_guess_tab_blue_found == True :
          title_xdif_y   = 'XDIF: Mean=%#.3g Med=%#.3g RMS=%#.3g'% (self.line_guess.mean_xdif,self.line_guess.median_xdif,self.line_guess.std_xdif) 
        elif self.line_guess_tab_red_found == True:
          title_xdif_y   = 'XDIF: Mean=%#.3g Med=%#.3g RMS=%#.3g'% (self.line_guess.mean_all_xdif,self.line_guess.median_all_xdif,self.line_guess.std_all_xdif) 
        self.line_guess.plotXDIFvsY(self.subplot_xdif_y, title_xdif_y, tooltip_xdif_y)
      
        #YDIF vs Y plot
        tooltip_ydif_y ="""Plot of the difference between the measured and predicted line Y coordinate (pix) versus the measured line Y coordinate (pix). 
The solid and dashed horizontal lines represent the median value and the +-1 sigma range respectively."""
        if self.line_guess_tab_blue_found == True :
          title_ydif_y   = 'YDIF: Mean=%#.3g Med=%#.3g RMS=%#.3g'% (self.line_guess.mean_ydif,self.line_guess.median_ydif,self.line_guess.std_ydif) 
        elif self.line_guess_tab_red_found == True:
          title_ydif_y   = 'YDIF: Mean=%#.3g Med=%#.3g RMS=%#.3g'% (self.line_guess.mean_all_ydif,self.line_guess.median_all_ydif,self.line_guess.std_all_ydif) 
        self.line_guess.plotYDIFvsY(self.subplot_ydif_y, title_ydif_y, tooltip_ydif_y)
        
        #YDIF vs XDIF plot
        title_ydif_xdif   = '' 
        tooltip_ydif_xdif ="""Plot of the difference between the measured and predicted line Y coordinate (pix) versus the difference between the measured and predicted line X coordinate (pix). Red points refer to REDU arm.
The solid horizontal and vertical lines represent the median values of the differences YDIF and XDIF respectively."""
        self.line_guess.plotYDIFvsXDIF(self.subplot_ydif_xdif, title_ydif_xdif, tooltip_ydif_xdif)

        #Y vs X plot
        title_y_x   = 'Arcline Positions' 
        tooltip_y_x ="""Plot of the measured line Y coordinate (pix) versus the measured line X coordinate (pix).
Blue points represent accepted line identifications, and red points represent unidentified detected lines.  
This plot shows the distribution of detected arc lines on the format check arc frame."""
        self.line_guess.plotYvsX(self.subplot_y_x, title_y_x, tooltip_y_x)

      else :
        #Data not found info
        self.subtext_nodata.set_axis_off()
        self.text_nodata = """Line prediction not found in the products:
For Blue data:(PRO.CATG=LINE_GUESS_TAB_BLUE)
For Red data:(PRO.CATG=LINE_GUESS_TAB_RED)"""
        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='Line prediction not found in the products'
 
  
    # 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='uves_cal_predict',displayName='mbox_x',group='predict',description='Match box X size'))
      paramList.append(reflex.RecipeParameter(recipe='uves_cal_predict',displayName='mbox_y',group='predict',description='Match box Y size'))
      paramList.append(reflex.RecipeParameter(recipe='uves_cal_predict',displayName='trans_x',group='predict',description='Detector translation along X'))
      paramList.append(reflex.RecipeParameter(recipe='uves_cal_predict',displayName='trans_y',group='predict',description='Detector translation along Y'))
      paramList.append(reflex.RecipeParameter(recipe='uves_cal_predict',displayName='ccd_rot_angle_off',group='predict',description='Offset on CCD rotation angle'))

      return paramList

    def setWindowHelp(self):
      help_text = """
In this window, the user should aim to adjust the median of the XDIF and YDIF values (shown in the titles of the upper two plots) to approximately zero pixels by changing the values of the parameters trans_x and trans_y.
This may be done by adding the current median XDIF and YDIF values to the current trans_x and trans_y parameter values, respectively, and clicking "Re-run recipe", and iterating this procedure until the median XDIF and YDIF values are in the range +-0.1 pix.
Note that the parameter ccd_rot_angle_off may be used to help "tighten" any less-well defined trends in the upper four plots. 
Rotations of the order of 0.01-0.1 in either sense may make improvements."""
      return help_text

    def setWindowTitle(self):
      title = 'Uves Interactive Spectral Format'
      return title

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

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

  # import reflex modules
  import reflex_interactive_app
  import sys

  # import UVES reflex modules
  import uves_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()
