from __future__ import absolute_import
import os

# get is_CASA6 and is_python3
from casatasks.private.casa_transition import *
if is_CASA6:
    from casatools import calibrater, ms
    from casatasks import casalog
    from .mstools import write_history
else:
    from taskinit import *
    from mstools import write_history
    calibrater = cbtool
    ms = mstool

def writeResultsHistory(myms, vis, mycasalog, indict):
    """                                                 
    write returned output of fluxscale to HISTORY subtable of the parent ms
    """                                                                      
    isOpen = False                                                           
    try:                                                                     
        myms.open(vis)                                                       
        isOpen = True                                                        

        mainkeys = indict.keys()

        spwids = indict['spwID']
        freqs = indict['freq']  
        msg0 = "Fluxscale results *****"
        myms.writehistory(message=msg0, origin='fluxscale')
        for ky in mainkeys:                                
            try:                                           
                fieldid = int(ky)                          
            except:                                        
                fieldid = None                             

            if fieldid!=None:
                fdict = indict[ky]
                fname = fdict['fieldName']   
                fitF = fdict['fitFluxd']     
                fitFerr = fdict['fitFluxdErr']
                fitRefFreq = fdict['fitRefFreq']
                spix = fdict['spidx']           
                spixerr = fdict['spidxerr']     
                msg1 = fname+"(field id="+ky+") " 
                myms.writehistory(message=msg1, origin='fluxscale')
                for ispw in spwids:                                
                    strspw = str(ispw)                             
                    spwfdict = fdict[strspw]                       
                    flux = spwfdict['fluxd']                       
                    fluxerr = spwfdict['fluxdErr']                 
                    freq = freqs[ispw]                             
                    fvalbase = 1.0                                 
                    funit=''                                       
                    if freq>1.e9:
                        fvalbase = 1.e9
                        funit = 'GHz'
                    elif freq>1.e6:
                        fvalbase = 1.e6
                        funit = 'MHz'
                    elif freq>1.e3:
                        fvalbase = 1.e3
                        funit = 'kHz'
                    else:
                        if freq > 0.0:
                            funit = 'Hz'
                    freq = freq/fvalbase
                    if funit!='':
                        funitlast=funit
                        fvalbaselast=fvalbase
                    if freq  < 0.0:
                        msg2 = "  Spw "+strspw+" insufficient data, flux density is not determined."
                    else:
                        msg2 = "  Spw "+strspw+"(freq = {:7.3f}".format(freq)+funit+") Flux density = {:10.6f}".format(flux[0])+\
                               "+/-{:10.6f}".format(fluxerr[0])+" Jy"
                    myms.writehistory(message=msg2, origin='fluxscale')
                if len(spwids) > 1:
                    msg3 = "  Spectral index fitting coefficients [zero-point, alpha, beta] with errors :"
                    msg3a = "["
                    msg3b = "["
                    nspix = len(spix)
                    for ispix in range(nspix):
                        msg3a += "{:5.3f}".format(spix[ispix])
                        msg3b += "{:5.3f}".format(spixerr[ispix])
                        if ispix!=nspix-1:
                            msg3a += ","
                            msg3b += ","
                    msg3a += "]"
                    msg3b += "]"
                    msg3 += msg3a + "+/-" + msg3b
                    fitreffreq = fitRefFreq/fvalbaselast
                    msg4 = "  Fitted flux density = {:10.6f}".format(fitF)+"+/-{:10.6f}".format(fitFerr)+\
                           " Jy (reference freq = {:7.3f}".format(fitreffreq)+funitlast+")"
                    myms.writehistory(message=msg3, origin='fluxscale')
                    myms.writehistory(message=msg4, origin='fluxscale')

    except Exception as instance:
        mycasalog.post("*** Error \'%s\' updating fluxscale results in HISTORY of %s" % (instance, vis), 'WARN' )

    finally:
        if isOpen:
            myms.close()

