# -*- coding: utf-8 -*-
"""
Created on Wed Oct 16 17:37:07 2024

@author: ym
"""

# import csv
import os
# import platform
# import sys
from pathlib import Path
import glob
import numpy as np
import copy
import matplotlib.pyplot as plt
from collections import OrderedDict

from event_time_specify import devide_motion_state #, state_measure

import sys


FILE = Path(__file__).resolve()
ROOT = FILE.parents[1]  # YOLOv5 root directory
if str(ROOT) not in sys.path:
    sys.path.append(str(ROOT))  # add ROOT to PATH






from imgs_inference import run_yolo
from tracking.utils.read_data import read_weight_sensor

# IMG_FORMATS = 'bmp', 'dng', 'jpeg', 'jpg', 'mpo', 'png', 'tif', 'tiff', 'webp', 'pfm'  # include image suffixes
# VID_FORMATS = 'asf', 'avi', 'gif', 'm4v', 'mkv', 'mov', 'mp4', 'mpeg', 'mpg', 'ts', 'wmv'  # include video suffixes

def filesort(p):
    '''
    需将图像文件名标准化
    '''
    
    
    files = []
    files.extend(sorted(glob.glob(os.path.join(p, '*.jpg'))))
    # images = [x for x in files if x.split('.')[-1].lower() in IMG_FORMATS]
    
    tamps_0, tamps_1 = [], []
    files_0, files_1 = [], []
    for file in files:
        basename = os.path.basename(file) 
        # if basename.find('frameId')<0: continue
        
        
        f, ext = os.path.splitext(basename)
        _, camer, tamp = f.split('_')
        
        if camer == '0':
            tamps_0.append(int(tamp))
            files_0.append(file)
            
        if camer == '1':
            tamps_1.append(int(tamp))
            files_1.append(file)
    
    idx0 = sorted(range(len(tamps_0)), key=lambda k: tamps_0[k])
    files0 = [files_0[i] for i in idx0]  
    
    idx1 = sorted(range(len(tamps_1)), key=lambda k: tamps_1[k])
    files1 = [files_1[i] for i in idx1] 

    
    return (files0, files1)





def rename(filePath, tmin):
    """
    重命名函数fun1
    输入：文件夹路径
    功能：对文件夹中的全部文件进行随机命名
    """
    suffix = '.png'  # 设置后缀，筛选特定文件以更改名称
    for file in os.listdir(filePath):
        if file.endswith(suffix):
            name = file.split('.')[0]
            
            tamp = int(name.split('_')[2])-tmin
            
            suffix = file.split('.')[1]
            
            newname = name +f'_{int(tamp)}.'+suffix
        
            os.rename(os.path.join(filePath, file), os.path.join(filePath, newname))


def rerename(filePath=None):
    """
    重命名函数fun1
    输入：文件夹路径
    功能：对文件夹中的全部文件进行随机命名
    """
    
    suffix = '.png'  # 设置后缀，筛选特定文件以更改名称
    for file in os.listdir(filePath):
        if file.endswith(suffix):
            name = file.split('.')[0]
            names = name.split('_')
            if len(names)>=6:
                newname = "_".join(names[0:5])+'.png'
                os.rename(os.path.join(filePath, file), os.path.join(filePath, newname))


