"""
Calibrate selected target with specific calibrator.

Synopsis:

run_gravi_recalibrate.py <indir> <outdir> --calibrator=<calibrator> --science=<target>

Explanation:

This script will look for vis-reduced files (PRO.CATG=*_SCI_VIS and
*_CAL_VIS) on <calibrator> and <target> in <indir> and copy these
files to <outdir>, including "_calibrator" and "_science" in the
copied file names. It will also change PRO.CATG in the various files
to *_CAL_VIS for the calibrator files and *_SCI_VIS for the science
files. It will then do the equivalent of running run_gravi_trend.py in
outdir.

The calibrator targets must be specified using the --calibrator/-c
option and the science targets using the --science/-s option. Both may
be used several times. See details below.

Example:

Let "reduced" be a directory containing reduced data for a calibrator
named INS.SOBJ.NAME=="A" and for two science targets named
INS.SOBJ.NAME=="B" and "C". Assume that the user would like to
calibrate all data (A, B and C) using B as a calibrator. They may do:

run_gravi_recalibrate.py reduced reduced_B -cB -sA -sB -sC
"""
import argparse
import os
import glob
import sys

try:
    import pyfits as fits
except ModuleNotFoundError:
    import astropy.io.fits as fits

from gravi_reduce import gravi_esorex as ge
from gravi_reduce import (log, ERROR, WARNING, NOTICE, set_verbose_type)
log = log.Log().log



parser = argparse.ArgumentParser(description=__doc__,
                                 formatter_class=argparse.RawDescriptionHelpFormatter,
                                 prefix_chars='-+')

parser.add_argument('indir', help="input directory")
parser.add_argument('outdir', help="output directory")
parser.add_argument("-c", "--calibrator", type=str, action="append",
                    help="target to use as a calibrator. May be used several time. "
                    "May be -cINS.SOBJ.NAME or -cINS.ROBJ.NAME:INS.SOBJ.NAME or -cFILENAME. "
                    "Only files with INS.SOBJ.OFFX==0 and INS.SOBJ.OFFY will be considered,"
                    "exept if --calibratorOFFX is set.",
                    default=[])

parser.add_argument("-s", "--science", type=str, action="append",
                    help="target to use as a science target. May be used several time. "
                    "May be -cINS.SOBJ.NAME or -cINS.ROBJ.NAME:INS.SOBJ.NAME or -cFILENAME. "
                    "All files will be considered, independent on INS.SOBJ.OFFX "
                    "and INS.SOBJ.OFFY. if the argument is 'all' all files are considered.",
                    default=[])

parser.add_argument("-cOFFX", "--calibratorOFFX", type=float, default=0.0,
                    help="INS SOBJ OFFX of the calibrator, only to be used when calibrator"
                    "files do not have OFFX==0.0.")

parser.add_argument("-phasec", "--phasecalib", type=str,
                    help="If set file to be used for separate phase calibration. "
                    "Only one file can be given",
                    default=None)

parser.add_argument("-m", "--mindate", type=str,
                    help="minimum date in PCR.ACQ.START format")

parser.add_argument("-M", "--maxdate", type=str,
                    help="maximum date in PCR.ACQ.START format")

parser.add_argument("--commoncalib-dir", dest="commoncalibdir", default="../../common_calibration",
                    help="Add this directory in the search path for common"
                    "calibration files   [../../common_calibration]")

options =[['gravity_viscal.force-calib',None],
          ['gravity_viscal.nsmooth-tfvis-sc',None],
          ['gravity_viscal.nsmooth-tfflux-sc',None],
          ['gravity_viscal.maxdeg-tfvis-sc',None],
          ['gravity_viscal.smoothing',None],
          ['esorex.msg-level','info'],
          ['esorex.time','TRUE'],
          ['esorex.mem-check','TRUE'],
          ['esorex.recipe-dir',None]]

ge.implement_recipe_options (parser,options)

def recalibrate(args):
    msg_level = vars(args)['esorex.msg-level']
    if msg_level == 'error':
        set_verbose_type(ERROR)
    elif msg_level == 'warning':
        set_verbose_type(ERROR+WARNING)
    else:
        set_verbose_type(ERROR+WARNING+NOTICE)
    
    copydata(args.indir, args.outdir, args.calibrator, args.science,
             args.calibratorOFFX, args.phasecalib, args.mindate, args.maxdate)
    calibrate(args)

