#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Created on Mon Mar 31 16:25:43 2025

@author: wqg
"""
import numpy as np
from scipy.spatial.distance import cdist


def get_topk_percent(data, k):
    """
    获取数据中最大的 k% 的元素
    """
    # 将数据转换为 NumPy 数组
    if isinstance(data, list):
        data = np.array(data)
    
    percentile = np.percentile(data, 100-k)
    top_k_percent = data[data >= percentile]
    
    return top_k_percent
def cluster(data, thresh=0.15):
    # data = np.array([0.1, 0.13, 0.7, 0.2, 0.8, 0.52, 0.3, 0.7, 0.85, 0.58])
    # data = np.array([0.1, 0.13, 0.2, 0.3])
    # data = np.array([0.1])
    
    if isinstance(data, list):
        data = np.array(data)
    
    data1 = np.sort(data)
    cluter, Cluters,  = [data1[0]], []
    for i in range(1, len(data1)):
        if data1[i] - data1[i-1]< thresh:
            cluter.append(data1[i])
        else:
            Cluters.append(cluter)
            cluter = [data1[i]]
    Cluters.append(cluter)
    
    clt_center = []
    for clt in Cluters:
        ## 是否应该在此处限制一个聚类中的最小轨迹样本数，应该将该因素放在轨迹分析中
        # if len(clt)>=3:
        #     clt_center.append(np.mean(clt))
        clt_center.append(np.mean(clt))
    
    # print(clt_center)
        
    return clt_center

def calsiml(feat1, feat2, topkp=75, cluth=0.15):
    '''轨迹样本和标准特征集样本相似度的选择策略'''
    matrix = 1 - cdist(feat1, feat2, 'cosine')
    simi_max = []
    for i in range(len(matrix)):
        sim = np.mean(get_topk_percent(matrix[i, :], topkp))
        simi_max.append(sim)
    cltc_max = cluster(simi_max, cluth)
    Simi = max(cltc_max) 
    
    ## cltc_max为空属于编程考虑不周，应予以排查解决 
    # if len(cltc_max):
    #     Simi = max(cltc_max) 
    # else:
    #     Simi = 0   #不应该走到该处

    return Simi


def calsimi_vs_stdfeat_new(event, stdfeat):
    '''事件与标准库的对比策略
       该比对策略是否可以拓展到事件与事件的比对？
    '''
    front_boxes = np.empty((0, 9), dtype=np.float64) ##和类doTracks兼容 
    front_feats = np.empty((0, 256), dtype=np.float64) ##和类doTracks兼容 
    for i in range(len(event.front_boxes)):
        front_boxes = np.concatenate((front_boxes, event.front_boxes[i]), axis=0)
        front_feats = np.concatenate((front_feats, event.front_feats[i]), axis=0)
    
    back_boxes = np.empty((0, 9), dtype=np.float64) ##和类doTracks兼容 
    back_feats = np.empty((0, 256), dtype=np.float64) ##和类doTracks兼容 
    for i in range(len(event.back_boxes)):
        back_boxes = np.concatenate((back_boxes, event.back_boxes[i]), axis=0)
        back_feats = np.concatenate((back_feats, event.back_feats[i]), axis=0)
    
    front_simi, back_simi = None, None
    if len(front_feats):
        front_simi = calsiml(front_feats, stdfeat)
    if len(back_feats):
        back_simi = calsiml(back_feats, stdfeat)

    '''前后摄相似度融合策略'''
    if len(front_feats) and len(back_feats):
        diff_simi = abs(front_simi - back_simi) 
        if diff_simi>0.15:
            Similar = max([front_simi, back_simi])
        else:
            Similar = (front_simi+back_simi)/2
    elif len(front_feats) and len(back_feats)==0:
        Similar = front_simi
    elif len(front_feats)==0 and len(back_feats):
        Similar = back_simi
    else:
        Similar = None   # 在event.front_feats和event.back_feats同时为空时

    return Similar, front_simi, back_simi





def calsimi_vs_stdfeat(event, stdfeat):
    evtfeat = event.feats_compose
    if isinstance(event.feats_select, list):
        if len(event.feats_select) and len(event.feats_select[0]):
            evtfeat = event.feats_select[0]
        else:
            return None, None, None
    else:
        evtfeat = event.feats_select

    if len(evtfeat)==0 or len(stdfeat)==0:
        return None, None, None
    
    
    evtfeat /= np.linalg.norm(evtfeat, axis=1)[:, None]
    stdfeat /= np.linalg.norm(stdfeat, axis=1)[:, None]

    matrix = 1 - cdist(evtfeat, stdfeat, 'cosine')
    matrix[matrix < 0] = 0
    
    simi_mean = np.mean(matrix)
    simi_max  = np.max(matrix)
    stdfeatm = np.mean(stdfeat, axis=0, keepdims=True)
    evtfeatm = np.mean(evtfeat, axis=0, keepdims=True)
    simi_mfeat = 1- np.maximum(0.0, cdist(stdfeatm, evtfeatm, 'cosine'))
    
    return simi_mean, simi_max, simi_mfeat[0,0]


def calsimi_vs_evts(evta, evtb, simType=1):
    if simType==1:
        if len(evta.feats_compose) and len(evtb.feats_compose):
            feata = evta.feats_compose
            featb = evtb.feats_compose
            matrix = 1 - cdist(feata, featb, 'cosine')
            similar = np.mean(matrix)
        else:
            similar = None
        return similar
    
    if simType==2:
        if len(evta.feats_compose) and len(evtb.feats_compose):
            feata = evta.feats_compose
            featb = evtb.feats_compose
            matrix = 1 - cdist(feata, featb, 'cosine')
            similar = np.max(matrix)
        else:
            similar = None
        return similar

    if simType==3:
        if len(evta.feats_compose) and len(evtb.feats_compose):
            feata = evta.feats_compose
            featb = evtb.feats_compose
            similar = calsiml(feata, featb)
        else:
            similar = None
        return similar
            
    
    ##1. the front feats of evta, evtb 
    fr_feata = np.empty((0, 256), dtype=np.float64) ##和类doTracks兼容 
    for i in range(len(evta.front_feats)):
        fr_feata = np.concatenate((fr_feata, evta.front_feats[i]), axis=0)
        
    fr_featb = np.empty((0, 256), dtype=np.float64) ##和类doTracks兼容 
    for i in range(len(evtb.front_feats)):
        fr_featb = np.concatenate((fr_featb, evtb.front_feats[i]), axis=0)
        
    ##2. the back feats of evta, evtb     
    bk_feata = np.empty((0, 256), dtype=np.float64) ##和类doTracks兼容 
    for i in range(len(evta.back_feats)):
        bk_feata = np.concatenate((bk_feata, evta.back_feats[i]), axis=0)
   
    bk_featb = np.empty((0, 256), dtype=np.float64) ##和类doTracks兼容 
    for i in range(len(evtb.back_feats)):
        bk_featb = np.concatenate((bk_featb, evtb.back_feats[i]), axis=0)
    
    
    front_simi, back_simi = None, None
    if len(fr_feata) and len(fr_featb):
        front_simi = calsiml(fr_feata, fr_featb)
    
    if len(bk_feata) and len(bk_featb):
        back_simi = calsiml(bk_feata, bk_featb)

    '''前后摄相似度融合策略'''
    if front_simi is not None and back_simi is not None:
        diff_simi = abs(front_simi - back_simi) 
        if diff_simi>0.15:
            similar = max([front_simi, back_simi])
        else:
            similar = (front_simi+back_simi)/2
    elif front_simi is not None and back_simi is None:
        similar = front_simi
    elif front_simi is None and back_simi is not None:
        similar = back_simi
    else:
        similar = None   # 在event.front_feats和event.back_feats同时为空时

    return similar


