using System.Collections.Generic;
using System;
using System.Drawing;
using System.Diagnostics;
using System.Data;
using System.Collections;
using System.Windows.Forms;
using System.Linq;
using System.Reflection;
using System.Runtime.InteropServices;
using TrendCtrlII;
using AR;
using System.Data.SqlTypes;
using System.Diagnostics.Eventing.Reader;
using System.Data.Linq;

namespace vmsnet
{

    public partial class Frm_trend_Real
    {
        private string lasttime = "";
        private DateTime EndDate = DateTime.Now;
        private bool init = false;
        private HMI.DispCtrl DispCtrl1;
        readonly ScottPlot.WinForms.FormsPlot formsPlot1;
        ScottPlot.Plottables.Scatter[] Streamer1;

        List<float>[] dataVolt = null;
        List<double>[] dataTime = null;

        short voltlimit = 0;
        short timelimit = 10;

        public Frm_trend_Real(HMI.DispCtrl dispctrl)
        {

            // 디자이너에서 이 호출이 필요합니다.
            InitializeComponent();
            // InitializeComponent() 호출 뒤에 초기화 코드를 추가하세요.

            //현재데이터베이스를 복제한다.
            MakeTempDatabase();


            formsPlot1 = new ScottPlot.WinForms.FormsPlot() { Dock = DockStyle.Fill };
            formsPlot1.MouseDown += FormsPlot1_MouseDown;
            formsPlot1.MouseUp += FormsPlot1_MouseUp;
            formsPlot1.MouseMove += FormsPlot1_MouseMove;

            CrossHair = formsPlot1.Plot.Add.Crosshair(0, 0);
            CrossHair.TextColor = ScottPlot.Colors.White;
            CrossHair.TextBackgroundColor = CrossHair.HorizontalLine.Color;

            formsPlot1.Plot.YLabel("VOLTAGE");
            formsPlot1.Plot.XLabel("COUNT");

            formsPlot1.Plot.Axes.Bottom.MinimumSize = PUB.TREND.graph_bottom_minsize;

            this.formsPlot1.Plot.ShowLegend();
            formsPlot1.Plot.Axes.DateTimeTicksBottom();
            this.formsPlot1.Plot.Axes.ContinuouslyAutoscale = true;
            this.formsPlot1.Plot.RenderManager.RenderStarting += (s1, e1) =>
            {
                ScottPlot.Tick[] ticks = formsPlot1.Plot.Axes.Bottom.TickGenerator.Ticks;
                for (int i = 0; i < ticks.Length; i++)
                {
                    DateTime dt = DateTime.FromOADate(ticks[i].Position);
                    string label = $"{dt:yy-MM-dd\nHH:mm:ss}";
                    ticks[i] = new ScottPlot.Tick(ticks[i].Position, label);
                }
            };




            Panel2.Controls.Clear();
            this.Panel2.Controls.Add(this.formsPlot1);

            ////그룹데이터목록
            this.cmb_tanks.Items.Clear();
            for (int i = 0; i <= dispctrl.GROUPS.Length - 1; i++)
            {
                var grp = dispctrl.GROUPS[i];
                this.cmb_tanks.Items.Add(grp.이름);
            }

            DispCtrl1 = dispctrl;

            PUB.RemoteCommandEvent += Pub_RemoteCommandEvent;

            Refresh_전해조목록();
            if (this.cmb_tanks.Items.Count > 0)
                this.cmb_tanks.SelectedIndex = 0;

            Streamer1 = new ScottPlot.Plottables.Scatter[0];
            dataVolt = new List<float>[0];
            dataTime = new List<double>[0];
        }

        public void Frm_trend_FormClosing(object sender, System.Windows.Forms.FormClosingEventArgs e)
        {
            saveviewSetting();
            PUB.RemoteCommandEvent -= Pub_RemoteCommandEvent;
            formsPlot1.MouseDown -= FormsPlot1_MouseDown;
            formsPlot1.MouseUp -= FormsPlot1_MouseUp;
            formsPlot1.MouseMove -= FormsPlot1_MouseMove;
            Timer1.Stop();
        }
        void MakeTempDatabase()
        {
            //현재데이터베이스를 복제한다.
            this.documentElement1.Clear();
            this.documentElement1.GRP.Merge(PUB.DS.GRP);
            this.documentElement1.CHANNEL.Merge(PUB.DS.CHANNEL);
            this.documentElement1.AcceptChanges();
            this.ds1.Clear();
            this.ds1.AcceptChanges();
        }
        private void Refresh_전해조목록()
        {
            this.cmb_tanks.Items.Clear();
            var grplist = this.documentElement1.GRP.Where(t => t.USE == 1);
            if (grplist.Any() == false)
            {
                UTIL.MsgE("활성화된 그룹이 없습니다");
                return;
            }

            var namelist = grplist.Select(t => $"[{t.IDX:00}] {t.TITLE}").ToArray();
            this.cmb_tanks.Items.AddRange(namelist);
        }


