using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Drawing;
using System.Linq;
using System.Windows;
using Aitex.Core.RT.Log;
using Aitex.Core.Util;
using Aitex.Core.Utilities;
using MECF.Framework.Common.ControlDataContext;
using MECF.Framework.Common.DataCenter;
using MECF.Framework.Common.Utilities;
using MECF.Framework.UI.Client.CenterViews.DataLogs.ProcessHistory;
using MECF.Framework.UI.Client.ClientBase;
using MECF.Framework.UI.Client.ClientBase.Charting;
using MECF.Framework.UI.Client.ClientBase.EventArgs;
using MECF.Framework.UI.Client.ClientBase.Tree;
using OpenSEMI.ClientBase;
using SciChart.Charting.Visuals.Axes;
using SciChart.Charting.Visuals.RenderableSeries;
using SciChart.Core.Extensions;
namespace MECF.Framework.UI.Client.CenterViews.Operations.RealTime
{
    public class RealtimeViewModel : BusyIndicateableUiViewModelBase
    {
        #region Variables
        /// 
        /// 允许监控的最大曲线数量
        /// 
        private const int MAX_PARAMETERS_ALLOWED = 200;
        private readonly RealtimeProvider _provider = new RealtimeProvider();
        private bool _enableAutoZoom = true;
        private int _pointCount;
        private readonly PeriodicJob _thread;
        /// 
        /// Monitor中添加数据点时直接向DataSeries对象添加,已实现跨线程操作。
        /// 
        private readonly List _dataSeriesList;
        /// 
        /// 更新报告导出信息。
        /// 
        private readonly IProgress _exportingProgressReporter;
        #endregion
        #region Constructors
        public RealtimeViewModel()
        {
            DisplayName = "Realtime";
            SelectedData = new ChartingLineSeriesCollection(DisplayName);
            ParameterNodes = new TreeNode(DisplayName)
            {
                MaxTerminalSelectionAllowed = MAX_PARAMETERS_ALLOWED
            };
            ParameterNodes.ChildNodes.AddRange(_provider.GetTreeNodeParameters());
            ParameterNodes.TerminalNodeSelectionChanged += OnNodeSelectionChanged;
            IntervalSaved = true;
            TrendInterval = 500;
            TimeSpanSaved = true;
            TrendTimeSpan = 60 * 5;
            _thread = new PeriodicJob(TrendInterval, MonitorData, "RealTime", true);
            _pointCount = Math.Max(TrendTimeSpan * 1000 / TrendInterval, 10);
            _dataSeriesList = new List();
            _exportingProgressReporter = new Progress(e =>
            {
                BusyIndicatorContent = e.Message;
            });
        }
        #endregion
        #region Properties
        public bool IsPermission => this.Permission == 3;
        public TreeNode ParameterNodes { get; }
        public ChartingLineSeriesCollection SelectedData { get; set; }
        public AutoRange ChartAutoRange => EnableAutoZoom ? AutoRange.Always : AutoRange.Never;
        public bool EnableAutoZoom
        {
            get => _enableAutoZoom;
            set
            {
                _enableAutoZoom = value;
                NotifyOfPropertyChange(nameof(EnableAutoZoom));
                NotifyOfPropertyChange(nameof(ChartAutoRange));
            }
        }
        [IgnorePropertyChange]
        public int TrendInterval { get; set; }
        public bool IntervalSaved { get; set; }
        [IgnorePropertyChange]
        public int TrendTimeSpan { get; set; }
        public bool TimeSpanSaved { get; set; }
        private bool  _IsHold;
        public bool  IsHold
        {
            get { return _IsHold; }
            set 
            {
                if (_IsHold!=value)
                {
                    _IsHold = value;
                    if (_IsHold) EnableAutoZoom = false;
                    else EnableAutoZoom = true;
                    NotifyOfPropertyChange(nameof(IsHold));
                }              
            }
        }
        #endregion
        #region Methods
        protected bool MonitorData()
        {
            try
            {
                Dictionary data = null;
                if (!IsHold&&SelectedData.Count > 0)
                {
                    data = QueryDataClient.Instance.Service.PollData(SelectedData.Select(r => (r as FastLineSeries)?.DataName).ToList());
                    AppendData(data);
                }
                for (var j = 0; j < ParameterNodes.ChildNodes.Count; j++)
                {
                    var par = ParameterNodes.ChildNodes[j];
                    par.IsVisibilityParentNode = Visibility.Hidden;
                }
            }
            catch (Exception ex)
            {
                LOG.Error(ex.Message);
            }
            return true;
        }
        public void AppendData(Dictionary data)
        {
            if (data == null)
                return;
            var dt = DateTime.Now;
            foreach (var ds in _dataSeriesList)
            {
                if (ds == null || !data.ContainsKey(ds.SeriesName))
                    continue;
                if (data[ds.SeriesName] is bool)
                {
                    ds.Append(dt, ((bool)data[ds.SeriesName] ? 1 : 0) * ds.Factor + ds.Offset, new ParameterNodePoint(dt, ((bool)data[ds.SeriesName] ? 1 : 0)));
                    continue;
                }
                if (!double.TryParse(data[ds.SeriesName].ToString(), out var value))
                    continue;
                ds.Append(dt, value * ds.Factor + ds.Offset, new ParameterNodePoint(dt, value));
            }
        }
        private void UpdateFifoCapacity(int capacity)
        {
            foreach (var renderableSeries in SelectedData)
            {
                if (renderableSeries is FastLineSeries line)
                {
                    var ds = line.GetDataSeries();
                    var copyMetaData = ds.Metadata.Where(x => x != null && ((ParameterNodePoint)x).Time > DateTime.Now.AddSeconds(-TrendTimeSpan)).ToList();
                    ds.FifoCapacity = capacity;
                    foreach (ParameterNodePoint item in copyMetaData)
                    {
                        ds.Append(item.Time, item.Value);
                    }
                }
            }
        }
        public void SetInterval()
        {
            _thread.ChangeInterval(TrendInterval);
            _pointCount = Math.Max(10, TrendTimeSpan * 1000 / TrendInterval);
            IntervalSaved = true;
            NotifyOfPropertyChange(nameof(IntervalSaved));
            UpdateFifoCapacity(_pointCount);
        }
        public void SetTimeSpan()
        {
            _pointCount = Math.Max(10, TrendTimeSpan * 1000 / TrendInterval);
            TimeSpanSaved = true;
            NotifyOfPropertyChange(nameof(TimeSpanSaved));
            UpdateFifoCapacity(_pointCount);
        }
        #endregion
        #region Events
        public void OnNodeSelectionChanged(object sender, TreeNodeSelectionChangedEventArgs e)
        {
            if (e.NewValue == true && SelectedData.Count >= MAX_PARAMETERS_ALLOWED)
            {
                e.Cancel = true;
                return;
            }
            var line = SelectedData.Cast().FirstOrDefault(x => x.DataName == e.Source.FullName);
            switch (e.NewValue)
            {
                case false:
                    {
                        if (line != null)
                        {
                            _dataSeriesList.Remove(line.GetDataSeries());
                            SelectedData.Remove(line);
                        }
                        break;
                    }
                case true:
                    {
                        if (line == null)
                        {
                            var series = new FastLineSeries(e.Source.FullName)
                            {
                                BackendParameterNode = e.Source
                            };
                            series.GetDataSeries().FifoCapacity = _pointCount;
                            SelectedData.Add(series);
                            _dataSeriesList.Add(series.GetDataSeries());
                            SelectedData.ResetColors();
                        }
                        break;
                    }
                default:
                    break;
            }
        }
        public void Deleted(object sender, RenderableSeriesDeletingEventArgs e)
        {
            var list = e.Source.Cast().ToList();
            var total = SelectedData.Count;
            for (var i = total - 1; i >= 0; i--)
            {
                if (i < list.Count)
                {
                    list[i].BackendParameterNode.IsSelected = false;
                }
            }
            _dataSeriesList.Clear();
            ((RealtimeView)View).tvParameterNodes.ClearPresetGroupSelectionOnly();
        }
        public void Exporting(object sender, EventArgs e)
        {
            BusyIndicatorContent = "Exporting ...";
            IsBusy = true;
        }
        public void Exported(object sender, EventArgs e)
        {
            IsBusy = false;
        }
        public void ProgressUpdating(object sender, ProgressUpdatingEventArgs e)
        {
            _exportingProgressReporter.Report(e);
        }
        public override void Cancel()
        {
            if (View is RealtimeView view)
            {
                view.dataGrid.CancelOperation();
            }
        }
        public void ToLeftClick(int index)
        {
            var view = GetView() as RealtimeView;
            index += 1;//从0开始
            if ((index & 0x01) == 1)
                view.sciChart.ChartModifier.XAxis.Scroll(50, SciChart.Charting.ClipMode.ClipAtMin);
            if ((index & 0x02) == 2)
            {
                view.sciChart.ChartModifier.YAxis.Scroll(50, SciChart.Charting.ClipMode.ClipAtMin);
            }
        }
        public void ToRightClick(int index)
        {
            var view = GetView() as RealtimeView;
            index += 1;
            if ((index & 0x01) == 1)
                view.sciChart.ChartModifier.XAxis.Scroll(-50, SciChart.Charting.ClipMode.ClipAtMax);
            if ((index & 0x02) == 2)
                view.sciChart.ChartModifier.YAxis.Scroll(-50, SciChart.Charting.ClipMode.ClipAtMax);
        }
        public void ZoomInClick(int index)
        {
            var view = GetView() as RealtimeView;
            index += 1;
            if ((index & 0x01) == 1)
                view.sciChart.ChartModifier.XAxis.ZoomBy(-0.1, -0.1);
            if ((index & 0x02) == 2)
                view.sciChart.ChartModifier.YAxis.ZoomBy(-0.1, -0.1);
        }
        public void ZoomOutClick(int index)
        {
            var view = GetView() as RealtimeView;
            index += 1;
            if ((index & 0x01) == 1)
                view.sciChart.ChartModifier.XAxis.ZoomBy(0.1, 0.1);
            if ((index & 0x02) == 2)
                view.sciChart.ChartModifier.YAxis.ZoomBy(0.1, 0.1);
        }
        #endregion
    }
}