# -*- coding: utf-8 -*-
"""
Created on Mon Mar  4 18:28:47 2024

@author: ym
"""
import cv2
import numpy as np
from scipy.spatial.distance import cdist
from sklearn.decomposition import PCA
from .dotracks import MoveState, Track
from tools.config import cfg

class backTrack(Track):
    # boxes: [x1, y1, x2, y2, track_id, score, cls, frame_index, box_index]
    #         0,  1,  2,  3,    4,       5,    6,      7,         8
    def __init__(self, boxes, imgshape=(1024, 1280)):
        
        super().__init__(boxes, imgshape)
        
        '''(cent_x, cent_y, mean_w, mean_h)'''
        
        
        
        
        '''5个关键点（中心点、左上点、右上点、左下点、右下点 ）轨迹特征'''
        self.compute_cornpts_feats()
        
        '''该函数依赖项: self.cornpoints'''
        self.isCornpoint = self.isimgborder()
        
        '''该函数依赖项: self.cornpoints、self.isCornpoint，定义 10 个轨迹特征：
            self.trajectory, self.trajmin, self.trajlens, self.trajdist
            self.feature = [trajlen_min,   trajlen_max, 
                            trajdist_min,  trajdist_max,
                            trajlen_rate,  trajdist_rate] '''
        self.trajfeature()
             
        


        '''静止点帧索引'''
        self.static_index = self.compute_static_fids()
        
        '''运动点帧索引(运动帧两端的静止帧索引)'''
        self.moving_index = self.compute_moving_fids()
        
        '''该函数依赖项: self.cornpoints，定义 4 个商品位置变量：
            self.Cent_isIncart, self.LB_isIncart, self.RB_isIncart
            self.posState = self.Cent_isIncart+self.LB_isIncart+self.RB_isIncart'''    
        self.PositionState()

        '''self.feature_ious = (incart_iou, outcart_iou, cartboarder_iou, maxbox_iou, minbox_iou)
           self.incartrates = incartrates'''
        self.compute_ious_feat()
        
        # self.PCA()
      

     
        
    
