# ========================================================================================================
#
# 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
import matplotlib
matplotlib.use('wxagg')
sys.path.append(os.path.dirname(__file__))

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
    from esotk_giraf_sci_gui import BaseDataPlotterManager, runInteractiveApp
    from giraf_plot_common import *
    from astropy.table import Table
    #from astroquery.utils import TableList
    import_sucess = True
    giraf_import_sucess = True

    class giss_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.tblLists = {}
            self.frameLabels = {}
            self.frameCRCMLabels = {}
            self.figure = None
            self.SCI_STD = {"SS": "SCI", "label": "Science", "recipe": "giscience"}

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

            # Read all the products
            self.sf = {}
            self.ef = {}
            # IDPs are listed in the fitsFile list, but since they don't have CMETHOD in the header...
            #self.idps = {}
            for frame in fitsFiles:
                if frame == '':
                    continue
                category = frame.category
                if category in ['SCIENCE_RBNSPECTRA','STD_RBNSPECTRA']:
                    if category in ['STD_RBNSPECTRA',]:
                        self.SCI_STD["SS"]="STD"
                        self.SCI_STD["label"]="Standard"
                        self.SCI_STD["recipe"]="gistandard"
                    HDUlist=pyfits.open(frame.name)
                    CRCM=HDUlist[0].header.get('CMETHOD','NONE')
                    HDUlist.close()
                    self.frameLabels[frame.name]=CRCM+': '+frame.name
                    self.frameCRCMLabels[frame.name]=CRCM
                    self.sf[CRCM]=frame
                elif category in ['SCIENCE_RBNERRORS','STD_RBNERRORS']:
                    HDUlist=pyfits.open(frame.name)
                    CRCM=HDUlist[0].header.get('CMETHOD','NONE')
                    HDUlist.close()
                    self.frameLabels[frame.name]=CRCM+': '+frame.name
                    self.frameCRCMLabels[frame.name]=CRCM
                    self.ef[CRCM]=frame
                elif category in ['SCIENCE','STD']:
                    self.raw_frames.append(frame)
                    HDUlist=pyfits.open(frame.name)
                    CRCM=HDUlist[0].header.get('CMETHOD','NONE')
                    tl={}
                    for i in range(len(HDUlist)) :
                        try:
                            t=Table.read(frame.name, hdu=i)
                            try :
                                extname=HDUlist[i].header['EXTNAME']
                            except :
                                extname="HDU%d" %(i)
                            tl[extname]=t
                        except ValueError :
                            pass
                    if not tl == [] :
                      #self.tblLists[CRCM]=TableList(tl)
                      self.tblLists[CRCM]=tl
            tsf=self.sf.copy()
            tef=self.ef.copy()
            # science frames
            self.science_frames.append(tsf['NONE'])
            del tsf['NONE']
            self.science_frames.extend(sorted(list(tsf.values()), key=lambda x: x.category, reverse=False))
            # error frames
            self.err_frames.append(tef['NONE'])
            del tef['NONE']
            self.err_frames.extend(sorted(list(tef.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.sci_rbnspectra        = PlotableSCI_RBNSPECTRA(self.science_frames[0])
                self.sci_rbnspectra_extr   = PlotableExtractedScience(self.science_frames,self.err_frames,self.tblLists)
                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|standard and object errs.
            """
            super(giss_DataPlotterManager, self).loadProducts(index)
            self.sci_rbnspectra        = PlotableSCI_RBNSPECTRA(self.science_frames[index])
            #self.sci_rbnspectra_extr   = PlotableExtractedScience(self.science_frames[index],self.err_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(200,1)
                self.subplot_sci_rbnspectra       = figure.add_subplot(gs[0:106,0])
                self.subplot_sci_rbnspectra_extr  = figure.add_subplot(gs[132:190,0])
                self.init_plot_sci_rbnspectra_extr()
                self.subplot_txtinfo              = figure.add_subplot(gs[199:200,0])
            else : 
                self.subtext_nodata               = figure.add_subplot(1,1,1)
            self.setupFigure(figure)
            self.figure = 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_sci_rbnspectra()
                self.plot_sci_rbnspectra_extr()

                #Additional text info
                self.showTextInfo()

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

        def computeSky(self, applyTo, method, statistic, numFibs=None ):
            self.sci_rbnspectra_extr.computeSky(applyTo, method, statistic, numFibs)
            self.plot_sci_rbnspectra_extr()

        def plot_sci_rbnspectra(self) :
            try:
              CRCM=self.sci_rbnspectra.rbnspectra.readKeyword('CMETHOD')
            except:
              CRCM="NONE"
            title_sci_rbnspectra   = '%s: Rebinned spectra [SCIENCE_RBNSPECTRA]\nCosmic Ray cleaning: %s' %(self.SCI_STD["label"],CRCM)
            tooltip_sci_rbnspectra = """%s: rebinned spectra.\nMiddle-button click on a fibre to display it in the window below.""" %(self.SCI_STD["label"])
            self.sci_rbnspectra.plot(self.subplot_sci_rbnspectra, title_sci_rbnspectra,
                                 tooltip_sci_rbnspectra)

        def init_plot_sci_rbnspectra_extr(self) :
            self.sci_rbnspectra_extr.init_spec_subplot(self.subplot_sci_rbnspectra_extr)

        def plot_sci_rbnspectra_extr(self) :
            title_sci_rbnspectra_extr   = 'Rebinned spectra of OBJECT, S/N = 0.'
            tooltip_sci_rbnspectra_extr = """%s: rebinned spectra.""" %(self.SCI_STD["label"])
            if self.fileChoice is None :
                self.sci_rbnspectra_extr.plot(self.subplot_sci_rbnspectra_extr, title_sci_rbnspectra_extr,
                                 tooltip_sci_rbnspectra_extr)
            else :
                self.sci_rbnspectra_extr.plot(self.subplot_sci_rbnspectra_extr, title_sci_rbnspectra_extr,
                                 tooltip_sci_rbnspectra_extr, CRCM=self.fileChoice.GetString(self.fileChoice.GetSelection()))

        def showTextInfo(self) :
          self.subplot_txtinfo.cla()
          self.subplot_txtinfo.set_axis_off()
          try:
            mode = self.sci_rbnspectra.rbnspectra.readKeyword('HIERARCH ESO INS SLITS ID')
          except:
            mode = 'unknown'
          try:
            filter_name = self.sci_rbnspectra.rbnspectra.readKeyword('HIERARCH ESO INS FILT NAME')
          except:
            filter_name = 'unknown'
          try:
            grat_wlen = self.sci_rbnspectra.rbnspectra.readKeyword('HIERARCH ESO INS GRAT WLEN')
          except:
            grat_wlen = 'unknown'
          try:
            raw1_name = self.sci_rbnspectra.rbnspectra.readKeyword('HIERARCH ESO PRO REC1 RAW1 NAME')
          except:
            raw1_name = 'unknown'
          self.subplot_txtinfo.text(0.5, 0., '\nDPid RAW1: %s -- DPR: %s :: %s :: %s -- Mode/Setting/WLen: %s/%s/%s'
                                   %(raw1_name,
                                     self.DPR_CATG,self.DPR_TYPE,self.DPR_TECH,
                                     mode,filter_name,str(grat_wlen)
                                    ),
                                   size='small', ha='center', 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 = 'No science or standard data not found in the products (PRO.CATG=SCIENCE_RBNSPECTRA,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='Science/Standard data not found in the products'

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

        def setExtractedObject(self, point) :
            obj = self.sci_rbnspectra.getObjectInPosition(point.xdata+0.5)
            if obj != -1 :
                self.sci_rbnspectra_extr.selectObject(obj)
                self.fib_id=obj
            self.objectByName.SetSelection(numpy.where(self.sci_rbnspectra_extr.objectSkyByName_ind == self.fib_id-1)[0][0])
            self.objectBySNR.SetSelection(numpy.where(self.sci_rbnspectra_extr.objectSkyBySNR_ind == self.fib_id-1)[0][0])
            self.plot_sci_rbnspectra_extr()
    
        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:
    import_sucess = False
    class giss_DataPlotterManager(object):
        """
        Empty class definition to prevent ImportError
        """
        def __init__(self):
            pass


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