using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http.Headers;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Text;
using System.Threading.Tasks;
using FxpConvert.Common;

namespace NIFPGA
{
    public class ReadFifo<T>:Fifo
        where T : unmanaged
    {
        internal ReadFifo(FPGASession session, uint fifosession) : base(session, fifosession)
        {
        }
        public void Read(ref T value,uint count, uint timeout, ref uint elementsRemaining)
        {
            switch(value)
            {
                case bool:
                    _Session.CheckResult(_Session.GetDelegate<Interop.NiFpgaDll_ReadFifoBool>()(_Session.Session, FifoSession, ref Unsafe.As<T, byte>(ref value), count, timeout, ref elementsRemaining));
                    break;
                case byte:
                    _Session.CheckResult(_Session.GetDelegate<Interop.NiFpgaDll_ReadFifoU8>()(_Session.Session, FifoSession, ref Unsafe.As<T, byte>(ref value), count, timeout, ref elementsRemaining));
                    break;
                case sbyte:
                    _Session.CheckResult(_Session.GetDelegate<Interop.NiFpgaDll_ReadFifoI8>()(_Session.Session, FifoSession, ref Unsafe.As<T, byte>(ref value), count, timeout, ref elementsRemaining));
                    break;
                case ushort:
                    _Session.CheckResult(_Session.GetDelegate<Interop.NiFpgaDll_ReadFifoU16>()(_Session.Session, FifoSession, ref Unsafe.As<T, byte>(ref value), count, timeout, ref elementsRemaining));
                    break;
                case short:
                    _Session.CheckResult(_Session.GetDelegate<Interop.NiFpgaDll_ReadFifoI16>()(_Session.Session, FifoSession, ref Unsafe.As<T, byte>(ref value), count, timeout, ref elementsRemaining));
                    break;
                case int:
                    _Session.CheckResult(_Session.GetDelegate<Interop.NiFpgaDll_ReadFifoI32>()(_Session.Session, FifoSession, ref Unsafe.As<T, byte>(ref value), count, timeout, ref elementsRemaining));
                    break;
                case uint:
                    _Session.CheckResult(_Session.GetDelegate<Interop.NiFpgaDll_ReadFifoU32>()(_Session.Session, FifoSession, ref Unsafe.As<T, byte>(ref value), count, timeout, ref elementsRemaining));
                    break;
                case long:
                    _Session.CheckResult(_Session.GetDelegate<Interop.NiFpgaDll_ReadFifoI64>()(_Session.Session, FifoSession, ref Unsafe.As<T, byte>(ref value), count, timeout, ref elementsRemaining));
                    break;
                case ulong:
                    _Session.CheckResult(_Session.GetDelegate<Interop.NiFpgaDll_ReadFifoU64>()(_Session.Session, FifoSession, ref Unsafe.As<T, byte>(ref value), count, timeout, ref elementsRemaining));
                    break;
                case float:
                    _Session.CheckResult(_Session.GetDelegate<Interop.NiFpgaDll_ReadFifoSgl>()(_Session.Session, FifoSession, ref Unsafe.As<T, byte>(ref value), count, timeout, ref elementsRemaining));
                    break;
                case double:
                    _Session.CheckResult(_Session.GetDelegate<Interop.NiFpgaDll_ReadFifoDbl>()(_Session.Session, FifoSession, ref Unsafe.As<T, byte>(ref value), count, timeout, ref elementsRemaining));
                    break;
            }
        }
        public uint ElementsRemaining
        {
            get
            {
                T val = default;
                uint elementsRemaining = 0;
                Read(ref val, 0, 5000, ref elementsRemaining);
                return elementsRemaining;
            }
        }
    }
    public class ReadFXPFifo : ReadFifo<ulong>
    {
        private NiFpga_FxpTypeInfo _TypeInfo;
        private IFxpConvert _Convert;
        internal ReadFXPFifo(FPGASession session, uint fifosession,NiFpga_FxpTypeInfo typeInfo, IFxpConvert convert) : base(session, fifosession)
        {
            if(convert ==null)throw new  ArgumentNullException(nameof(convert));
            _Convert = convert;
            _TypeInfo = typeInfo;
        }
        public void Read(ref float value,uint count, uint timeout, ref uint elementsRemaining)
        {
            ulong[] temp = new ulong[count];
            base.Read(ref temp[0],count, timeout, ref elementsRemaining);
            _Convert.FxpConvertToFloat(ref temp[0], _TypeInfo, ref value, count);
        }
    }
}
