using FLY.OBJComponents.Common;
using FLY.OBJComponents.IService;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace FLY.OBJComponents.Client
{
    /// <summary>
    /// IBuffer<T>的分页观察
    /// 
    /// </summary>
    public class BufferPage<T> : INotifyPropertyChanged, IDisposable
    {
        const int MARKNO_UPDATE_GCURRPAGE = 1;

        public event PropertyChangedEventHandler PropertyChanged;

        /// <summary>
        /// IBuffer<T>
        /// </summary>
        public IBuffer<T> Buffer;

        #region property
        /// <summary>
        /// 窗口中的数据
        /// </summary>
        public ObservableCollection<T> Record { get; } = new ObservableCollection<T>();
        /// <summary>
        /// 最新数据的ID,就是 Buffer.NewestID, 
        /// 但不直接使用Buffer.NewestID,因为 Buffer.NewestID可能与接收的数据滞后,或超前
        /// </summary>
        public int RecordLastID { get; private set; } = -1;
       

        /// <summary>
        /// 保持最新,改变WindowID 无效,它是输入
        /// </summary>
        public bool IsKeepNewest { get; private set; }

        /// <summary>
        /// 当前全局页码,GCurrPage*Size 就是页码第1行的ID
        /// </summary>
        public int GCurrPage { get; set; }

        private int size = 30;
        /// <summary>
        /// 窗口大小
        /// </summary>
        public int Size
        {
            get { return size; }
            set
            {
                if (value < 10)
                    value = 10;
                if (size != value)
                {
                    size = value;
                }
            }
        }
        /// <summary>
        /// buffer 的总页数
        /// </summary>
        public int TotalPages => GPageLast - GPage1st + 1;
        /// <summary>
        /// 当前页码, 页码从1-TotalPages
        /// </summary>
        public int CurrentPage => GCurrPage - GPage1st + 1;

        /// <summary>
        /// 最后一页
        /// </summary>
        public bool IsLastPage => (CurrentPage >= TotalPages);
        /// <summary>
        /// 最前一页
        /// </summary>
        public bool IsFirstPage => (CurrentPage <= 1);

        public int GPage1st { get; private set; }
        public int GPageLast { get; private set; }
        #endregion



        public BufferPage(IBuffer<T> buffer, int size = 30)
        {
            Size = size;
            Buffer = buffer;

            IsKeepNewest = true;
            updatePageInfo();
            updateGCurrPage();
            GetWindow();

            Buffer.BufferChanged += Buffer_BufferChanged;
            Buffer.PropertyChanged += Buffer_PropertyChanged;
            this.PropertyChanged += BufferWindow_PropertyChanged;
        }

        private void BufferWindow_PropertyChanged(object sender, PropertyChangedEventArgs e)
        {
            if (e.PropertyName == "Size")
            {
                updatePageInfo();
                updateGCurrPage();
                GetWindow();
            }
        }

        

        /// <summary>
        /// GCurrPage 肯定在合理位置
        /// Buffer.Count 肯定大于0
        /// </summary>
        void GetWindow()
        {
            int firstId = GCurrPage * Size;
            int lastId = firstId + Size - 1;

            int Buffer1stId = Buffer.NewestID - Buffer.Count + 1;
            if (firstId < Buffer1stId)
                firstId = Buffer1stId;
            
            if (lastId > Buffer.NewestID)
                lastId = Buffer.NewestID;


            int size = lastId - firstId + 1;
            Buffer.GetRecord(lastId, size, (asyncContext, retData) =>
            {
                GetRecordReponse<T> getRecordReponse = retData as GetRecordReponse<T>;
                if (getRecordReponse.Items != null)
                    push(getRecordReponse.LastID, getRecordReponse.Items);

            }, null);

            
        }

        private void Buffer_PropertyChanged(object sender, PropertyChangedEventArgs e)
        {
            if ((e.PropertyName == "Count") ||
                (e.PropertyName == "NewestID"))
            {
                updatePageInfo();
                

                FObjBase.PollModule.Current.Poll_JustOnce(() =>
                {
                    if (updateGCurrPage()) 
                    {
                        GetWindow();
                    }


                }, this, MARKNO_UPDATE_GCURRPAGE);
            }
        }

        private void Buffer_BufferChanged(object sender, NotifyBufferChangedEventArgs<T> e)
        {
            switch (e.Action)
            {
                case NotifyBufferChangedAction.Add:
                case NotifyBufferChangedAction.Replace:
                    {
                        //判断添加的数据是否在当前窗口内
                        int newEndingID = e.EndingID;
                        int nFirstID = e.EndingID;
                        int nLastID = newEndingID;

                        int wFirstID = GCurrPage * Size;
                        int wLastID = wFirstID + Size - 1;

                        if (wFirstID<nLastID)
                            return;//什么都不用干
                        if(wLastID<nFirstID)
                            return;//什么都不用干

                        //有交集把数据放入
                        push(newEndingID, (IList<T>)e.Items);
                    }
                    break;
                case NotifyBufferChangedAction.Remove:
                    {
                        remove(e.EndingID, e.Count);
                    }
                    break;
                case NotifyBufferChangedAction.Reset:
                    {
                        //数据清空
                        Record.Clear();
                        RecordLastID = 0;
                    }
                    break;
                case NotifyBufferChangedAction.IsConnected:
                    {
                        //重新连接上服务器,获取全部数据
                        GetWindow();
                    }
                    break;
            }
        }

        void push(int items_lastID, IList<T> items)
        {
            if (Record.Count() == 0)
            {
                foreach (T item in items)
                {
                    Record.Add(item);
                }
                RecordLastID = items_lastID;
            }
            else
            {
                //找Record 中的数据,是否与新推送过来的数据有交集
                int firstID = items_lastID - items.Count + 1;
                int lastID = items_lastID;

                int rFirstID = RecordLastID - Record.Count() + 1;
                int rLastID = RecordLastID;

                //转换坐标,以rFirstID=0,全部平移
                int offset = -rFirstID;
                firstID += offset;
                lastID += offset;
                rLastID += offset;// = Record.Count()-1
                rFirstID = 0;// = 0

                if (lastID < -1)//新数据在旧数据前面,不能合并
                {
                    Record.Clear();
                    foreach (T item in items)
                    {
                        Record.Add(item);
                    }
                    RecordLastID = items_lastID;
                }
                else if (firstID > Record.Count())//新数据在旧数据后面,不能合并
                {
                    Record.Clear();
                    foreach (T item in items)
                    {
                        Record.Add(item);
                    }
                    RecordLastID = items_lastID;
                }
                else//可以拼接
                {
                    for (int i = lastID; i >= firstID; i--)
                    {
                        int items_idx = i - firstID;
                        T item = items[items_idx];
                        if (i > rLastID)
                        {
                            if (Record.Count > (rLastID + 1))
                                Record.Insert(rLastID + 1, item);
                            else
                                Record.Add(item);
                        }
                        else if (i >= 0)
                        {
                            Record[i] = item;
                        }
                        else
                        {
                            Record.Insert(0, item);
                        }
                    }
                    if (lastID > rLastID)
                        RecordLastID = items_lastID;
                }
            }
            FitWindow();
        }
        void remove(int items_lastID, int cnt)
        {
            if (Record.Count() == 0)
            {
                return;
            }
            else
            {
                //找Record 中的数据,是否与新推送过来的数据有交集
                int firstID = items_lastID - cnt + 1;
                int lastID = items_lastID;
                FitRecord(firstID, lastID);
            }
        }

        /// <summary>
        /// 把多出window范围的数据删除
        /// </summary>
        void FitWindow()
        {
            int wFirstID = GCurrPage * Size;
            int wLastID = wFirstID + Size - 1;
            FitRecord(wFirstID, wLastID);
        }
        void FitRecord(int firstID, int lastID)
        { 
            int rFirstID = RecordLastID - Record.Count() + 1;
            int rLastID = RecordLastID;

            //删除交集以外的数据

            if (rFirstID < firstID)
            {
                int remove_cnt = firstID - rFirstID;
                if (remove_cnt >= Record.Count())
                {
                    //全部删除
                    Record.Clear();
                    RecordLastID = -1;
                    return;
                }
                else
                {
                    for (int i = 0; i < remove_cnt; i++)
                        Record.RemoveAt(0);
                }
            }

            if (rLastID > lastID)
            {
                int remove_cnt = rLastID - lastID;
                if (remove_cnt >= Record.Count())
                {
                    //全部删除
                    Record.Clear();
                    RecordLastID = -1;
                    return;
                }
                else
                {
                    for (int i = 0; i < remove_cnt; i++)
                        Record.RemoveAt(Record.Count() - 1);
                    RecordLastID = lastID;
                }
            }
        }

        void updatePageInfo()
        {
            if (Buffer.Count == 0)
            {
                //没有数据
                GPage1st = 0;
                GPageLast = -1;
                return;
            }
            
            GPage1st = (Buffer.NewestID - (Buffer.Count - 1)) / Size;
            GPageLast = Buffer.NewestID / Size;
        }
        bool updateGCurrPage() 
        {
            int gCurrPage = GCurrPage;
            if (IsKeepNewest)
            {
                gCurrPage = GPageLast;
            }
            else
            {
                if (GCurrPage < GPage1st)
                    gCurrPage = GPage1st;
                else if (GCurrPage > GPageLast)
                    gCurrPage = GPageLast;
            }
            if (gCurrPage != GCurrPage)
            {
                GCurrPage = gCurrPage;
                return true;
            }
            else 
            {
                return false;
            }
        }
        #region 窗口移动
        /// <summary>
        /// 下一页, 让窗口向后移,TailerID+=Capacity
        /// </summary>
        public void MoveNextPage()
        {
            MovePage(CurrentPage + 1);
        }

        /// <summary>
        /// 上一页,让窗口向前移,TailerID-=Capacity
        /// </summary>
        public void MovePrePage()
        {
            MovePage(CurrentPage - 1);
        }
        /// <summary>
        /// 移动到最新数据
        /// </summary>
        public void MoveNewest()
        {
            IsKeepNewest = true;
            if(updateGCurrPage())
                GetWindow();
        }
        /// <summary>
        /// 移动到某页
        /// </summary>
        /// <param name="page"></param>
        public void MovePage(int page)
        {
            if (CurrentPage != page)
            {
                if ((page <= TotalPages) && (page > 0))
                {
                    GCurrPage = page + GPage1st - 1;
                    IsKeepNewest = (GCurrPage == GPageLast);
                    GetWindow();
                }
            }
        }

        #endregion
        /// <summary>
        /// 释放窗口,数据不再更新
        /// </summary>
        public void Dispose()
        {

        }
    }
}