"""
提供基本的UAII类，把各种函数封装在这里。
"""
import os, sys
import numpy as np
import damei as dm
import cv2
logger = dm.getLogger('base_uaii')
from . import general


class BaseUAII(object):
    def __init__(self):
        self._modules = None
        self._scripts = None
        self._ios = None
        self._streams = None
        self._name2cls = None
        self.cfg = None

    def _configure(self):
        """初始化配置，还需要考虑重新初始化配置"""
        streams = self.streams
        for i, (k, v) in enumerate(self.streams.module_dict.items()):
             print(i, k, isinstance(v, type))
        for i, (k, v) in enumerate(self.modules.module_dict.items()):
            print(i, k, type(v), v, isinstance(v, type))
        exit()
        pass

    def register_name2cls(self):
        name2cls = dict()
        for k, v in self.modules.module_dict.items():
            name = k
            name2cls[name] = 'MODULE'
        for k, v in self.scripts.module_dict.items():
            name2cls[k] = 'SCRIPT'
        for k, v in self.streams.module_dict.items():
            name2cls[k] = 'STREAM'
        for k, v in self.ios.module_dict.items():
            name2cls[k] = 'IO'
        return name2cls

    @property
    def modules(self):
        return self._modules

    @property
    def scripts(self):
        return self._scripts

    @property
    def streams(self):
        return self._streams

    @property
    def ios(self):
        return self._ios

    def get_module(self, name, cls=None, *args, **kwargs):
        """根据模块名和类别获取模块，是未初始化的"""
        # print(args, kwargs, cls)
        ps = self.ps(**kwargs)
        # 输入的名字也可以是ID
        exist_names = [x.split()[2] for x in ps.split('\n')[1::]]
        if name not in exist_names:
            exist_ids = [x.split()[0] for x in ps.split('\n')[1::]]
            assert len(exist_ids) == len(exist_names)
            if name in exist_ids:
                name = exist_names[exist_ids.index(name)]
            else:
                raise ModuleNotFoundError(f"Expected module name: '{name}' not found in exist modules: {exist_names}.")

        try:
            cls = cls if cls else self._name2cls[name]
        except Exception as e:
            raise ModuleNotFoundError(
                f'Error: {e}. \nAll modules: {self.modules}.')

        # print(cls)
        if cls == 'MODULE':
            return self.modules.get(name)
        elif cls == 'SCRIPT':
            return self.scripts.get(name)
        elif cls == 'STREAM':
            return self.streams.get(name)
        elif cls == 'IO':
            return self.ios.get(name)
        else:
            raise NotImplementedError(f'UAII get module name: {name} cls: {cls} not implemented.')

    def build_stream(self, cfg=None, **kwargs):
        """
        根据流配置文件创建新的流，注册到streams里
        cfg: stream config, for example：
            cfg = dict(
                type='radar_detection_stream',
                description='雷达目标探测流',
                models=[
                    dict(type='radardet', cfg=None)
            ])
        return: stream object
        """

        name = cfg['type']
        if name in self.streams.names:
            logger.warn(f'Build stream, name:{name} exist, return existing stream.')
            return self.get_stream(name=name)

        self.streams.build_new_stream(cfg, **kwargs)

        return self.get_stream(name)

    def get_stream(self, name):
        """获得存在的流，并初始化内部的所有模块"""
        stream = self.get_module(name=name, cls='STREAM')
        return stream

    def get_model(self, name):
        """读取单独的模块，内部是把单独的模块组装成流"""
        exists_streams = self.streams.names
        if name in exists_streams:
            mono_flow = self.get_module(name=name, cls='STREAM')
        else:
            cfg = dict(
                type=f'{name}_flow',
                description=f'mono module flow: {name}',
                models=[
                    dict(type=name, cfg=None),
                    ]
            )
            mono_flow = self.build_stream(cfg=cfg)
        return mono_flow

    def stream_info(self, name):
        return self.get_stream(name=name).info()

    def ps(self, stream=None, module=None, io=None, script=None):
        """返回全部模块的状态"""
        ps0 = [['ID', 'TYPE', 'NAME', 'STATUS', 'INCLUDE', 'DESCRIPTION']]
        if stream is None and module is None and io is None and script is None:
            tmp = self.streams.ps(include_dict=self.modules.name2id_dict)
            ps0 += tmp
            tmp2 = self.modules.ps(include_dict=self.ios.name2id_dict)
            ps0 += tmp2
            ps0 += self.ios.ps()
            # print(ps0, len(ps0))
            # ps0.append(self.scripts.ps())
        else:
            if stream:
                tmp = self.streams.ps(include_dict=self.modules.name2id_dict)
                ps0 += tmp
            if module:
                tmp = self.modules.ps(include_dict=self.modules.name2id_dict)
                ps0 += tmp
            if io:
                ps0 += self.ios.ps(module=None)
            if script:
                ps0 += self.scripts.ps(module=None)
        # ps_all = ps0
        # lenth = np.array([[len(x) for x in xx] for xx in ps_all])  # (n, 4)
        # print()
        # lenth = np.max(lenth, axis=0)  # (4,)
        # ps_list = [[f'{x:<{lenth[i]}}' for i, x in enumerate(xx)] for xx in ps_all]
        # ps_str = '\n'.join(['  '.join(x) for x in ps_list])
        ps_str = dm.misc.list2table(ps0)
        return ps_str

    def show_vis(self, ret, im0, target_names):

        return general.single_plot(ret, im0, target_names=target_names)

