using AutoMapper;
using FLY.Thick.Base.Common;
using FLY.Thick.Base.Server;
using Newtonsoft.Json;
using OfficeOpenXml;
using System;
using System.Collections.Generic;
using System.Data;
using System.IO;
using System.Linq;

namespace FLY.Simulation.Calender.GuRuiShiYe
{
    public class GageAd : ISimulationGageAD
    {
        #region 涂料轮廓
        /// <summary>
        /// 涂料的横向视图, 精度1mm，
        /// um
        /// </summary>
        public List<double> HorizontalView = new List<double>();

        /// <summary>
        /// 涂料的纵向视图，精度1mm，纵向是周长发生的
        /// um
        /// </summary>
        public List<double> VerticalView = new List<double>();

        #endregion

        #region 机架信息

        /// <summary>
        /// 机架视图 AD值，精度1mm，
        /// </summary>
        public List<double> GageView = new List<double>();
        /// <summary>
        /// 机架视图 均值
        /// </summary>
        public double GageViewAvg { get; set; }

        public double Mmpp { get; set; } = 0.0945;
        /// 编码器2 mm/p 胶轮周长200mm，编码器 转1圈800脉冲 正确应该0.25
        /// </summary>
        public double Mmpp2 = 0.24925;

        public int TotalLength { get; private set; } = 1600;
        /// <summary>
        /// 测速辊周长 314mm
        /// </summary>
        public double MmOfRoll { get; set; } = 314;
        /// <summary>
        /// 测速辊上接近开关信号长度
        /// </summary>
        public double MmOfRoundSign { get; set; } = 10;
        /// <summary>
        /// 纵向位置偏移 单位m
        /// </summary>
        public double FilmPositionOffset { get; set; }
        #endregion

        /// <summary>
        /// 相对于机架 左起始位置 mm
        /// </summary>
        public int FilmBegin { get; set; } = 170;

        /// <summary>
        /// 纵向速度 m/min
        /// </summary>
        public double FilmVelocity { get; set; } = 20;

        /// <summary>
        /// 当前极片位置 m
        /// </summary>
        public double FilmPosition { get; set; } = 0;
        private double filmPosition_real;
        public bool IsSyncLight { get; set; }
        /// <summary>
        /// AD曲线
        /// </summary>
        public CurveCollection curve;

        string gageName;

        /// <summary>
        /// 获取膜上厚度值
        /// </summary>
        /// <param name="mm_h">膜上横向位置</param>
        /// <param name="mm_v">膜上纵向位置</param>
        /// <returns></returns>
        public delegate double GetFilmValueHandler(int mm_h, int mm_v);
        GetFilmValueHandler GetBaseMaterialValue;
        public GetFilmValueHandler GetFilmValue; 
        public GageAd() {
            GetFilmValue = new GetFilmValueHandler(_GetFilmValue);
        }
      
        private double _GetFilmValue(int mm_h, int mm_v)
        {
            if (mm_h >= 0 && mm_h < HorizontalView.Count)
            {
                double bValue = 0;
                if (GetBaseMaterialValue != null)
                    bValue = GetBaseMaterialValue(mm_h, mm_v);

                var hValue = HorizontalView[mm_h];
                int vIndex = (int)GetRemainder(mm_v, VerticalView.Count());
                var vValue = VerticalView[vIndex];

                return bValue+(vValue + hValue) / 2;
            }
            else {
                return 0;
            }
        }

        public void Init(string gageName, GetFilmValueHandler getBaseMaterialValue)
        {
            this.gageName = gageName;
            this.GetBaseMaterialValue = getBaseMaterialValue;
            curve = new CurveCollection($@"{gageName}\curve.json");

            LoadXlsx_film($@"{gageName}\FilmView.xlsx");
            LoadXlsx_scancorr($@"{gageName}\GageView.xlsx");

            if (!GageAdJsonDb.Load(this, $@"{gageName}\gageAd.json"))
                GageAdJsonDb.Save(this, $@"{gageName}\gageAd.json");

            GageViewAvg = GageView.Average();

            TotalLength = GageView.Count();
        }

        void Load_double(List<double> datas, string csvFilePath)
        {
            datas.Clear();
            using (StreamReader sr = new StreamReader(csvFilePath))
            {
                string header = sr.ReadLine();//标题 , Thick, HSign

                while (!sr.EndOfStream)
                {
                    string s = sr.ReadLine();
                    string[] ss = s.Split(',');

                    double thk = double.Parse(ss[0]);
                    datas.Add(thk);
                }
                sr.Close();
            }
        }