# =============================================================================
#     def compute_cornpoints(self):
#         '''
#         cornpoints 共10项，分别是个点的坐标值（x, y）
#             (center, top_left, top_right, bottom_left, bottom_right)
#         '''
#         boxes = self.boxes
#         cornpoints = np.zeros((self.frnum, 10))
#         cornpoints[:,0], cornpoints[:,1] = boxes[:, 0], boxes[:, 1]
#         cornpoints[:,2], cornpoints[:,3] = boxes[:, 0] - boxes[:, 2]/2, boxes[:, 1] - boxes[:, 3]/2
#         cornpoints[:,4], cornpoints[:,5] = boxes[:, 0] + boxes[:, 2]/2, boxes[:, 1] - boxes[:, 3]/2
#         cornpoints[:,6], cornpoints[:,7] = boxes[:, 0] - boxes[:, 2]/2, boxes[:, 1] + boxes[:, 3]/2
#         cornpoints[:,8], cornpoints[:,9] = boxes[:, 0] + boxes[:, 2]/2, boxes[:, 1] + boxes[:, 3]/2
# 
#         self.cornpoints = cornpoints
# =============================================================================
    
    def isimgborder(self, BoundPixel=10, BoundThresh=0.3):
    
        x1, y1 = self.cornpoints[:,2], self.cornpoints[:,3],
        x2, y2 = self.cornpoints[:,8], self.cornpoints[:,9]

        cont1 = sum(abs(x1)<BoundPixel) / self.frnum > BoundThresh
        cont2 = sum(abs(y1)<BoundPixel) / self.frnum > BoundThresh
        cont3 = sum(abs(x2-self.imgshape[0])<BoundPixel) / self.frnum > BoundThresh
        cont4 = sum(abs(y2-self.imgshape[1])<BoundPixel) / self.frnum > BoundThresh

        cont = cont1 or cont2 or cont3 or cont4
        isCornpoint = False
        if cont:
            isCornpoint = True
        
        return isCornpoint


    def PositionState(self, camerType="back"):
        '''
        camerType: back, 后置摄像头
                   front, 前置摄像头
        '''
        if camerType=="front":
            incart = cv2.imread(cfg.incart, cv2.IMREAD_GRAYSCALE)
        else:
            incart = cv2.imread(cfg.incart_ftmp, cv2.IMREAD_GRAYSCALE)

        xc, yc = self.cornpoints[:,0].clip(0,self.imgshape[0]-1).astype(np.int64), self.cornpoints[:,1].clip(0,self.imgshape[1]-1).astype(np.int64)
        x1, y1 = self.cornpoints[:,6].clip(0,self.imgshape[0]-1).astype(np.int64), self.cornpoints[:,7].clip(0,self.imgshape[1]-1).astype(np.int64)
        x2, y2 = self.cornpoints[:,8].clip(0,self.imgshape[0]-1).astype(np.int64), self.cornpoints[:,9].clip(0,self.imgshape[1]-1).astype(np.int64)
        
        # print(self.tid)
        Cent_inCartnum = np.count_nonzero(incart[(yc, xc)])
        LB_inCartnum = np.count_nonzero(incart[(y1, x1)])
        RB_inCartnum = np.count_nonzero(incart[(y2, x2)])
        
        self.Cent_isIncart = False
        self.LB_isIncart = False
        self.RB_isIncart = False
        if Cent_inCartnum: self.Cent_isIncart = True
        if LB_inCartnum: self.LB_isIncart = True
        if RB_inCartnum: self.RB_isIncart = True
        
        self.posState = self.Cent_isIncart+self.LB_isIncart+self.RB_isIncart
        
        
        
    def PCA(self):
        self.pca = PCA()
        
        X = self.cornpoints[:, 0:2]
        self.pca.fit(X)
        

    


    def compute_ious_feat(self):
        '''输出：
            self.feature_ious = (incart_iou, outcart_iou, cartboarder_iou, maxbox_iou, minbox_iou)
            self.incartrates = incartrates，
        其中：        
            boxes流：track中所有boxes形成的轨迹图，可分为三部分：incart, outcart, cartboarder
            incart_iou, outcart_iou, cartboarder_iou：各部分和 boxes流的 iou。
            incart_iou = 0，track在购物车外，
            outcart_iou = 0，track在购物车内，也可能是通过左下角、右下角置入购物车，
            maxbox_iou, minbox_iou：track中最大、最小 box 和boxes流的iou，二者差值越小，越接近 1，表明track的运动型越小。
            incartrates: 各box和incart的iou时序，由小变大，反应的是置入过程，由大变小，反应的是取出过程
        '''
        incart = cv2.imread(cfg.incart, cv2.IMREAD_GRAYSCALE)
        outcart = cv2.imread(cfg.outcart, cv2.IMREAD_GRAYSCALE)
        cartboarder = cv2.imread(cfg.cartboarder, cv2.IMREAD_GRAYSCALE)
        
        incartrates = []
        temp = np.zeros(incart.shape, np.uint8)
        maxarea, minarea = 0, self.imgshape[0]*self.imgshape[1]
        for i in range(self.frnum):
            # x, y, w, h = self.boxes[i, 0:4]
            
            x = (self.boxes[i, 2] + self.boxes[i, 0]) / 2
            w = (self.boxes[i, 2] - self.boxes[i, 0]) / 2
            y = (self.boxes[i, 3] + self.boxes[i, 1]) / 2
            h = (self.boxes[i, 3] - self.boxes[i, 1]) / 2
            
            
            if w*h > maxarea: maxarea = w*h
            if w*h < minarea: minarea = w*h
            cv2.rectangle(temp, (int(x-w/2), int(y-h/2)), (int(x+w/2), int(y+h/2)), 255, cv2.FILLED)
            
            temp1 = np.zeros(incart.shape, np.uint8)
            cv2.rectangle(temp1, (int(x-w/2), int(y-h/2)), (int(x+w/2), int(y+h/2)), 255, cv2.FILLED)
            temp2 = cv2.bitwise_and(incart, temp1)
            inrate = cv2.countNonZero(temp1)/(w*h)
            incartrates.append(inrate)

        isincart = cv2.bitwise_and(incart, temp)
        isoutcart = cv2.bitwise_and(outcart, temp)
        iscartboarder = cv2.bitwise_and(cartboarder, temp)
        
        num_temp = cv2.countNonZero(temp)
        num_incart = cv2.countNonZero(isincart)
        num_outcart = cv2.countNonZero(isoutcart)
        num_cartboarder = cv2.countNonZero(iscartboarder)

        incart_iou = num_incart/num_temp
        outcart_iou = num_outcart/num_temp
        cartboarder_iou = num_cartboarder/num_temp
        maxbox_iou = maxarea/num_temp
        minbox_iou = minarea/num_temp
        
        self.feature_ious = (incart_iou, outcart_iou, cartboarder_iou, maxbox_iou, minbox_iou)
        self.incartrates = incartrates
        

 
    
    def compute_static_fids(self, thresh1 = 12, thresh2 = 3):
        '''
        计算 track 的轨迹中相对处于静止状态的轨迹点的（start_frame_id, end_frame_id）
        thresh1: 相邻两帧目标中心点是否静止的的阈值，以像素为单位，
        thresh2: 连续捕捉到目标处于静止状态的帧数
        '''
        
        BoundPixel = 8
        x1, y1 = self.cornpoints[:,2], self.cornpoints[:,3],
        x2, y2 = self.cornpoints[:,8], self.cornpoints[:,9]
        cont1 = sum(abs(x1)<BoundPixel) > 3
        # cont2 = sum(abs(y1)<BoundPixel)  > 3
        cont3 = sum(abs(x2-self.imgshape[0])<BoundPixel) > 3
        # cont4 = sum(abs(y2-self.imgshape[1])<BoundPixel) > 3
        cont = not(cont1 or cont3)
        
        ## ============== 下一步，启用中心点，选择具有最小运动幅度的角点作为参考点
   
        static_index = []    
        if self.frnum>=2 and cont:
            x1 = self.boxes[1:,7]
            x2 = [i for i in range(int(min(x1)), int(max(x1)+1))]
            dist_adjc = np.interp(x2, x1, self.trajmin)
        
        
            # dist_adjc = self.trajmin
            
            static_thresh = (dist_adjc < thresh1)[:, None].astype(np.uint8)
            static_cnts, _ = cv2.findContours(static_thresh, cv2.RETR_LIST, cv2.CHAIN_APPROX_NONE)
        
            for cnt in static_cnts:
                _, start, _, num = cv2.boundingRect(cnt)      
                end = start + num
                if num <= thresh2:
                    continue 
                static_index.append((start, end))
            
