using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.ComponentModel;
using FObjBase;
using System.Collections.Specialized;

namespace FLY.Thick.BulkDataModule
{
    public class BulkDataService : IBulkDataService, IBulkDataServiceAdd 
    {

        #region 成员变量
        int m_size;//最大纵向幅数
        int m_nbolts;//分区数
        int m_boltno1st;//第1分区号
        int pushmix_max = -1;


        /// <summary>
        /// 缓冲数据区
        /// </summary>
        private List<FR_DATA> m_fr_data;

        public List<FR_DATA> Datas
        {
            get { return m_fr_data; }
        }
        public event NotifyDatasChangedEventHandler DatasChanged;

   
        private int count = 0;
        /// <summary>
        /// 数量
        /// </summary>
        public int Count {
            get { return count; }
            set {
                if (count != value) {
                    count = value;
                    NotifyPropertyChanged("Count");
                }
            }
        }
        private int currentbookmark = -1;
        /// <summary>
        /// 最新的bookmark
        /// </summary>
        public int CurrentBookmark
        {
            get { return currentbookmark; }
            set
            {
                if (currentbookmark != value)
                {
                    currentbookmark = value;
                    NotifyPropertyChanged("CurrentBookmark");
                }
            }
        }


        #endregion

        private string param_path = "bulk.csv";

        public BulkDataService(int nbolts, int boltno1st, int size) : this(nbolts, boltno1st, size, "bulk.csv")
        {

        }
        public BulkDataService(int nbolts, int boltno1st, int size, string param_path)
        {

            m_nbolts = nbolts;
            m_size = size;
            m_boltno1st = boltno1st;
            m_fr_data = new List<FR_DATA>();

            if (!string.IsNullOrEmpty(param_path))
                this.param_path = param_path;

            Load();
        }
        #region ITDParam 成员


        public bool Load()
        {
            
            if (!File.Exists(param_path))
                return false;

            StreamReader sr = new StreamReader(param_path);
            string s = sr.ReadLine();
            if (s == null)
                return false;
            //第1行，标题
            //bookmark,time,type,0,1,2,3...........
            string[] ss = s.Split(new char[] { ',' });
            int nbs = ss.Length - 3;

            if (nbs != NBolts)
            {
                sr.Close();
                return false;		// boltmap does not match!
            }
            int boltno1st;
            if (!int.TryParse(ss[3], out boltno1st))
                return false;		// boltmap does not match!

            BoltNo1st = boltno1st;

            m_fr_data.Clear();
            int i = 0;
            while (!sr.EndOfStream)
            {
                if (i >= m_size)
                {
                    sr.Close(); return true;
                }
                s = sr.ReadLine();

                ss = s.Split(new char[] { ',' });
                FR_DATA frdata = new FR_DATA();
                if (!int.TryParse(ss[0], out  frdata.bookmark))
                {
                    //失败,跳过
                    continue;
                }
                if (!DateTime.TryParse(ss[1], out frdata.timemark))
                {
                    //失败,跳过
                    continue;
                }
                int t;
                if (!int.TryParse(ss[2], out  t))
                {
                    //失败,跳过
                    continue;
                }
                frdata.type = (FR_DATA_TYPE)t;

                frdata.m_data = new int[m_nbolts];
                for (int j = 0; j < ss.Length - 3; j++)
                {
                    if (j >= m_nbolts)
                        break;
                    string data_str = ss[j + 3];
                    if (string.IsNullOrWhiteSpace(data_str))
                        frdata.m_data[j] = Misc.MyBase.NULL_VALUE;
                    else
                    {

                        if (!int.TryParse(ss[j + 3], out  frdata.m_data[j]))
                            frdata.m_data[j] = Misc.MyBase.NULL_VALUE;
                    }
                }
                m_fr_data.Add(frdata);
                i++;
            }
            sr.Close();
            return true;
        }

        public void Save()
        {
            if (string.IsNullOrEmpty(param_path))
                return;

            StreamWriter sw = new StreamWriter(param_path, false);
            //第1行，标题
            //bookmark, time, type, 0,1,2,3......
            sw.Write("bookmark,time,type");
            for (int i = 0; i < NBolts; i++)
            {
                sw.Write("," + (BoltNo1st+i).ToString());
            }
            sw.WriteLine();
            for (int i = 0; i < m_fr_data.Count; i++)
            {
                string s = m_fr_data[i].bookmark.ToString() + "," +
                    m_fr_data[i].timemark.ToString("yyyy/MM/dd HH:mm:ss") + "," +
                    ((int)m_fr_data[i].type).ToString() + ",";

                for (int j = 0; j < m_nbolts; j++)
                {
                    if (Misc.MyBase.ISVALIDATA(m_fr_data[i].m_data[j]))
                        s += m_fr_data[i].m_data[j].ToString();
                    if (j != m_nbolts - 1)
                        s += ",";
                }
                sw.WriteLine(s);
            }
            sw.Flush();
            sw.Close();
            return;
        }

        #endregion
        #region IBulkDataService
        /// <summary>
        /// 注册新数据推送
        /// </summary>
        /// <param name="param"></param>
        /// <param name="AsyncDelegate"></param>
        /// <param name="AsyncState"></param>
        public void PushNewFrameData(
            BULKDATA_OBJ_INTERFACE.Pack_CallPushNewFrameDataParam param, AsyncCBHandler AsyncDelegate, object AsyncState) 
        {
            if (!dataRequestList.Exists(dr => dr.AsyncState.Equals(AsyncState) && IsSameParam(dr.Param, param)))
            {
                dataRequestList.Add(
                    new DataRequest()
                    {
                        Param = param,
                        AsyncState = AsyncState,
                        AsyncDelegate = AsyncDelegate
                    });
            }
        }

