# -*- coding: utf-8 -*-
"""
Created on Sat Jul 27 14:07:25 2024

现场测试数据，在不同特征组合情况下的精度、召回率分析程序

@author: ym
"""
import os.path
import numpy as np
from scipy.spatial.distance import cdist
import matplotlib.pyplot as plt
import sys
sys.path.append(r"D:\DetectTracking")
from tracking.utils.read_data import extract_data, read_deletedBarcode_file, read_tracking_output
# from tracking.dotrack.dotracks import Track

from one2n_contrast import compute_recall_precision, show_recall_prec
from one2n_contrast import performance_evaluate, one2n_return, one2n_deleted

def compute_similar(feat1, feat2):

    if len(feat1)==0 or len(feat2)==0: 
        return 0
    
    similar = 1 - np.maximum(0.0, cdist(feat1, feat2, metric = 'cosine'))
    smean = np.mean(similar)
    
    return smean
    

def update_event(datapath):
    '''一次购物事件，包含 8 个keys
    back_sole_boxes：后摄boxes
    front_sole_boxes：前摄boxes
    back_sole_feats：后摄特征
    front_sole_feats：前摄特征
    feats_compose：将前后摄特征进行合并
    feats_select：特征选择，优先选择前摄特征
    '''
    event = {}
    # event['front_tracking_boxes'] = []
    # event['front_tracking_feats'] = {}
    # event['back_tracking_boxes'] = []
    # event['back_tracking_feats'] = {}
    
    event['back_sole_boxes'] = np.empty((0, 9), dtype=np.float64)
    event['front_sole_boxes'] = np.empty((0, 9), dtype=np.float64)
    
    event['back_sole_feats'] = np.empty((0, 256), dtype=np.float64)
    event['front_sole_feats'] = np.empty((0, 256), dtype=np.float64)

    event['feats_compose'] = np.empty((0, 256), dtype=np.float64)
    event['feats_select'] = np.empty((0, 256), dtype=np.float64)


    # '''读取 track.data 文件中的数据'''
    # fpath_0_track = os.path.join(datapath, '0_track.data')
    # fpath_1_track = os.path.join(datapath, '1_track.data')
    # if os.path.exists(fpath_0_track) and os.path.isfile(fpath_0_track):
    #     _, _, _, _, tracking_boxes, tracking_feat_dict = extract_data(fpath_0_track)
    #     event['back_tracking_boxes'] = tracking_boxes
    #     event['back_tracking_feats'] = tracking_feat_dict
    
    # if os.path.exists(fpath_1_track) and os.path.isfile(fpath_1_track):
    #     _, _, _, _, tracking_boxes, tracking_feat_dict = extract_data(fpath_1_track)
    #     event['front_tracking_boxes'] = tracking_boxes
    #     event['front_tracking_feats'] = tracking_feat_dict
    
# =============================================================================
#     '''================1. 直接指定读取，速度快======================================'''    
#     '''读取 tracking_output.data 文件中的数据'''    
#     fpath_0_tracking = os.path.join(datapath, '0_tracking_output.data')
#     fpath_1_tracking = os.path.join(datapath, '1_tracking_output.data')    
#     if os.path.exists(fpath_0_tracking) and os.path.isfile(fpath_0_tracking):
#         tracking_output_boxes, tracking_output_feats = read_tracking_output(fpath_0_tracking)
#         event['back_sole_boxes'] = tracking_output_boxes
#         event['back_sole_feats'] = tracking_output_feats
#     
#     if os.path.exists(fpath_1_tracking) and os.path.isfile(fpath_1_tracking):
#         tracking_output_boxes, tracking_output_feats = read_tracking_output(fpath_1_tracking)
#         event['front_sole_boxes'] = tracking_output_boxes
#         event['front_sole_feats'] = tracking_output_feats
# =============================================================================


    '''================2. 遍历方式读取（与以上方式二选一）======================================'''
    '''读取当前事件的 data 文件'''
    for filename in os.listdir(datapath):
        # filename = '1_track.data'
        fpath = os.path.join(datapath, filename)
        CamerType = filename.split('_')[0]
        # if os.path.isfile(fpath) and filename.find("track.data")>0:
        #     bboxes, ffeats, trackerboxes, tracker_feat_dict, tracking_boxes, tracking_feat_dict = extract_data(fpath)
            
        #     if CamerType == '0':
        #         event['back_tracking_boxes'] = tracking_boxes
        #         event['back_tracking_feats'] = tracking_feat_dict
        #     elif CamerType == '1':
        #         event['front_tracking_boxes'] = tracking_boxes
        #         event['front_tracking_feats'] = tracking_feat_dict

        if os.path.isfile(fpath) and filename.find("tracking_output.data")>0:
            tracking_output_boxes, tracking_output_feats = read_tracking_output(fpath)
            if CamerType == '0':
                event['back_sole_boxes'] = tracking_output_boxes
                event['back_sole_feats'] = tracking_output_feats
            elif CamerType == '1':
                event['front_sole_boxes'] = tracking_output_boxes
                event['front_sole_feats'] = tracking_output_feats

    
    '''事件的特征表征方式选择'''
    fs_feats = event['front_sole_feats']
    bs_feats = event['back_sole_feats']
    
    '''1. 如果前后摄均没有轨迹选择输出，返回'''
    condt1 = len(fs_feats) + len(bs_feats) == 0
    if condt1:
        return event
    
    
    '''2. 构造综合特征'''   
    feats_compose = np.empty((0, 256), dtype=np.float64)
    if len(fs_feats):
        feats_compose = np.concatenate((feats_compose, fs_feats), axis=0)
    if len(bs_feats):
        feats_compose = np.concatenate((feats_compose, bs_feats), axis=0)
    event['feats_compose'] = feats_compose
    
    '''3. 构造前摄特征'''
    if len(fs_feats):
        event['feats_select'] = fs_feats
        return event


    '''4. 从前摄输出轨迹中选取特定轨迹对应的特征'''
