#from .base_definition import (Trend, table, insert, column,
#                              insertdec, columndec, keyword, header, headerinsert)

from .oivisdb import (OIVisDB, DBDefinition, table, insert, column,
                      insertdec, columndec, keyword, header, headerinsert,
                      nightof, get_fileid, FILEID_TYPE
                      )
try:
    from astropy.io import fits as fits
except:
    import pyfits as fits

import os
import numpy as np

# Extver
FT_P2 = 22
FT_P1 = 21
SC_P1 = 11
SC_P2 = 12
SC = 10
FT = 20

OI_VIS2_FT_P2 = ("OI_VIS2",FT_P2)
OI_VIS2_FT_P1 = ("OI_VIS2",FT_P1)
OI_VIS2_SC_P2 = ("OI_VIS2",SC_P2)
OI_VIS2_SC_P1 = ("OI_VIS2",SC_P1)
OI_VIS2_FT = ("OI_VIS2",FT)
OI_VIS2_SC = ("OI_VIS2",SC)

OI_VIS_FT_P2 = ("OI_VIS",FT_P2)
OI_VIS_FT_P1 = ("OI_VIS",FT_P1)
OI_VIS_SC_P2 = ("OI_VIS",SC_P2)
OI_VIS_SC_P1 = ("OI_VIS",SC_P1)
OI_VIS_FT = ("OI_VIS",FT)
OI_VIS_SC = ("OI_VIS",SC)

OI_T3_FT_P2 = ("OI_T3",FT_P2)
OI_T3_FT_P1 = ("OI_T3",FT_P1)
OI_T3_SC_P2 = ("OI_T3",SC_P2)
OI_T3_SC_P1 = ("OI_T3",SC_P1)
OI_T3_FT = ("OI_T3",FT)
OI_T3_SC = ("OI_T3",SC)

OI_FLUX_FT_P2 = ("OI_FLUX",FT_P2)
OI_FLUX_FT_P1 = ("OI_FLUX",FT_P1)
OI_FLUX_SC_P2 = ("OI_FLUX",SC_P2)
OI_FLUX_SC_P1 = ("OI_FLUX",SC_P1)
OI_FLUX_FT = ("OI_FLUX",FT)
OI_FLUX_SC = ("OI_FLUX",SC)

OI_WAVELENGTH_FT_P2 = ("OI_WAVELENGTH",FT_P2)
OI_WAVELENGTH_FT_P1 = ("OI_WAVELENGTH",FT_P1)
OI_WAVELENGTH_SC_P2 = ("OI_WAVELENGTH",SC_P2)
OI_WAVELENGTH_SC_P1 = ("OI_WAVELENGTH",SC_P1)
OI_WAVELENGTH_FT = ("OI_WAVELENGTH",FT)
OI_WAVELENGTH_SC = ("OI_WAVELENGTH",SC)

OI_TARGET = "OI_TARGET"
OI_ARRAY  = "OI_ARRAY"

idtest = 0;

def convert_recarray_row(keys, row):
    tmp = []
    for k in keys:
        v = row[k]

        if getattr(v, "shape", None) == tuple():
            tmp.append(v.item())
        else:
            tmp.append(v)
    return tmp