# =============================================================================
#         '''========= 输出帧id，不太合适 ========='''
#         static_fids = []
#         for i in range(len(static_index)):
#             i1, i2 = static_index[i]
#             fid1, fid2 = boxes[i1, 7], boxes[i2, 7]
#             static_fids.append([fid1, fid2])
#         static_fids = np.array(static_fids)
# =============================================================================
  
        static_index = np.array(static_index)
        if static_index.size:
            indx = np.argsort(static_index[:, 0])
            static_index = static_index[indx]
        
        return static_index
            
    def compute_moving_fids(self, thresh1 = 12, thresh2 = 3):
        '''
        计算 track 的轨迹中运动轨迹点的（start_frame_id, end_frame_id）
        thresh1: 相邻两帧目标中心点是否运动的阈值，以像素为单位，
        thresh2: 连续捕捉到目标连续运动的帧数
        目标：
            1. 计算轨迹方向
            2. 计算和手部运动的关联性
        '''
        moving_index = []
        if self.frnum>=2:
            x1 = self.boxes[1:,7]
            x2 = [i for i in range(int(min(x1)), int(max(x1)+1))]
            dist_adjc = np.interp(x2, x1, self.trajmin)

            moving_thresh = (dist_adjc >= thresh1)[:, None].astype(np.uint8)
            moving_cnts, _ = cv2.findContours(moving_thresh, cv2.RETR_LIST, cv2.CHAIN_APPROX_NONE)

            for cnt in moving_cnts:
                _, start, _, num = cv2.boundingRect(cnt)      
                if num < thresh2:
                    continue
                end = start + num
                moving_index.append((start, end))
            
# =============================================================================
#         '''========= 输出帧id，不太合适 ========='''
#         moving_fids = []
#         for i in range(len(moving_index)):
#             i1, i2 = moving_index[i]
#             fid1, fid2 = boxes[i1, 7], boxes[i2, 7]
#             moving_fids.append([fid1, fid2])
#         moving_fids = np.array(moving_fids)
# =============================================================================
        moving_index = np.array(moving_index)
        if moving_index.size:
            indx = np.argsort(moving_index[:, 0])
            moving_index = moving_index[indx]
        
        return moving_index     
    

        
    
    def compute_distance(self):
        pass
    
    
    def move_start_fid(self):
        pass
    
    
    def move_end_fid(self):
        pass