        void GetNewFrameData(BULKDATA_OBJ_INTERFACE.Pack_CallPushNewFrameDataParam param, AsyncCBHandler AsyncDelegate, object AsyncState)
        {

            int[] result;
            if (pushmix_max < 1)
                return;

            int mix = (param.mix < pushmix_max) ? param.mix : pushmix_max;

            GetFrame(out result, -1, param.mix, 0, NBolts);

            BULKDATA_OBJ_INTERFACE.Pack_CallPushNewFrameDataReturn reponse = new BULKDATA_OBJ_INTERFACE.Pack_CallPushNewFrameDataReturn()
            {
                mix = param.mix
            };

            FR_DATA frdata = GetBulkFrame(-1);

            if (frdata != null)
            {
                reponse.bookmark = frdata.bookmark;//结果对应的 bookmark
                reponse.dt = frdata.timemark;//结果对应的 时间
                reponse.type = frdata.type;//结果.数据是否有效
                reponse.result = result;//结果， 当needPush=true, 以后推送时，只发送变化了的数据
            }

            AsyncDelegate(AsyncState, reponse);
        }
        /// <summary>
        /// 获取一幅数据， 默认带推送
        /// </summary>
        /// <param name="param"></param>
        /// <param name="AsyncDelegate"></param>
        /// <param name="AsyncState"></param>
        public void GetFrameData(BULKDATA_OBJ_INTERFACE.Pack_CallGetFrameDataParam param, AsyncCBHandler AsyncDelegate, object AsyncState)
        {
            if (param.NeedPush)//推送
            {
                if (!dataRequestList.Exists(dr => dr.AsyncState.Equals(AsyncState) && IsSameParam(dr.Param, param)))
                {
                    dataRequestList.Add(
                        new DataRequest()
                        {
                            Param = param,
                            AsyncState = AsyncState,
                            AsyncDelegate = AsyncDelegate
                        });
                }
            }

            int[] result;
            GetFrame(out result, param.bm, param.mix, 0, NBolts);

            BULKDATA_OBJ_INTERFACE.Pack_CallGetFrameDataReturn reponse = new BULKDATA_OBJ_INTERFACE.Pack_CallGetFrameDataReturn()
            {
                NeedPush = param.NeedPush,
                bm = param.bm,
                mix = param.mix
            };

            FR_DATA frdata = GetBulkFrame(param.bm);

            if (frdata != null)
            {
                reponse.bookmark = frdata.bookmark;//结果对应的 bookmark
                reponse.dt = frdata.timemark;//结果对应的 时间
                reponse.fromBoltIndex = 0;//开始分区index
                reponse.toBoltIndex = result.Length - 1;//结束分区index
                reponse.type = frdata.type;//结果.数据是否有效
                reponse.result = result;//结果， 当needPush=true, 以后推送时，只发送变化了的数据
            }

            AsyncDelegate(AsyncState, reponse);
        }
        void GetFrameData(BULKDATA_OBJ_INTERFACE.Pack_CallGetFrameDataParam param, AsyncCBHandler AsyncDelegate, object AsyncState, int boltIndex, int len) 
        {

            int[] result;
            GetFrame(out result, param.bm, param.mix, boltIndex, len);

            BULKDATA_OBJ_INTERFACE.Pack_CallGetFrameDataReturn reponse = new BULKDATA_OBJ_INTERFACE.Pack_CallGetFrameDataReturn()
            {
                NeedPush = param.NeedPush,
                bm = param.bm,
                mix = param.mix
            };

            FR_DATA frdata = GetBulkFrame(param.bm);

            if (frdata != null)
            {
                reponse.bookmark = frdata.bookmark;//结果对应的 bookmark
                reponse.dt = frdata.timemark;//结果对应的 时间
                reponse.fromBoltIndex = boltIndex;//开始分区index
                reponse.toBoltIndex = boltIndex + len - 1;//结束分区index
                reponse.type = frdata.type;//结果.数据是否有效
                reponse.result = result;//结果， 当needPush=true, 以后推送时，只发送变化了的数据
            }

            AsyncDelegate(AsyncState, reponse);
        }
        bool IsSameParam_PushNewFrameData(object src, object dest)
        {
            if ((src is BULKDATA_OBJ_INTERFACE.Pack_CallPushNewFrameDataParam)
                && (dest is BULKDATA_OBJ_INTERFACE.Pack_CallPushNewFrameDataParam))
            {
                BULKDATA_OBJ_INTERFACE.Pack_CallPushNewFrameDataParam fdparam
                    = src as BULKDATA_OBJ_INTERFACE.Pack_CallPushNewFrameDataParam;
                BULKDATA_OBJ_INTERFACE.Pack_CallPushNewFrameDataParam cfdparam
                    = dest as BULKDATA_OBJ_INTERFACE.Pack_CallPushNewFrameDataParam;
                if (fdparam.mix == cfdparam.mix)
                {
                    return true;
                }
                else
                {
                    return false;
                }
            }
            return false;
        }
        bool IsSameParam_GetFrameData(object src, object dest)
        {
            if ((src is BULKDATA_OBJ_INTERFACE.Pack_CallClosePushFrameData) &&
                (dest is BULKDATA_OBJ_INTERFACE.Pack_CallClosePushFrameData))
            {
                BULKDATA_OBJ_INTERFACE.Pack_CallClosePushFrameData fdparam =
                    src as BULKDATA_OBJ_INTERFACE.Pack_CallClosePushFrameData;
                BULKDATA_OBJ_INTERFACE.Pack_CallClosePushFrameData cfdparam =
                    dest as BULKDATA_OBJ_INTERFACE.Pack_CallClosePushFrameData;

                if ((fdparam.bm == cfdparam.bm) && (fdparam.mix == cfdparam.mix))
                {
                    return true;
                }
                else
                {
                    return false;
                }
            }
            return false;
        }
        bool IsSameParam_GetTrendData(object src, object dest)
        {
            if ((src is BULKDATA_OBJ_INTERFACE.Pack_CallClosePushTrendData) &&
                (dest is BULKDATA_OBJ_INTERFACE.Pack_CallClosePushTrendData))
            {
                BULKDATA_OBJ_INTERFACE.Pack_CallClosePushTrendData tdparam =
                    src as BULKDATA_OBJ_INTERFACE.Pack_CallClosePushTrendData;
                BULKDATA_OBJ_INTERFACE.Pack_CallClosePushTrendData ctdparam =
                    dest as BULKDATA_OBJ_INTERFACE.Pack_CallClosePushTrendData;
                if ((tdparam.mix == ctdparam.mix) &&
                    (tdparam.fromBoltNo == ctdparam.fromBoltNo) &&
                    (tdparam.toBoltNo == ctdparam.toBoltNo))
                {
                    return true;
                }
                else
                {
                    return false;
                }
            }
            return false;
        }
        bool IsSameParam_GetFrameDataMix(object src, object dest)
        {
            if ((src is Pack_CallClosePushFrameDataMixRequest) &&
                (dest is Pack_CallClosePushFrameDataMixRequest))
            {
                return ((Pack_CallClosePushFrameDataMixRequest)src).IsSame(
                    (Pack_CallClosePushFrameDataMixRequest)dest);
            }
            return false;
        }
        bool IsSameParam(object src, object dest)
        {
            if (IsSameParam_GetFrameData(src, dest) == true)
                return true;

            if (IsSameParam_GetTrendData(src, dest) == true)
                return true;

            if (IsSameParam_PushNewFrameData(src, dest) == true)
                return true;

            if (IsSameParam_GetFrameDataMix(src, dest) == true)
                return true;

            return false;
        }
        /// <summary>
        /// 获取纵向趋势图，默认带推送
        /// </summary>
        /// <param name="param"></param>
        /// <param name="AsyncDelegate"></param>
        /// <param name="AsyncState"></param>
        public void GetTrendData(BULKDATA_OBJ_INTERFACE.Pack_CallGetTrendDataParam param, AsyncCBHandler AsyncDelegate, object AsyncState)
        {
            if (param.NeedPush)
            {
                if (!dataRequestList.Exists(dr => dr.AsyncState.Equals(AsyncState) && IsSameParam(dr.Param, param)))
                {
                    dataRequestList.Add(
                        new DataRequest()
                        {
                            Param = param,
                            AsyncState = AsyncState,
                            AsyncDelegate = AsyncDelegate
                        });
                }
            }


            TrendDataCell[] result;
            GetTrend(out result, param.len, param.mix, param.fromBoltNo, param.toBoltNo);


            BULKDATA_OBJ_INTERFACE.Pack_CallGetTrendDataReturn reponse = new BULKDATA_OBJ_INTERFACE.Pack_CallGetTrendDataReturn();
            reponse.NeedPush = param.NeedPush;//当数据变化时，是否需要推送
            reponse.len = param.len;//获取的长度
            reponse.mix = param.mix;//混合数
            reponse.fromBoltNo = param.fromBoltNo;//开始分区index
            reponse.toBoltNo = param.toBoltNo;//结束分区index
            //TODO
            //输出
            //FR_DATA frdata = GetBulkFrame(-1);
            //if (frdata != null)//有数据，不是空的！！！！！
            //{
            if(result != null)
            {
                reponse.edit_position = 0;
                reponse.result = result;//结果
            }


            AsyncDelegate(AsyncState, reponse);
        }