def state_measure(periods, weights, hands, spath=None):
    '''
    数据类型
        后摄: 0, 前摄: 1, CV综合: 2, 重力: 9
    frstate_0/1:
        帧ID   时间戳  单摄状态1  单摄状态2  活动轨迹标记
         0      1       2          3          4:end
        
    
    
    time_stream = np.concatenate((tstream, weights))
    time_stream:
        序列索引号 数据类型  时间戳  单摄状态1/重力值  单摄状态2/重力(t0, t1)  CV状态/重力(t0', t1')  综合数据类型 综合状态
            0        1        2         3                 4                      5                     6         7
        
        单摄状态1：基于运动轨迹的起止点确定的运动区间
        单摄状态2: 基于滑动窗口的起止点(窗口终点)确定的运动区间
        重力(t0, t1): 重力波动的精确时间区间，基于重力波动的起止点，而不是仅依赖重力稳定时间
        重力(t0', t1'): 根据加退购对重力波动窗口进行扩展，扩展应该涵盖购物事件的发生过程
    方案：
        前后摄状态进行或运算
        CV与重力状态进行与运算
    '''
    
    # BackType = 0            # 后摄数据类型
    # FrontType = 1           # 前摄数据类型
    CameraType = 2            # CV数据综合类型
    HandType = 3              # 手部类型
    WeightType = 9            # 重力数据类型
    WeightStableThresh = 7.5  # 单位：g，重力稳定状态下的最大波动范围
    WeightWinWidth = 10       # 单位：重力数据点数，该值和采样间隔关联，重力稳定时间设定为500ms = WeightWinWidth * 采样间隔
    CameraTimeInterval = 100  # 单位：ms，前后摄状态进行或运算时的时间间隔阈值
    InputFrontNum = 10        # 重力增加（放入）向前延拓的重力数据点数
    InputBackNum = 0          # 重力增加（放入）向后延拓的重力数据点数
    OutputFrontNum = 2        # 重力减少（取出）向前延拓的重力数据点数
    OutputBackNum = 10        # 重力减少（取出）向前延拓的重力数据点数
    CompTimeInterval = 150    # 单位：ms，CV状态和重力状态进行与运算时的时间间隔阈值
    

    '''==================== 1.1 Weight 数据综合并排序 =======================''' 
    nw = len(weights)        
    widx = np.array([k for k in range(0, nw)])[:, None]  
    wtype = WeightType * np.ones((nw, 1))
    wstate = np.zeros((nw, 4))
    weights = np.concatenate((widx, wtype, weights, wstate), axis=1).astype(np.int64)
    weights[:, 6] = WeightType
    
    weights = weights[np.argsort(weights[:, 2]), :]
    
    '''=================== 1.2 基确Weight的状态切割 ========================='''
    w_max = np.max(weights[:, 3])
    # i0=0
    for i2 in range(0, nw):
        i1 = max(i2 - WeightWinWidth, 0)
        wvalue = weights[i1:i2+1, 3]
        wi2 = weights[i2, 3]
        wmin = np.min(wvalue)
        wmax = np.max(wvalue)
        
        
        '''对重力波动区间进行标记，并标记最新一次重力稳定值的索引和相应重力值'''
        if wmax - wmin > WeightStableThresh:
            weights[i2, 4] = w_max
        
        if i2==0:
            i0=0
            wi0 = weights[i0, 3]
        elif i2>0 and weights[i2-1, 4]==0:
            i0 = copy.deepcopy(i2)
            wi0 = weights[i0, 3]

            
        if i2>0 and weights[i2-1, 4]!=0 and weights[i2, 4]==0:
            # 当前稳定状态下的重力值和前一次重力稳定值的差值，确定放入还是取出
            if wi2-wi0 > WeightStableThresh:
                i00 = max(i0 - InputFrontNum, 0)
                i22 = min(i2 + InputBackNum, nw)
            elif wi2-wi0 < -1*WeightStableThresh:
                i00 = max(i0 - OutputFrontNum, 0)
                i22 = min(i2 + OutputBackNum, nw)
            else:
                i00 = max(i0 - max(InputFrontNum, OutputFrontNum), 0)
                i22 = min(i2 + max(InputBackNum, OutputBackNum), nw)
            
            weights[i00:i22, 5] = w_max + 100

                             
    '''===================== 2.1 CV 数据综合并排序 =========================='''        
    BackType, frstate_0 =  periods[0]
    FrontType, frstate_1 =  periods[1]
    
    
    n0, n1 = len(frstate_0), len(frstate_1)
    idx0 = np.array([i for i in range(0, n0)], dtype=np.int64)[:, None]
    idx1 = np.array([i for i in range(0, n1)], dtype=np.int64)[:, None]
    ctype0 = BackType * np.ones((n0, 1), dtype=np.int64)
    ctype1 = FrontType * np.ones((n1, 1), dtype=np.int64)
    tstamp0 = frstate_0[:,1][:, None]
    tstamp1 = frstate_1[:,1][:, None]
    state0 = frstate_0[:,2][:, None]
    state00 = frstate_0[:,3][:, None]
    
    state1 = frstate_1[:,2][:, None]
    state11 = frstate_1[:,3][:, None]


    
    '''序列索引号， 相机类型，时间戳, 单摄状态1、单摄状态2、CV综合状态、综合数据类型、综合状态
          0           1       2        3         4          5           6           7
    '''
    tstream0 = np.concatenate((idx0, ctype0, tstamp0, state0, state00), axis=1)
    tstream1 = np.concatenate((idx1, ctype1, tstamp1, state1, state11), axis=1)
    tstream = np.concatenate((tstream0, tstream1), axis=0)
    tstream = np.concatenate((tstream, np.zeros((len(tstream), 3), dtype=np.int64)), axis=1)
    tstream[:, 6] = CameraType
    tstream = tstream[np.argsort(tstream[:, 2]), :]
    
    '''=============== 2.2 基于前后摄运动轨迹起止点确定CV综合状态 ============'''
    for i in range(0, len(tstream)):
        idx, ctype, stamp, state = tstream[i, :4]
        if i==0: 
            tstream[i, 5] = state
        if i>0:
            j = i-1
            idx0, ctype0, stamp0, state0 = tstream[j, :4]
            while stamp-stamp0 < CameraTimeInterval and ctype == ctype0 and j>0:
                j -= 1
                idx0, ctype0, stamp0, state0 = tstream[j, :4]
            
            '''两摄像头状态的或运算. 由于前后摄图像不同时，如何构造或运算，关键在于选择不同摄像头的对齐点
                i时刻摄像头(ctype)状态state，另一摄像头(ctype0 != ctype)距 i 最近最近时刻 j 的状态state0
            '''
            if ctype != ctype0 and state0==1:
                tstream[i, 5] = state0
            else:
                tstream[i, 5] = state
    
    
    '''================ 3.1 CV、Wweight 数据综合并排序 ======================'''
    time_stream = np.concatenate((tstream, weights), axis=0, dtype=np.int64)
    time_stream = time_stream[np.argsort(time_stream[:, 2]), :]
    tmin = np.min(time_stream[:, 2])
    time_stream[:, 2] = time_stream[:, 2] - tmin
    
    '''============== 3.2 基于 CV 和 Weight 确定 Cart 的综合状态 ============'''    
    for i in range(0, len(time_stream)):
        idx, _, stamp, value, _, state, ctype = time_stream[i, :7]
        state = min(state, 1)
        
        if i==0:
            time_stream[i, 7] = state        
        
        if i>0:
            j = i-1
            idx0, _, stamp0, value0, _, state0, ctype0 = time_stream[j, :7]
            while stamp-stamp0 < CompTimeInterval and ctype == ctype0 and j>0:
                j -= 1
                idx0, _, stamp0, value0, _, state0, ctype0 = time_stream[j, :7]
            
            '''CV与Weight的与运算. 由于CV与Weight不同时，如何构造与运算，关键在于选择不同数据源的对齐点
                i时数据类型(ctype)状态state，另一数据类型(ctype0 != ctype)距 i 最近最近时刻 j 的状态state0
            '''    
            if ctype != ctype0 and  state !=0 and state0 !=0:
                time_stream[i, 7] = 1

    MotionSlice, motion_slice = [], []
    t0 = time_stream[0, 7]
    for i in range(1, len(time_stream)):
        f0 = time_stream[i-1, 7]
        f1 = time_stream[i, 7]
        if f0==0 and f1==1:
            t0 = time_stream[i, 2] 
        elif f0==1 and f1==0:
            t1 = time_stream[i, 2]
            if t1-t0>100:  #ms
                MotionSlice.append((t0+tmin, t1+tmin))
                motion_slice.append((t0, t1))
            else:
                print(f"T0: {t0}, T1: {t1}")
                
    
    
    
    '''===================== 4. Hands数据综合并排序 =========================='''
    BackType, hdstate_0 =  hands[0]
    FrontType, hdstate_1 =  hands[1]
    n0, n1 = len(hdstate_0), len(hdstate_1)
    idx0 = np.array([i for i in range(0, n0)], dtype=np.int64)[:, None]
    idx1 = np.array([i for i in range(0, n1)], dtype=np.int64)[:, None]
    ctype0 = BackType * np.ones((n0, 1), dtype=np.int64)
    ctype1 = FrontType * np.ones((n1, 1), dtype=np.int64)
    hstamp0 = hdstate_0[:,1][:, None]
    hstamp1 = hdstate_1[:,1][:, None]
    state0 = hdstate_0[:,2][:, None]
    state1 = hdstate_1[:,2][:, None]
    
    '''序列索引号， 相机类型，时间戳, 单摄手部状态、手部综合状态、保留位2、综合数据类型、综合状态
          0           1       2        3              4           5        6           7
    '''
    hstream0 = np.concatenate((idx0, ctype0, hstamp0, state0), axis=1)
    hstream1 = np.concatenate((idx1, ctype1, hstamp1, state1), axis=1)
    hstream = np.concatenate((hstream0, hstream1), axis=0)
    hstream = np.concatenate((hstream, np.zeros((len(hstream), 4), dtype=np.int64)), axis=1)
    hstream[:, 6] = HandType
    hstream = hstream[np.argsort(hstream[:, 2]), :]
    
    for i in range(0, len(hstream)):
        idx, ctype, stamp, state = hstream[i, :4]
        if i==0: 
            hstream[i, 4] = state
        if i>0:
            j = i-1
            idx0, ctype0, stamp0, state0 = hstream[j, :4]
            while stamp-stamp0 < CameraTimeInterval and ctype == ctype0 and j>0:
                j -= 1
                idx0, ctype0, stamp0, state0 = hstream[j, :4]
            
            '''两摄像头状态的或运算. 由于前后摄图像不同时，如何构造或运算，关键在于选择不同摄像头的对齐点
                i时刻摄像头(ctype)状态state，另一摄像头(ctype0 != ctype)距 i 最近最近时刻 j 的状态state0
            '''
            if ctype != ctype0 and state0==2:
                hstream[i, 4] = state0
            elif ctype != ctype0 and state0==1:
                hstream[i, 4] = state0
            else:
                hstream[i, 4] = state
    

                
                


    '''========================== 5 结果显示 ================================'''   
    frstate_0[:, 1] = frstate_0[:, 1]-tmin
    frstate_1[:, 1] = frstate_1[:, 1]-tmin
    tstream[:, 2] = tstream[:, 2]-tmin

    fig, (ax1, ax2, ax3, ax4, ax5, ax6) = plt.subplots(6, 1)
    during = np.max(time_stream[:, 2])
    
    ax1.plot(weights[:, 2]-tmin, weights[:, 3], 'bo-', linewidth=1, markersize=4)
    ax1.plot(weights[:, 2]-tmin, weights[:, 4], 'mx-', linewidth=1, markersize=4)
    ax1.plot(weights[:, 2]-tmin, weights[:, 5], 'gx-', linewidth=1, markersize=4)
    ax1.set_xlim([0, during])
    ax1.set_title('Weight (gram)')
    
    ax2.plot(frstate_0[:, 1], frstate_0[:, 3], 'rx-', linewidth=1, markersize=8)
    ax2.plot(frstate_0[:, 1], frstate_0[:, 2], 'bo-', linewidth=1, markersize=4)
    ax2.set_xlim([0, during])
    ax2.set_title('Back Camera')
    
    ax3.plot(frstate_1[:, 1], frstate_1[:, 3], 'rx-', linewidth=1, markersize=8)
    ax3.plot(frstate_1[:, 1], frstate_1[:, 2], 'bo-', linewidth=1, markersize=4)
    ax3.set_xlim([0, during])
    ax3.set_title('Front Camera')
    
    ax4.plot(tstream[:, 2], tstream[:, 5], 'bx-', linewidth=1, markersize=4)
    ax4.set_xlim([0, during])
    ax4.set_title('CV State')

    ax5.plot(time_stream[:, 2], time_stream[:, 7], 'gx-', linewidth=1, markersize=4)
    ax5.set_xlim([0, during])
    ax5.set_title('Cart State')

    ax6.plot(hstream[:, 2]-tmin, hstream[:, 4], 'gx-', linewidth=1, markersize=4)
    ax6.set_xlim([0, during])
    ax6.set_title('Hand State')


    plt.show()
    if spath:        
        plt.savefig(spath)
        
    return tmin, MotionSlice

