import re


from tklib.tkobject import tkObject
from tklib.tkutils import pint, pfloat, print_line, print_data


class tkFilter(tkObject):
    def __init__(self, app, cparams, plugin_dir, module_file, target = "read_data", is_print = False, **args):
        super().__init__()
        
        self.app = app
        self.cparams = cparams
        self._plugin_dir  = plugin_dir
        self._module_file = module_file
        self.target  = target
        self.is_print = is_print

        self.module_names = None
        self.modules   = None
        self.iregion   = None
        self.label     = None
        self.data      = None
        self.ispectrum = None
        self.inf       = None

        self.update(**args)

    def __del__(self):
        pass

    def __str__(self):
        return self.ClassPath()


    def load(self, target = None, is_print = None):
        if target is not None:
            self.target = target
        if is_print is not None:
            self.is_print = is_print

        self.module_names, self.modules \
            = self.app.load_modules(plugin_dir = self._plugin_dir, fmask = self._module_file, 
                                        target = self.target, is_print = self.is_print)

        for m in self.modules:
            input_type  = m.get_input_type(app = self.app, cparams = self.cparams)
            output_type = m.get_output_type(app = self.app, cparams = self.cparams)
            if is_print:
                print(f"  {m.name}: input_type={input_type}  output_type={output_type}")

        return self.module_names, self.modules

    def read_datalist(self, idata = None, imodule = 0, infile = None, target = '',
                        app = None, cparams = None, is_print = False):
        self.load(target = target, is_print = is_print)
        self.inf = self.modules[imodule].read_data(infile, app = app, cparams = cparams, is_print = is_print)

        labels = []
        data_list = []
        for idx in idata:
            if type(idx) is int:
                label,  data = self.find_data_array(0, idx)
            elif type(idx) is str:
                label,  data = self.find_data_array(idx)
            elif type(idx) is list or type(idx) is tuple:
                label,  data = self.find_data_array(idx[0], idx[1])
            else:
                print(f"\nError in tkfilter.read_datalist(): Invalid idata [{idata}]")
                exit()

            labels.append(label)
            data_list.append(data)

        return labels, data_list, self.inf

    def read_data(self, imodule = 0, infile = None, idata = None, target = '', 
                    app = None, cparams = None, is_print = False):
        if type(idata) is list or type(idata) is tuple:
            return self.read_datalist(idata = idata, imodule = imodule, infile = infile, target = target,
                        app = app, cparams = cparams, is_print = is_print)

        self.inf = self.modules[imodule].read_data(infile, app = app, cparams = cparams, is_print = is_print)
        return self.inf
    
    def print_line(self, data_list, format = '{:^10}'):
        print_line(data_list, format)

    def print_data(self, labels = None, data_list = None, label_format = '{:^10}', data_format = '{:>10}', header = None, print_level = 0):
        print_data(labels = labels, data_list = data_list, label_format = label_format, data_format = data_format, header = header, print_level = print_level)

    def get_hash_data(self, idx, inf = None):
        if inf is None:
            inf = self.inf

        labels = inf["labels"]

        hash = {}
        for iregion, ls in enumerate(labels):
            for ispectrum, l in enumerate(ls):
                hash[l] = inf["data_list"][iregion][ispectrum]
        return hash

    def find_label_index(self, regexp, flag = '', inf = None):
        if inf is None:
            inf = self.inf

        labels = inf["labels"]
    
        if type(regexp) is int:
           return 0, regexp
        else:
            idx = pint(regexp, defval = None)
            if idx is not None:
                return 0, idx

        for iregion, ls in enumerate(labels):
            for ispectrum, l in enumerate(ls):
                if flag == '':
                    ret = re.search(regexp, l)
                else:
                    ret = re.search(regexp, l, flag)
                if ret:
                    return iregion, ispectrum

        return None, None

    def find_data_array(self, regexp, flag = '', inf = None):
        if inf is None:
            inf = self.inf

        if type(regexp) is int and type(flag) is int:
            self.iregion = regexp
            self.ispectrum = flag
        else:
            self.iregion, self.ispectrum = self.find_label_index(regexp, flag, inf = inf)
    
        if self.iregion is None:
            return None, None

        self.label = inf["labels"][self.iregion][self.ispectrum]
        self.data  = inf["data_list"][self.iregion][self.ispectrum]

        return self.label, self.data
        