# =============================================================================
#     ftrboxes = event['front_tracking_boxes']
#     ftrfeats = event['front_tracking_feats']
#     
#     condt2 = len(ftrboxes) + len(ftrfeats) == 0
#     condt3 = len(ftrfeats) != len(ftrboxes)
#     if condt2 or condt3:
#         return event
# 
#     bprops = []
#     for boxes in ftrboxes:
#         track = Track(boxes)
#         bprops.append(max(track.trajdist))
#         
#     index = bprops.index(max(bprops))
#     box_select = ftrboxes[index]
#     tid = int(box_select[0, 4])
#     
#     feat_select = ftrfeats[f"track_{tid}"]
#     feats_select = np.empty((0, 256), dtype=np.float64)
#     for fid_bid, feat in feat_select['feats'].items():
#         feats_select = np.concatenate((feats_select, feat[None, :]), axis=0)
#     event['feats_select'] = feats_select
# =============================================================================

    return event


def creatd_deletedBarcode_front(filepath):
    '''
    生成deletedBarcodeTest.txt
    '''

    # filepath = r'\\192.168.1.28\share\测试_202406\0723\0723_1\deletedBarcode.txt'
    basepath, _ = os.path.split(filepath)
      
    bcdlist = read_deletedBarcode_file(filepath)
    
    MatchList = []
    k = 0
    for s_list in bcdlist:
        getout_fold = s_list['SeqDir'].strip()
        getout_path = os.path.join(basepath, getout_fold)
        
        '''取出事件文件夹不存在，跳出循环'''
        if not os.path.exists(getout_path) and not os.path.isdir(getout_path):
            continue

        day, hms = getout_fold.strip('_').split('-')

        ''' 生成取出事件字典 '''
        getout_event = {}
        getout_event['barcode'] = s_list['Deleted'].strip()
        getout_event['path'] = getout_path
        
        getout_event['feats_compose'] = np.empty((0, 256), dtype=np.float64)
        getout_event['feats_select'] = np.empty((0, 256), dtype=np.float64)
        

        InputList = []
        barcodes = [s.strip() for s in s_list['barcode']]
        similarity = [float(s.strip()) for s in s_list['similarity']]
        for i, barcode in enumerate(barcodes):
            
            ''' 生成放入事件字典 '''
            input_event = {}
            
            input_folds, times = [], []            
            for pathname in os.listdir(basepath):
                if pathname.endswith('_'): continue
                if os.path.isfile(os.path.join(basepath, pathname)):continue
                
                infold = pathname.split('_')
                if len(infold)!=2: continue  
                if len(infold[0])<=14 or len(infold[1])<=10: continue     

                day1, hms1 = infold[0].split('-') 

                if day1==day and infold[1]==barcode and int(hms1)<int(hms):
                    input_folds.append(pathname)
                    times.append(int(hms1))
            if len(input_folds)==0: continue
                
            ''' 根据时间排序，选择离取出操作最近时间的文件夹，作为取出操作应的放入操作所对应的文件夹 '''
            input_fold = input_folds[times.index(max(times))]
            input_path = os.path.join(basepath, input_fold)
            if not os.path.exists(getout_path) and not os.path.isdir(getout_path):
                continue

            input_event['barcode'] = barcode
            input_event['path'] = input_path
            input_event['similarity'] = float(similarity[i])
            input_event['feats_compose'] = np.empty((0, 256), dtype=np.float64)
            input_event['feats_select'] = np.empty((0, 256), dtype=np.float64)
            
            
            InputList.append(input_event)
            
        MatchList.append((getout_event, InputList))
 
        # k += 1
        # if k==2:
        #     break
    print('Step 1: Event init Done!')
        
    for getout_event, InputList in MatchList:
        getout_path = getout_event['path']
        
        if os.path.exists(getout_path) and os.path.isdir(getout_path):
            event = update_event(getout_path)
            getout_event.update(event)
            
            '''====== 放入事件是在取出事件存在的情况下分析 ======'''
            for input_event in InputList:
                input_path = input_event['path']
                if os.path.exists(input_path) and os.path.isdir(input_path):
                    event = update_event(input_path)
                    input_event.update(event)
        
    print('Step 2: Event update Done!')   
    results = []
    for getout_event, InputList in MatchList:
        getout_barcode = getout_event['barcode']
        getout_feats_compose = getout_event['feats_compose']
        getout_feats_select = getout_event['feats_select']

        if len(getout_feats_select):
            outfeats_select = getout_feats_select.copy()
        else:
            outfeats_select = getout_feats_compose.copy()

        result = {}
        result['SeqDir'] = os.path.split(getout_event['path'])[1]
        result['Deleted'] = getout_barcode
        result['List'] = {}
        for input_event in InputList:
            input_barcode = input_event['barcode']
            
            input_feats_compose = input_event['feats_compose']
            input_feats_select = input_event['feats_select']
            
            if len(input_feats_select):
                infeats_select = input_feats_select.copy()
            else:
                infeats_select = input_feats_compose.copy()
                
            similar_comp = compute_similar(getout_feats_compose, input_feats_compose)
            similar_selt = compute_similar(outfeats_select, infeats_select)

            '''现场测试相似度，组合特征相似度，前摄选择特征相似度'''
            result['List'][f'{input_barcode}'] = (input_event['similarity'], similar_comp, similar_selt)
            # result[f'{input_barcode}'] = (input_event['similarity'], similar_comp, similar_selt)
        results.append(result)
    
    print('Step 3: Similarity conputation Done!') 
    
    wpath = os.path.split(filepath)[0]
    wfile = os.path.join(wpath, 'deletedBarcodeTest.txt')
    with open(wfile, 'w', encoding='utf-8') as file:
        for result in results:
            
            SeqDir = result['SeqDir']
            Deleted = result['Deleted']
            
            file.write('\n')
            file.write(f'SeqDir: {SeqDir}\n')
            file.write(f'Deleted: {Deleted}\n')
            file.write('List:\n')
            for key, value in  result['List'].items():
                file.write(f'{key}: ')
                file.write(f'{value[0]}, {value[1]:.3f}, {value[2]:.3f}\n')
    
    print('Step 4: File writting Done!') 