        private void LoadXlsx_film(string filepath)
        {
            //检测标题

            DataTable dataTable_h = new DataTable("table_horizontal");
            dataTable_h.Columns.Add(new DataColumn() { ColumnName = "位置mm", DataType = typeof(double), Caption = "0" });
            dataTable_h.Columns.Add(new DataColumn() { ColumnName = "涂料", DataType = typeof(double), Caption = "0" });

            DataTable dataTable_v = new DataTable("table_vertical");
            dataTable_v.Columns.Add(new DataColumn() { ColumnName = "位置mm", DataType = typeof(double), Caption = "0" });
            dataTable_v.Columns.Add(new DataColumn() { ColumnName = "涂料", DataType = typeof(double), Caption = "0" });

            using (ExcelPackage p = new ExcelPackage(new FileInfo(filepath)))
            {
                ExcelWorksheet sheet = p.Workbook.Worksheets["横向数据"];
                FromSheet(sheet, dataTable_h);

                ExcelWorksheet sheet2 = p.Workbook.Worksheets["纵向数据"];
                FromSheet(sheet2, dataTable_v);
            }


            HorizontalView.Clear();
            for (int i = 0; i < dataTable_h.Rows.Count; i++)
            {
                double mm = (double)dataTable_h.Rows[i]["位置mm"];
                double value = (double)dataTable_h.Rows[i]["涂料"];
                for (int j = HorizontalView.Count(); j <= mm; j++)
                {
                    HorizontalView.Add(value);
                }
            }

            VerticalView.Clear();
            for (int i = 0; i < dataTable_v.Rows.Count; i++)
            {
                double mm = (double)dataTable_v.Rows[i]["位置mm"];
                double value = (double)dataTable_v.Rows[i]["涂料"];
                for (int j = VerticalView.Count(); j <= mm; j++)
                {
                    VerticalView.Add(value);
                }
            }
        }
        private void LoadXlsx_scancorr(string filepath)
        {
            //检测标题

            DataTable dataTable = new DataTable("table_scancorr");
            dataTable.Columns.Add(new DataColumn() { ColumnName = "序号", DataType = typeof(double), Caption = "0" });
            dataTable.Columns.Add(new DataColumn() { ColumnName = "脉冲", DataType = typeof(double), Caption = "0" });
            dataTable.Columns.Add(new DataColumn() { ColumnName = "位置mm", DataType = typeof(double), Caption = "0" });
            dataTable.Columns.Add(new DataColumn() { ColumnName = "正向原始", DataType = typeof(double), Caption = "0" });
            dataTable.Columns.Add(new DataColumn() { ColumnName = "反向原始", DataType = typeof(double), Caption = "0" });
            dataTable.Columns.Add(new DataColumn() { ColumnName = "正向滤波", DataType = typeof(double), Caption = "0" });
            dataTable.Columns.Add(new DataColumn() { ColumnName = "反向滤波", DataType = typeof(double), Caption = "0" });


            using (ExcelPackage p = new ExcelPackage(new FileInfo(filepath)))
            {
                ExcelWorksheet sheet = p.Workbook.Worksheets["机架修正"];
                FromSheet(sheet, dataTable);
            }

            //获取正向滤波数据
            GageView.Clear();
            for (int i = 0; i < dataTable.Rows.Count; i++)
            {
                double mm = (double)dataTable.Rows[i]["位置mm"];
                double ad = (double)dataTable.Rows[i]["正向滤波"];
                for (int j = GageView.Count(); j <= mm; j++)
                {
                    GageView.Add(ad);
                }
            }
        }

        void FromSheet(ExcelWorksheet sheet, DataTable dataTable)
        {

            int from_row = 1;
            int row = from_row;


            for (int i = 0; i < dataTable.Columns.Count; i++)
            {
                int col = i + 1;
                if ((string)(sheet.Cells[row, col].Value) != dataTable.Columns[i].ColumnName)
                {
                    throw new Exception($"格式出错, 第{i}列 不是{dataTable.Columns[i].ColumnName}");
                }
            }

            row++;
            while (true)
            {
                var newRow = dataTable.NewRow();
                //当一行都是空的，认为没有数据
                int nullCnt = 0;
                for (int j = 0; j < dataTable.Columns.Count; j++)
                {
                    int col = j + 1;
                    object value = sheet.Cells[row, col].Value;

                    if (value is string || value == null)
                    {
                        if (string.IsNullOrEmpty((string)(value)))
                        {
                            //空的
                            nullCnt++;
                            //continue;
                            return;
                        }

                    }
                    try
                    {
                        newRow[j] = sheet.Cells[row, col].Value;
                    }
                    catch (Exception e)
                    {
                        throw e;
                    }
                }
                if (nullCnt == dataTable.Columns.Count)
                {
                    //没有数据了
                    break;
                }
                dataTable.Rows.Add(newRow);
                row++;
            }

        }

