using UnityEngine.Events;
using System.Threading;

namespace Aidlab
{
    public static class Data
    {
        public abstract class DataDelegates
        {
            protected string name;

            public DataDelegates(string name)
            {
                this.name = name;
                dispatchEvent.AddListener(() =>
                {
                    Interlocked.Exchange(ref dispatchQueued, 0);
                    onDataReceivedEvents.Invoke();
                });
            }

            private readonly UnityEvent onDataReceivedEvents = new UnityEvent();
            private readonly UnityEvent dispatchEvent = new UnityEvent();
            private int dispatchQueued = 0;
            public void Subscribe(UnityAction action) { onDataReceivedEvents.AddListener(action); }
            public void Unsubscribe(UnityAction action) { onDataReceivedEvents.RemoveListener(action); }
		            protected void AfterDataReceived()
		            {
		                AidlabSDK.DebugNotifySignalUpdated();
                        // Coalesce high-frequency signals (e.g. ECG 250Hz) to at most one main-thread dispatch at a time.
                        if (Interlocked.Exchange(ref dispatchQueued, 1) == 1)
                            return;
		                MainThreadWorker.Enqueue(dispatchEvent);
		            }
		        }


        public class Data1<T> : DataDelegates
        {            
            public T value;
            public System.UInt64 timestamp;

            public Data1(string name) : base(name) { }

            public void ReceiveData(T value, System.UInt64 timestamp)
            {
                this.value = value;
                this.timestamp = timestamp;
                AfterDataReceived();
            }
        }

        public class Data3<T> : DataDelegates
        {
            public T x;
            public T y;
            public T z;
            public System.UInt64 timestamp;

            public Data3(string name) : base(name) { }

            public void ReceiveData(T x, T y, T z, System.UInt64 timestamp)
            {
                this.x = x;
                this.y = y;
                this.z = z;
                this.timestamp = timestamp;
                AfterDataReceived();
            }
        }

        public class Data2<T1, T2> : DataDelegates
        {
            public T1 a;
            public T2 b;
            public System.UInt64 timestamp;

            public Data2(string name) : base(name) { }

            public void ReceiveData(T1 a, T2 b, System.UInt64 timestamp)
            {
                this.a = a;
                this.b = b;
                this.timestamp = timestamp;
                AfterDataReceived();
            }
        }

        public class Data4<T, W> : DataDelegates
        {
            public T x;
            public T y;
            public T z;
            public W w;
            public System.UInt64 timestamp;

            public Data4(string name) : base(name) { }

            public void ReceiveData(T x, T y, T z, W w, System.UInt64 timestamp)
            {
                this.x = x;
                this.y = y;
                this.z = z;
                this.w = w;
                this.timestamp = timestamp;
                AfterDataReceived();
            }
        }

        public class Data6 : DataDelegates
        {
            public float a;
            public float b;
            public float c;
            public float d;
            public float e;
            public float f;
            public System.UInt64 timestamp;

            public Data6(string name) : base(name) { }

            public void ReceiveData(float a, float b, float c, float d, float e, float f, System.UInt64 timestamp)
            {
                this.a = a;
                this.b = b;
                this.c = c;
                this.d = d;
                this.e = e;
                this.f = f;
                this.timestamp = timestamp;
                AfterDataReceived();
            }
        }

    }
}