def splitevent(imgpath, MotionSlice):
    suffix = '.png'
    
    imgfiles = [f for f in os.listdir(imgpath) if f.endswith(suffix)]
    timestamp = np.array([int(f.split('_')[2]) for f in imgfiles])
    
    indexes = []
    k = 0 
    for t0, t1 in MotionSlice:
        idx0 = set(np.where(timestamp >= t0)[0])
        idx1 = set(np.where(timestamp <= t1)[0])
        idx2 = list(idx0.intersection(idx1))
        files = [imgfiles[i] for i in idx2]
        
        for filename in files:
            file, ext = os.path.splitext(filename)
            newname = file + f'_{k}.png'
            os.rename(os.path.join(imgpath, filename), os.path.join(imgpath, newname))
        k += 1
            
    print("Done!")
        

    
def runyolo():
    eventdirs = r"\\192.168.1.28\share\个人文件\wqg\realtime\eventdata"
    savedir = r"\\192.168.1.28\share\个人文件\wqg\realtime\result"
    
    k = 0
    for edir in os.listdir(eventdirs):
        edir = "1731316835560"
        source = os.path.join(eventdirs, edir)
        files = filesort(source)
        for flist in files:
            run_yolo(flist, savedir)
        
        k += 1
        if k==1:
            break