        public void Frm_trend_Load(System.Object sender, System.EventArgs e)
        {
            EndDate = DateTime.Now;

            ////마지막으로 선택한 그룹을 선택해준다.
            var selidx0 = (PUB.CONFIG.tvr_selectgroup0); // XMl.Data("trendview", "selectgroup0", "0")
            this.cmb_tanks.SelectedIndex = selidx0;
            loadviewSetting();
            init = true;
            Timer1.Start();
        }


        private void Pub_RemoteCommandEvent(object sender, RemoteCommand e)
        {
            if (e.Command == rCommand.ValueUpdate)
            {
                //스트리머,데이터,선택된 채널 정보가 있어야 업데이트 가능하다
                if (e.Data != null && this.Streamer1 != null && this.selectchlist.Any())
                {
                    var data = e.Data as List<NotifyData>;

                    //선택된 채널의 정보만 사용
                    var recvdatas = data.Where(t => selectchlist.Contains(t.chno)).Select(t => t);
                    if (recvdatas.Any() == false) return; //대상채널데이터가 없다.


                    //받은데이터를 화면에 추가한다.
                    foreach (var newdata in recvdatas)
                    {
                        var ch = newdata.chno - 1;
                        var val = newdata.value;
                        var time = newdata.time;

                        //자료가없거나 스트리머가 없는 경우
                        if (ch >= this.Streamer1.Length || this.Streamer1[ch] == null) continue;


                        float value = 0;
                        if (PUB.CONFIG.datadiv != 0 && PUB.CONFIG.datadiv != 1)
                            value = (newdata.value) / PUB.CONFIG.datadiv;
                        else
                            value = (newdata.value);

                        //채널정보를 통해서 소수점위치와 옾셋값을 가져온다
                        if (newdata.decpos > 0) value = (float)(value / Math.Pow(10, newdata.decpos));

                        //최종옵셋
                        value += newdata.offset;

                        //데이터 추가
                        if (this.Streamer1[ch].IsVisible)
                        {
                            var v_time = DateTime.Parse(time);
                            this.dataTime[ch].Add(v_time.ToOADate());
                            this.dataVolt[ch].Add(value);

                            var mintime = DateTime.FromOADate(dataTime[ch].First());
                            var maxtime = DateTime.FromOADate(dataTime[ch].Last());
                            var ts = (maxtime - mintime);
                            if (ts.TotalMinutes >= this.timelimit)
                            {
                                //10개지운다
                                if (dataTime[ch].Count > 10)
                                {
                                    dataTime[ch].RemoveRange(0, 10);
                                    dataVolt[ch].RemoveRange(0, 10);
                                }

                            }

                        }

                    }
                    this.BeginInvoke(new Action(() =>
                    {
                        if (voltlimit != 0) formsPlot1.Plot.Axes.AutoScaleX();
                        this.formsPlot1.Refresh();
                    }));
                }
            }

        }

        #region "scott plot mouse event"
        ScottPlot.Plottables.Crosshair CrossHair;
        ScottPlot.Plottables.VerticalLine[] CursorLine;
        private ScottPlot.Plottables.AxisLine GetLineUnderMouse(float x, float y)
        {
            ScottPlot.CoordinateRect rect = formsPlot1.Plot.GetCoordinateRect(x, y, radius: 10);

            foreach (var axLine in formsPlot1.Plot.GetPlottables<ScottPlot.Plottables.AxisLine>().Reverse())
            {
                if (axLine.IsUnderMouse(rect))
                    return axLine;
            }

            return null;
        }



        private void FormsPlot1_MouseDown(object sender, MouseEventArgs e)
        {
            var lineUnderMouse = GetLineUnderMouse(e.X, e.Y);
            if (lineUnderMouse != null)
            {
                PlottableBeingDragged = lineUnderMouse;
                formsPlot1.Interaction.Disable(); // disable panning while dragging
            }
        }

