using System;
using System.Collections.Generic;
using System.Diagnostics.Tracing;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Text;
using System.Threading.Tasks;
using FxpConvert.Common;

namespace NIFPGA
{
    public class WriteFifo<T>:Fifo
        where T : unmanaged
    {
        internal WriteFifo(FPGASession session, uint fifosession) : base(session, fifosession)
        {
        }
        public void Write(T[] value,uint timeout,ref uint emptyElementsRemaining)
        {
            if (value.Length == 0) return;
            switch(value[0])
            {
                case bool:
                    _Session.CheckResult(_Session.GetDelegate<Interop.NiFpgaDll_WriteFifoBool>()(_Session.Session, FifoSession,ref Unsafe.As<T, byte>(ref value[0]), (uint)value.Length, timeout, ref emptyElementsRemaining));
                    break;
                case byte:
                    _Session.CheckResult(_Session.GetDelegate<Interop.NiFpgaDll_WriteFifoU8>()(_Session.Session, FifoSession, ref Unsafe.As<T, byte>(ref value[0]), (uint)value.Length, timeout, ref emptyElementsRemaining));
                    break;
                case sbyte:
                    _Session.CheckResult(_Session.GetDelegate<Interop.NiFpgaDll_WriteFifoI8>()(_Session.Session, FifoSession, ref Unsafe.As<T, byte>(ref value[0]), (uint)value.Length, timeout, ref emptyElementsRemaining));
                    break;
                case short:
                    _Session.CheckResult(_Session.GetDelegate<Interop.NiFpgaDll_WriteFifoI16>()(_Session.Session, FifoSession, ref Unsafe.As<T, byte>(ref value[0]), (uint)value.Length, timeout, ref emptyElementsRemaining));
                    break;
                case ushort:
                    _Session.CheckResult(_Session.GetDelegate<Interop.NiFpgaDll_WriteFifoU16>()(_Session.Session, FifoSession, ref Unsafe.As<T, byte>(ref value[0]), (uint)value.Length, timeout, ref emptyElementsRemaining));
                    break;
                case int:
                    _Session.CheckResult(_Session.GetDelegate<Interop.NiFpgaDll_WriteFifoI32>()(_Session.Session, FifoSession, ref Unsafe.As<T, byte>(ref value[0]), (uint)value.Length, timeout, ref emptyElementsRemaining));
                    break;
                case uint:
                    _Session.CheckResult(_Session.GetDelegate<Interop.NiFpgaDll_WriteFifoU32>()(_Session.Session, FifoSession, ref Unsafe.As<T, byte>(ref value[0]), (uint)value.Length, timeout, ref emptyElementsRemaining));
                    break;
                case long:
                    _Session.CheckResult(_Session.GetDelegate<Interop.NiFpgaDll_WriteFifoI64>()(_Session.Session, FifoSession, ref Unsafe.As<T, byte>(ref value[0]), (uint)value.Length, timeout, ref emptyElementsRemaining));
                    break;
                case ulong:
                    _Session.CheckResult(_Session.GetDelegate<Interop.NiFpgaDll_WriteFifoU64>()(_Session.Session, FifoSession, ref Unsafe.As<T, byte>(ref value[0]), (uint)value.Length, timeout, ref emptyElementsRemaining));
                    break;
                case float:
                    _Session.CheckResult(_Session.GetDelegate<Interop.NiFpgaDll_WriteFifoSgl>()(_Session.Session, FifoSession, ref Unsafe.As<T, byte>(ref value[0]), (uint)value.Length, timeout, ref emptyElementsRemaining));
                    break;
                case double:
                    _Session.CheckResult(_Session.GetDelegate<Interop.NiFpgaDll_WriteFifoDbl>()(_Session.Session, FifoSession, ref Unsafe.As<T, byte>(ref value[0]), (uint)value.Length, timeout, ref emptyElementsRemaining));
                    break;
            }
        }
    }
    public class WriteFXPFifo : WriteFifo<ulong>
    {
        private IFxpConvert _Convert;
        private NiFpga_FxpTypeInfo _TypeInfo;
        internal WriteFXPFifo(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 Write(ref float value, uint timeout, uint length, ref uint emptyElementsRemaining)
        {
            if (length == 0) return;
            ulong[] temp= new ulong[length];
            _Convert.FloatConvertToDxp(ref value, _TypeInfo, ref temp[0], (uint)length);
            //for(int i=0;i<value.Length;i++)
            //{
            //    temp[i] = Interop.NiFpgaDll_ConvertFromDoubleToFxp(_TypeInfo, value[i]);
            //}
            base.Write(temp, timeout, ref emptyElementsRemaining);
        }
    }
}