        /// <summary>
        /// 关闭 扫描图 推送
        /// </summary>
        /// <param name="param"></param>
        /// <param name="AsyncState"></param>
        public void ClosePushFrameData(BULKDATA_OBJ_INTERFACE.Pack_CallClosePushFrameData param, object AsyncState)
        {
            dataRequestList.RemoveAll(
                dr => dr.AsyncState.Equals(AsyncState) && IsSameParam(dr.Param, param));
        }
        /// <summary>
        /// 关闭 新数据推送
        /// </summary>
        /// <param name="param"></param>
        /// <param name="AsyncState"></param>
        public void ClosePushNewFrameData(BULKDATA_OBJ_INTERFACE.Pack_CallClosePushNewFrameData param, object AsyncState)
        {
            dataRequestList.RemoveAll(
                dr => dr.AsyncState.Equals(AsyncState) && IsSameParam(dr.Param, param));
        }

        /// <summary>
        /// 关闭 纵向趋势图 推送
        /// </summary>
        /// <param name="param"></param>
        /// <param name="AsyncState"></param>
        public void ClosePushTrendData(BULKDATA_OBJ_INTERFACE.Pack_CallClosePushTrendData param, object AsyncState)
        {
            dataRequestList.RemoveAll(
                dr => dr.AsyncState.Equals(AsyncState) && IsSameParam(dr.Param, param));
        }