        private void FormsPlot1_MouseUp(object sender, MouseEventArgs e)
        {
            PlottableBeingDragged = null;
            formsPlot1.Interaction.Enable(); // enable panning again
            formsPlot1.Refresh();
        }
        ScottPlot.Plottables.AxisLine PlottableBeingDragged = null;
        private void FormsPlot1_MouseMove(object sender, MouseEventArgs e)
        {

            //update cross line
            ScottPlot.Pixel mousePixel = new ScottPlot.Pixel(e.X, e.Y);
            ScottPlot.Coordinates mouseCoordinates = formsPlot1.Plot.GetCoordinates(mousePixel);

            if (mouseCoordinates.X is double.NaN || mouseCoordinates.Y is double.NaN ||
               mouseCoordinates.X is double.PositiveInfinity || mouseCoordinates.Y is double.PositiveInfinity ||
               mouseCoordinates.X is double.NegativeInfinity || mouseCoordinates.Y is double.NegativeInfinity)
            {
                return;
            }

            if (CrossHair != null)
            {
                CrossHair.Position = mouseCoordinates;
                var time = DateTime.FromOADate(mouseCoordinates.X);

                CrossHair.VerticalLine.Text = $"{time:yy-MM-dd\nHH:mm:ss}";

                CrossHair.HorizontalLine.Text = $"{mouseCoordinates.Y:N2}v";
                formsPlot1.Refresh();
            }




            // this rectangle is the area around the mouse in coordinate units
            ScottPlot.CoordinateRect rect = formsPlot1.Plot.GetCoordinateRect(e.X, e.Y, radius: 10);

            if (PlottableBeingDragged is null)
            {
                // set cursor based on what's beneath the plottable
                var lineUnderMouse = GetLineUnderMouse(e.X, e.Y);
                if (lineUnderMouse is null) Cursor = Cursors.Default;
                else if (lineUnderMouse.IsDraggable && lineUnderMouse is ScottPlot.Plottables.VerticalLine) Cursor = Cursors.SizeWE;
                else if (lineUnderMouse.IsDraggable && lineUnderMouse is ScottPlot.Plottables.HorizontalLine) Cursor = Cursors.SizeNS;
            }
            else
            {
                // update the position of the plottable being dragged
                if (PlottableBeingDragged is ScottPlot.Plottables.HorizontalLine hl)
                {
                    hl.Y = rect.VerticalCenter;
                    hl.Text = $"{hl.Y:0.00}v";
                }
                else if (PlottableBeingDragged is ScottPlot.Plottables.VerticalLine vl)
                {
                    vl.X = rect.HorizontalCenter;
                    var time = DateTime.FromOADate(vl.X);
                    //vl.Text = $"{vl.X:0.00}";
                    vl.Text = $"{time:yy-MM-dd\nHH:mm:ss}";
                }
                formsPlot1.Refresh();
            }
        }
        #endregion



        //그룹이 선택된 경우
        public void cmb_group_SelectedIndexChanged(System.Object sender, System.EventArgs e)
        {
            if (cmb_tanks.SelectedIndex < 0) return;
            if (System.Diagnostics.Debugger.IsAttached) Console.WriteLine($"grp selectedindex val={cmb_tanks.SelectedIndex}");

            /* 작성자: 이재웅, 작성일: 2024-11-22, 내용: 차트/Scatter/Volt/Time 초기화 */
            this.formsPlot1.Plot.Clear();
            this.Streamer1 = new ScottPlot.Plottables.Scatter[0];
            this.dataVolt = new List<float>[0];
            this.dataTime = new List<double>[0];
            /**********************************************************************/

            //현재등록된 목록을 모두 삭제
            this.ds1.channel.Clear();
            this.formsPlot1.Plot.Remove<ScottPlot.Plottables.DataStreamer>();   //데이터스트림삭제
            this.formsPlot1.Refresh();

            var grpName = cmb_tanks.Text.Substring(4).Trim();
            var grpNo = int.Parse(cmb_tanks.Text.Substring(1, 2));

            var grpdr = this.documentElement1.GRP.Where(t => t.TITLE.Equals(grpName)).FirstOrDefault();
            if (grpdr == null) return;

            var chlist = this.documentElement1.CHANNEL.Where(t => t.GIDX == grpdr.IDX);
            if (chlist.Any() == false) return;


            // 미리저장된 목록을 확인한다.
            var chstr = "";
            if (grpNo == 0) chstr = PUB.CONFIG.grp0chlist;
            else if (grpNo == 1) chstr = PUB.CONFIG.grp1chlist;
            else if (grpNo == 2) chstr = PUB.CONFIG.grp2chlist;
            else if (grpNo == 3) chstr = PUB.CONFIG.grp3chlist;
            else if (grpNo == 4) chstr = PUB.CONFIG.grp4chlist;
            else if (grpNo == 5) chstr = PUB.CONFIG.grp5chlist;
            else if (grpNo == 6) chstr = PUB.CONFIG.grp6chlist;
            else if (grpNo == 7) chstr = PUB.CONFIG.grp7chlist;
            else if (grpNo == 8) chstr = PUB.CONFIG.grp8chlist;
            else if (grpNo == 9) chstr = PUB.CONFIG.grp9chlist;

            var chbuf = chstr.Split((char[])(new[] { ',' }), StringSplitOptions.RemoveEmptyEntries);


            //목록은 추가하지만 스트립을 추가하지 않으니 최초 선택시에는 데이터가 나오지 않는다.
            //사용자는 채널 선택을 사용해야 데이터가 보인다.
            this.ds1.channel.Clear();
            this.selectchlist.Clear();
            foreach (var dr in chlist)
            {
                var newdr = ds1.channel.NewchannelRow();
                newdr.idx = dr.IDX;
                newdr.use = chbuf.Contains(dr.IDX.ToString()) ? true : false;
                newdr.c1 = "";
                newdr.c2 = "";
                newdr.cname = dr.TITLE;
                newdr.cc = dr.COLOR;
                ds1.channel.AddchannelRow(newdr);
            }
            ds1.channel.AcceptChanges();
            formsPlot1.Refresh();
        }