def precision_compare(filepath, savepath):
    '''
    1. deletedBarcode.txt 中的相似度的计算为现场算法前后摄轨迹特征合并
    2. deletedBarcodeTest.txt 中的 3 个相似度计算方式依次为：
          (1)现场算法前后摄轨迹特征合并;
          (2)本地算法前后摄轨迹特征合并；
          (3)本地算法优先选择前摄
    '''
    
    fpath = os.path.split(filepath)[0]
    _, basefile = os.path.split(fpath)

    '''1. 综合前后摄特征的相似度比对性能'''
    fpath1 = os.path.join(fpath, 'deletedBarcode.txt')
    blist1 = read_deletedBarcode_file(fpath1)  
    errpairs, corrpairs, err_similarity, correct_similarity = performance_evaluate(blist1)
    recall, prec, ths = compute_recall_precision(err_similarity, correct_similarity)
    
    
    
    os.path.split(fpath1)
    plt1 = show_recall_prec(recall, prec, ths)
    # plt1.show()
    plt1.xlabel(f'threshold, Num: {len(blist1)}')
    plt1.title(basefile + ', compose')
    plt1.savefig(os.path.join(savepath, basefile+'_pr.png'))
    plt1.close()
    
    '''2. 优先选取前摄特征的相似度比对性能'''
    fpath2 = os.path.join(fpath, 'deletedBarcodeTest.txt')
    blist2 = read_deletedBarcode_file(fpath2)
    front_errpairs, front_corrpairs, front_err_similarity, front_correct_similarity = performance_evaluate(blist2)
    front_recall, front_prec, front_ths = compute_recall_precision(front_err_similarity, front_correct_similarity)
    
    plt2 = show_recall_prec(front_recall, front_prec, front_ths)
    # plt2.show()
    plt2.xlabel(f'threshold, Num: {len(blist2)}')
    plt1.title(basefile + ', front')
    plt2.savefig(os.path.join(savepath, basefile+'_pr_front.png'))
    plt2.close()
   