        /// <summary>
        /// 获取一幅数据， 默认带推送
        /// 参数 Pack_CallGetFrameDataMixRequest
        /// 回复 Pack_CallGetFrameDataMixReponse
        /// </summary>
        /// <param name="param"></param>
        /// <param name="AsyncDelegate"></param>
        /// <param name="AsyncState"></param>
        public void GetFrameDataMix(
            Pack_CallGetFrameDataMixRequest param, AsyncCBHandler AsyncDelegate, object AsyncState)
        {
            if (param.NeedPush)//推送
            {
                if (!dataRequestList.Exists(dr => dr.AsyncState.Equals(AsyncState) && IsSameParam(dr.Param, param)))
                {
                    dataRequestList.Add(
                        new DataRequest()
                        {
                            Param = param,
                            AsyncState = AsyncState,
                            AsyncDelegate = AsyncDelegate
                        });
                }
            }
            GetFrameDataMix(param, AsyncDelegate, AsyncState, 0, NBolts);
        }
        void GetFrameDataMix(Pack_CallGetFrameDataMixRequest param, AsyncCBHandler AsyncDelegate, object AsyncState, int boltIndex, int len)
        {

            FrameDataCell[] result;
            int start_bookmark;
            GetFrameMix(out result,out start_bookmark, param.bm, param.mix, boltIndex, len, param.start_dt);

            Pack_CallGetFrameDataMixReponse reponse = new Pack_CallGetFrameDataMixReponse()
            {
                NeedPush = param.NeedPush,
                bm = param.bm,
                mix = param.mix,
                start_dt = param.start_dt
            };

            FR_DATA frdata = GetBulkFrame(param.bm);

            if (frdata != null)
            {
                reponse.bookmark = frdata.bookmark;//结果对应的 bookmark
                reponse.dt = frdata.timemark;//结果对应的 时间
                reponse.fromBoltIndex = boltIndex;//开始分区index
                reponse.toBoltIndex = boltIndex + len - 1;//结束分区index
                reponse.type = frdata.type;//结果.数据是否有效
                reponse.result = result;//结果， 当needPush=true, 以后推送时，只发送变化了的数据


                FR_DATA start_frdata = GetBulkFrame(start_bookmark);
                reponse.act_startDt = start_frdata.timemark;//结果对应的 实际开始时间
            }

            AsyncDelegate(AsyncState, reponse);
        }
        /// <summary>
        /// 关闭 扫描图 推送
        /// </summary>
        /// <param name="param"></param>
        /// <param name="AsyncState"></param>
        public void ClosePushFrameDataMix(
            Pack_CallClosePushFrameDataMixRequest param, object AsyncState)
        {
            dataRequestList.RemoveAll(
                dr => dr.AsyncState.Equals(AsyncState) && IsSameParam(dr.Param, param));
        }


        /// <summary>
        /// 只要关于AsyncState 的都要删除
        /// </summary>
        /// <param name="match"></param>
        public void ClosePush(Predicate<object> match)
        {
            dataRequestList.RemoveAll(delegate(DataRequest dr)
            {
                return match(dr.AsyncState);
            });
        }
        
        /// <summary>
        /// 清空缓存
        /// </summary>
        public void Clear()
        {
            m_fr_data.Clear();
            ClearedEvent();
        }

        /// <summary>
        /// 准备好，只有在 IsReady=true ，发送的命令才能执行，才能推送
        /// </summary>
        public bool IsConnected
        {
            get { return true; }
        }
        /// <summary>
        /// 全部数据被删除
        /// </summary>
        void ClearedEvent()
        {
            CurrentBookmark = -1;
            Count = 0;
            {
                DatasChanged?.Invoke(
                    this,
                    new NotifyDatasChangedEventArgs() { Action = NotifyDatasChangedAction.Reset });
            }

            foreach (DataRequest dr in dataRequestList)
            {
                if (dr.Param is BULKDATA_OBJ_INTERFACE.Pack_CallGetFrameDataParam)
                {
                    BULKDATA_OBJ_INTERFACE.Pack_CallGetFrameDataParam fdp = dr.Param as BULKDATA_OBJ_INTERFACE.Pack_CallGetFrameDataParam;
                    BULKDATA_OBJ_INTERFACE.Pack_CallGetFrameDataReturn reqonse = new BULKDATA_OBJ_INTERFACE.Pack_CallGetFrameDataReturn();

                    reqonse.NeedPush =fdp.NeedPush;//当数据变化时，是否需要推送
                    reqonse.bm = fdp.bm;//标记, 当bm>0 为bookmark，当bm <=0 为往前面数
                    reqonse.mix = fdp.mix;//混合数
                    //输出

                    reqonse.bookmark = -1;//结果对应的 bookmark
                    reqonse.dt = DateTime.MinValue;//结果对应的 时间
                    reqonse.fromBoltIndex = 0;//开始分区index
                    reqonse.toBoltIndex = NBolts - 1;//结束分区index
                    reqonse.type = FR_DATA_TYPE.INVALID;//结果.数据是否有效
                    reqonse.result = null;//结果， 当needPush=true, 以后推送时，只发送变化了的数据

                    dr.AsyncDelegate(dr.AsyncState, reqonse);
                }
                else if (dr.Param is BULKDATA_OBJ_INTERFACE.Pack_CallGetTrendDataParam)
                {
                    BULKDATA_OBJ_INTERFACE.Pack_CallGetTrendDataParam tdp = dr.Param as BULKDATA_OBJ_INTERFACE.Pack_CallGetTrendDataParam;
                    BULKDATA_OBJ_INTERFACE.Pack_CallGetTrendDataReturn reqonse = new BULKDATA_OBJ_INTERFACE.Pack_CallGetTrendDataReturn();

                    reqonse.NeedPush = tdp.NeedPush;//当数据变化时，是否需要推送
                    reqonse.len = tdp.len;//获取的长度
                    reqonse.mix = tdp.mix;//混合数
                    reqonse.fromBoltNo = tdp.fromBoltNo;//开始分区index
                    reqonse.toBoltNo = tdp.toBoltNo;//结束分区index
                    //输出


                    reqonse.edit_position = 0;
                    reqonse.result = null;//结果
                    dr.AsyncDelegate(dr.AsyncState, reqonse);
                }
            }
        }

