using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace FLY.HeatingHelper
{
    /// <summary>
    /// IThickHeatData定义一个Thick和Heat数据的维护对象的接口,屏蔽了数据保存的方式,对于用SQLite或SQLServer或
    /// 文件等,应该用不同的类实现,但必须实现这个接口
    /// 注意:1.实现该接口的类是一个维护运行时数据的类,并不负责数据的保存
    ///       2.实现该接口的类的对象在创建时从“数据库”中提取最近数据,然后根据数据检测风环移位和加热失效问题
    /// </summary>
    public interface IThickHeatData : INotifyPropertyChanged
    {
        #region 用于UI的接口(数据库数据选择接口)
        /// <summary>
        /// 数据库路径(含数据库名)
        /// </summary>
        string DBPath { get; set; }
        /// <summary>
        /// 数据库中存在的数据范围
        /// </summary>
        DateTime TotalDataFrom { get; }
        DateTime TotalDataTo { get; }

        /// <summary>
        /// DataTo和DataSpan确定数据的起始位置,对象中存在的数据范围
        /// </summary>
        DateTime LoadDataFrom { get; set; }
        DateTime LoadDataTo { get; set; }

        int LoadDataMinID { get; }
        int LoadDataMaxID { get; }
        /// <summary>
        /// 加载数据时是否过滤掉加热相同的连续数据
        /// </summary>
        bool IsDataFilter { get; set; }
        /// <summary>
        /// 重新设定加载数据的缺省范围
        /// </summary>
        void SetLoadDaTaDefault();
        /// <summary>
        /// 加载元数据,主要包括数据的范围,即TotalDataFrom和TotalDataTo
        /// </summary>
        /// <returns></returns>
        int LoadMetaDataFromDB();
        /// <summary>
        /// 根据上面的设定加载数据,reload=0自动判断是否是否重新加载所有数据,
        ///                         reload=1强制重新加载所有数据
        ///                         reload=-1只加载之后产生的数据
        /// </summary>
        /// <returns></returns>
        int LoadDataFromDB(int reload);
        #endregion


        /// <summary>
        /// 风环偏差值
        /// </summary>
        int AirRingShift { get; }

        StateCode State { get; }

        int CalculateFromToByClass(int selected_class, ref int from, ref int to);

        #region 一些辅助计算的函数
        /// <summary>
        /// 计算两个frame的加热和厚度差的协相关向量。
        /// </summary>
        double[] CalculateCorrelVector(double[] heats, double[] thicks);

        Tuple<int, double> CalculateAirRingShiftFromCorelVector(double[] correlVec);
        #endregion

        #region 获取数据接口
        /// <summary>
        /// 获取厚度和加热的值
        /// </summary>
        /// <param name="idx"></param>
        /// <returns></returns>
        double[] GetThicks(int idx, int from, int to);
        double[] GetHeats(int idx, int from, int to);
        double[] GetThicks(int idx, int newResetBolt, double newAngle);
        int GetResetBolt(int idx);
        double GetRotAngle(int idx);
        int NormalBolt(int bolt, int boltcnt);

        List<DateTime> Dat_Times { get; }
        List<double> Dat_Sigmas { get; }
        List<double> Dat_Means { get; }

        int GetIndexFromID(int id);
        int GetRelativeID(int id, int relative);
        /// <summary>
        /// 依据数据ID获取数据时间
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        DateTime? GetDateTimeByID(int id);
        #endregion
        int BoltCnt { get; }

        double[] HeatEffect { get; set; }
        #region 整体分析和局部分析的功能接口(数据处理)
        List<HeatBoltAnalystItem> SearchFeaturedBoltsItem(int startIdx, int endIdx, 
                                    int searchNum, int maxFrameInterval, int heatRating,
                                    int neglectHeatRate, int Separation, int shiftRange);
        List<HeatBoltAnalystItem> FilterFeaturedBoltsItem(List<HeatBoltAnalystItem> items, double similarityThredhold);
        void StartSearchMaxSimilarity(int startIdx, int endIdx, int searchNum, int frameInterval, MaxSimilarityResult result,
                        ProgressChangedEventHandler report,
                        RunWorkerCompletedEventHandler runcomplete,
                        int midbolt, double searchRange, bool SearchRotAngle, bool isAsync);
        /// <summary>
        /// 
        /// </summary>
        /// <param name="idxL"></param>
        /// <param name="idxB"></param>
        /// <param name="searchRange"></param>
        /// <param name="SearchRotAngle"></param>
        /// <returns>返回值:Tuple<偏转数,相关系数,旋转角度变化量></returns>
        Tuple<int, double, double> SearchMaxSimilarity(int idxL, int idxB, double searchRange, bool SearchRotAngle);
        #endregion

        #region 数据库数据变化后自动运行
        List<ThickHeatEvent> AutoDetectEvents { get; }

        /// <summary>
        /// 自动运行是否旋转角度
        /// </summary>
        bool HasRotateAngleSearched { get; set; }
        /// <summary>
        /// 搜索旋转角度的范围,例如15,则在当前度数下搜索正负15度
        /// </summary>
        double SearchingAngle { get; set; }

        /// <summary>
        /// 检查数据库,当数据库有新数据时,更新DataTo属性,并读取新数据到对象中。该函数可以一定时间间隔执行。
        /// </summary>
        void RefreshData();

        int DataChanged { get; set; }
        //bool IsDataReady { get; }

        bool BeginUse(bool isAsync = true);
        void EndUse();

        #endregion
    }


    public enum StateCode
    {
        STC_NODAT,              // 没有数据
        STC_IDLE,               // 空闲
        STC_READING,            // 读取数据
        STC_UPDATING            // 检查新数据
    }

    #region 厚度加热数据自动处理结果事件
    public class ThickHeatEvent
    {
        public ThickHeatEventCode EvtCode;
        public object EvtData;
    }

    public enum ThickHeatEventCode
    {
        EVC_RingShift,
        EVC_HeatBoltItem,
    }

    public class MaxSimilarityResult
    {
        public int frameIdx1;
        public int frameIdx2;
        public int frameShift;
        public double similarity;
        public double deltaAngle;
        public double ThickToHeatFactor;
    }

    public class HeatBoltAnalystItem
    {
        public int FrameIdx1 { get; set; }
        public int FrameIdx2 { get; set; }
        public int StartBolt { get; set; }
        public int EndBolt { get; set; }
        /// <summary>
        /// 偏差的位置
        /// </summary>
        public int DisPos { get; set; }
        public double Similarity { get; set; }

        public void Clone(HeatBoltAnalystItem from)
        {
            FrameIdx1 = from.FrameIdx1;
            FrameIdx2 = from.FrameIdx2;
            StartBolt = from.StartBolt;
            EndBolt = from.EndBolt;
            DisPos = from.DisPos;
            Similarity = from.Similarity;
        }
    }
    #endregion

    #region DataHelper
    public class DataHelper
    {
        public static double[] VectorAdd(double[] a, double[] b)
        {
            int cnt = a.Count();
            double[] result = new double[cnt];
            for (int i = 0; i < cnt; i++)
            {
                if (double.IsNaN(a[i]) || double.IsNaN(b[i]))
                {
                    result[i] = double.NaN;
                }
                else
                {
                    result[i] = a[i] + b[i];
                }
            }
            return result;
        }
        public static double[] VectorSub(double[] a, double[] b)
        {
            int cnt = a.Count();
            double[] result = new double[cnt];
            for(int i = 0; i < cnt; i++)
            {
                if (double.IsNaN(a[i]) || double.IsNaN(b[i]))
                {
                    result[i] = double.NaN;
                }
                else
                {
                    result[i] = a[i] - b[i];
                }
            }
            return result;
        }
    }
    #endregion
}