using Misc;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace FLY.FeedbackRenZiJia.Common
{
    public static class MyMath
    {
        #region 数列操作
        /// <summary>
        /// 转为 % 数据,单位 %
        /// </summary>
        /// <param name="data"></param>
        /// <returns></returns>
        public static int[] GetPercent(int[] data)
        {
            int avg = Misc.MyMath.Avg(data);

            int[] percent = new int[data.Count()];
            for (int i = 0; i < data.Count(); i++)
            {
                if (Misc.MyBase.ISVALIDATA(data[i]))
                {
                    percent[i] = 100 * (data[i] - avg) / avg;
                }
                else
                {
                    percent[i] = Misc.MyBase.NULL_VALUE;
                }
            }
            return percent;
        }


        /// <summary>
        /// 两列数据相减
        /// </summary>
        /// <param name="data1"></param>
        /// <param name="data2"></param>
        /// <returns></returns>
        public static int[] GetDiff(int[] data1, int[] data2)
        {
            int[] diff = new int[data1.Count()];
            for (int i = 0; i < data1.Count(); i++)
            {
                if (Misc.MyBase.ISVALIDATA(data1[i]) && Misc.MyBase.ISVALIDATA(data2[i]))
                {
                    diff[i] = data1[i] - data2[i];
                }
                else
                {
                    diff[i] = Misc.MyBase.NULL_VALUE;
                }
            }
            return diff;
        }
        /// <summary>
        /// 两列数据中间值
        /// </summary>
        /// <param name="data1"></param>
        /// <param name="data2"></param>
        /// <returns></returns>
        public static int[] GetMid(int[] data1, int[] data2)
        {
            int[] mid = new int[data1.Count()];
            for (int i = 0; i < data1.Count(); i++)
            {
                if (Misc.MyBase.ISVALIDATA(data1[i]) && Misc.MyBase.ISVALIDATA(data2[i]))
                {
                    mid[i] = (data1[i] + data2[i]) / 2;
                }
                else
                {
                    mid[i] = Misc.MyBase.NULL_VALUE;
                }
            }
            return mid;
        }
        /// <summary>
        /// 上下平移,使平均值为0
        /// </summary>
        /// <param name="data"></param>
        /// <returns></returns>
        public static int[] OffsetAvgBe0(int[] data)
        {
            int avg = Misc.MyMath.Avg(data);

            int[] data_out = new int[data.Count()];
            for (int i = 0; i < data.Count(); i++)
            {
                if (Misc.MyBase.ISVALIDATA(data[i]))
                {
                    data_out[i] = data[i] - avg;
                }
                else
                {
                    data_out[i] = Misc.MyBase.NULL_VALUE;
                }
            }
            return data_out;
        }

        /// <summary>
        /// 放大数量
        /// </summary>
        /// <param name="data"></param>
        /// <param name="z"></param>
        /// <returns></returns>
        public static int[] ZoomIn(int[] data, int z)
        {
            if (z == 1)
            {
                return data.Clone() as int[];
            }
            int[] data_out = new int[data.Count() * z];
            for (int i = 0; i < data.Count(); i++)
            {
                for (int j = 0; j < z; j++)
                    data_out[i * z + j] = data[i];
            }
            return data_out;

        }

        /// <summary>
        /// 缩小数量
        /// </summary>
        /// <param name="data"></param>
        /// <param name="z"></param>
        /// <returns></returns>
        public static int[] ZoomOut(int[] data, int z)
        {
            if (z == 1)
            {
                return data.Clone() as int[];
            }
            int[] data_out = new int[data.Count() / z];
            for (int i = 0; i < data_out.Count(); i++)
            {
                data_out[i] = Misc.MyMath.Avg(data, i * z, (i + 1) * z - 1);
            }
            return data_out;
        }

        /// <summary>
        /// 滤波操作
        /// </summary>
        /// <param name="data">数据源</param>
        /// <param name="cell">滤波器</param>
        /// <returns></returns>
        public static int[] Filter(int[] data, int[] cell)
        {
            if (cell == null || cell.Count()==0)
            {
                return data.Clone() as int[];
            }
            int[] data_out = new int[data.Count()];

            for (int i = 0; i < data.Count(); i++)
            {
                int sum = 0;
                int cnt = 0;
                for (int j = 0; j < cell.Count(); j++)
                {
                    int idx = i - cell.Count() / 2 + j;
                    if (idx < 0)
                        idx += data.Count();
                    else if (idx >= data.Count())
                        idx -= data.Count();
                    if (Misc.MyBase.ISVALIDATA(data[idx]))
                    {
                        sum += data[idx] * cell[j];
                        cnt += cell[j];
                    }
                }
                if (cnt > 0)
                {
                    data_out[i] = sum / cnt;
                }
                else
                {
                    data_out[i] = Misc.MyBase.NULL_VALUE;
                }
            }
            return data_out;
        }

        /// <summary>
        /// 数据 放大
        /// </summary>
        /// <param name="data"></param>
        /// <param name="z">放大倍数</param>
        /// <returns></returns>
        public static int[] ZoomY(int[] data, double z)
        {
            if (z == 1 )
            {
                return data.Clone() as int[];
            }
            int[] data_out = new int[data.Count()];

            for (int i = 0; i < data.Count(); i++)
            {
                if (Misc.MyBase.ISVALIDATA(data[i]))
                {
                    data_out[i] = (int)(data[i] * z);
                }
                else
                {
                    data_out[i] = Misc.MyBase.NULL_VALUE;
                }
            }
            return data_out;
        }
        /// <summary>
        /// 滤波操作,均值滤波
        /// </summary>
        /// <param name="data">数据源</param>
        /// <param name="cell">滤波器宽度</param>
        /// <returns></returns>
        public static int[] Filter(int[] data, int cell_width)
        {

            int[] data_out = new int[data.Count()];

            for (int i = 0; i < data.Count(); i++)
            {
                int sum = 0;
                int cnt = 0;
                for (int j = 0; j < cell_width; j++)
                {
                    int idx = i - cell_width / 2 + j;
                    if (idx < 0)
                        idx += data.Count();
                    else if (idx >= data.Count())
                        idx -= data.Count();
                    if (Misc.MyBase.ISVALIDATA(data[idx]))
                    {
                        sum += data[idx];
                        cnt += 1;
                    }
                }
                if (cnt > 0)
                {
                    data_out[i] = sum / cnt;
                }
                else
                {
                    data_out[i] = Misc.MyBase.NULL_VALUE;
                }
            }
            return data_out;
        }
        /// <summary>
        /// 通过data2 平移,找到与 data1 最相似的位置, data1 与 data2 必须大小一致
        /// </summary>
        /// <param name="data1"></param>
        /// <param name="data2"></param>
        /// <param name="range_percent">0~1</param>
        /// <param name="offset"></param>
        /// <param name="r"></param>
        public static void CalBestMove(int[] data1, int[] data2, double range_percent, out int data2_move, out double max_r)
        {
            if (data1.Length != data2.Length)
            {
                throw new Exception("CalBestMove() 参数错误 (data1.Length = " + data1.Length.ToString() + ")!=(data2.Length =" + data2.Length.ToString() + ")");
            }

            if ((range_percent > 1) || (range_percent < 0))
            {
                throw new Exception("CalBestMove() 参数错误 range_percent = " + range_percent.ToString() + " 异常");
            }
            int range = (int)(Math.Ceiling(range_percent * data1.Length));

            if (range <= 0)
                range = 1;


            double mr = 0;
            int mi = -1;
            for (int i = -range; i <= range; i++)
            {
                int[] data22 = Move(data2, i);
                double r = Misc.MyMath.Correl(data1, data22);
                if (mi == -1)
                {
                    mr = r;
                    mi = i;
                }
                else
                {
                    if (r > mr)
                    {
                        mr = r;
                        mi = i;
                    }
                }

            }

            //找到了!!!

            max_r = mr;
            data2_move = mi;
        }

        /// <summary>
        /// 平移
        /// </summary>
        /// <param name="data">原始厚度数组</param>
        /// <param name="move">平移量 向右移动为正</param>
        public static int[] Move(int[] data, int move)
        {
            if (move == 0)
            {
                //什么都不用做
                return data.Clone() as int[];
            }
            int cnt = data.Count();
            int[] data_out = new int[cnt];


            for (int i = 0; i < cnt; i++)
            {
                int idx = i - move;
                if (idx >= cnt)
                    idx -= cnt;
                else if (idx < 0)
                    idx += cnt;

                data_out[i] = data[idx];

            }
            return data_out;

        }

        /// <summary>
        /// 计算极差
        /// </summary>
        /// <param name="data"></param>
        public static int CalMaxMin(int[] data)
        {
            int max = Misc.MyMath.Max(data);
            int min = Misc.MyMath.Min(data);
            if (Misc.MyBase.ISVALIDATA(max))
            {
                return max - min;
            }
            return 0;
        }

        /// <summary>
        /// X轴放大
        /// </summary>
        /// <param name="data"></param>
        /// <param name="mid">中心位置</param>
        /// <param name="z"></param>
        /// <returns></returns>
        public static int[] ZoomX(int[] data, int mid, double z)
        {
            if ( Math.Abs(z - 1)<0.001 )
            {
                return data.Clone() as int[];
            }
            //放大
            int[] _diff = new int[data.Count()];
            for (int i = 0; i < data.Count(); i++)
            {
                double new_offset = i - (mid);
                if (Math.Abs(new_offset) > data.Count() / 2)
                {
                    if (new_offset > 0)
                        new_offset -= data.Count();
                    else
                        new_offset += data.Count();
                }
                double old_offset = new_offset * 1 / z;
                if (Math.Abs(old_offset) > data.Count() / 2)
                {
                    //没数据了
                    _diff[i] = Misc.MyBase.NULL_VALUE;
                }
                else
                {
                    int d1 = (int)Math.Ceiling(old_offset);
                    int d2 = (int)Math.Floor(old_offset);
                    double p1 = old_offset - d2;
                    double p2 = d1 - old_offset;

                    d1 += (mid);
                    if (d1 >= data.Count())
                        d1 -= data.Count();
                    else if (d1 < 0)
                        d1 += data.Count();

                    d2 += (mid);
                    if (d2 >= data.Count())
                        d2 -= data.Count();
                    else if (d2 < 0)
                        d2 += data.Count();

                    if (d1 == d2)
                    {
                        _diff[i] = data[d1];
                    }
                    else
                    {
                        if (Misc.MyBase.ISVALIDATA(data[d1]) && Misc.MyBase.ISVALIDATA(data[d2]))
                            _diff[i] = (int)(data[d1] * p1 + data[d2] * p2);
                        else if (Misc.MyBase.ISVALIDATA(data[d1]))
                            _diff[i] = data[d1];
                        else
                            _diff[i] = data[d2];
                    }
                }
            }
            return _diff;
        }

        public static double BreakUp(int[] data)
        {
            int avg = Misc.MyMath.Avg(data);
            Dictionary<Range, bool> block = new Dictionary<Range, bool>();
            Range range = new Range();
            bool isBigger = false;
            for (int i = 0; i < data.Count(); i++)
            {
                int idx = i;

                if (range.IsValid)
                {
                    if (data[idx] == avg)
                    {
                        //切换点
                        block.Add(range, isBigger);
                        range = new Range();
                    }
                    else if ((data[idx] > avg))
                    {
                        if (isBigger)
                            range.End = idx;
                        else
                        {
                            //切换点
                            block.Add(range, isBigger);
                            range = new Range() { Begin = idx, End = idx };
                            isBigger = true;
                        }
                    }
                    else
                    {
                        if (!isBigger)
                            range.End = idx;
                        else
                        {
                            //切换点
                            block.Add(range, isBigger);
                            range = new Range() { Begin = idx, End = idx };
                            isBigger = false;
                        }
                    }
                }
                else
                {
                    if (data[idx] == avg)
                    {

                    }
                    else if ((data[idx] > avg))
                    {
                        range = new Range() { Begin = idx, End = idx };
                        isBigger = true;
                    }
                    else
                    {
                        range = new Range() { Begin = idx, End = idx };
                        isBigger = false;
                    }
                }
            }

            Range f = block.Keys.First();
            bool fb = block[f];
            Range l = block.Keys.Last();
            bool lb = block[l];

            if (fb == lb)
            {
                //可能一起的
                if ((f.Begin == 0) && (l.End == data.Count() - 1))
                {
                    //同一块
                    f.End += l.Width;
                    block.Remove(l);
                }
            }

            double block_width_max = block.Keys.Max((r) => { return r.Width; });
            return block_width_max / data.Count();
        }

        public static Range[] Break(int[] data)
        {
            int avg = Misc.MyMath.Avg(data);
            Dictionary<Range, bool> block = new Dictionary<Range, bool>();
            Range range = new Range();
            bool isBigger = false;
            for (int i = 0; i < data.Count(); i++)
            {
                int idx = i;

                if (range.IsValid)
                {
                    if (data[idx] == avg)
                    {
                        //切换点
                        block.Add(range, isBigger);
                        range = new Range();
                    }
                    else if ((data[idx] > avg))
                    {
                        if (isBigger)
                            range.End = idx;
                        else
                        {
                            //切换点
                            block.Add(range, isBigger);
                            range = new Range() { Begin = idx, End = idx };
                            isBigger = true;
                        }
                    }
                    else
                    {
                        if (!isBigger)
                            range.End = idx;
                        else
                        {
                            //切换点
                            block.Add(range, isBigger);
                            range = new Range() { Begin = idx, End = idx };
                            isBigger = false;
                        }
                    }
                }
                else
                {
                    if (data[idx] == avg)
                    {

                    }
                    else if ((data[idx] > avg))
                    {
                        range = new Range() { Begin = idx, End = idx };
                        isBigger = true;
                    }
                    else
                    {
                        range = new Range() { Begin = idx, End = idx };
                        isBigger = false;
                    }
                }
            }

            if (block.Count() == 0)
            {
                return null;
            }
            else if (block.Count() > 1)
            {
                Range f = block.Keys.First();
                bool fb = block[f];
                Range l = block.Keys.Last();
                bool lb = block[l];

                if (fb == lb)
                {
                    //可能一起的
                    if ((f.Begin == 0) && (l.End == data.Count() - 1))
                    {
                        //同一块
                        //f.Begin变为负数
                        f.Begin = f.Begin - l.Width;
                        block.Remove(l);
                    }
                }
            }

            return block.Keys.ToArray();
        }
        #endregion
    }
}