        public void ToolStripButton1_Click_1(object sender, EventArgs e)
        {
            string dir = System.IO.Path.Combine(PUB.CONFIG.GetDatabasePath(), "DataBase", "volt");
            UTIL.RunExplorer(dir);
        }

        private void loadviewSetting()
        {
            cmb_volt.SelectedIndex = (PUB.CONFIG.cell_voltindex); // Xml.Data("rtlview", "voltindex", "1")
            cmb_time.SelectedIndex = (PUB.CONFIG.cell_timeindex); // XMl.Data("rtlview", "timeindex", "0")
        }
        private void saveviewSetting()
        {
            PUB.CONFIG.cell_voltindex = (cmb_volt.SelectedIndex);
            PUB.CONFIG.cell_timeindex = (cmb_time.SelectedIndex);
            PUB.CONFIG.Save();
        }

        public void bs_grp_CurrentChanged(object sender, EventArgs e)
        {
            ////사용자가 그룹을 선택하면 해당 그룹에 연결된 채널목록을 가지고 사용 데이터 그룹을 결정함
        }

        /// <summary>
        /// 1부터시작하는 채널의 번호입니다.(인덱스가 아님)
        /// 채널선택화면에서 선택된 채널 번호만 들어있다.
        /// docuementElement1 에는 모든 그룹/채널 정보가 들어있다
        /// </summary>
        List<int> selectchlist = new List<int>();
        public void btSelectCH_Click(object sender, EventArgs e)
        {
            var grpName = cmb_tanks.Text.Substring(4).Trim();
            var grpNo = int.Parse(cmb_tanks.Text.Substring(1, 2));

            //현재선택된 그룹의 채널목록을 추출해야한다.
            if (grpName.isEmpty())
            {
                UTIL.MsgE("채널 그룹을 선택하세요");
                return;
            }

            var drGrp = documentElement1.GRP.Where(t => t.TITLE == grpName).FirstOrDefault();
            if (drGrp == null)
            {
                UTIL.MsgE("선택된 채널 그룹 정보가 없습니다");
                return;
            }

            //채널목록을 확인한다.
            var chrows = documentElement1.CHANNEL.Where(t => t.GIDX == drGrp.IDX);
            if (chrows.Any() == false)
            {
                UTIL.MsgE("해당 그룹에 등록된 채널정보가 없습니다");
                return;
            }

            //현재 등록된 채널정보를 토대로 데이터를 선택한다
            using (var f = new Frm_SelectCH(ds1.channel))
            {
                if (f.ShowDialog() == DialogResult.OK)
                {
                    //현재등록된 목록을 모두 삭제
                    this.formsPlot1.Plot.Remove<ScottPlot.Plottables.Scatter>();   //데이터스트림삭제
                    this.formsPlot1.Refresh();

                    this.selectchlist.Clear();
                    //기존에 선택된 자료 선택하제
                    foreach (var item in ds1.channel.Where(t => t.use))
                    {
                        item.use = false;
                    }
                    ds1.channel.AcceptChanges();

                    foreach (ListViewItem item in f.CheckedListBox1.Items)  //선택된 목록만 가져온다
                    {
                        int idx = int.Parse(item.Tag.ToString()); //.SubItems(0).Text)

                        //지정된 플롯의 표시여부를 변경한다.
                        if (this.Streamer1.Length < idx)
                        {
                            Array.Resize(ref Streamer1, idx);
                            Array.Resize(ref dataVolt, idx);
                            Array.Resize(ref dataTime, idx);
                        }

                        if (dataTime[idx - 1] == null) dataTime[idx - 1] = new List<double>();
                        if (dataVolt[idx - 1] == null) dataVolt[idx - 1] = new List<float>();
                        if (Streamer1[idx - 1] != null) this.Streamer1[idx - 1] = null;

                        Streamer1[idx - 1] = this.formsPlot1.Plot.Add.ScatterPoints(dataTime[idx - 1], dataVolt[idx - 1]);
                        Streamer1[idx - 1].LineWidth = 1;
                        Streamer1[idx - 1].MarkerSize = 0;
                        /* 작성자: 이재웅, 작성일: 2024-11-27, 내용: 변경한 셀이름으로 차트범례 표시 */
                        Streamer1[idx - 1].LegendText = item.Text; //$"CH{idx}";
                        Streamer1[idx - 1].IsVisible = item.Checked;

                        var dr = ds1.channel.Where(t => t.idx == idx).FirstOrDefault();
                        if (dr != null)
                        {
                            dr.use = item.Checked;
                            dr.EndEdit();
                        }
                        if (item.Checked) selectchlist.Add(idx);    //선택채널에 추가한다.
                    }

                    ds1.channel.AcceptChanges();

                    //사용자목록에 저장한다
                    string chstr = string.Join(",", selectchlist.ToArray());
                    if (grpNo == 0) PUB.CONFIG.grp0chlist = chstr;
                    else if (grpNo == 1) PUB.CONFIG.grp1chlist = chstr;
                    else if (grpNo == 2) PUB.CONFIG.grp2chlist = chstr;
                    else if (grpNo == 3) PUB.CONFIG.grp3chlist = chstr;
                    else if (grpNo == 4) PUB.CONFIG.grp4chlist = chstr;
                    else if (grpNo == 5) PUB.CONFIG.grp5chlist = chstr;
                    else if (grpNo == 6) PUB.CONFIG.grp6chlist = chstr;
                    else if (grpNo == 7) PUB.CONFIG.grp7chlist = chstr;
                    else if (grpNo == 8) PUB.CONFIG.grp8chlist = chstr;
                    else if (grpNo == 9) PUB.CONFIG.grp9chlist = chstr;

                    PUB.CONFIG.Save();

                    if (CrossHair == null)
                    {
                        CrossHair = formsPlot1.Plot.Add.Crosshair(0, 0);
                        CrossHair.TextColor = ScottPlot.Colors.White;
                        CrossHair.TextBackgroundColor = CrossHair.HorizontalLine.Color;
                    }

                    formsPlot1.Plot.Axes.ContinuouslyAutoscale = true;
                    this.formsPlot1.Refresh();
                }
            }

        }
        public void Timer1_Tick(object sender, EventArgs e)
        {

        }