        bool IsFit(DataRequest dr , int bm_relative)
        {
            if(dr.Param is BULKDATA_OBJ_INTERFACE.Pack_CallGetFrameDataParam)
            {
                BULKDATA_OBJ_INTERFACE.Pack_CallGetFrameDataParam fdp = dr.Param as BULKDATA_OBJ_INTERFACE.Pack_CallGetFrameDataParam;
                int fdp_bm_relative = BM2Relative(fdp.bm);
                if ((fdp_bm_relative - fdp.mix < bm_relative) && (fdp_bm_relative >= bm_relative))
                    return true;
                else
                    return false;
            }
            else if(dr.Param is BULKDATA_OBJ_INTERFACE.Pack_CallGetTrendDataParam)
            {
                BULKDATA_OBJ_INTERFACE.Pack_CallGetTrendDataParam tdp = dr.Param as BULKDATA_OBJ_INTERFACE.Pack_CallGetTrendDataParam;
                if((BM2Relative(-1) - tdp.mix <bm_relative) &&  (BM2Relative(-1) >= bm_relative))
                    return true;
                else
                    return false;
            }
            return false;
        }
        /// <summary>
        /// 某幅数据被修改
        /// </summary>
        void ChangedEvent(FR_DATA fr_data, int boltIndex, int len)
        {
            {
                int idx = Datas.FindLastIndex((d) => d == fr_data);
                DatasChanged?.Invoke(
                    this, new NotifyDatasChangedEventArgs()
                    {
                        Action = NotifyDatasChangedAction.Replace,
                        Items = new List<FR_DATA>(new FR_DATA[] { fr_data }),
                        NewStartingIndex = idx
                    });
            }

            int bookmark = fr_data.bookmark;

            int bm_relative = BM2Relative(bookmark);

            var drs = from _dr in dataRequestList
                      where IsFit(_dr, bm_relative) select _dr;

            if (drs.Count() > 0)
            {
                foreach (DataRequest dr in drs)
                {
                    if (dr.Param is BULKDATA_OBJ_INTERFACE.Pack_CallGetFrameDataParam)
                    {

                        BULKDATA_OBJ_INTERFACE.Pack_CallGetFrameDataParam param = dr.Param as BULKDATA_OBJ_INTERFACE.Pack_CallGetFrameDataParam;
                        GetFrameData(
                            param,
                            dr.AsyncDelegate,
                            dr.AsyncState,
                            boltIndex,
                            len);
                    }
                    else if (dr.Param is Pack_CallGetFrameDataMixRequest)
                    {

                        Pack_CallGetFrameDataMixRequest param = dr.Param as Pack_CallGetFrameDataMixRequest;
                        GetFrameDataMix(
                            param,
                            dr.AsyncDelegate,
                            dr.AsyncState,
                            boltIndex,
                            len);
                    }
                    else if (dr.Param is BULKDATA_OBJ_INTERFACE.Pack_CallGetTrendDataParam)
                    {
                        BULKDATA_OBJ_INTERFACE.Pack_CallGetTrendDataParam param = dr.Param as BULKDATA_OBJ_INTERFACE.Pack_CallGetTrendDataParam;

                        //GetTrend只能获取 BM= -1 的数据，其它不管
                        if (bm_relative > -1)
                            return;

                        if(bm_relative<-param.mix)
                            return;

                        //判断是否有交集
                        int fromBoltIndex = boltIndex;
                        int toBoltIndex = boltIndex + len - 1;

                        int ts1 = (param.fromBoltNo-BoltNo1st) - fromBoltIndex;
                        int ts2;
                        if (ts1 > 0)//  fromBoltIndex  < param.fromBoltIndex
                            ts2 = (param.fromBoltNo - BoltNo1st) - toBoltIndex;
                        else// param.fromBoltIndex < fromBoltIndex
                            ts2 = fromBoltIndex - (param.toBoltNo - BoltNo1st);

                        if (ts2 > 0)
                            return;//无交集


                        TrendDataCell[] result;
                        GetTrend(out result, param.mix, param.mix, param.fromBoltNo, param.toBoltNo);
                        if (result.Length == 0)
                            continue;


                        BULKDATA_OBJ_INTERFACE.Pack_CallGetTrendDataReturn reponse = new BULKDATA_OBJ_INTERFACE.Pack_CallGetTrendDataReturn();
                        reponse.NeedPush = param.NeedPush;//当数据变化时，是否需要推送
                        reponse.len = param.len;//获取的长度
                        reponse.mix = param.mix;//混合数
                        reponse.fromBoltNo = param.fromBoltNo;//开始分区index
                        reponse.toBoltNo = param.toBoltNo;//结束分区index
                        //输出
                        FR_DATA frdata = GetBulkFrame(bookmark);

                        
                        reponse.edit_position = 0;
                        reponse.result = result;//结果
                        dr.AsyncDelegate(dr.AsyncState, reponse);
                        
                    }
                }
            }
        }