        DateTime lastTime = DateTime.MinValue;
        public void OnPoll(DateTime now)
        {


            if (lastTime == DateTime.MinValue)
            {
                lastTime = now;
                return;
            }

            var ts = now - lastTime;

            double ms = 1.0 * ts.Ticks / TimeSpan.TicksPerMillisecond;
            double minute = ms / 1000 / 60;
            if (FilmVelocity != 0)
            {
                filmPosition_real += minute * FilmVelocity;
            }
            FilmPosition = filmPosition_real - FilmPositionOffset;

            //int index = (int)(filmPosition_real * 1000 % VerticalView.Count());

            lastTime = now;
        }



        public int GetAD(int mm)
        {
            if (mm < 0)
                return (int)GageView[0];
            else if (mm >= GageView.Count())
                return (int)GageView.Last();


            if (mm < FilmBegin || mm >= FilmBegin+HorizontalView.Count()) {
                //膜的外面
                return (int)GageView[mm];
            }


            int posLength = (int)(FilmPosition * 1000);


            double value = GetFilmValue(mm - FilmBegin, posLength);

            double ad = curve.Value2Ad(value, AD2ValueFlag.NoRevised);
            double ad_zero = curve.Value2Ad(0, AD2ValueFlag.NoRevised);
            //ad *= GageViewAvg / ad_zero;

            //ad *= GageView[mm] / GageViewAvg;

            ad *= GageView[mm] / ad_zero;


            if (ad > 65535)
                ad = 65535;
            else if (ad < 0)
                ad = 0;

            return (int)ad;
        }

        public ushort GetInput()
        {
            UInt16 istatus = 0x0fff;
            double mmInRoll = GetRemainder(FilmPosition * 1000, MmOfRoll);
            if (mmInRoll < MmOfRoundSign)
            {
                //亮灯
                Misc.MyBase.CLEARBIT(ref istatus, IODefinition.IN_RSENSOR);
            }
            if (IsSyncLight)
                Misc.MyBase.CLEARBIT(ref istatus, IODefinition.IN_SYNC);
            return istatus;
        }
        static double GetRemainder(double a, double b)
        {
            if (a >= 0)
            {
                return a % b;
            }
            else
            {
                double ret = a % b;
                if (ret != 0)
                    ret += Math.Abs(b);
                return ret;
            }
        }
        public int GetPosition2()
        {
            return (int)(FilmPosition * 1000 / Mmpp2);
        }

        public int GetSpeed2()
        {
            return (int)(FilmVelocity * 1000 / 60 / Mmpp2);
        }

        public void SetOutput(ushort output)
        {
            if (!Misc.MyBase.CHECKBIT(output, IODefinition.OUT_SYNC))
                IsSyncLight = true;
            else
                IsSyncLight = false;
        }
    }
    public class GageAdJsonDb 
    {
        static Mapper Mapper { get; } = new AutoMapper.Mapper(new MapperConfiguration(c =>
        {
            c.CreateMap<GageAd, GageAdJsonDb>().ReverseMap();
        }));

        public static bool Save(GageAd src, string filePath)
        {
            if (string.IsNullOrEmpty(filePath))
                return false;

            var p = Mapper.Map<GageAdJsonDb>(src);
            try
            {
                File.WriteAllText(filePath, JsonConvert.SerializeObject(p, Formatting.Indented));
                return true;
            }
            catch
            {
                //异常，没有json 编码失败
            }
            return false;
        }


        public static bool Load(GageAd src, string filePath)
        {
            if (string.IsNullOrEmpty(filePath))
                return false;

            try
            {
                if (File.Exists(filePath))
                {
                    string json = File.ReadAllText(filePath);
                    var p = JsonConvert.DeserializeObject<GageAdJsonDb>(json);
                    Mapper.Map(p, src);
                    return true;
                }
            }
            catch
            {
                //异常，没有json 解码失败
            }
            return false;
        }
        public double FilmPositionOffset;
    }
}