        private void Panel1_Paint(object sender, PaintEventArgs e)
        {

        }

        private void cmb_volt_SelectedIndexChanged(object sender, EventArgs e)
        {
            if (cmb_volt.SelectedIndex < 0) return;
            if (cmb_volt.SelectedIndex == 0) voltlimit = 0;
            else voltlimit = short.Parse(this.cmb_volt.Text.Replace("v", ""));
            if (this.formsPlot1 != null)
            {
                if (voltlimit == 0)
                    this.formsPlot1.Plot.Axes.ContinuouslyAutoscale = true;
                else
                {
                    this.formsPlot1.Plot.Axes.ContinuouslyAutoscale = false;
                    this.formsPlot1.Plot.Axes.SetLimitsY(0, voltlimit);
                }
            }
        }

        private void cmb_time_SelectedIndexChanged_1(object sender, EventArgs e)
        {
            if (cmb_time.SelectedIndex < 0) return;

            timelimit = short.Parse(this.cmb_time.Text.Replace("분", ""));
        }

        private void btConfig_Click(object sender, EventArgs e)
        {
            if (UTIL.ShowPropertyDialog(PUB.TREND) == DialogResult.OK)
            {
                PUB.TREND.Save();

                formsPlot1.Plot.Axes.Bottom.MinimumSize = PUB.TREND.graph_bottom_minsize;
                if (PUB.TREND.y_scale_auto)
                    formsPlot1.Plot.Axes.AutoScaleY();
                else
                    formsPlot1.Plot.Axes.SetLimitsY(PUB.TREND.graph_y_start, PUB.TREND.graph_y_end);

                formsPlot1.Refresh();
            }
        }
    }
}