def fluxscale(vis=None, caltable=None, fluxtable=None, reference=None, transfer=None, listfile=None, append=None,
              refspwmap=None, gainthreshold=None, antenna=None, timerange=None, scan=None, incremental=None,
              fitorder=None, display=None):
    """Bootstrap the flux density scale from standard calibrators:

    After running gaincal on standard flux density calibrators (with or
    without a model), and other calibrators with unknown flux densities,
    fluxscale will determine the flux density of the unknowns calibrators
    that are most consistent with the standard calibrator antenna gains.

    Keyword arguments:
    vis -- Name of input visibility file
               default: none; example: vis='ngc5921.ms'
    caltable -- Name of input calibration table
               default: none; example: caltable='ngc5921.gcal'
               This cal table was obtained from task gaincal.
    fluxtable -- Name of output, flux-scaled calibration table
               default: none; example: fluxtable='ngc5921.gcal2'
               The gains in this table have been adjusted by the
               derived flux density each calibrator.  The MODEL_DATA
               column has NOT been updated for the flux density of the
               calibrator.  Use setjy to do this if it is a point source.
    reference -- Reference field name(s)
               The names of the fields with a known flux densities or
                  visibilties that have been placed in the MODEL column
                  by setjy or ft for a model not in the CASA system.
               The syntax is similar to field.  Hence field index or
                  names can be used.
               default: none; example: reference='1328+307'
    transfer -- Transfer field name(s)
               The names of the fields with unknown flux densities.
                  These should be point-like calibrator sources
               The syntax is similar to field.  Hence source index or
                 names can be used.
               default: '' = all sources in caltable that are not specified
                  as reference sources.  Do not include unknown target sources
               example: transfer='1445+099, 3C84'; transfer = '0,4'

               NOTE: All fields in reference and transfer must have solutions
               in the caltable.

    listfile -- Fit listfile name
               The list file contains the flux density, flux density error,
                 S/N, and number of solutions (all antennas and feeds) for each
                 spectral window.  NOTE: The nominal spectral window frequencies
                 will be included in the future.
               default: '' = no fit listfile will be created.

    append -- Append fluxscaled solutions to the fluxtable.
               default: False; (will overwrite if already existing)
               example: append=True
    refspwmap -- Vector of spectral windows enablings scaling across
               spectral windows
               default: [-1]==> none.
               Example with 4 spectral windows:
               if the reference fields were observed only in spw=1 & 3,
               and the transfer fields were observed in all 4 spws (0,1,2,3),
               specify refspwmap=[1,1,3,3].
               This will ensure that transfer fields observed in spws 0,1,2,3
               will be referenced to reference field solutions only in
               spw 1 or 3.

    gainthreshold -- % deviation threshold from the median gain to be used flux scaling derivation

    antenna -- Select antennas to be used to derive flux scaling 

    timerange -- Select timerage to be used to derive flux scaling with given antenna selection

    scan -- Select scans to be used to derived flux scaling with given antenna selection

    incremental -- Create an incremental caltable containing only the gain correction 
                    factors. 
               default: False; (older behavior, produces flux scaled gain table)

    fitorder -- the order of spectral fitting when solutions for multiple spws are available
               default: 1

    display -- display statistics (histogram)  of derived correction factors
               default: false
    """

    try:
        casalog.origin('fluxscale')

        mycb = calibrater()
        # check the input param
        if fluxtable=="":
            casalog.post("Missing fluxtable name.","SEVERRE")
            raise ValueError("Missing fluxtable name.")
        else:
            if os.path.exists(fluxtable) and not append:
                casalog.post("fluxtable %s exists." % fluxtable, "SEVERE")
                raise ValueError("fluxtable %s exists. Please specify a different name. Or set append=True, to append the results to the table." % fluxtable)

        mycb.open(filename=vis,compress=False,addcorr=False,addmodel=False)
        output = mycb.fluxscale(tablein=caltable,tableout=fluxtable,reference=reference,
                                transfer=transfer,listfile=listfile,append=append,
                                refspwmap=refspwmap,gainthreshold=gainthreshold,antenna=antenna,
                                timerange=timerange,scan=scan,
                                incremental=incremental,fitorder=fitorder,display=display)

        #write history
        try:
            param_names = fluxscale.__code__.co_varnames[:fluxscale.__code__.co_argcount]
            if is_python3:
                vars = locals( )
                param_vals = [vars[p] for p in param_names]
            else:
                param_vals = [eval(p) for p in param_names]
            write_history(ms(), vis, 'fluxscale', param_names,
                          param_vals, casalog)
            writeResultsHistory(ms(), vis, casalog, output)
        except Exception as instance:
            casalog.post( "*** Error \'%s\' updating HISTORY" % (instance), 'WARN' )

    finally:
        mycb.close()

    return output