import cv2
import numpy as np
from numpy import genfromtxt
from KalmanFilter import KalmanFilter
import math
import os
import glob

datasets="2DMOT2015Labels/train"
dataset="PETS09-S2L1"

distance_mini=500
rectangle=0
trace=0

dir_images=datasets+"/"+dataset+"/img1/"
fichier_label=datasets+"/"+dataset+"/gt/gt.txt"

if not os.path.exists(dir_images):
    print("Le repertoire n'existe pas ...", dir_images)
    quit()

if not os.path.exists(fichier_label):
    print("Le fichier de label n'existe pas ...", fichier)
    quit()

objets_points=[]
objets_id=[]
objets_KF=[]
objets_historique=[]

def distance(point, liste_points):
    distances=[]
    for p in liste_points:
        distances.append(np.sum(np.power(p-np.expand_dims(point, axis=-1), 2)))
    return distances

def trace_historique(tab_points, longueur, couleur=(0, 255, 255)):
    historique=np.array(tab_points)
    nbr_point=len(historique)
    longueur=min(nbr_point, longueur)
    for i in range(nbr_point-1, nbr_point-longueur, -1):
        cv2.line(frame,
                 (historique[i-1, 0], historique[i-1, 1]),
                 (historique[i, 0], historique[i, 1]),
                 couleur,
                 2)

data=genfromtxt(fichier_label, delimiter=',')
id_frame=0
id_objet=0

start=0
for image in glob.glob(dir_images+"*.jpg"):
    frame=cv2.imread(image)

    # Prediction de l'ensemble des objets + affichage
    for id_obj in range(len(objets_points)):
        etat=objets_KF[id_obj].predict()
        etat=np.array(etat, dtype=np.int32)
        objets_points[id_obj]=np.array([etat[0], etat[1], etat[4], etat[5]])
        objets_historique[id_obj].append([etat[0], etat[1]])
        cv2.circle(frame, (etat[0], etat[1]), 5, (0, 0, 255), 2)
        if rectangle:
            cv2.rectangle(frame,
                          (int(etat[0]-etat[4]/2), int(etat[1]-etat[5]/2)),
                          (int(etat[0]+etat[4]/2), int(etat[1]+etat[5]/2)),
                          (0, 0, 255),
                          2)
        cv2.arrowedLine(frame,
                        (etat[0], etat[1]),
                        (etat[0]+3*etat[2], etat[1]+3*etat[3]),
                        color=(0, 0, 255),
                        thickness=2,
                        tipLength=0.2)
        cv2.putText(frame,
                    "ID{:d}".format(objets_id[id_obj]),
                    (int(etat[0]-etat[4]/2), int(etat[1]-etat[5]/2)),
                    cv2.FONT_HERSHEY_PLAIN,
                    1.5,
                    (255, 0, 0),
                    2)

        if trace:
            trace_historique(objets_historique[id_obj], 42)

        # Permet de suivre l'ID 0 avec une flèche
        if objets_id[id_obj]==0:
            cv2.arrowedLine(frame,
                            (etat[0], int(etat[1]-etat[5]/2-80)),
                            (etat[0], int(etat[1]-etat[5]/2-30)),
                            color=(0, 0, 255),
                            thickness=5,
                            tipLength=0.2)

    # Récupération des objets de la frame concernée
    mask=data[:, 0]==id_frame

    # Affichage des données (rectangle) du detecteur
    points=[]
    for d in data[mask, :]:
        #if np.random.randint(2):
        if rectangle:
            cv2.rectangle(frame, (int(d[2]), int(d[3])), (int(d[2]+d[4]), int(d[3]+d[5])), (0, 255, 0), 2)
        xm=int(d[2]+d[4]/2)
        ym=int(d[3]+d[5]/2)
        cv2.circle(frame, (xm, ym), 2, (0, 255, 0), 2)
        points.append([xm, ym, int(d[4]), int(d[5])])

    # calcul des distances
    nouveaux_objets=np.ones((len(points)))
    tab_distances=[]
    if len(objets_points):
        for point_id in range(len(points)):
            distances=distance(points[point_id], objets_points)
            tab_distances.append(distances)

        tab_distances=np.array(tab_distances)
        sorted_distances=np.sort(tab_distances, axis=None)

        for d in sorted_distances:
            if d>distance_mini:
                break
            id1, id2=np.where(tab_distances==d)
            if not len(id1) or not len(id2):
                continue
            tab_distances[id1, :]=distance_mini+1
            tab_distances[:, id2]=distance_mini+1
            objets_KF[id2[0]].update(np.expand_dims(points[id1[0]], axis=-1))
            nouveaux_objets[id1]=0

    # Création du filtre de Kalman pour les nouveaux objets
    for point_id in range(len(points)):
        if nouveaux_objets[point_id]:
            print("NOUVEAU", points[point_id])
            objets_points.append(points[point_id])
            objets_KF.append(KalmanFilter(0.5, [points[point_id][0], points[point_id][1]], [points[point_id][2], points[point_id][3]]))
            objets_id.append(id_objet)
            objets_historique.append([])
            id_objet+=1

    # Nettoyage ...
    tab_id=[]
    for id_point in range(len(objets_points)):
        if int(objets_points[id_point][0])<-100 or \
        int(objets_points[id_point][1])<-100 or \
            objets_points[id_point][0]>frame.shape[1]+100 or \
            objets_points[id_point][1]>frame.shape[0]+100:
            print("SUPPRESSION", objets_points[id_point])
            tab_id.append(id_point)

    for index in sorted(tab_id, reverse=True):
        del objets_points[index]
        del objets_KF[index]
        del objets_id[index]
        del objets_historique[index]

    cv2.rectangle(frame, (0, 0), (frame.shape[1], 30), (100, 100, 100), cv2.FILLED)
    message="Frame: {:03d}  Nbr personne: {:d}  nbr filtre: {:d}   [r]Rectangle: {:3}  [t]Trace: {:3}".format(id_frame,
                                                                                                            len(points),
                                                                                                            len(objets_points),
                                                                                                            "ON" if rectangle else "OFF",
                                                                                                            "ON" if trace else "OFF")
    cv2.putText(frame,
                message,
                (20, 20),
                cv2.FONT_HERSHEY_PLAIN,
                1,
                (255, 255, 255),
                1)

    cv2.imshow("frame", frame)
    key=cv2.waitKey(70)&0xFF
    if key==ord('r'):
        rectangle=not rectangle
    if key==ord('t'):
        trace=not trace
    if key==ord('q'):
        quit()
    id_frame+=1