def run_tracking(trackboxes, MotionSlice):
    pass
            

def read_wsensor(filepath):
    WeightDict = OrderedDict()
    with open(filepath, 'r', encoding='utf-8') as f:
        lines = f.readlines()
        clean_lines = [line.strip().replace("'", '').replace('"', '') for line in lines]  
        for i, line in enumerate(clean_lines):
            line = line.strip()
            
            line = line.strip()
            
            if line.find(':') < 0: continue
            # if line.find("Weight") >= 0: 
            #     label = "Weight"
            #     continue
 
            
            keyword = line.split(':')[0]
            value = line.split(':')[1]
            
            # if label == "Weight":
            if len(keyword) and len(value):
                vdata = [float(s) for s in value.split(',') if len(s)]
                WeightDict[keyword] = vdata[-1]
                
                
    weights = [(float(t), w) for t, w in WeightDict.items()]
    weights = np.array(weights).astype(np.int64)
    
    return weights

            
def show_seri():    
    datapath = r"\\192.168.1.28\share\个人文件\wqg\realtime\eventdata\1731316835560"
    savedir = r"\\192.168.1.28\share\个人文件\wqg\realtime\1"
    
    
    imgdir = datapath.split('\\')[-2] + "_" + datapath.split('\\')[-1]
    imgpath = os.path.join(savedir, imgdir)
    
    eventname = Path(datapath).stem
    
    datafiles = sorted(glob.glob(os.path.join(datapath, '*.npy')))

    periods, trackboxes, hands = [], [], []
    win_width = 12
    for npypath in datafiles:
        CameraType = Path(npypath).stem.split('_')[-1]
        tkboxes = np.load(npypath)
        
        trackboxes.append((CameraType, tkboxes))
        
        period, handState = devide_motion_state(tkboxes, win_width)
        periods.append((int(CameraType), period))
        hands.append((int(CameraType), handState))
        
    
        
    '''===============读取重力信号数据==================='''
    seneorfile = os.path.join(datapath, 'sensor.txt')
    weights = read_wsensor(seneorfile)
    
    # weights = [(float(t), w) for t, w in WeightDict.items()]
    # weights = np.array(weights)
    
    
    '''===============重力、图像信息融合==================='''
    spath = os.path.join(savedir, f"{eventname}.png" )
    tmin, MotionSlice = state_measure(periods, weights, hands, spath)

    # 第一次运行时用于更改图像文件名
    # rerename(imgpath)
    # rename(imgpath, tmin)

    # splitevent(imgpath, MotionSlice)
    
    


def main():
    # runyolo()
    show_seri()
 
if __name__ == '__main__':
    main()
    
    # imgpaths = r"\\192.168.1.28\share\realtime\result\eventdata_1728978106733"
    # rerename(imgpaths)
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    