def calibrate(args):
    common = []
    reduced = []
    calibrated = []
    
    if args.phasecalib is not None:
        setattr(args, 'gravity_viscal.separate-phase-calib', 'TRUE')
    
    reduceddir=args.outdir
    commoncalibdir=args.commoncalibdir
    calibrateddir=args.outdir+'/calibrated'
    ge.add_gravity (common, glob.glob(commoncalibdir+'/GRAVI*fits'))
    ge.add_gravity (reduced, glob.glob(reduceddir+'/GRAVI*.fits'))
    ge.compute_tf (reduced, reduced+common, calibrateddir, options=args, overwrite=True)
    ge.add_gravity (calibrated, glob.glob(calibrateddir+'/GRAVI*.fits'))
    ge.add_gravity (reduced, glob.glob(reduceddir+'/GRAVI*.fits'))
    ge.calibrate_vis (reduced, calibrated, calibrateddir, options=args, overwrite=True)



def copydata(indir, outdir, calibrator, science, calibratorOFFX, phasecalib, mindate=None, maxdate=None):
    if not os.path.exists(outdir):
        print(f'Creating directory {outdir}')
        os.makedirs(outdir)
    else:
        print(f'{outdir} exists')
    allfiles=sorted(glob.glob(indir+'/GRAVI*.fits'))
    for fname in allfiles:
        try:
            hdulist = fits.open(fname)
        except(IOError):
            continue
        header=hdulist[0].header
        try:
            FTname=header["HIERARCH ESO FT ROBJ NAME"]
            SCname=header["HIERARCH ESO INS SOBJ NAME"]
            PRO_CATG=header["HIERARCH ESO PRO CATG"]
            ACQ_START=header["HIERARCH ESO PCR ACQ START"]
        except (IOError, KeyError):
            continue
        if (   (mindate is not None and ACQ_START < mindate)
            or (maxdate is not None and ACQ_START > maxdate)):
            continue
        try:
            OFFX=header["HIERARCH ESO INS SOBJ OFFX"]
            OFFY=header["HIERARCH ESO INS SOBJ OFFY"]
        except (IOError, KeyError): 
            OFFX=0.
            OFFY=0.

        pair=FTname.replace(':', '::') + ':' + SCname.replace(':', '::')
        if calibratorOFFX == 0.0:
            if ((pair in calibrator
                or SCname in calibrator
                or fname in calibrator
                or fname[len(indir):] in calibrator)
                and PRO_CATG in ['DUAL_CAL_VIS',
                                'DUAL_SCI_VIS',
                                'SINGLE_SCI_VIS',
                                'SINGLE_CAL_VIS']
                and OFFX == 0. and OFFY == 0.):
                print(("Copying file "+fname+" as calibrator"))
                if PRO_CATG == 'DUAL_SCI_VIS':
                    header['HIERARCH ESO PRO CATG']='DUAL_CAL_VIS'
                elif PRO_CATG == 'SINGLE_SCI_VIS':
                    header['HIERARCH ESO PRO CATG']='SINGLE_CAL_VIS'
                outfname=outdir+'/'+fname[len(indir):-5]+'_calibrator.fits'
                try:
                    hdulist.writeto(outfname, overwrite=True)
                except (TypeError):
                    hdulist.writeto(outfname, clobber=True)
                if PRO_CATG in ['DUAL_CAL_VIS',
                                'SINGLE_SCI_VIS']:
                    print(("Copying file "+fname+" as science"))
                    if PRO_CATG == 'DUAL_CAL_VIS':
                        header['HIERARCH ESO PRO CATG']='DUAL_SCI_VIS'
                    elif PRO_CATG == 'SINGLE_CAL_VIS':
                        header['HIERARCH ESO PRO CATG']='SINGLE_SCI_VIS'
                    outfname=outdir+'/'+fname[len(indir):-5]+'_science.fits'
                    try:
                        hdulist.writeto(outfname, overwrite=True)
                    except (TypeError):
                        hdulist.writeto(outfname, clobber=True)                    
            header["HIERARCH ESO PRO CATG"]=PRO_CATG
            
            
        else:
            if ((pair in calibrator
                or SCname in calibrator
                or fname in calibrator
                or fname[len(indir):] in calibrator)
                and PRO_CATG in ['DUAL_CAL_VIS',
                                'DUAL_SCI_VIS',
                                'SINGLE_SCI_VIS',
                                'SINGLE_CAL_VIS']
                and OFFX == calibratorOFFX):
                print(("Copying file "+fname+" as calibrator"))
                if PRO_CATG == 'DUAL_SCI_VIS':
                    header['HIERARCH ESO PRO CATG']='DUAL_CAL_VIS'
                elif PRO_CATG == 'SINGLE_SCI_VIS':
                    header['HIERARCH ESO PRO CATG']='SINGLE_CAL_VIS'
                outfname=outdir+'/'+fname[len(indir):-5]+'_calibrator.fits'
                try:
                    hdulist.writeto(outfname, overwrite=True)
                except (TypeError):
                    hdulist.writeto(outfname, clobber=True)
                if PRO_CATG in ['DUAL_CAL_VIS',
                                'SINGLE_SCI_VIS']:
                    print(("Copying file "+fname+" as science"))
                    if PRO_CATG == 'DUAL_CAL_VIS':
                        header['HIERARCH ESO PRO CATG']='DUAL_SCI_VIS'
                    elif PRO_CATG == 'SINGLE_CAL_VIS':
                        header['HIERARCH ESO PRO CATG']='SINGLE_SCI_VIS'
                    outfname=outdir+'/'+fname[len(indir):-5]+'_science.fits'
                    try:
                        hdulist.writeto(outfname, overwrite=True)
                    except (TypeError):
                        hdulist.writeto(outfname, clobber=True)
            header["HIERARCH ESO PRO CATG"]=PRO_CATG

        if phasecalib is not None:
            if (fname[len(indir):] in phasecalib
                and PRO_CATG in ['DUAL_CAL_VIS',
                                 'DUAL_SCI_VIS',
                                 'SINGLE_SCI_VIS',
                                 'SINGLE_CAL_VIS']):
                print(("Copying file "+fname+" as phase calibrator"))
                if PRO_CATG in ['DUAL_SCI_VIS', 'DUAL_CAL_VIS']:
                    header['HIERARCH ESO PRO CATG']='DUAL_CAL_VISPHI'
                elif PRO_CATG in ['SINGLE_SCI_VIS', 'SINGLE_CAL_VIS']:
                    header['HIERARCH ESO PRO CATG']='SINGLE_CAL_VISPHI'
                outfname=outdir+'/'+fname[len(indir):-5]+'_phasecalibrator.fits'
                try:
                    hdulist.writeto(outfname, overwrite=True)
                except (TypeError):
                    hdulist.writeto(outfname, clobber=True)
            header["HIERARCH ESO PRO CATG"]=PRO_CATG        

        if ((pair in science
             or SCname in science
             or fname in science
             or fname[len(indir):] in science)
            and PRO_CATG in ['DUAL_CAL_VIS',
                             'DUAL_SCI_VIS',
                             'SINGLE_SCI_VIS',
                             'SINGLE_CAL_VIS']):
            print(("Copying file "+fname+" as science"))
            if PRO_CATG == 'DUAL_CAL_VIS':
                header['HIERARCH ESO PRO CATG']='DUAL_SCI_VIS'
            elif PRO_CATG == 'SINGLE_CAL_VIS':
                header['HIERARCH ESO PRO CATG']='SINGLE_SCI_VIS'
            outfname=outdir+'/'+fname[len(indir):-5]+'_science.fits'
            try:
                hdulist.writeto(outfname, overwrite=True)
            except (TypeError):
                hdulist.writeto(outfname, clobber=True)
            header["HIERARCH ESO PRO CATG"]=PRO_CATG
        
        if 'all' in science and PRO_CATG in ['DUAL_CAL_VIS',
                             'DUAL_SCI_VIS',
                             'SINGLE_SCI_VIS',
                             'SINGLE_CAL_VIS']:
            print(("Copying file "+fname+" as science"))
            if PRO_CATG == 'DUAL_CAL_VIS':
                header['HIERARCH ESO PRO CATG']='DUAL_SCI_VIS'
            elif PRO_CATG == 'SINGLE_CAL_VIS':
                header['HIERARCH ESO PRO CATG']='SINGLE_SCI_VIS'
            outfname=outdir+'/'+fname[len(indir):-5]+'_science.fits'
            try:
                hdulist.writeto(outfname, overwrite=True)
            except (TypeError):
                hdulist.writeto(outfname, clobber=True)
            header["HIERARCH ESO PRO CATG"]=PRO_CATG