        bool IsFit2(DataRequest dr)
        {
            if (dr.Param is BULKDATA_OBJ_INTERFACE.Pack_CallGetFrameDataParam)
            {
                BULKDATA_OBJ_INTERFACE.Pack_CallGetFrameDataParam fdp = dr.Param as BULKDATA_OBJ_INTERFACE.Pack_CallGetFrameDataParam;
                if (fdp.bm <= 0)
                    return true;
                else
                    return false;
            }
            else if (dr.Param is Pack_CallGetFrameDataMixRequest)
            {
                Pack_CallGetFrameDataMixRequest fdp = dr.Param as Pack_CallGetFrameDataMixRequest;
                if (fdp.bm <= 0)
                    return true;
                else
                    return false;
            }
            else if (dr.Param is BULKDATA_OBJ_INTERFACE.Pack_CallGetTrendDataParam)
            {
                return true;
            }
            else if (dr.Param is BULKDATA_OBJ_INTERFACE.Pack_CallPushNewFrameDataParam)
            {
                return true;
            }

            return false;
        }
        /// <summary>
        /// 添加了一幅数据, 推送数据
        /// </summary>
        void AddedEvent()
        {
            Count = Datas.Count();
            CurrentBookmark = Datas.Last().bookmark;

            {
                DatasChanged?.Invoke(
                    this,
                    new NotifyDatasChangedEventArgs()
                    {
                        Action = NotifyDatasChangedAction.Add,
                        Items = new List<FR_DATA>(new FR_DATA[] { Datas.Last() }),
                        NewStartingIndex = Datas.Count() - 1
                    });
            }
            var drs = from _dr in dataRequestList
                      where IsFit2(_dr)
                      select _dr;

            if (drs.Count() > 0)
            {
                foreach (DataRequest dr in drs)
                {
                    if (dr.Param is BULKDATA_OBJ_INTERFACE.Pack_CallPushNewFrameDataParam)
                    {
                        BULKDATA_OBJ_INTERFACE.Pack_CallPushNewFrameDataParam param = dr.Param as BULKDATA_OBJ_INTERFACE.Pack_CallPushNewFrameDataParam;
                        GetNewFrameData(
                            dr.Param as BULKDATA_OBJ_INTERFACE.Pack_CallPushNewFrameDataParam,
                            dr.AsyncDelegate,
                            dr.AsyncState);

                    }
                    else if (dr.Param is BULKDATA_OBJ_INTERFACE.Pack_CallGetFrameDataParam)
                    {
                        BULKDATA_OBJ_INTERFACE.Pack_CallGetFrameDataParam param = dr.Param as BULKDATA_OBJ_INTERFACE.Pack_CallGetFrameDataParam;
                        GetFrameData(
                           param,
                            dr.AsyncDelegate,
                            dr.AsyncState,
                            0,
                            NBolts);

                    }
                    else if (dr.Param is Pack_CallGetFrameDataMixRequest)
                    {
                        Pack_CallGetFrameDataMixRequest param = dr.Param as Pack_CallGetFrameDataMixRequest;
                        GetFrameDataMix(
                            param,
                            dr.AsyncDelegate,
                            dr.AsyncState,
                            0,
                            NBolts);

                    }
                    else if (dr.Param is BULKDATA_OBJ_INTERFACE.Pack_CallGetTrendDataParam)
                    {
                        BULKDATA_OBJ_INTERFACE.Pack_CallGetTrendDataParam param = dr.Param as BULKDATA_OBJ_INTERFACE.Pack_CallGetTrendDataParam;

                        TrendDataCell[] result;
                        GetTrend(out result,  1, param.mix, param.fromBoltNo, param.toBoltNo);
                        if (result == null)
                            continue;
                        if (result.Length == 0)
                            continue;

                        BULKDATA_OBJ_INTERFACE.Pack_CallGetTrendDataReturn reponse = new BULKDATA_OBJ_INTERFACE.Pack_CallGetTrendDataReturn();
                        reponse.NeedPush = param.NeedPush;//当数据变化时，是否需要推送
                        reponse.len = param.len;//获取的长度
                        reponse.mix = param.mix;//混合数
                        reponse.fromBoltNo = param.fromBoltNo;//开始分区index
                        reponse.toBoltNo = param.toBoltNo;//结束分区index
                        //输出
                        //FR_DATA frdata = GetBulkFrame(-1);
                        
                        reponse.edit_position = 1;
                        reponse.result = result;//结果
                        dr.AsyncDelegate(dr.AsyncState, reponse);
                    }
                }
            }
        }
        #endregion

        #region IBulkDataService
        class DataRequest
        {
            public object Param;
            public object AsyncState;
            public AsyncCBHandler AsyncDelegate;
        }
        List<DataRequest> dataRequestList = new List<DataRequest>();

        #endregion

        #region bookmark 取值
        int GetCurrentBookmark()
        {
            FR_DATA frdata = m_fr_data.Last();
            if (frdata == null)
                return -1;

            return frdata.bookmark;
        }
        /// <summary>
        /// 最大bookmark
        /// </summary>
        int MaxBookmark 
        {
            get {
                return 4000;
            }
        }
        /// <summary>
        /// 最小bookmark
        /// </summary>
        int MinBookmark 
        {
            get {
                return 1;
            }
        }

        /// <summary>
        /// 获取下一个bookmark ，bookmark的取值范围 MinBookmark~MaxBookmark，反正 大于 0
        /// </summary>
        /// <param name="bookmark"></param>
        /// <returns></returns>
        int GetNextBookmark(int bookmark)
        {
            if (bookmark < 0)
                return 1;

            bookmark++;
            if (bookmark > MaxBookmark)
                bookmark = MinBookmark;
            return bookmark;
        }
        /// <summary>
        /// 获取上一个bookmark，bookmark的取值范围 MinBookmark~MaxBookmark，反正 大于 0
        /// </summary>
        /// <param name="bookmark"></param>
        /// <returns></returns>
        int GetPreBookmark(int bookmark)
        {
            if (bookmark < 0)
                return 1;

            bookmark--;
            if (bookmark < MinBookmark)
                bookmark = MaxBookmark;

            return bookmark;
        }
        #endregion

        int GetBulkBookmark(int bm)
        {
            FR_DATA frdata = GetBulkFrame(bm);
            if (frdata == null)
            {
                return -1;
            }
            return frdata.bookmark;
        }
        /// <summary>
        /// 当bm&gt;0,获取 bookmark=bm 的数据
        /// 当bm&lt;=0, 获取 bookmark= 最新的数据bookmark-bm
        /// </summary>
        /// <param name="bm"></param>
        /// <returns></returns>
        FR_DATA GetBulkFrame(int bm)
        {
            if (m_fr_data.Count == 0)
                return null;
            int bookmark = BM2Bookmark(bm);

            try
            {
                return m_fr_data.Find(dat => dat.bookmark == bookmark);
            }
            catch
            {
                return null;
            }
        }

