using Misc;
using NLog.Fluent;
using NLog.LayoutRenderers.Wrappers;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace FlyADBase
{
    /// <summary>
    /// 高级timegrid助手
    /// 使用说明：
    /// ADPool 只能储存 1min数据, 其它XXXPool 保存1.5min数据
    /// 
    /// 
    /// 获取最后一次运行动作的开始与结束时间
    /// bool ret = mTimeGridAdvHelper.GetLastRunningTime(out DateTime beginTime, out DateTime endTime, out int marker, out DRIVE_MAN_ORDER order);
    /// 
    /// 获取 指定时间范围的 timegrid 数据
    /// var adList = mTimeGridAdvHelper.GetAD(beginTime, endTime, out DateTime reponse_endTime);
    ///
    /// 获取 指定时间范围的 pos 数据
    /// var posList = mTimeGridAdvHelper.GetPos(reponse_endTime,adList.Count());
    /// 
    /// 获取 指定时间范围的 pos2 数据
    /// var pos2List = mTimeGridAdvHelper.GetPos2(reponse_endTime,adList.Count());
    /// 
    /// 获取 指定时间范围的 输入口 数据
    /// var istatusList = mTimeGridAdvHelper.GetIStatus(reponse_endTime,adList.Count());
    /// 
    /// 转为 grid 数据
    /// int posLen = 8900;
    /// var grid = ToGrid(adList, posList, posOfGrid = 10, gridLen = posLen/10);
    /// 
    /// </summary>
    public class TimeGridAdvHelper
    {
        NLog.Logger logger = NLog.LogManager.GetCurrentClassLogger();

        #region 一分钟数据缓存池, 目标每个AD数据（1ms） 都有对应的其它数据
        public const int POOL_SIZE_SECOND = 120;
        /// <summary>
        /// AD数据池时间间隔为1ms，数据是肯定是连续的。Add数据时，非连续，填充数据直到连续 
        /// </summary>
        public List<DateTimeUnit5> DataPool = new List<DateTimeUnit5>();

        /// <summary>
        /// DriveStatus 数据池, 肯定最少有一个数据
        /// </summary>
        public List<DateTimeUnit4> DriveStatusPool = new List<DateTimeUnit4>();
        #endregion

        public DateTime NewestTime = DateTime.MinValue;

        /// <summary>
        /// 上一次脉冲改变的时间
        /// </summary>
        public DateTime positionChangedTime;
        /// <summary>
        /// 上一次脉冲2改变的时间
        /// </summary>
        public DateTime position2ChangedTime;
        /// <summary>
        /// 上一次输入口改变的时间
        /// </summary>
        public DateTime istatusChangedTime;

        /// <summary>
        /// 
        /// </summary>
        public void Init()
        {
            Clear();
        }
        public int Time2Index(DateTime time)
        {
            if (time == DateTime.MinValue)
                return -1;

            return TimeGridAdvHelperExt.Time2Index(DataPool.Count(), NewestTime, time);
        }
        public DateTime Index2Time(int index)
        {
            return TimeGridAdvHelperExt.Index2Time(DataPool.Count(), NewestTime, index);
        }

        public class AddDataResponse
        {
            public bool isChanged => isPosChanged || isPos2Changed || isIstatusChanged;
            public bool isPosChanged;
            public bool isPos2Changed;
            public bool isIstatusChanged;
            public UInt16 ichanged;
        }


        
        /// <summary>
        /// <para>添加数据，且判断数据量是否够触发事件, 时间间隔为 1ms</para> 
        /// <para>postion, 与 postion2 比较特别。 会记录最后一次改变的时间。</para> 
        /// <para>当再此改变， 两个数据点的数据，需要重新修正。 线性插值。</para>  
        /// <para>两个时间点限制在150ms内。</para>
        /// </summary>
        /// <param name="dt"></param>
        /// <param name="ad"></param>
        /// <param name="ad2"></param>
        /// <param name="postion"></param>
        /// <param name="postion2"></param>
        /// <param name="istatus"></param>
        public AddDataResponse AddData(DateTime dt, int ad, int ad2, int postion, int postion2, UInt16 istatus)
        {

            if (DataPool.Count()==0) 
            {
                //第1次添加
                DataPool.Add(new DateTimeUnit5() { ad = ad, ad2 = ad2, pos = postion, pos2 = postion2, istatus = istatus });
                NewestTime = dt;

                //记录脉冲改变点
                positionChangedTime = NewestTime;
                position2ChangedTime = NewestTime;
                istatusChangedTime = NewestTime;
                return new AddDataResponse();
            }
            
            if (dt < NewestTime && NewestTime - dt > TimeSpan.FromMilliseconds(2))  //时间异常，居然早2秒了，数据全部删除
            {
                //TODO, 不能没有状态
                Clear();

                DataPool.Add(new DateTimeUnit5() { ad = ad, ad2 = ad2, pos = postion, pos2 = postion2, istatus = istatus });
                NewestTime = dt;

                //记录脉冲改变点
                positionChangedTime = NewestTime;
                position2ChangedTime = NewestTime;
                istatusChangedTime = NewestTime;
                return new AddDataResponse();
            }

            if ( dt > NewestTime && (dt - NewestTime > TimeSpan.FromSeconds(0.5)))//超过0.5s没放数据，异常
            {
                //TODO, 不能没有状态
                Clear();
                
                DataPool.Add(new DateTimeUnit5() { ad = ad, ad2 = ad2, pos = postion, pos2 = postion2, istatus = istatus });
                NewestTime = dt;

                //记录脉冲改变点
                positionChangedTime = NewestTime;
                position2ChangedTime = NewestTime;
                istatusChangedTime = NewestTime;
                return new AddDataResponse();
            }
                
            if (dt <= NewestTime)
            {
                //把最后一个删除, 换为这个新的
                DataPool.RemoveAt(DataPool.Count() - 1);

                DataPool.Add(new DateTimeUnit5() { ad = ad, ad2 = ad2, pos = postion, pos2 = postion2, istatus = istatus });
                NewestTime = dt;
            }
            else
            {
                DateTime last_dt = NewestTime;
                while (true)
                {
                    last_dt += TimeSpan.FromTicks(TimeSpan.TicksPerMillisecond);
                    if (last_dt < dt)
                    {
                        //填充之前的数据
                        DataPool.Add(DataPool.Last());
                    }
                    else
                    {
                        //填充完了，放入新的数据
                        DataPool.Add(new DateTimeUnit5() { ad = ad, ad2 = ad2, pos = postion, pos2 = postion2, istatus = istatus });
                        NewestTime = last_dt;

                        break;
                    }
                }
            }
            


            LimitPool();

            AddDataResponse response = new AddDataResponse();


            //检查是否改变了
            if (DataPool.Count > 1)
            {
                var data_last_2 = DataPool[DataPool.Count - 2];
                response.ichanged = (UInt16)(data_last_2.istatus ^ istatus);
                if (response.ichanged != 0)
                {
                    response.isIstatusChanged = true;

                    istatusChangedTime = NewestTime;
                }

                if (data_last_2.pos != postion) {

                    response.isPosChanged = true;

                    //插值！！！！
                    LinearInterpolation(1, positionChangedTime);

                    positionChangedTime = NewestTime;

                    
                }

                if (data_last_2.pos2 != postion2)
                {
                    response.isPos2Changed = true;

                    //插值！！！！
                    LinearInterpolation(2, position2ChangedTime);

                    position2ChangedTime = NewestTime;
                }
            }
            return response;
        }
        /// <summary>
        /// 脉冲的线性插值
        /// </summary>
        void LinearInterpolation(int posNo, DateTime keyTime) 
        {
            if(posNo!=1 && posNo != 2)
            {
                throw new Exception($"写错程序, posNo={posNo} 只能是 1或2");
            }
            //插值！！！！
            int len = (int)(NewestTime - keyTime).TotalMilliseconds;
            
            if (len > 150)
            {
                //限制时间
                len = 150;
            }
            if (len > DataPool.Count - 1)
            {
                //异常
                len = DataPool.Count - 1;
            }
            var dataLastPoint = DataPool[DataPool.Count - 1];
            var dataKeyPoint = DataPool[DataPool.Count - len - 1];

            int kp;
            int distance;
            if (posNo == 1)
            {
                kp = dataKeyPoint.pos;
                distance = (dataLastPoint.pos - dataKeyPoint.pos);
            }
            else 
            {
                kp = dataKeyPoint.pos2;
                distance = (dataLastPoint.pos2 - dataKeyPoint.pos2);
            }


            for (int i = 0; i < len - 1; i++)
            {
                int index = DataPool.Count - len + i;
                int pos = distance * (i + 1) / len + kp;
                var data = DataPool[index];
                
                if(posNo==1)
                    data.pos = pos;
                else
                    data.pos2 = pos;

                DataPool[index] = data;
            }
        }
        void LimitPool() 
        {
            if (NewestTime == DateTime.MinValue)
                return;


            if (DataPool.Count() < (POOL_SIZE_SECOND + 30) * 1000)
            {
                //比限定的多了30秒 才会动作
                return;
            }

            //只保持1分钟数据
            int remove_cnt = DataPool.Count() - POOL_SIZE_SECOND * 1000;
            DataPool.RemoveRange(0, remove_cnt);


            //限制的时间
            var limitTime_other = NewestTime - TimeSpan.FromSeconds(POOL_SIZE_SECOND + 30);
            LimitSimplePool(DriveStatusPool, limitTime_other);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <typeparam name="T">IDateTimeUnit</typeparam>
        /// <param name="pool">缓存区</param>
        /// <param name="cap_min">缓存区容量单位min</param>
        void LimitSimplePool<T>(List<T> pool, DateTime limitTime) where T : IDateTimeUnit 
        {

            //删除Pos 数据池
            int removeCnt = 0;
            for (int i = 0; i < pool.Count(); i++)
            {
                var cell = pool[i];
                if (cell.dt < limitTime)
                {
                    //需要删除
                    removeCnt = i + 1;
                }
                else
                {
                    break;
                }
            }

            if (removeCnt > 0)
            {
                //不能全部数据删除完,必须留一个

                if (removeCnt == pool.Count())
                {
                    removeCnt--;
                    if (removeCnt <= 0)
                        return;//不用删除了
                }

                pool.RemoveRange(0, removeCnt);
            }
        }



        /// <summary>
        /// 添加驱动状态, 返回true，则driveStatus变化了
        /// </summary>
        /// <param name="time"></param>
        /// <param name="order"></param>
        /// <param name="driveStatus"></param>
        public bool AddDriveStatus(DateTime time,DRIVE_MAN_ORDER order,  DRIVE_MAN_STATUS driveStatus)
        {
            var pool = DriveStatusPool;
            if (pool.Count > 0)
            {
                if (pool.Last().dt > time)
                {
                    //异常，把之前的数据删除
                    pool.Clear();
                }
                else if (pool.Last().dt == time)
                {
                    //删除之前那个
                    pool.RemoveAt(pool.Count() - 1);
                }
            }
            
            pool.Add(new DateTimeUnit4() { dt = time, order = order, driveStatus = driveStatus });
            
            if (pool.Count() > 1)
            {
                return pool[pool.Count() - 2].driveStatus != driveStatus;
            }
            return false;
        }

        /// <summary>
        /// 
        /// </summary>
        public void Clear()
        {
            DataPool.Clear();
            DriveStatusPool.Clear();
        }


        /// <summary>
        /// 获取最后一次运行的时间段
        /// </summary>
        /// <param name="begin"></param>
        /// <param name="end"></param>
        /// <param name="order"></param>
        /// <returns></returns>
        public bool GetLastRunningTime(out DateTime begin, out DateTime end, out DRIVE_MAN_ORDER order) {
            begin = DateTime.MinValue;
            end = DateTime.MinValue;
            order = DRIVE_MAN_ORDER.IDLE;
            //1. 找 最后一个 driveStatus!=running的
            int idxOfStop = -1;
            for (int i = DriveStatusPool.Count() - 1; i >= 0; i--)
            {

                var cell = DriveStatusPool[i];
                if (cell.driveStatus != DRIVE_MAN_STATUS.RUNNING)
                {
                    //对！！它是。但继续向前找找看
                    idxOfStop = i;
                }
                else
                {
                    if (idxOfStop != -1)
                    {
                        //之前已经找到了，
                        break;
                    }
                }
            }
            if (idxOfStop == -1)
            {
                //一直在running，还没停下来
                return false;
            }

            //2. 最向前找running的
            int idxOfRunning = -1;
            for (int i = idxOfStop - 1; i >= 0; i--)
            {
                var cell = DriveStatusPool[i];
                if (cell.driveStatus == DRIVE_MAN_STATUS.RUNNING)
                {
                    //对！！它是。但继续向前找找看
                    idxOfRunning = i;
                }
                else
                {
                    //没了
                    break;
                }
            }

            if (idxOfRunning == -1)
            {
                //一直停着，没有运行过
                return false;
            }

            begin = DriveStatusPool[idxOfRunning].dt;
            end = DriveStatusPool[idxOfStop].dt;
            order = DriveStatusPool[idxOfStop].order;
           
            return true;
        }


        /// <summary>
        /// 获取最后一次运行中的timegrid;
        /// 找到最后一个 driveStatus!=running的, 最向前找running的
        /// </summary>
        /// <param name="begin">开始时间</param>
        /// <param name="end">结束时间</param>
        /// <returns></returns>
        public List<DateTimeUnit5> GetData(DateTime begin, DateTime end, out DateTime response_endTime)
        {
            return TimeGridAdvHelperExt.GetData(DataPool, NewestTime, begin, end, out response_endTime);
        }
        public List<DateTimeUnit5> GetData(DateTime begin)
        {
            return TimeGridAdvHelperExt.GetData(DataPool, NewestTime, begin);
        }

        
    }
    public interface IDateTimeUnit 
    {
        DateTime dt { get; set; }
    }
    public struct DateTimeUnit: IDateTimeUnit
    {
        public int data;
        public DateTime dt { get; set; }
        public override string ToString()
        {
            return $"{dt.Ticks} | {data}";
        }
    }

    public struct DateTimeUnit4 : IDateTimeUnit
    {
        public DateTime dt { get; set; }
        public DRIVE_MAN_ORDER order;
        public DRIVE_MAN_STATUS driveStatus;
        public int marker;

        public override string ToString()
        {
            return $"{dt.Ticks} | {order} | {driveStatus} | {marker}";
        }
    }
    public struct DateTimeUnit5
    {
        public int ad;
        public int ad2;
        public int pos;
        public int pos2;
        public UInt16 istatus;
        public int GetPos(int no) 
        {
            if (no == 1)
                return pos;
            else
                return pos2;
        }
        public int GetPosByIndex(int index)
        {
            if (index == 0)
                return pos;
            else
                return pos2;
        }

        public override string ToString()
        {
            return $"ad={ad} | ad2={ad2} | p={pos} | p2={pos2} | i={istatus:X4}";
        }
    }

    public struct DateTimeUnit2: IDateTimeUnit
    {
        public DateTime dt { get; set; }
        public UInt16 istatus;
        public bool isPosValid;
        public int pos;
        public int pos2;
        public override string ToString()
        {
            if(isPosValid)
                return $"{dt.Ticks} | ({istatus:X2}) | 1={pos} | 2={pos2}";
            else
                return $"{dt.Ticks} | ({istatus:X2})";

        }
    }

    public static class TimeGridAdvHelperExt 
    {
        public static int Time2Index(int dataCount, DateTime newestTime, DateTime time)
        {
            //TODO .TotalMilliseconds 是double，有机会出现0.99999问题
            int index = dataCount - 1 - (int)(newestTime - time).TotalMilliseconds;
            return index;
        }
        public static DateTime Index2Time(int dataCount, DateTime newestTime, int index)
        {
            return newestTime - TimeSpan.FromMilliseconds(dataCount - 1 - index);
        }

        /// <summary>
        /// 导出的数据间隔是1ms 一个
        /// </summary>
        /// <param name="adPool">AD缓存区</param>
        /// <param name="begin">开始时间点</param>
        /// <returns></returns>
        public static List<DateTimeUnit5> GetData(List<DateTimeUnit5> dataPool, DateTime newestTime, DateTime begin)
        {
            //时间转为序号
            int begin_idx = Time2Index(dataPool.Count(), newestTime, begin) + 1;

            //限制序号位置
            if (begin_idx < 0)
                begin_idx = 0;
            if (begin_idx > dataPool.Count() - 1)
                begin_idx = dataPool.Count() - 1;

            List<DateTimeUnit5> reponse = dataPool.GetRange(begin_idx, dataPool.Count()-1 - begin_idx + 1);

            return reponse;
        }

        /// <summary>
        /// 获取 时间在 begin~end 的 Data数据
        /// </summary>
        /// <param name="dataPool">缓存区</param>
        /// <param name="newestTime">缓存区最后一个点的时间</param>
        /// <param name="begin">开始时间点</param>
        /// <param name="end">结束时间点</param>
        /// <param name="response_endTime">导出数据最后一个点的时间</param>
        /// <returns></returns>
        public static List<DateTimeUnit5> GetData(List<DateTimeUnit5> dataPool, DateTime newestTime, DateTime begin, DateTime end, out DateTime response_endTime)
        {
            //时间转为序号
            int begin_idx = Time2Index(dataPool.Count(), newestTime, begin) + 1;

            //限制序号位置
            if (begin_idx < 0)
                begin_idx = 0;
            if (begin_idx > dataPool.Count() - 1)
                begin_idx = dataPool.Count() - 1;

            int end_idx = dataPool.Count() - (int)((newestTime - end).TotalMilliseconds);
            if (end_idx < 0)
                end_idx = 0;
            if (end_idx > dataPool.Count() - 1)
                end_idx = dataPool.Count() - 1;

            if (begin_idx > end_idx)
            {
                var t = begin_idx;
                begin_idx = end_idx;
                end_idx=t;
            }

            response_endTime = newestTime - TimeSpan.FromMilliseconds(dataPool.Count() - 1 - end_idx);

            List <DateTimeUnit5> reponse = dataPool.GetRange(begin_idx, end_idx-begin_idx+1);

            return reponse;
        }

        /// <summary>
        /// 数据滞后
        /// </summary>
        /// <param name="dataPool"></param>
        /// <param name="ad1Lag"></param>
        /// <param name="ad2Lag"></param>
        public static bool AdLagCorr(List<DateTimeUnit5> dataPool, ref DateTime endTime, int ad1Lag, int ad2Lag) 
        {
            int lag = Math.Max(ad1Lag, ad2Lag);
            if (lag == 0)
                return true;

            int endIdx = dataPool.Count() - 1 - lag;
            if (endIdx < 0)
                return false;

            int removeCnt = lag;
            for (int i = 0; i <endIdx; i++)
            {
                int index = i;
                int idxOfAd1 = index + ad1Lag;
                int idxOfAd2 = index + ad2Lag;

                if (idxOfAd1 > dataPool.Count() - 1)
                    continue;
                if (idxOfAd2 > dataPool.Count() - 1)
                    continue;

                var data = dataPool[index];

                data.ad = dataPool[idxOfAd1].ad;
                data.ad2 = dataPool[idxOfAd2].ad2;

                dataPool[index] = data;
            }

            //删除没有改动的数据
            if (removeCnt > 0)
            {
                dataPool.RemoveRange(endIdx + 1, removeCnt);
                endTime -= TimeSpan.FromMilliseconds(removeCnt);
            }
            return true;
        }
        /// <summary>
        /// 获取平均速度, 单位 脉冲/min
        /// </summary>
        /// <param name="posPool">脉冲缓存区</param>
        /// <param name="begin">开始时间点</param>
        /// <param name="end">结束时间点</param>
        /// <returns></returns>
        public static double GetSpeed(List<DateTimeUnit5> dataPool, DateTime newestTime, DateTime begin, DateTime end, int posNo) 
        {
            if (posNo != 1 && posNo != 2)
                throw new Exception($"写错程序 GetSpeed posNo={posNo} 只能是1 或 2");

            int begin_idx = dataPool.Count() - (int)((newestTime - begin).TotalMilliseconds);
            int end_idx = dataPool.Count() - (int)((newestTime - end).TotalMilliseconds);
            if (begin_idx < 0)
                begin_idx = 0;
            if (end_idx > dataPool.Count() - 1)
                end_idx = dataPool.Count() - 1;

            var beginPoint = dataPool[begin_idx];
            var endPoint = dataPool[end_idx];
            return (endPoint.GetPos(posNo) - beginPoint.GetPos(posNo)) / ((end_idx - begin_idx) / 60000.0);
        }

        /// <summary>
        /// 获取平均速度, 单位 脉冲/min
        /// </summary>
        /// <param name="posPool">脉冲缓存区</param>
        /// <param name="begin">开始时间点</param>
        /// <param name="end">结束时间点</param>
        /// <returns></returns>
        public static double GetSpeedByIndex(List<DateTimeUnit5> dataPool, DateTime newestTime, DateTime begin, DateTime end, int posIndex)
        {
            if (posIndex != 0 && posIndex != 1)
                throw new Exception($"写错程序 GetSpeedByIndex posIndex={posIndex} 只能是0 或 1");

            int begin_idx = dataPool.Count() - (int)(newestTime - begin).TotalMilliseconds;
            int end_idx = dataPool.Count() - (int)(newestTime - end).TotalMilliseconds;
            if (begin_idx < 0)
                begin_idx = 0;
            if (end_idx > dataPool.Count() - 1)
                end_idx = dataPool.Count() - 1;

            var beginPoint = dataPool[begin_idx];
            var endPoint = dataPool[end_idx];
            return (endPoint.GetPosByIndex(posIndex) - beginPoint.GetPosByIndex(posIndex)) / ((end_idx - begin_idx) / 60000.0);
        }

        /// <summary>
        /// 获取平均速度, 单位 脉冲/min
        /// </summary>
        /// <param name="posPool">脉冲缓存区</param>
        /// <param name="begin">开始时间点</param>
        /// <param name="end">结束时间点</param>
        /// <returns></returns>
        public static double GetSpeed(List<DateTimeUnit5> dataPool, int dataLen, int posNo)
        {
            if (posNo != 1 && posNo != 2)
                throw new Exception($"写错程序 GetSpeed posNo={posNo} 只能是1 或 2");

            int begin_idx = dataPool.Count() - dataLen;
            int end_idx = dataPool.Count() - 1;
            if (begin_idx < 0)
                begin_idx = 0;
            if (end_idx > dataPool.Count() - 1)
                end_idx = dataPool.Count() - 1;

            var beginPoint = dataPool[begin_idx];
            var endPoint = dataPool[end_idx];
            return (endPoint.GetPos(posNo) - beginPoint.GetPos(posNo)) / ((end_idx - begin_idx) / 60000.0);
        }

        /// <summary>
        /// 获取平均速度, 单位 脉冲/min
        /// </summary>
        /// <param name="posPool">脉冲缓存区</param>
        /// <param name="begin">开始时间点</param>
        /// <param name="end">结束时间点</param>
        /// <returns></returns>
        public static double GetSpeedByIndex(List<DateTimeUnit5> dataPool, int dataLen, int posIndex)
        {
            if (posIndex != 0 && posIndex != 1)
                throw new Exception($"写错程序 GetSpeed posIndex={posIndex} 只能是0 或 1");

            int begin_idx = dataPool.Count() - dataLen;
            int end_idx = dataPool.Count() - 1;
            if (begin_idx < 0)
                begin_idx = 0;
            if (end_idx > dataPool.Count() - 1)
                end_idx = dataPool.Count() - 1;

            var beginPoint = dataPool[begin_idx];
            var endPoint = dataPool[end_idx];
            return (endPoint.GetPosByIndex(posIndex) - beginPoint.GetPosByIndex(posIndex)) / ((end_idx - begin_idx) / 60000.0);
        }

        /// <summary>
        /// 获取时间对应的 位置点
        /// </summary>
        /// <param name="dt"></param>
        /// <param name="posPool">脉冲缓存池</param>
        /// <param name="searchIdx">查询开始序号</param>
        /// <returns></returns>
        public static int GetPos(List<DateTimeUnit5> dataPool, DateTime newestTime, DateTime dt, int posNo)
        {
            if (posNo != 1 && posNo != 2)
                throw new Exception($"写错程序 GetSpeed posNo={posNo} 只能是1 或 2");

            int idx = dataPool.Count() - (int)((newestTime - dt).TotalMilliseconds);
            if (idx < 0)
                idx = 0;
            if (idx > dataPool.Count() - 1)
                idx = dataPool.Count() - 1;

            var point = dataPool[idx];
            return point.GetPos(posNo);
        }
        /// <summary>
        /// 获取时间对应的 位置点
        /// </summary>
        /// <param name="dt"></param>
        /// <param name="posPool">脉冲缓存池</param>
        /// <param name="searchIdx">查询开始序号</param>
        /// <returns></returns>
        public static int GetPosByIndex(List<DateTimeUnit5> dataPool, DateTime newestTime, DateTime dt, int posIndex)
        {
            if (posIndex != 0 && posIndex != 1)
                throw new Exception($"写错程序 GetSpeed posIndex={posIndex} 只能是0 或 1");

            int idx = dataPool.Count() - (int)((newestTime - dt).TotalMilliseconds);
            if (idx < 0)
                idx = 0;
            if (idx > dataPool.Count() - 1)
                idx = dataPool.Count() - 1;

            var point = dataPool[idx];
            return point.GetPosByIndex(posIndex);
        }

        /// <summary>
        /// 输出 grid图。 dataPool[x+ad0Lag].ad 对应 dataPool[x].position
        /// </summary>
        /// <param name="dataPool">1ms数据缓存区</param>
        /// <param name="posOfGrid">1grid的脉冲数</param>
        /// <param name="gridLen">grid总数</param>
        /// <param name="grid_start">数据有效部分开始点</param>
        /// <param name="grid_end">数据有效部分结束点</param>
        /// <param name="gridsOfAd1">导出的AD1 grid图</param>
        /// <param name="gridsOfAd2">导出的AD2 grid图</param>
        /// <param name="ad1Lag">AD1 滞后</param>
        /// <param name="ad2Lag">AD2 滞后</param>
        /// <param name="isMiniGrid">裁剪grid图 只导出有效部分</param>
        public static void ToGrid(
            List<DateTimeUnit5> dataPool, int posOfGrid, 
            int gridLen, 
            out int grid_start, out int grid_end, 
            out int[] gridsOfAd1, out int[] gridsOfAd2,
            bool isMiniGrid=false)
        {
            int[] gridsOfAd1_sum = new int[gridLen];
            int[] gridsOfAd1_cnt = new int[gridLen];

            int[] gridsOfAd2_sum = new int[gridLen];
            int[] gridsOfAd2_cnt = new int[gridLen];


            int grid_idx_last = -1;
            grid_start = Misc.MyBase.NULL_VALUE;
            grid_end = Misc.MyBase.NULL_VALUE;

            //grid_idx 应该要连续变化，不是，那就插值
            for (int j = 0; j < dataPool.Count(); j++)
            {

                int ad1 = dataPool[j].ad;
                int ad2 = dataPool[j].ad2;
                int pos = dataPool[j].pos;

                int grid_idx = pos / posOfGrid;
                //grid不能小于0 或 大于等于 gridLen
                if (grid_idx < 0 || grid_idx >= gridLen)
                    continue;

                if (!Misc.MyBase.ISVALIDATA(grid_start))
                {
                    grid_start = grid_idx;
                    grid_end = grid_idx;
                }
                else
                {
                    if (grid_idx < grid_start)
                        grid_start = grid_idx;
                    if (grid_idx > grid_end)
                        grid_end = grid_idx;
                }
                
                if (grid_idx_last != -1 && (Math.Abs(grid_idx_last - grid_idx) > 1))
                {
                    //步子太大，需要插值
                    if (grid_idx_last < grid_idx)
                    {
                        for (int i = grid_idx_last; i < grid_idx; i++)
                        {
                            toGrid_step1(gridsOfAd1_sum, gridsOfAd1_cnt, gridLen, i, ad1);
                            toGrid_step1(gridsOfAd2_sum, gridsOfAd2_cnt, gridLen, i, ad2);
                        }
                    }
                    else
                    {
                        for (int i = grid_idx_last; i > grid_idx; i--)
                        {
                            toGrid_step1(gridsOfAd1_sum, gridsOfAd1_cnt, gridLen, i, ad1);
                            toGrid_step1(gridsOfAd2_sum, gridsOfAd2_cnt, gridLen, i, ad2);
                        }
                    }
                }

                toGrid_step1(gridsOfAd1_sum, gridsOfAd1_cnt, gridLen, grid_idx, ad1);
                toGrid_step1(gridsOfAd2_sum, gridsOfAd2_cnt, gridLen, grid_idx, ad2);

                grid_idx_last = grid_idx;
            }

            for (int i = 0; i < gridLen; i++)
            {
                if (gridsOfAd1_cnt[i] == 0)
                    gridsOfAd1_sum[i] = Misc.MyBase.NULL_VALUE;
                else
                    gridsOfAd1_sum[i] = (int)(gridsOfAd1_sum[i] / gridsOfAd1_cnt[i]);

                if (gridsOfAd2_cnt[i] == 0)
                    gridsOfAd2_sum[i] = Misc.MyBase.NULL_VALUE;
                else
                    gridsOfAd2_sum[i] = (int)(gridsOfAd2_sum[i] / gridsOfAd2_cnt[i]);
            }

            if (isMiniGrid)
            {
                //只导出 grid_start~grid_end 数据
                if (Misc.MyBase.ISVALIDATA(grid_start))
                {
                    gridsOfAd1 = gridsOfAd1_sum.Skip(grid_start).Take(grid_end - grid_start + 1).ToArray();
                    gridsOfAd2 = gridsOfAd2_sum.Skip(grid_start).Take(grid_end - grid_start + 1).ToArray();
                    return;
                }
                else {
                    //一个数据都没有
                    gridsOfAd1 = null;
                    gridsOfAd2 = null;
                    return;
                }
            }
            else
            {
                gridsOfAd1 = gridsOfAd1_sum;
                gridsOfAd2 = gridsOfAd2_sum;
            }
        }


        static void toGrid_step1(int[] grids_sum, int[] grids_cnt, int gridLen, int grid_idx, int ad)
        {
            if ((grid_idx < 0) || (grid_idx >= gridLen))
            {
                return;
            }

            if (!Misc.MyBase.ISVALIDATA(ad))
                return;

            grids_cnt[grid_idx]++;
            grids_sum[grid_idx] += ad;
        }


        /// <summary>
        /// <para>data0s 的 输入口=false 序号范围</para>
        /// <para>data1s 的 输入口=true 序号范围</para>
        /// </summary>
        /// <param name="dataPool">数据池</param>
        /// <param name="newestTime">数据池最后一个数据时间</param>
        /// <param name="istatusIndex">输入口序号</param>
        /// <param name="beginTime">开始时间</param>
        /// <param name="endTime">结束时间</param>
        /// <param name="data0s">输入口=false 序号范围<</param>
        /// <param name="data1s">输入口=true 序号范围</param>
        public static void GetIStatusRange(
            List<DateTimeUnit5> dataPool,
            DateTime newestTime,
            int istatusIndex,
            DateTime beginTime, DateTime endTime,
            out List<Range> data0s, out List<Range> data1s)
        {
            data0s = new List<Range>();
            data1s = new List<Range>();
            
            Range range = new Range();
            bool is1 = false;

            int begin_idx = dataPool.Count() - (int)((newestTime - beginTime).TotalMilliseconds);

            if (begin_idx < 0)
                begin_idx = 0;
            if (begin_idx > dataPool.Count() - 1)
                begin_idx = dataPool.Count() - 1;

            int end_idx = dataPool.Count() - (int)((newestTime - endTime).TotalMilliseconds);

            if (end_idx < 0)
                end_idx = 0;
            if (end_idx > dataPool.Count() - 1)
                end_idx = dataPool.Count() - 1;

            for (int i = begin_idx; i <= end_idx; i++) 
            {
                var data = dataPool[i];
                bool istatus_bit = Misc.MyBase.CHECKBIT(data.istatus, istatusIndex);
                if (!range.IsValid)
                {
                    //第1次
                    range.Begin = i;
                    range.End = i;
                    is1 = istatus_bit;
                    if (is1)
                    {
                        data1s.Add(range);
                    }
                    else
                    {
                        data0s.Add(range);
                    }
                }
                else
                {
                    if (istatus_bit == is1)
                    {
                        //信号一样
                        range.End = i;
                    }
                    else {
                        //信号改变了
                        range = new Range();
                        range.Begin = i;
                        range.End = i;
                        is1 = istatus_bit;
                        if (is1)
                        {
                            data1s.Add(range);
                        }
                        else
                        {
                            data0s.Add(range);
                        }
                    }
                }
            }
        }


        /// <summary>
        /// <para>data0s 的 输入口=false 序号范围</para>
        /// <para>data1s 的 输入口=true 序号范围</para>
        /// </summary>
        /// <param name="dataPool">数据池</param>
        /// <param name="newestTime">数据池最后一个数据时间</param>
        /// <param name="istatusIndex">输入口序号</param>
        /// <param name="beginTime">开始时间</param>
        /// <param name="endTime">结束时间</param>
        /// <param name="data0s">输入口=false 序号范围<</param>
        /// <param name="data1s">输入口=true 序号范围</param>
        public static void GetIStatusRange(
            List<DateTimeUnit5> dataPool,
            int istatusIndex,
            int dataLen,
            out List<Range> data0s, out List<Range> data1s)
        {
            data0s = new List<Range>();
            data1s = new List<Range>();

            Range range = new Range();
            bool is1 = false;

            int begin_idx = dataPool.Count() - dataLen;

            if (begin_idx < 0)
                begin_idx = 0;
            if (begin_idx > dataPool.Count() - 1)
                begin_idx = dataPool.Count() - 1;

            int end_idx = dataPool.Count() - 1;

            for (int i = begin_idx; i <= end_idx; i++)
            {
                var data = dataPool[i];
                bool istatus_bit = Misc.MyBase.CHECKBIT(data.istatus, istatusIndex);
                if (!range.IsValid)
                {
                    //第1次
                    range.Begin = i;
                    range.End = i;
                    is1 = istatus_bit;
                    if (is1)
                    {
                        data1s.Add(range);
                    }
                    else
                    {
                        data0s.Add(range);
                    }
                }
                else
                {
                    if (istatus_bit == is1)
                    {
                        //信号一样
                        range.End = i;
                    }
                    else
                    {
                        //信号改变了
                        range = new Range();
                        range.Begin = i;
                        range.End = i;
                        is1 = istatus_bit;
                        if (is1)
                        {
                            data1s.Add(range);
                        }
                        else
                        {
                            data0s.Add(range);
                        }
                    }
                }
            }
        }
    }
    public class Range_DateTime 
    {
        public DateTime Begin;
        public DateTime End;
    }
}
