# ========================================================================================================
#
# John Pritchard
#
# Developed from esotk_fringe_obj_mask.py by Mark Neeser
#
# A python interactive window for use in the Austrian in-kind
# fringe-correction Reflex workflow.  This interactive window
# shows the results of the fringe-correction pipeline, allowing
# the User to compare the input image with the fringe-corrected
# image, and the fringe map.   From this interactive Actor the
# User can modify pipeline parameters and re-initiate the
# processing.
#
#
#
# ========================================================================================================

import os
import re
import sys
sys.path.append(os.path.dirname(__file__))
from esotk_giraf_gui import BaseDataPlotterManager, runInteractiveApp

try:
    # Import non-standard but needed modules. These must be as subset of what
    # the esotk_fringe_gui module tries to load.
    import reflex
    import pipeline_product
    import pipeline_display
    import matplotlib
    from giraf_plot_common import *

    class DataPlotterManager(BaseDataPlotterManager):

        # 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().
        def readFitsData(self, fitsFiles):
            # Control variable to check if the interesting files were found in
            # the input.
            self.science_frames = []
            self.err_frames = []
            self.raw_frames = []
            self.frameLabels = {}

            #Initialise the objects to read/display
            self.std_rbnspectra     = None
            self.fib_id = -1

            # Read all the products
            sf = {}
            ef = {}
            for frame in fitsFiles:
                if frame == '':
                    continue
                category = frame.category
                if category == 'STD_RBNSPECTRA':
                    HDUlist=pyfits.open(frame.name)
                    CRCM=HDUlist[0].header['CMETHOD']
                    HDUlist.close()
                    self.frameLabels[frame.name]=CRCM+': '+frame.name
                    sf[CRCM]=frame
                elif category == 'STD_RBNERRORS':
                    HDUlist=pyfits.open(frame.name)
                    CRCM=HDUlist[0].header['CMETHOD']
                    HDUlist.close()
                    self.frameLabels[frame.name]=CRCM+': '+frame.name
                    ef[CRCM]=frame
                elif category == 'STD':
                    self.raw_frames.append(frame)
            self.science_frames.append(sf['NONE'])
            del sf['NONE']
            self.science_frames.extend(sorted(sf.values(), key=lambda x: x.category, reverse=False))
            self.err_frames.append(ef['NONE'])
            del ef['NONE']
            self.err_frames.extend(sorted(ef.values(), key=lambda x: x.category, reverse=False))

            self.science_found = len(self.science_frames) > 0
            self.err_found = len(self.err_frames) > 0
            self.raw_found = len(self.raw_frames) > 0

            if self.science_found:
                frame = self.science_frames[0]
                self.science = pipeline_product.PipelineProduct(frame)
                self.std_rbnspectra        = PlotableSCI_RBNSPECTRA(self.science_frames[0])
                self.std_rbnspectra_extr   = PlotableExtractedScience(self.science_frames[0])
                self.esorex_log_file_name  = re.sub(".*/giraffe/" ,"../../", os.path.dirname(frame.name))+"/log_dir/esorex.log"

            if self.err_found:
                frame = self.err_frames[0]
                self.err = pipeline_product.PipelineProduct(frame)

            self.DPR_CATG = "unknown"
            self.DPR_TYPE = "unknown"
            self.DPR_TECH = "unknown"
            if self.raw_found:
                HDUlist=pyfits.open(self.raw_frames[0].name)
                self.DPR_CATG = HDUlist[0].header['HIERARCH ESO DPR CATG']
                self.DPR_TYPE = HDUlist[0].header['HIERARCH ESO DPR TYPE']
                self.DPR_TECH = HDUlist[0].header['HIERARCH ESO DPR TECH']
                HDUlist.close()

        def loadProducts(self, index):
            """
            Loading both science and object errs.
            """
            super(DataPlotterManager, self).loadProducts(index)
            self.std_rbnspectra        = PlotableSCI_RBNSPECTRA(self.science_frames[index])
            self.std_rbnspectra_extr   = PlotableExtractedScience(self.science_frames[index], fib_id=self.fib_id)
            self.esorex_log_file_name  = re.sub(".*/giraffe/" ,"../../", os.path.dirname(self.science_frames[index].name))+"/log_dir/esorex.log"
            if index >= 0 and index < len(self.err_frames):
                frame = self.err_frames[index]
                self.err = pipeline_product.PipelineProduct(frame)

        # 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):
            self.list_subplot_image     = []
            if self.science_found == True and self.err_found == True:
                gs = matplotlib.gridspec.GridSpec(100,1)
                self.subplot_std_rbnspectra       = figure.add_subplot(gs[0:58,0])
                self.subplot_std_rbnspectra_extr  = figure.add_subplot(gs[70:92,0])
                self.subplot_txtinfo       = figure.add_subplot(gs[95:100,0])
            else : 
                self.subtext_nodata      = figure.add_subplot(1,1,1)
            self.setupFigure(figure)

        # 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.science_found == True and self.err_found == True:
                
                self.plot_std_rbnspectra()
                self.plot_std_rbnspectra_extr()
                
                #Additional text info
                self.showTextInfo()

            else :
                #Data not found info
                self.showNoData()

        def plot_std_rbnspectra(self) :
            title_std_rbnspectra   = 'Standard: Rebinned spectra [STD_RBNSPECTRA]\nCosmic Ray cleaning: %s' %(self.std_rbnspectra.rbnspectra.readKeyword('CMETHOD'))
            tooltip_std_rbnspectra = """Standard: rebinned spectra.\nMiddle-button click on a fibre to display it in the window below."""
            self.std_rbnspectra.plot(self.subplot_std_rbnspectra, title_std_rbnspectra,
                                 tooltip_std_rbnspectra)

        def plot_std_rbnspectra_extr(self) :
            title_std_rbnspectra_extr   = 'Rebinned spectra of OBJECT, S/N = 0.'
            tooltip_std_rbnspectra_extr = """Standard: rebinned spectra."""
            self.std_rbnspectra_extr.plot(self.subplot_std_rbnspectra_extr, title_std_rbnspectra_extr,
                                 tooltip_std_rbnspectra_extr)

        def showTextInfo(self) :
          self.subplot_txtinfo.cla()
          self.subplot_txtinfo.set_axis_off()
          try:
            mode = self.std_rbnspectra.rbnspectra.readKeyword('HIERARCH ESO INS SLITS ID')
          except:
            mode = 'unknown'
          try:
            filter_name = self.std_rbnspectra.rbnspectra.readKeyword('HIERARCH ESO INS FILT NAME')
          except:
            filter_name = 'unknown'
          try:
            grat_wlen = self.std_rbnspectra.rbnspectra.readKeyword('HIERARCH ESO INS GRAT WLEN')
          except:
            grat_wlen = 'unknown'
          try:
            raw1_name = self.std_rbnspectra.rbnspectra.readKeyword('HIERARCH ESO PRO REC1 RAW1 NAME')
          except:
            raw1_name = 'unknown'
          self.subplot_txtinfo.text(0.1, 0., 'DPid RAW1: %s\nDPR: %s :: %s :: %s\nMode/Setting/WLen: %s/%s/%s'
                                   %(raw1_name,
                                     self.DPR_CATG,self.DPR_TYPE,self.DPR_TECH,
                                     mode,filter_name,str(grat_wlen)
                                    ),
                                   ha='left', va='top', weight='bold')
          try:
            slit = self.sci_extracted.extractedscience.readKeyword('HIERARCH ESO INS SLIT NAME')
            self.subplot_txtinfo.text(0.5, 0., 'Slit name (LSS): '+slit, 
                                   ha='left', va='center', weight='bold')
          except:
            pass
          try:
            checksum = self.sci_extracted.extractedscience.readKeyword('HIERARCH ESO INS MOS CHECKSUM')
            self.subplot_txtinfo.text(0.5, 0., 'Slits checksum (MOS): '+str(checksum), 
                                   ha='left', va='center', weight='bold')
          except:
            pass
          try:
            mask_id = self.sci_extracted.extractedscience.readKeyword('HIERARCH ESO INS MASK ID')
            self.subplot_txtinfo.text(0.5, 0., 'Mask id (MXU): '+mask_id, 
                                   ha='left', va='center', weight='bold')
          except:
            pass
          try:
            target_name = self.sci_extracted.extractedscience.readKeyword('HIERARCH ESO OBS TARG NAME')
            self.subplot_txtinfo.text(0.1, 0.6, 'Target name: '+target_name, 
                                   ha='left', va='center', weight='bold')
          except:
            pass

        def showNoData(self) :
          #Data not found info
          self.subtext_nodata.set_axis_off()
          self.text_nodata = 'Standard data not found in the products (PRO.CATG=STD_RBNSPECTRA)'
          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='Standard data not found in the products'

        def plotWidgets(self) :
          widgets = list()
          if self.std_rbnspectra is not None :
            # Clickable subplot
            self.clickablesmapped = InteractiveClickableSubplot(
              self.subplot_std_rbnspectra, self.setExtractedObject)
            widgets.append(self.clickablesmapped)
          return widgets

        def setExtractedObject(self, point) :
            obj = self.std_rbnspectra.getObjectInPosition(point.xdata+0.5)
            if obj != -1 :
                self.std_rbnspectra_extr.selectObject(obj)
                self.fib_id=obj
            self.plot_std_rbnspectra_extr()

    
        # 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('gistandard','bsremove-method',group='Bkg Sub',description='Backgruond subtraction method'))
            paramList.append(reflex.RecipeParameter('gistandard','bsremove-yorder',group='Bkg Sub',description='Background subtraction yorder of 2-D polynomial fit'))
            paramList.append(reflex.RecipeParameter('gistandard','extr-method',group='Extr',description="Extraction method: 'SUM', 'HORNE' or 'OPTIMAL'. <SUM | OPTIMAL | HORNE> [SUM]"))
            paramList.append(reflex.RecipeParameter('gistandard','flat-apply',group='Flat',description="Apply or not the flat field correction. [TRUE]"))
            return paramList

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

        def setWindowTitle(self):
            title = 'Pipeline Interactive Window'
            return title

except ImportError:
    DataPlotterManager = None


if __name__ == '__main__':
    runInteractiveApp(DataPlotterManager)