class OIVIS(DBDefinition, fits.HDUList):
    ftype = "OIVIS"
    databases = [OIVisDB]
    @classmethod
    def parse_file(cl, fh):
        if isinstance(fh, str):
            fh = fits.open(fh)
        try:
            catg = fh[0].header["ESO DPR CATG"]
        except KeyError:
            catg = fh[0].header["ESO PRO CATG"]

        if "VIS" in catg or "TF" in catg:
            return cl(fh)

        raise ValueError("Not a 'VIS' file")

    def get_hdu(self, name):
        if isinstance(name, tuple):
            name, ver = name
        else:
            name, ver = name, None

        if ver is None:
            return self[name]

        if isinstance(ver, str):
            names = [(f.name,f.header.get('INSNAME',None)) for f in self]
            try:
                id = names.index((name,ver))
            except ValueError as e:
                raise KeyError(e.message)
            return self[id]
        else:
            return self[name, ver]

    ## File
    files = table('files', [('FILENAME', 'TEXT'), ('FILEID',FILEID_TYPE)],
                  keys_index=['FILEID'],
                  links= [("vis2", ("FILEID",)),
                          ("vis", ("FILEID",)),
                          ("t3", ("FILEID",)),
                          ("flux", ("FILEID",)),
                          ("headers", ("FILEID",))
                         ]
                  )

    @insertdec(files)
    def f_insert(fh, tbl):
        # print ("f_insert")
        finfo = fh[0].fileinfo()
        if not finfo:
            filename = "?"
        else:
            filename = str(os.path.split(finfo['file'].name))
        return {"FILENAME":filename, "FILEID":get_fileid(fh)}

    ## Main HEADER
    headers = table('headers',[("ESO INS SPEC RES", "TEXT"),
                              ("ESO INS POLA MODE", "TEXT"),
                              ("ESO INS TIM2 PERIOD","TEXT"),
                              ("ESO DET2 SEQ1 DIT","TEXT"),
                              ("ESO PRO CATG","TEXT"),
                              ("MJD-OBS", "FLOAT"),
                              ("FILEID", FILEID_TYPE),
                              ('NIGHT', 'TEXT') # computed ESO Night
                              ],
                              keys_index=["FILEID","ESO PRO CATG","NIGHT"],
                              links=[("files", ("FILEID",)),
                                     ("vis2", ("FILEID",)),
                                     ("vis", ("FILEID",)),
                                     ("t3", ("FILEID",)),
                                     ("flux", ("FILEID",))]
                    )
    @insertdec(headers)
    def h_insert(fh, tbl):
        # print ("h_insert")
        keys = list(tbl.columns.keys())
        keys.remove('FILEID')
        keys.remove('NIGHT')
        d = {k: fh[0].header[k] for k in keys }
        d["FILEID"] = get_fileid(fh)
        d['NIGHT'] = nightof(d['MJD-OBS'])
        return d;

    ## OI_VIS2
    vis2 = table('vis2',
                   [('TARGET_ID', 'INTEGER'),
                   ('TIME', 'FLOAT'),
                   ('MJD', 'FLOAT'),
                   ('INT_TIME', 'FLOAT'),
                   ('VIS2DATA','array'),
                   ('VIS2ERR', 'array'),
                   ('UCOORD', 'FLOAT'),
                   ('VCOORD', 'FLOAT'),
                   ('STA1_INDEX', 'INTEGER'),
                   ('STA2_INDEX', 'INTEGER'),
                   ('FLAG', 'array'),
                   ('INSNAME', 'TEXT'),
                   ('BASENAME', "TEXT"),
                   ('FILEID', FILEID_TYPE)

                   ],
                  keys_index=['MJD', 'FILEID', 'STA1_INDEX','STA2_INDEX', 'INSNAME'],
                  links = [("files", ("FILEID",)),
                           ("targets",("TARGET_ID", "FILEID")),
                           ("arrays", ("FILEID",)),
                           ("headers", ("FILEID",)),
                           ("wavelengths", ("FILEID", "INSNAME")) ]
                  )

    @insertdec(vis2, many=True)
    def b2_insert(fh, tbl):
        # print ("b2_insert")
        lookup = [
                  OI_VIS2_FT_P1,
                  OI_VIS2_SC_P1,
                  OI_VIS2_FT_P2,
                  OI_VIS2_SC_P2,
                  OI_VIS2_FT   ,
                  OI_VIS2_SC   
                  ]
        output = []
        id = get_fileid(fh)
        keys = ['TIME','MJD','INT_TIME',
                'VIS2DATA','VIS2ERR',
                'UCOORD','VCOORD',
                'FLAG']

        for hdu in lookup:
            try:
                h = fh.get_hdu(hdu)
            except KeyError:
                continue
            
            ins_name = h.header['INSNAME']
            # print ("OI_VIS2, "+ins_name)
            keys_present = list(set(h.columns.names).intersection(keys))

            for row in h.data:
                tmp = convert_recarray_row(keys_present, row)
                tmp += [id, ins_name, int(row["STA_INDEX"][0]+idtest), int(row["STA_INDEX"][1]+idtest),
                        int(row["TARGET_ID"]+idtest)]
                output.append( tmp )
        return keys_present+["FILEID","INSNAME","STA1_INDEX", "STA2_INDEX","TARGET_ID"], output

    ## OI_VIS
    vis = table('vis',
                   [('TARGET_ID', 'INTEGER'),
                   ('TIME', 'FLOAT'),
                   ('MJD', 'FLOAT'),
                   ('INT_TIME', 'FLOAT'),
                   ('UCOORD', 'FLOAT'),
                   ('VCOORD', 'FLOAT'),
                   ('STA1_INDEX', 'INTEGER'),
                   ('STA2_INDEX', 'INTEGER'),
                   ('FLAG', 'array'),
                   ('INSNAME', 'TEXT'),
                   ('VISAMP', "array"),
                   ('VISAMPERR', "array"),
                   ('VISPHI', "array"),
                   ('VISPHIERR', "array"),
                   ('BASENAME', "TEXT"),
                   ('FILEID', FILEID_TYPE)
                   ],
                  keys_index=['MJD', 'FILEID', 'STA1_INDEX','STA2_INDEX', 'INSNAME'],
                  links = [("files", ("FILEID",)),
                           ("vis2", ("FILEID", "INSNAME", "STA1_INDEX", "STA2_INDEX")),
                           # ("targets",("TARGET_ID", "FILEID")),
                           ("targets",("TARGET_ID",)),
                           ("arrays", ("FILEID",)),
                           ("headers", ("FILEID",)),
                           ("wavelengths", ("FILEID", "INSNAME")) ]
                  )

    @insertdec(vis, many=True)
    def b_insert(fh, tbl):
        # print ("b_insert")
        lookup = [
                  OI_VIS_FT_P1,
                  OI_VIS_SC_P1,
                  OI_VIS_FT_P2,
                  OI_VIS_SC_P2,
                  OI_VIS_FT   ,
                  OI_VIS_SC   
                  ]
        id = get_fileid(fh)
        output = []
        keys = ['TIME','MJD','INT_TIME',
                'VISAMP','VISAMPERR',
                'VISPHI','VISPHIERR',
                'UCOORD','VCOORD',
                'FLAG']

        for hdu in lookup:
            try:
                h = fh.get_hdu(hdu)
            except KeyError:
                continue
            
            ins_name = h.header['INSNAME']
            # print ("OI_VIS, "+ins_name)
            keys_present = list(set(h.columns.names).intersection(keys))

            for row in h.data:
                tmp = convert_recarray_row(keys_present, row)
                tmp += [id, ins_name,int(row["STA_INDEX"][0]+idtest), int(row["STA_INDEX"][1])+idtest,
                        int(row["TARGET_ID"]+idtest)]
                output.append( tmp )
        return keys_present+["FILEID","INSNAME","STA1_INDEX", "STA2_INDEX","TARGET_ID"], output

    ## OI_T3
    t3 = table('t3',
                   [('TARGET_ID', 'INTEGER'),
                   ('TIME', 'FLOAT'),
                   ('MJD', 'FLOAT'),
                   ('INT_TIME', 'FLOAT'),
                   ('U1COORD', 'FLOAT'),
                   ('V1COORD', 'FLOAT'),
                   ('U2COORD', 'FLOAT'),
                   ('V2COORD', 'FLOAT'),
                   ('STA1_INDEX', 'INTEGER'),
                   ('STA2_INDEX', 'INTEGER'),
                   ('STA3_INDEX', 'INTEGER'),
                   ('FLAG', 'array'),
                   ('INSNAME', 'TEXT'),
                   ('T3AMP', "array"),
                   ('T3AMPERR', "array"),
                   ('T3PHI', "array"),
                   ('T3PHIERR', "array"),
                   ('BASENAME', "TEXT"),
                   ('FILEID', FILEID_TYPE)
                   ],
                  keys_index=['MJD', 'FILEID', 'STA1_INDEX','STA2_INDEX','STA3_INDEX', 'INSNAME'],
                  links = [("files", ("FILEID",)),
                           ("targets",("TARGET_ID", "FILEID")),
                           ("arrays", ("FILEID",)),
                           ("headers", ("FILEID",)),
                           ("wavelengths", ("FILEID", "INSNAME")) ]
                  )

    @insertdec(t3, many=True)
    def t3_insert(fh, tbl):
        # print ("t3_insert")
        lookup = [
                  OI_T3_FT_P1,
                  OI_T3_SC_P1,
                  OI_T3_FT_P2,
                  OI_T3_SC_P2,
                  OI_T3_FT   ,
                  OI_T3_SC   ]
        id = get_fileid(fh)
        output = []
        keys = ['TIME','MJD','INT_TIME',
                'T3AMP','T3AMPERR',
                'T3PHI','T3PHIERR',
                'U1COORD','V1COORD','U2COORD','V2COORD',
                'FLAG']

        for hdu in lookup:
            try:
                h = fh.get_hdu(hdu)
            except KeyError:
                continue

            ins_name = h.header['INSNAME']
            # print ("OI_T3, "+ins_name)
            keys_present = list(set(h.columns.names).intersection(keys))

            for row in h.data:
                tmp = convert_recarray_row(keys_present, row)
                tmp += [id, ins_name, int(row["STA_INDEX"][0]+idtest), int(row["STA_INDEX"][1]+idtest),
                        int(row["STA_INDEX"][2]+idtest),int(row["TARGET_ID"]+idtest)]
                output.append( tmp )
        return keys_present+["FILEID","INSNAME","STA1_INDEX", "STA2_INDEX", "STA3_INDEX","TARGET_ID"], output

    ## OI_FLUX
    flux = table('flux',
                   [('TARGET_ID', 'INTEGER'),
                   ('TIME', 'FLOAT'),
                   ('MJD', 'FLOAT'),
                   ('INT_TIME', 'FLOAT'),
                   ('STA1_INDEX', 'INTEGER'),
                   ('FLAG', 'array'),
                   ('INSNAME', 'TEXT'),
                   ('FLUX', "array"),
                   ('FLUXERR', "array"),
                   ('BASENAME', "TEXT"),
                   ('FILEID', FILEID_TYPE)
                   ],
                  keys_index=['MJD', 'FILEID', 'STA1_INDEX','INSNAME'],
                  links = [("files", ("FILEID",)),
                           ("targets",("TARGET_ID", "FILEID")),
                           ("arrays", ("FILEID",)),
                           ("headers", ("FILEID",)),
                           ("wavelengths", ("FILEID", "INSNAME")) ]
                  )

    @insertdec(flux, many=True)
    def flux_insert(fh, tbl):
        # print ("flux_insert")
        lookup = [
                  OI_FLUX_FT_P1,
                  OI_FLUX_SC_P1,
                  OI_FLUX_FT_P2,
                  OI_FLUX_SC_P2,
                  OI_FLUX_FT   ,
                  OI_FLUX_SC   
                  ]
        id = get_fileid(fh)
        output = []
        keys = ['TIME','MJD','INT_TIME',
                'FLUX','FLUXERR','FLAG']

        for hdu in lookup:
            try:
                h = fh.get_hdu(hdu)
            except KeyError:
                continue

            ins_name = h.header['INSNAME']
            keys_present = list(set(h.columns.names).intersection(keys))

            for row in h.data:
                tmp = convert_recarray_row(keys_present, row)
                tmp += [id, ins_name,int(row["STA_INDEX"]+idtest),
                        int(row["TARGET_ID"]+idtest) ]
                output.append( tmp )
        return keys_present+["FILEID","INSNAME","STA1_INDEX","TARGET_ID"], output


    ## OI_TARGET
    targets = table("targets", [('TARGET_ID', 'INTEGER'),
                                ('TARGET', 'TEXT'),
                                ('RAEP0', 'FLOAT'), ('DECEP0', 'FLOAT'),
                                ('FILEID', FILEID_TYPE)
                                ],
                    keys_index = ['FILEID','TARGET_ID'],
                    links = [("files",  ("FILEID",)),
                             ("headers", ("FILEID",))]
                    )

    @insertdec(targets, many=True)
    def t_insert(fh, tbl):
        # print ("t_insert")
        keys = ['TARGET','RAEP0', 'DECEP0']
        id = get_fileid(fh)
        hdu = fh.get_hdu("OI_TARGET")
        output = []
        for row in hdu.data:
            tmp = convert_recarray_row(keys, row)
            tmp += [id, int(row["TARGET_ID"]+idtest) ]
            output.append(tmp)
        return keys+["FILEID","TARGET_ID"], output

    ## OI_ARRAY
    arrays =  table("arrays",
                    [('TEL_NAME', 'TEXT'), ('STA_NAME', 'TEXT'),
                     ('STA_INDEX', 'INTEGER'),
                     ('DIAMETER', 'FLOAT'), ('STAXYZ', 'array'),
                     ('MNTSTA', 'INTEGER'),
                     ('FILEID', FILEID_TYPE)
                     ],
                     keys_index = ["FILEID","STA_NAME","STA_INDEX"],
                    links = [("files",   ("FILEID",)),
                             ("headers", ("FILEID",)),
                             #### for vis, vis2, t3, flux other
                             #### links are made with the STA#_INDEX
                             #### here are the static ones
                             ("vis", ("FILEID",)),
                             ("vis2", ("FILEID",)),
                             ("t3", ("FILEID",)),
                             ("flux", ("FILEID",))
                             ]
                   )
    @insertdec(arrays, many=True)
    def a_insert(fh, tbl):
        # print ("a_insert")
        keys = ['TEL_NAME','STA_NAME',
                'DIAMETER', 'STAXYZ',
                'MNTSTA']
        id = get_fileid(fh)
        hdu = fh.get_hdu("OI_ARRAY")
        output = []

        for row in hdu.data:
            tmp = convert_recarray_row(keys, row)
            tmp += [id, int(row["STA_INDEX"]+idtest) ]
            # tmp += [id]
            output.append(tmp)

        return keys+[ "FILEID","STA_INDEX"], output

    ## OI_WAVELENGTH
    wavelengths = table("wavelengths",
                        [ ('EFF_WAVE', 'array'),
                          ('EFF_BAND', 'array'),
                          ('FILEID', FILEID_TYPE),
                          ('INSNAME', "TEXT"),
                          ("DET_NAME", "TEXT"),
                          ("POLAR_ID", "INTEGER"),
                          ("WImin", "INTEGER"),
                          ("WImax", "INTEGER"),
                          ("Wmin", "FLOAT"),
                          ("Wmax", "FLOAT")
                        ],
                        keys_index = ["FILEID", "INSNAME"],
                        links = [("files",  ("FILEID",)),
                                ("headers", ("FILEID",))]
                        )
    @insertdec(wavelengths, many=True)
    def w_insert(fh, tbl):
        # print ("w_insert")
        keys = ['EFF_WAVE', 'EFF_BAND']
        lookup = [('sc',0,OI_WAVELENGTH_SC   ),
                  ('sc',1,OI_WAVELENGTH_SC_P1),
                  ('sc',2,OI_WAVELENGTH_SC_P2),
                  ('ft',0,OI_WAVELENGTH_FT   ),
                  ('ft',1,OI_WAVELENGTH_FT_P1),
                  ('ft',2,OI_WAVELENGTH_FT_P2)]
        output = []
        id = get_fileid(fh)
        for det_name, polar_id,  hdu in lookup:
            try:
                h = fh.get_hdu(hdu)
            except KeyError:
                continue

            ins_name = h.header['INSNAME']
            # print ("OI_WAVELENGTH, "+ins_name)
            data = h.data
            w = data['EFF_WAVE']
            output.append([data[k] for k in keys]+\
                          [id,ins_name,det_name, polar_id]+\
                          [0, len(w), float(np.min(w)), float(np.max(w))]
                          )
        return keys+["FILEID","INSNAME","DET_NAME","POLAR_ID"]+["WImin", "WImax", "Wmin", "Wmax"], output


