using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using bbiwarg.Utility;

namespace bbiwarg.Recognition.Tracking
{
    class TrackableObjectHistory<T> where T : TrackableObject
    {
        private static List<int> usedIDs = new List<int>();
        public int ID { get; private set; }
        public List<T> TrackedObjects { get; private set; }
        public List<TrackingState> States { get; private set; }
        public TrackableObject LastObject { get; private set; }
        public TrackableObject CurrentObject { get { return TrackedObjects[TrackedObjects.Count - 1]; } }
        public TrackingState CurrentState { get { return States[States.Count - 1]; } }
        public int NumFramesInCurrentState { get; private set; }
        private String className;
        private LogSubject logSubject;
        private int numFramesUntilTracked;

        public TrackableObjectHistory(LogSubject logSubject, int numFramesUntilTracked)
        {
            ID = getNextUnusedID();
            TrackedObjects = new List<T>();
            States = new List<TrackingState>();
            TrackedObjects.Add(null);
            States.Add(TrackingState.None);
            NumFramesInCurrentState = 1;
            this.className = typeof(T).Name;
            this.logSubject = logSubject;
            this.numFramesUntilTracked = numFramesUntilTracked;
        }

        ~TrackableObjectHistory()
        {
            setIDUnused(ID);
        }

        public void addObjectToHistory(T detectedObject)
        {
            TrackingState previousState = CurrentState;
            TrackingState newState = TrackingState.None;

            if (detectedObject != null)
            {
                if (previousState == TrackingState.None)
                {
                    newState = TrackingState.Detected;
                    Logger.log(className + " #" + ID + " detected", logSubject);
                }
                else if (previousState == TrackingState.Lost)
                {
                    newState = TrackingState.Tracked;
                    Logger.log(className + " #" + ID.ToString() + " re-tracked", logSubject);
                }
                else if (previousState == TrackingState.Tracked)
                    newState = TrackingState.Tracked;
                else if (previousState == TrackingState.Detected)
                {
                    if (NumFramesInCurrentState == numFramesUntilTracked)
                    {
                        newState = TrackingState.Tracked;
                        Logger.log(className + " #" + ID.ToString() + " tracked", logSubject);
                    }
                    else
                        newState = TrackingState.Detected;
                }

                LastObject = detectedObject;
                detectedObject.setTracked(ID);
            }
            else
                newState = TrackingState.Lost;

            if (newState == previousState)
                NumFramesInCurrentState++;

            TrackedObjects.Add(detectedObject);
            States.Add(newState);

        }

        public static int getNextUnusedID()
        {
            int id = 1;
            while (usedIDs.Contains(id))
                id++;
            usedIDs.Add(id);
            return id;
        }

        public static void setIDUnused(int id)
        {
            usedIDs.Remove(id);
        }
    }
}