def main():
    '''
    1. 成deletedBarcodeTest.txt
    2. 不同特征选择下的精度比对性能比较
    '''
    
    fplist = [#r'\\192.168.1.28\share\测试_202406\0723\0723_1\deletedBarcode.txt',
              # r'\\192.168.1.28\share\测试_202406\0723\0723_2\deletedBarcode.txt',
               r'\\192.168.1.28\share\测试_202406\0723\0723_3\deletedBarcode.txt',
              # r'\\192.168.1.28\share\测试_202406\0722\0722_01\deletedBarcode.txt',
              # r'\\192.168.1.28\share\测试_202406\0722\0722_02\deletedBarcode.txt',
              # r'\\192.168.1.28\share\测试_202406\0719\719_1\deletedBarcode.txt',
              # r'\\192.168.1.28\share\测试_202406\0719\719_2\deletedBarcode.txt',
              # r'\\192.168.1.28\share\测试_202406\0719\719_3\deletedBarcode.txt',
              # r'\\192.168.1.28\share\测试_202406\0719\719_4\deletedBarcode.txt',
              # r'\\192.168.1.28\share\测试_202406\0718\0718-1\deletedBarcode.txt',
              # r'\\192.168.1.28\share\测试_202406\0718\0718-2\deletedBarcode.txt',
              # r'\\192.168.1.28\share\测试_202406\0717\0717-1\deletedBarcode.txt',
              # r'\\192.168.1.28\share\测试_202406\0717\0717-2\deletedBarcode.txt',
              # r'\\192.168.1.28\share\测试_202406\0717\0717-3\deletedBarcode.txt',
              # r'\\192.168.1.28\share\测试_202406\0716\0716_1\deletedBarcode.txt',
              # r'\\192.168.1.28\share\测试_202406\0716\0716_2\deletedBarcode.txt',
              # r'\\192.168.1.28\share\测试_202406\0716\0716_3\deletedBarcode.txt',
              # r'\\192.168.1.28\share\测试_202406\0715\0715_1\deletedBarcode.txt',
              # r'\\192.168.1.28\share\测试_202406\0715\0715_2\deletedBarcode.txt',
              # r'\\192.168.1.28\share\测试_202406\0715\0715_3\deletedBarcode.txt',
              # r'\\192.168.1.28\share\测试_202406\0712\0712_1\deletedBarcode.txt',
              # r'\\192.168.1.28\share\测试_202406\0712\0712_2\deletedBarcode.txt',
              # r'\\192.168.1.28\share\测试_202406\711\images01\deletedBarcode.txt',
              # r'\\192.168.1.28\share\测试_202406\711\images02\deletedBarcode.txt',
              # r'\\192.168.1.28\share\测试_202406\710\images_1\deletedBarcode.txt',
              # r'\\192.168.1.28\share\测试_202406\710\images_2\deletedBarcode.txt',
              # r'\\192.168.1.28\share\测试_202406\709\deletedBarcode.txt',
              # r'\\192.168.1.28\share\测试_202406\705\deletedBarcode.txt',
              # r'\\192.168.1.28\share\测试_202406\703\deletedBarcode.txt',
              # r'\\192.168.1.28\share\测试_202406\702_pm_1\702_pm_1\deletedBarcode.txt',
              # r'\\192.168.1.28\share\测试_202406\702_pm_3\702_pm_3\deletedBarcode.txt',
              # r'\\192.168.1.28\share\测试_202406\701_am\deletedBarcode.txt',
              # r'\\192.168.1.28\share\测试_202406\701_pm\701_pm\deletedBarcode.txt',
              # r'\\192.168.1.28\share\测试_202406\628\1\deletedBarcode.txt',
              # r'\\192.168.1.28\share\测试_202406\628\2\deletedBarcode.txt',
              # r'\\192.168.1.28\share\测试_202406\627\deletedBarcode.txt',
              ]
    
    savepath = r'\\192.168.1.28\share\测试_202406\deletedBarcode\illustration'
    for filepath in  fplist:
        try:
            #1. 生成deletedBarcodeTest.txt 文件
            creatd_deletedBarcode_front(filepath)
                
            #2. 确保该目录下存在deletedBarcode.txt, deletedBarcodeTest.txt 文件
            precision_compare(filepath, savepath)
        except Exception as e:
            print(f'{filepath}, Error: {e}') 
        
if __name__ == '__main__':
    
    main()

    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    