#!/usr/bin/env python3
# -*- coding: utf-8 -*-

_author = "Francesco de Gasperin (astro@voo.it)"

import os, sys, time, gc
import atexit
import tables
from losoto import _version, _logging
from losoto.h5parm import h5parm
from losoto.lib_losoto import LosotoParser, getStepSoltabs

def my_close_open_files(verbose):
    open_files = tables.file._open_files
    are_open_files = len(open_files) > 0
    if verbose and are_open_files:
        print("Closing remaining open files:")
    # Compatibility fix
    if tables.__version__>='3.1.0':
        for fileh in list(open_files.handlers):
            if verbose:
                print("%s..." % (fileh.filename,))
            fileh.close()
    else:
        for fileh in open_files.keys():
            if verbose:
                print("%s..." % (open_files[fileh].filename,))
            open_files[fileh].close()
        if verbose:
            print("Done closing files.")
    if verbose and are_open_files:
        print('\n')

if __name__=='__main__':
    # Options
    import argparse
    parser = argparse.ArgumentParser(description='LoSoTo - '+_author)
    parser.add_argument('--version', action='version', version=_version.__version__)
    parser.add_argument('--quiet', '-q', dest='quiet', help='Quiet', default=False, action='store_true')
    parser.add_argument('--verbose', '-V', '-v', dest='verbose', help='Verbose', default=False, action='store_true')
    parser.add_argument('--filter', '-f', dest='filter', help='Filter to use with "-i" option to filter on solution set names (default=None)', default=None, type=str)
    parser.add_argument('--info', '-i', dest='info', help='List information about h5parm file (default=False). A filter on the solution set names can be specified with the "-f" option.', default=False, action='store_true')
    parser.add_argument('--delete', '-d', dest='delete', help='Specify a solution table to be deleted. Use the solset/soltab sintax.', default=None, type=str)
    parser.add_argument('h5parm', help='H5parm filename.', default=None, type=str)
    parser.add_argument('parset', help='LoSoTo parset.', nargs='?', default='losoto.parset', type=str)
    args = parser.parse_args()

    logger = _logging.Logger('info')
    atexit.register(my_close_open_files, False) # Suppress info about closing open files at exit

    if args.quiet:
        logger.set_level('warning')
    if args.verbose:
        logger.set_level('debug')
        atexit.register(my_close_open_files, True) # Print info about closing open files at exit

    logging = _logging.logger

    # Check h5parm
    if args.h5parm == None:
        logging.error('No h5parm given.')
        sys.exit(1)

    if not os.path.isfile(args.h5parm):
        logging.critical("Missing h5parm file.")
        sys.exit(1)

    if not tables.is_hdf5_file(args.h5parm):
        logging.critical('File \"%s\" is not a valid HDF5-file!'%(args.h5parm))
        sys.exit(1)

    # do actions that do not require a parset
    if args.info:
        H = h5parm(args.h5parm, readonly=True)
        # List h5parm information if desired
        print(H.printInfo(args.filter, verbose=args.verbose))
        H.close()
        sys.exit(0)
    elif args.delete != None:
        H = h5parm(args.h5parm, readonly=False)
        # Delete the soltab and exit
        solset, soltab = args.delete.split('/')
        ss = H.getSolset(solset)
        st = ss.getSoltab(soltab)
        st.delete()
        H.close()
        logging.warning('To reduce file size after deleting SolTabs use "h5repack infile outfile".')
        sys.exit(0)

    # check parset
    if not os.path.isfile(args.parset) and args.delete == None:
        logging.critical("Missing parset file, I don't know what to do :'(")
        sys.exit(1)

    # read parset
    parser = LosotoParser(args.parset)
    steps = parser.sections()

    # Possible operations, linked to relative function
    import losoto.operations as operations
    ops = {
                   "ABS": operations.abs,
                   "CLIP": operations.clip,
                   "CLOCKTEC": operations.clocktec,
                   "DELETEAXIS": operations.deleteaxis,
                   "POLALIGN": operations.polalign,
                   "DIRECTIONSCREEN": operations.directionscreen,
                   "DUPLICATE": operations.duplicate,
                   "FARADAY": operations.faraday,
                   "FLAG": operations.flag,
                   "FLAGEXTEND": operations.flagextend,
                   "FLAGSTATION": operations.flagstation,
                   "FRJUMP": operations.frjump,
                   "GLOBALDELAY": operations.globaldelay,
                   "INTERPOLATE": operations.interpolate,
                   "INTERPOLATEDIRECTIONS": operations.interpolatedirections,
                   "LOFARBEAM": operations.lofarbeam,
                   "NORM": operations.norm,
                   "PLOT": operations.plot,
                   "PLOTSCREEN": operations.plotscreen,
                   "REPLICATEONAXIS": operations.replicateonaxis,
                   "REFERENCE": operations.reference,
                   "RESET": operations.reset,
                   "RESIDUALS": operations.residuals,
                   "REWEIGHT": operations.reweight,
                   "SMOOTH": operations.smooth,
                   #"SPLITLEAK": operations.splitleak,
                   "STRUCTURE": operations.structure,
                   "PREFACTOR_BANDPASS": operations.prefactor_bandpass,
                   "PREFACTOR_XYOFFSET": operations.prefactor_XYoffset,
                   "TEC": operations.tec,
                   #"TECFIT": operations.tecfit,
                   #"TECSINGLEFREQ": operations.tecsinglefreq,
                   "TECJUMP": operations.tecjump,
                   #"TECSCREEN": operations.tecscreen,
                   # example operation
                   #"EXAMPLE": operations.example
    }

    globalstart = time.time()
    H = h5parm(args.h5parm, readonly=False)
    for step in steps:

        if step == '_global': continue # skip global setting

        op = parser.getstr(step,'Operation')
        if not op in ops:
            logging.error('Unkown operation: '+op)
            continue

        returncode = 0
        with operations.Timer(logging, step, op) as t:
            # global+local selection on axes are applied by this function
            for soltab in getStepSoltabs(parser, step, H):
                returncode += ops[ op ]._run_parser( soltab, parser, step )
            if returncode != 0:
               logging.error("Step \'" + step + "\' incomplete. Try to continue anyway.")
            else:
               logging.info("Step \'" + step + "\' completed successfully.")

        gc.collect()

        # Memory debug
       # def namestr(obj, namespace):
       #     return [name for name in namespace if namespace[name] is obj]
       # referrers = gc.get_referrers(H)
       # for referrer in referrers:
       #     print namestr(referrer, globals())
       #     print namestr(referrer, locals())
       # print gc.garbage
    H.close()

    logging.info("Time for all steps: %i s." % ( time.time() - globalstart ))
    logging.info("Done.")
