using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace AGVEmulator.UC
{
    public partial class AgvViewer : Control
    {

        public AgvViewer()
        {
            InitializeComponent();

            // Set Optimized Double Buffer to reduce flickering
            this.SetStyle(ControlStyles.UserPaint, true);
            this.SetStyle(ControlStyles.AllPaintingInWmPaint, true);
            this.SetStyle(ControlStyles.OptimizedDoubleBuffer, true);

            // Redraw when resized
            this.SetStyle(ControlStyles.ResizeRedraw, true);
        }

        public class TagArgs : EventArgs
        {
            public string Data { get; set; }
            public bool Active { get; set; }
            public TagArgs(string tag,bool act)
            {
                this.Data = tag;
                this.Active = act;
            }
        }
        public event EventHandler<TagArgs> TagTouched;
        public event EventHandler<TagArgs> MarkTouched;
        public event EventHandler<TagArgs> Command;

        public bool StopbyMark { get; set; }
        public float mpos = 100;
        public float posmax = 1200;
        public float posmin = 0;
        public float mspd = 10;
        public System.Diagnostics.Stopwatch wat = new System.Diagnostics.Stopwatch();
        public Font FontTag { get; set; }
        public Font FontMrk { get; set; }
        public int dir = 1;

        public class ptdata
        {
            public float pos { get; set; } = 0f;
            public string data { get; set; } = string.Empty;
            public Boolean active { get; set; } = false;
        }
        public ptdata[] listMRK { get; set; }
        public ptdata[] listTAG { get; set; }

        public string lasttag { get; set; } = string.Empty;
        public string lasttagdir { get; set; } = string.Empty;
        public string lastmark { get; set; } = string.Empty;
        public string lastmarkdir { get; set; } = string.Empty;

        protected override void OnPaint(PaintEventArgs pe)
        {
            pe.Graphics.Clear(this.BackColor);
            var r = new Rectangle(DisplayRectangle.Left + Padding.Left,
                DisplayRectangle.Top + Padding.Top,
                DisplayRectangle.Width - Padding.Right - Padding.Left - 1,
                DisplayRectangle.Height - Padding.Top - Padding.Bottom - 1);


            // pe.Graphics.FillRectangle(new SolidBrush(this.BackColor), DisplayRectangle);
            pe.Graphics.DrawRectangle(Pens.Black, r);


            var ptwidth = 25;
            var ptheight = 35;
            if (listMRK != null && listMRK.Any() && FontMrk != null)
            {
                foreach (var item in listMRK)
                {
                    var x = r.Left + ((item.pos * 1f) / posmax) * r.Width;
                    var rr = new RectangleF(x - ptwidth, r.Top + r.Height / 2f - ptheight / 2f, ptwidth * 2, ptheight);
                    pe.Graphics.DrawLine(Pens.Gray, x, r.Top, x, r.Bottom);
                    pe.Graphics.FillRectangle(new SolidBrush(Color.FromArgb(120, Color.Gold)), rr);
                    pe.Graphics.DrawRectangle(Pens.DimGray, rr.Left, rr.Top, rr.Width, rr.Height);
                    pe.Graphics.DrawString(item.data, FontMrk, Brushes.Gray, rr, new StringFormat
                    {
                        Alignment = StringAlignment.Center,
                        LineAlignment = StringAlignment.Center,
                    });

                }
            }

            ptwidth = 15;
            if (listTAG != null && listTAG.Any() && FontTag != null)
            {
                var lst = listTAG.Where(t => t.data.EndsWith("1"));
                foreach (var item in lst)
                {
                    var x = r.Left + ((item.pos * 1f) / posmax) * r.Width;
                    var rr = new RectangleF(x - ptwidth, r.Top + 5, ptwidth * 2, 15);
                    pe.Graphics.DrawLine(Pens.Orange, x, r.Top, x, rr.Top);
                    pe.Graphics.FillRectangle(Brushes.Orange, rr);
                    pe.Graphics.DrawRectangle(Pens.DimGray, rr.Left, rr.Top, rr.Width, rr.Height);
                    pe.Graphics.DrawString(item.data, FontTag, Brushes.Black, rr, new StringFormat
                    {
                        Alignment = StringAlignment.Center,
                        LineAlignment = StringAlignment.Center,
                    });
                }

                lst = listTAG.Where(t => t.data.EndsWith("0"));
                foreach (var item in lst)
                {
                    var x = r.Left + ((item.pos * 1f) / posmax) * r.Width;
                    var rr = new RectangleF(x - ptwidth, r.Bottom - 20, ptwidth * 2, 15);
                    pe.Graphics.DrawLine(Pens.Orange, x, rr.Bottom, x, r.Bottom);
                    pe.Graphics.FillRectangle(Brushes.Orange, rr);
                    pe.Graphics.DrawRectangle(Pens.DimGray, rr.Left, rr.Top, rr.Width, rr.Height);
                    pe.Graphics.DrawString(item.data, FontTag, Brushes.Black, rr, new StringFormat
                    {
                        Alignment = StringAlignment.Center,
                        LineAlignment = StringAlignment.Center,
                    });
                }
            }

            var posX = r.Left + (mpos / posmax) * r.Width;
            var posY = r.Top + r.Height / 2f;
            var boxw = r.Width * 0.030f;
            var boxh = r.Height * 0.15f;
            var box = new RectangleF(posX - boxw, posY - boxh, boxw * 2, boxh * 2);
            var box2 = new RectangleF(box.Left - 5, box.Top + 3, 10, box.Height - 6);
            for (int i = 0; i < posmax; i += 100)
            {
                var x = r.Left + ((i * 1f) / posmax) * r.Width;
                pe.Graphics.DrawLine(Pens.Black, x, r.Bottom - 3, x, r.Bottom);
                if (i > 0)
                    pe.Graphics.DrawString($"{i / 10f}m", this.Font, Brushes.Black, x - 12, r.Bottom - 15);
            }
            pe.Graphics.FillRectangle(Brushes.LightSkyBlue, box);
            pe.Graphics.DrawRectangle(Pens.Black, box.Left, box.Top, box.Width, box.Height);
            pe.Graphics.DrawLine(new Pen(Color.Black, 4), posX, box.Top - 5, posX, box.Bottom + 5);

            pe.Graphics.FillRectangle(Brushes.Gold, box2);
            pe.Graphics.DrawRectangle(Pens.Black, box2.Left, box2.Top, box2.Width, box2.Height);
            //pe.Graphics.DrawString((mpos / 10f).ToString("N1") + "m", this.Font, Brushes.Black, box, new StringFormat
            //{
            //    Alignment = StringAlignment.Center,
            //    LineAlignment = StringAlignment.Center,
            //});

            if (StopbyMark)
                pe.Graphics.DrawString("!MRK-STP!", this.Font, Brushes.Blue, r.Left+2, r.Top+2);

            if (wat.IsRunning)
            {
                var newpos = mspd * (wat.ElapsedMilliseconds / 1000f);
                if (dir < 0) //forward
                {
                    if (mpos - newpos < 0)
                        mpos = posmax;
                    else mpos -= newpos;

                    //내위치주변에 마커가 있는지 본다
                    var mlist = listMRK.Where(t => t.pos <= mpos && (mpos - t.pos) < 10);
                    var mrk = mlist.FirstOrDefault();
                    if (mrk != null)
                    {
                        //대상마커가있다
                        if (lastmark.Equals(mrk.data) == false || lastmarkdir.Equals("F") == false)
                        {
                            lastmark = mrk.data;
                            lastmarkdir = "F";
                            mrk.active = true;
                            MarkTouched?.Invoke(this, new TagArgs(mrk.data,true));
                            if(StopbyMark)
                            {
                                Command?.Invoke(this, new TagArgs("stop",true));
                                StopbyMark = false;
                            }
                        }
                    }
                    else
                    {
                        if (string.IsNullOrEmpty(lastmark) == false)
                        {
                            foreach(var item in listMRK.Where(t=>t.active))
                            {
                                item.active = false;
                                MarkTouched?.Invoke(this, new TagArgs(item.data,false));
                            }
                        }
                    }

                    //주변태그확인
                    var tlist = listTAG.Where(t => t.pos <= mpos && (mpos - t.pos) < 10);
                    var tag = tlist.FirstOrDefault();
                    if (tag != null)
                    {
                        //대상마커가있다
                        if (lasttag.Equals(tag.data) == false || lasttagdir.Equals("F") == false)
                        {
                            lasttag = tag.data;
                            lasttagdir = "F";
                            TagTouched?.Invoke(this, new TagArgs(tag.data, true));
                        }
                    }
                }
                else //backward
                {
                    if (mpos + newpos > posmax)
                        mpos = 0;
                    else mpos += newpos;

                    //내위치주변에 마커가 있는지 본다
                    var mlist = listMRK.Where(t => t.pos >= mpos && (t.pos - mpos) < 10);
                    var mrk = mlist.FirstOrDefault();
                    if (mrk != null)
                    {
                        //대상마커가있다
                        if (lastmark.Equals(mrk.data) == false || lastmarkdir.Equals("B") == false)
                        {
                            lastmark = mrk.data;
                            lastmarkdir = "B";
                            mrk.active = true;
                            MarkTouched?.Invoke(this, new TagArgs(mrk.data, true));
                            if (StopbyMark)
                            {
                                Command?.Invoke(this, new TagArgs("stop", true));
                                StopbyMark = false;
                            }
                        }
                    }
                    else
                    {
                        if (string.IsNullOrEmpty(lastmark) == false)
                        {
                            foreach (var item in listMRK.Where(t => t.active))
                            {
                                item.active = false;
                                MarkTouched?.Invoke(this, new TagArgs(item.data, false));
                            }
                        }
                    }

                    //주변태그확인
                    var tlist = listTAG.Where(t => t.pos >= mpos && (t.pos - mpos) < 10);
                    var tag = tlist.FirstOrDefault();
                    if (tag != null)
                    {
                        //대상마커가있다
                        if (lasttag.Equals(tag.data) == false || lasttagdir.Equals("B") == false)
                        {
                            lasttag = tag.data;
                            lasttagdir = "B";
                            TagTouched?.Invoke(this, new TagArgs(tag.data, true));
                        }
                    }
                }

                wat.Restart();
            }
        }
    }
}
