#! /usr/bin/env python
# -*- coding: utf-8 -*-
'''
Created on 2020/6/4 17:25:47

@author: LiuKuan
@copyright: Apache License, Version 2.0
'''
import inspect, sys, time, traceback, math, re, codecs
from datetime import datetime
#===============================================================================
# 交互式运行
#===============================================================================
_PRINT_FUNC_COUNT = 3

__all__ = ['run']

# 执行计时
def _time_run(_kvfunc, **kws):
    try:
        name, func = _kvfunc
        print( '{}==begin[date:{}]'.format(name, datetime.now().strftime('%Y-%m-%d %H:%M:%S')) )
        t0 = time.time()
        func(**kws)
    except SystemExit:
        exit(0)
    except Exception as e:
        print ( '\nexception in call function---->\n%s' % traceback.format_exc() )
    finally:
        elapse = time.time() - t0
        print ( '{}==end[use time:{}s]\n'.format(name, elapse) )

#从文件提取特定函数名字,主要是用于排序
def _find_order_names(filename, re_pat):
    with codecs.open(filename, encoding='utf8') as f:
        for i,line in enumerate(f, 1):
            res = re_pat.match(line)
            if res:
                yield i,res.group(1)

def run(_opt='last', _suffix ='_lk', **kws):
    '''执行以 _suffix 结尾的函数
    :param _opt: last/first/select/once/all/function_name
    :return:
    '''
    RE_PAT = re.compile(r"^def\s*(.*?{pat})|({pat}.*?)\(.*?\):.*".format(pat = _suffix))

    # 获取所有 _suffix 结尾的函数
    mainMod = sys.modules['__main__']
    kvList = [(k.strip(_suffix), v)
              for k,v in inspect.getmembers(mainMod, inspect.isfunction)
              if k.endswith(_suffix)]

    # 检测是否有测试用例
    if not kvList:
        return

    # 按照代码文本顺序排序
    _kvOrder = {}
    for order, name in  _find_order_names(mainMod.__file__, RE_PAT):
        _kvOrder[name.strip(_suffix)] = order
    kvList.sort(key = lambda pair: _kvOrder[pair[0]])

    # 根据选择,执行函数
    if _opt == 'first':
        return _time_run(kvList[0], **kws)
    elif _opt == 'last':
        return _time_run(kvList[-1], **kws)
    elif _opt == 'all':
        for kv in kvList:
            _time_run(kv, **kws)
    elif _opt in ['select','once', '']:
        listLen = len(kvList)
        while True:
            index_width = math.ceil(math.log10(listLen)) + 2
            name_width = max(len(kv[0]) for kv in kvList) + 2
            fmt = "%0{}s==%-0{}s".format(index_width, name_width)

            for i, kv in enumerate(kvList):
                print(fmt % (f"<{i}>", f"<{kv[0]}>"), end=" ")
                if (i+1) % _PRINT_FUNC_COUNT == 0:
                    print()
            if (i+1) % _PRINT_FUNC_COUNT != 0:
                print()

            i = input('which func do you want to run , -1=quit , -2=run-all:')
            try:
                i = int(i)
            except:
                i = listLen - 1
            if i == -2:
                for kv in kvList:
                    _time_run(kv, **kws)
                return
            elif i == -1:
                return
            else:
                i = (i + listLen) % listLen
                _time_run( kvList[i], **kws)

            if _opt == 'once':
                return
    else :
        if not isinstance(_opt, list):
            run_list = [ _opt ]
        else:
            run_list = _opt

        for _run_op in run_list:
            for kv in kvList:
                if (isinstance(_run_op, str) and kv[0] == _run_op.strip(_suffix) ) \
                        or (inspect.isfunction(_run_op) and kv[1] == _run_op):
                    _time_run(kv, **kws)