        /// <summary>
        /// 当bm&gt;0,返回 bookmark
        /// 当bm&lt;=0,返回 bm + 最新的数据bookmark
        /// </summary>
        /// <param name="bm"></param>
        /// <returns></returns>
        int BM2Bookmark(int bm)
        {
            if (bm > 0)
            {
                return bm;
            }
            else
            {
                int bookmark = GetCurrentBookmark();
                bookmark += bm;
                if (bookmark < MinBookmark)
                {
                    bookmark = MaxBookmark - (MinBookmark - bookmark - 1);
                }


                return bookmark;
            }
        }

        /// <summary>
        /// 用于比较;
        /// 当bm&gt;0,返回 bm - 最新的数据bookmark
        /// 当bm&lt;=0,返回 bm;
        /// </summary>
        /// <param name="bm"></param>
        /// <returns></returns>
        int BM2Relative(int bm)
        {
            if (bm <= 0)
                return bm;
            else
            {
                int bookmark = bm;
                int current = GetCurrentBookmark();
                int d = bookmark - current;
                if (d > 0)
                {
                    d -= (MaxBookmark - MinBookmark + 1);
                }
                
                return d;
            }
        }
        /// <summary>
        /// 获取纵向趋势图, 数据是从后向前排的，[0]是最新的数据
        /// </summary>
        /// <param name="result">输出结果</param>
        /// <param name="len">result的长度</param>
        /// <param name="mix">混合数</param>
        /// <param name="avg_from">求平均值 开始的分区No</param>
        /// <param name="avg_to">求平均值 结束的分区No</param>
        /// <returns></returns>
        bool GetTrend(out TrendDataCell[] result, int len, int mix, int avg_from, int avg_to)
        {
            if (mix <= 0) mix = 1;
            int bookmark = -1;
            //错误纠正
            if((!Misc.MyBase.ISVALIDATA(avg_from)) || (!Misc.MyBase.ISVALIDATA(avg_to)))
            {
                avg_from = 0;
                avg_to = NBolts;
            }
            else
            {
                avg_from -= BoltNo1st;
                avg_to -= BoltNo1st;

                if (avg_from < 0 || avg_to < 0)
                {
                    avg_from = 0;
                    avg_to = NBolts;
                }
                else if (avg_to < avg_from)
                {
                    int t = avg_to;
                    avg_to = avg_from;
                    avg_from = t;
                }
            }
            //------------------------------------------------------------------------------------------------
            //类型不一样，不能混合
            FR_DATA_TYPE type;
            DateTime time;
            List<TrendDataCell> _result = new List<TrendDataCell>();

            int i = 0;
            for (i = 0; i < len; i++)
            {
                FR_DATA fr_data = GetBulkFrame(bookmark);
                if (fr_data == null)
                    break;

                bookmark = fr_data.bookmark;
                type = fr_data.type;
                time = fr_data.timemark;

                int bm = bookmark;
                List<int> datas = new List<int>();
                
                int k;
                for (k = 0; k < mix; k++)
                {
                    if (k > 0)
                    {
                        fr_data = GetBulkFrame(bm);
                        if (fr_data == null)
                            break;
                        //different type can`t mix together~~~~~~~~~~~~~~~~~~~~
                        if (fr_data.type != type)
                            break;
                    }

                    //int dat;
                    //dat = Misc.MyMath.Avg(fr_data.m_data, avg_from, avg_to);

                    datas.AddRange(fr_data.m_data.Skip(avg_from).Take(avg_to - avg_from + 1));
                    bm = GetPreBookmark(bm);
                }
                //LogMessage2("bulkdata.c",1,"GetFixData mix=%d i=%d type=%d cnt=%d",mix,i,type,cnt);
                
                int avg = Misc.MyMath.Avg(datas.ToArray());
                int sigma = Misc.MyMath.Sigma(datas.ToArray());
                

                _result.Add(
                    new TrendDataCell()
                    {
                        Avg = avg,
                        Sigma = sigma,
                        Time = time,
                        Type = type
                    });

                bookmark = GetPreBookmark(bookmark);
            }
            if (_result.Count == 0)
            {
                result = null;
                return false;
            }
            result = _result.ToArray();

            return true;
        }

        //获取混合曲线
        bool GetFrame(out int[] result, int bm, int mix, int start_boltIndex, int len)
        {
            if (mix < 0) mix = 1;

            result = null;
            FR_DATA fr_data = GetBulkFrame(bm);
            if (fr_data == null)
                return false;

            int bookmark = fr_data.bookmark;
            //------------------------------------------------------------------------------------------------
            //类型不一样，不能混合
            FR_DATA_TYPE type = fr_data.type;

            List<FR_DATA> fr_datas = new List<FR_DATA>();

            result = new int[len];

            int i;
            for (i = 0; i < mix; i++)
            {
                if (i > 0)
                {
                    fr_data = GetBulkFrame(bookmark);

                    if (fr_data == null)
                        break;

                    if (fr_data.type != type)
                        break;
                }
                fr_datas.Add(fr_data);

                bookmark = GetPreBookmark(bookmark);
            }
            mix = i;

            int j;
            for (j = start_boltIndex; (j < (start_boltIndex + len)) && (j < m_nbolts); j++)
            {
                int sum = 0;
                int cnt = 0;

                for (i = 0; i < mix; i++)
                {
                    int dat = fr_datas[i].m_data[j];
                    if (Misc.MyBase.ISVALIDATA(dat))
                    {
                        sum += dat;
                        cnt++;
                    }
                }
                if (cnt > 0)
                {

                    result[j - start_boltIndex] = sum / cnt;
                }
                else
                {
                    result[j - start_boltIndex] = Misc.MyBase.NULL_VALUE;
                }
            }
            return true;
        }


        //获取混合曲线
        bool GetFrameMix(out FrameDataCell[] result,out int start_bookmark, int bm, int mix, int start_boltIndex, int len, DateTime start_dt)
        {
            if (mix < 0) mix = 1;

            result = null;
            start_bookmark = -1;

            FR_DATA fr_data = GetBulkFrame(bm);
            if (fr_data == null)
                return false;

            //------------------------------------------------------------------------------------------------
            //就算start_dt 是在未来的，也要有一幅数据
            if (fr_data.timemark < start_dt)//时间不对
                start_dt = fr_data.timemark;


            int bookmark = fr_data.bookmark;
            //------------------------------------------------------------------------------------------------
            //类型不一样，不能混合
            FR_DATA_TYPE type = fr_data.type;


            List<FR_DATA> fr_datas = new List<FR_DATA>();

            result = new FrameDataCell[len];

            int i;
            for (i = 0; i < mix; i++)
            {
                if (i > 0)
                {
                    fr_data = GetBulkFrame(bookmark);

                    if (fr_data == null)
                        break;

                    if (fr_data.type != type)
                        break;

                    if (fr_data.timemark < start_dt)//时间不对
                        break;
                }
                fr_datas.Add(fr_data);
                start_bookmark = bookmark;

                bookmark = GetPreBookmark(bookmark);
            }
            mix = i;

            List<int> datas = new List<int>();
            int j;
            for (j = start_boltIndex; (j < (start_boltIndex + len)) && (j < m_nbolts); j++)
            {
                for (i = 0; i < mix; i++)
                {
                    int dat = fr_datas[i].m_data[j];
                    datas.Add(dat);
                }
                FrameDataCell r = new FrameDataCell();
                r.Avg = Misc.MyMath.Avg(datas);
                r.Sigma = Misc.MyMath.Sigma(datas);
                datas.Clear();
                result[j - start_boltIndex] = r;
            }
            return true;
        }

        #region IBulkDataServiceAdd
        public int NBolts
        {
            get
            {
                return m_nbolts;
            }
            set
            {
                if (m_nbolts != value)
                {
                    Clear();
                    m_nbolts = value;
                    NotifyPropertyChanged("NBolts");
                }
            }
        }
        public int BoltNo1st
        {
            get
            {
                return m_boltno1st;
            }
            set
            {
                if (m_boltno1st != value)
                {
                    Clear();
                    m_boltno1st = value;
                    NotifyPropertyChanged("BoltNo1st");
                }
            }
        }
        public void InitPush() 
        {
            pushmix_max = -1;
        }

        public int Add(int[] buf, FR_DATA_TYPE type, DateTime dt)
        {
            if (m_fr_data.Count > m_size)
                m_fr_data.RemoveAt(0);
            int bm;

            if (m_fr_data.Count > 0)
            {
                bm = GetNextBookmark(m_fr_data.Last().bookmark);
            }
            else
            {
                bm = GetNextBookmark(-1);
            }

            FR_DATA frdata = new FR_DATA(bm, buf, type);
            frdata.timemark = dt;
            m_fr_data.Add(frdata);

            if (pushmix_max < (m_fr_data.Count() - 1))
                pushmix_max++;
            
            
            AddedEvent();
            return GetBulkBookmark(0);
        }

        public int Add(int[] buf, FR_DATA_TYPE type)
        {
            return Add(buf, type, DateTime.Now);
        }

        public int AddEmply()
        {
            int[] buf = new int[NBolts];
          
            for (int i = 0; i < NBolts; i++)
            {
                buf[i] = Misc.MyBase.NULL_VALUE;
            }

            return Add(buf, FR_DATA_TYPE.INVALID);
        }

        public bool Change(int bm, int start_boltIndex, int[] buf, FR_DATA_TYPE type, DateTime time)
        {
            FR_DATA fr_data = GetBulkFrame(bm);
            if (fr_data == null)
                return false;
            //bool debug = false;
            //if (m_fr_data.Count > 1 && bm == 1)
            //{
            //    for (int i = 0; i < buf.Count(); i++) 
            //    {
            //        if (buf[i] != fr_data.m_data[i]) 
            //        {
            //            //找到了
            //            debug = true;
            //            break;
            //        }
            //    }
            //}
            //if (debug) 
            //{
            
            //}
            fr_data.type = type;
            if(time != DateTime.MinValue)
                fr_data.timemark = time;
            Array.Copy(buf, 0, fr_data.m_data, start_boltIndex, buf.Length);

            //if (debug) 
            //{
            //    debug = false;
            //    for (int i = 0; i < buf.Count(); i++)
            //    {
            //        if (buf[i] != fr_data.m_data[i])
            //        {
            //            //异常
            //            debug = true;
            //            break;
            //        }
            //    }
            //    if (debug) 
            //    {

            //    }
            //}

            
            ChangedEvent(fr_data, start_boltIndex, buf.Length);

            return true;
        }

        public bool Change(int bm, int start_boltIndex, int[] buf, FR_DATA_TYPE type)
        {
            return Change(bm, start_boltIndex, buf, type, DateTime.MinValue);
        }

        public bool ChangeEmply(int bm)
        {
            int[] buf = new int[NBolts];

            for (int i = 0; i < NBolts; i++)
            {
                buf[i] = Misc.MyBase.NULL_VALUE;
            }
            return Change(bm, 0, buf, FR_DATA_TYPE.INVALID);
        }

        public bool ChangeEmply()
        {
            int[] buf = new int[NBolts];

            for (int i = 0; i < NBolts; i++)
            {
                buf[i] = Misc.MyBase.NULL_VALUE;
            }
            return Change(0, 0, buf, FR_DATA_TYPE.INVALID, DateTime.Now);
        }
        #endregion
        #region INotifyPropertyChanged 成员
        protected void NotifyPropertyChanged(string propertyName)
        {
            if (PropertyChanged != null)
            {
                PropertyChanged.Invoke(this, new PropertyChangedEventArgs(propertyName));
            }
        }
        public event PropertyChangedEventHandler PropertyChanged;

        #endregion
    }
}
