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

namespace CMSControl
{
    public enum eSystemStep : byte
    {
        IDLE = 0,
        INPUT,
        OUTPUT,
        REINPUT,
        FINISH,
        RESULT,
        CLOSING = 90,
        CLOSEWAIT,
        CLOSED,
    }


    public partial class cmsview : Control
    {

        public eSystemStep step = eSystemStep.IDLE;
        public UInt16 _page;
        private Point _gridcount;
        public UInt16 GridItemCount { get { return (UInt16)(_gridcount.X * _gridcount.Y); } }
        public Boolean isDebug { get; set; }
        public int LastContactSlotIDX = -1;

        //private Font _fontid;
        //private Font _fontno;
        //private Font _fontcontent;

        public float NoStrSize = 100f;

        public Boolean bRePaint;
        public List<Slot> Slots = new List<Slot>();
        public List<Item> Items = new List<Item>();
        public UInt16 ItemMargin { get; set; }

        public Point GridCount { get { return _gridcount; } set { _gridcount = value; } }

        public Font Font_No;    //slotno
        public Font Font_Top;   //top
        public Font Font_Bottom;   //bottom
        public Font Font_Middle;   //bottom
        public Font Font_Count;   //bottom

        public System.Drawing.Color color_font_no = Color.White;
        public System.Drawing.Color color_font_top = Color.White;
        public System.Drawing.Color color_font_middle = Color.White;
        public System.Drawing.Color color_font_bottom_left = Color.White;
        public System.Drawing.Color color_font_bottom_right = Color.White;

        public Padding Padding_No;
        public Padding Padding_Top;
        public Padding Padding_Bottom;
        public Padding Padding_Middle;
        public Padding Padding_Count;

        public string DisplayT;
        public string DisplayM;
        public string DisplayBL;
        public string DisplayBR;

        public System.Windows.Forms.HorizontalAlignment TextAlignT = HorizontalAlignment.Left;
        public System.Windows.Forms.HorizontalAlignment TextAlignM = HorizontalAlignment.Left;
        public System.Windows.Forms.HorizontalAlignment TextAlignBL = HorizontalAlignment.Left;
        public System.Windows.Forms.HorizontalAlignment TextAlignBR = HorizontalAlignment.Right;

        public Boolean Enable_MultiBox = false;

        public event EventHandler<ItemClickEvent> ItemClick;
        public event EventHandler<MessageEvent> Message;

        public UInt16 GetMaxPageCount
        {
            get
            {
                if (GridItemCount == 0) return 0;
                return (UInt16)(Math.Ceiling(Slots.Count * 1.0 / GridItemCount));
            }
        }

        public UInt16 Page
        {
            get
            {
                return _page;
            }
            set
            {
                if (value < 1) value = 1;
                UInt16 MaxPage = GetMaxPageCount;
                if (MaxPage < 1) MaxPage = 1;
                if (value > MaxPage) value = MaxPage;
                if (value != _page)
                {
                    _page = value;
                    bRePaint = true;
                    this.Invalidate();
                }
            }
        }
        public cmsview()
        {
            this.SetStyle(ControlStyles.UserPaint, true);
            this.SetStyle(ControlStyles.AllPaintingInWmPaint, true);
            this.SetStyle(ControlStyles.OptimizedDoubleBuffer, true);
            this.SetStyle(ControlStyles.SupportsTransparentBackColor, true);

            // Redraw when resized
            this.SetStyle(ControlStyles.ResizeRedraw, true);
            this.Resize += arLabel_Resize;
            this.MouseDown += cmsview_MouseDown;

            this._page = 1;
            ItemMargin = 3;
            this.GridCount = new Point(8, 12);
            Font_No = new Font("Consolas", 15f);
            Font_Bottom = new Font("Consolas", 8f);
            Font_Top = new Font("Consolas", 8f);
            bRePaint = false;
            isDebug = false;
        }


        public void RaiseMessage(Boolean iserr, string msg)
        {
            if (Message != null)
                Message(this, new MessageEvent(iserr, msg));
        }
        public void ClearSelectItem()
        {
            foreach (var no in preSelectedIndex)
                this.Slots[no].Selected = false;
        }
        /// <summary>
        /// 지정한 index 의 아이템을 선택합니다. 페이지는 자동 전환됩니다.
        /// </summary>
        /// <param name="idx"></param>
        public Boolean SelectItem(int idx)
        {
            ushort newPage = (ushort)(Math.Ceiling((double)(idx + 1) / GridItemCount));
            if (newPage != this._page) Page = newPage;

            if (idx >= Slots.Count)
            {
                RaiseMessage(true, "Index (" + idx.ToString() + ")Range Error ItemCount=" + this.Slots.Count.ToString());
                return false; //존재하지않는 아이템이다.
            }
            Slots[idx].Selected = true;


            if (ItemClick != null)
                ItemClick(this, new ItemClickEvent(Point.Empty, idx, MouseButtons.Left, eClickArea.No));

            //이전에 선택된 것은 제거한다.
            ClearPreSelected();
            preSelectedIndex.Add(idx);

            this.Invalidate();
            return true;
        }

        /// <summary>
        /// id가 일치하는 대상을 모두 찾습니다.
        /// </summary>
        /// <param name="ID1"></param>
        public int SelectItem(string ID1, string ID2)
        {
            int retval = 0;

            //이전에 선택된 것은 제거한다.
            ClearPreSelected();

            //자식데이터가 속해있다면 그것들을 모두 체크해야한다.
            var items = this.Items.Where(t => t.ID1 == ID1 && t.ID2 == ID2);
            if (items.Count() < 1)
            {
                RaiseMessage(false, "Not Found UID=" + ID1);
                return retval;
            }

            //해당 자식들이 속해잇는 슬롯을 모두 선택해준다.
            foreach (var item in items)
            {
                if (item.SlotIDX < this.Slots.Count)
                {
                    var slot = this.Slots[item.SlotIDX];
                    if (!slot.Selected)
                    {
                        slot.Selected = true;
                        retval += 1;
                        preSelectedIndex.Add(slot.Index);
                    }
                }
            }


            ushort newPage = 1;
            if (preSelectedIndex.Count > 0)
                newPage = (ushort)(Math.Ceiling((double)(preSelectedIndex[preSelectedIndex.Count - 1] + 1) / GridItemCount));

            if (newPage != this._page) Page = newPage;

            if (ItemClick != null && preSelectedIndex.Count > 0)
                ItemClick(this, new ItemClickEvent(Point.Empty, preSelectedIndex[0], MouseButtons.Left, eClickArea.No));

            this.Invalidate();
            return retval;
        }
        public int SelectItem(string ID1)
        {
            int retval = 0;

            //이전에 선택된 것은 제거한다.
            ClearPreSelected();

            //자식데이터가 속해있다면 그것들을 모두 체크해야한다.
            var items = this.Items.Where(t => t.ID1 == ID1);
            if (items.Count() < 1)
            {
                RaiseMessage(false, "Not Found UID=" + ID1);
                return 0;
            }

            //해당 자식들이 속해잇는 슬롯을 모두 선택해준다.
            foreach (var item in items)
            {
                if (item.SlotIDX < this.Slots.Count)
                {
                    var slot = this.Slots[item.SlotIDX];
                    if (!slot.Selected)
                    {
                        slot.Selected = true;
                        retval += 1;
                        preSelectedIndex.Add(slot.Index);
                    }
                }
            }

            ushort newPage = 1;
            if (preSelectedIndex.Count > 0)
                newPage = (ushort)(Math.Ceiling((double)(preSelectedIndex[preSelectedIndex.Count - 1] + 1) / GridItemCount));

            if (newPage != this._page) Page = newPage;

            this.Invalidate();
            return retval;
        }

        public List<int> preSelectedIndex = new List<int>();

        void cmsview_MouseDown(object sender, MouseEventArgs e)
        {
            //클릭을 하면 어떤개체가 
            if (GridItemCount < 1 || Slots.Count < 1)
            {
                RaiseMessage(true, "No items");
                return;
            }
            int StartIndex = (this.Page - 1) * GridItemCount;
            for (int i = StartIndex; i < (StartIndex + GridItemCount); i++)
            {
                if (i < Slots.Count)
                {
                    var item = Slots[i];
                    if (item.Rect.Contains(e.Location))
                    {
                        eClickArea area = eClickArea.Normal;
                        if (item.RectNo.Contains(e.Location)) area = eClickArea.No;
                        else if (item.RectM.Contains(e.Location)) area = eClickArea.Title;
                        else if (item.RectB.Contains(e.Location)) area = eClickArea.Content;

                        item.Selected = true;
                        if (ItemClick != null)
                            ItemClick(this, new ItemClickEvent(e.Location, item.Index, e.Button, area));

                        ClearPreSelected();
                        preSelectedIndex.Add(item.Index);
                        item.Selected = true;

                        this.Invalidate();

                        break;
                    }
                }
                else break;
            }
        }

        void ClearPreSelected()
        {
            //이전에 선택된 것은 제거한다.
            foreach (var index in preSelectedIndex)
                if (index < Slots.Count) Slots[index].Selected = false;
            preSelectedIndex.Clear();
        }
        void arLabel_Resize(object sender, EventArgs e)
        {
            bRePaint = true;
            Invalidate();
        }

        int cnt = 0;
        protected override void OnPaint(PaintEventArgs pe)
        {
            base.OnPaint(pe);
            cnt += 1;

            int StartIndex = (this.Page - 1) * GridItemCount;

            if (GridItemCount < 1)
            {
                DrawHelp(pe.Graphics);
            }
            else
            {
                ///테스트로 데이터를 만든다.
                if (Slots.Count < 1)
                {
                    for(int i = 0; i < this.GridItemCount;i++)
                    {
                        Slots.Add(new Slot()
                        {
                            BackColor = Color.Lime,
                            BorderColor = Color.Gray,
                            BorderSize = 2f,
                            Enable = true,
                            ForeColor = Color.Black,
                            Name = "test" + i.ToString(),
                            Index = (byte)i,
                            No = (i+1).ToString(),
                            Selected = false
                        });
                    }
                    bRePaint = true;


                }

                //영역을 다시그려야하는 상황
                if (bRePaint && GridItemCount > 0 && Slots.Count > 0)
                {
                    int gridW = (int)((this.Width - this.Padding.Left - this.Padding.Right) / GridCount.X);
                    int gridH = (int)((this.Height - this.Padding.Top - this.Padding.Bottom) / GridCount.Y);

                    Rectangle rect, rect2, rectNo, rectT, rectM, rectB, rectCNT;
                    int idx = 0;
                    for (int r = 0; r < GridCount.Y; r++)
                    {
                        for (int c = 0; c < GridCount.X; c++)
                        {
                            int x = (c * gridW);
                            int y = (r * gridH);
                            rect = new Rectangle(x + this.Padding.Left, y + this.Padding.Top, gridW, gridH);
                            rect2 = new Rectangle(
                                rect.Left + this.ItemMargin,
                                rect.Top + ItemMargin,
                                rect.Width - ItemMargin * 2,
                                rect.Height - ItemMargin * 2);

                            float NoWidth = NoStrSize; // rect2.Width * 0.2f;
                            rectNo = new Rectangle(rect2.Left, rect2.Top, (int)NoWidth, (int)(rect2.Height * 0.3));
                            var dispHeight1 = (int)(rect2.Height * 0.3);
                            var dispHeight2 = (int)(rect2.Height * 0.4);
                            var dispHeight3 = rect2.Height - dispHeight1 - dispHeight2;
                            rectT = new Rectangle(rectNo.Right, rect2.Top, rect2.Width - rectNo.Width, dispHeight1); ;
                            rectM = new Rectangle(rectNo.Left, rectT.Bottom, rect2.Width, dispHeight2);
                            rectB = new Rectangle(rectNo.Left, rectM.Bottom, (int)(rect2.Width / 2.0), dispHeight3);
                            rectCNT = new Rectangle(rectB.Right, rectM.Bottom, (int)(rect2.Width / 2.0), dispHeight3);

                            if (StartIndex + idx < Slots.Count)
                            {
                                //items[StartIndex + idx].No = (byte)( idx + 1);
                                Slots[StartIndex + idx].Rect = rect2;
                                Slots[StartIndex + idx].RectNo = rectNo;
                                Slots[StartIndex + idx].RectT = rectT;
                                Slots[StartIndex + idx].RectM = rectM;
                                Slots[StartIndex + idx].RectB = rectB;
                                Slots[StartIndex + idx].RectCnt = rectCNT;
                                Slots[StartIndex + idx].ForeColor = this.ForeColor;
                                idx += 1;
                            }
                            else break;
                        }
                        if (StartIndex + idx >= Slots.Count) break;
                    }
                    bRePaint = false;
                }

                for (int i = StartIndex; i < StartIndex + GridItemCount; i++)
                {
                    if (i >= Slots.Count) break; //over check
                    var item = Slots[i];
                    var slotItems = Items.Where(t => t.SlotIDX == item.Index);
                    DrawSlot(pe.Graphics, item, slotItems);
                }

                if (isDebug)
                {
                    using (Font f = new Font("Consolas", 15))
                    {
                        System.Text.StringBuilder sb = new StringBuilder();
                        sb.AppendLine("## Debug Message ##");
                        sb.AppendLine("Step : " + this.step.ToString());
                        sb.AppendLine("Refresh Count : " + this.cnt.ToString());
                        sb.AppendLine("Slot count : " + Slots.Count.ToString());
                        sb.AppendLine("Item Count : " + Items.Count.ToString());

                        sb.AppendLine("font no : " + this.Font_No.ToString());
                        sb.AppendLine("font top : " + this.Font_Top.ToString());
                        sb.AppendLine("font mid : " + this.Font.ToString());
                        sb.AppendLine("font bot : " + this.Font_Bottom.ToString());
                        sb.Append("Pre Selected index : ");
                        foreach (var item in preSelectedIndex)
                            sb.Append(item + ",");

                        if (preSelectedIndex.Count == 1)
                        {
                            //세부내역도 표시한다.
                            var slot = this.Slots[preSelectedIndex[0]];
                            var items = this.Items.Where(t => t.SlotIDX == slot.Index);
                            foreach (var item in items)
                            {
                                sb.Append("item " + item.ID1 + ",qty=" + item.Qty.ToString());
                            }
                        }
                        pe.Graphics.DrawString(sb.ToString(), f, Brushes.Black, 11f, 11f);
                        pe.Graphics.DrawString(sb.ToString(), f, Brushes.Yellow, 10f, 10f);
                    }

                }

            }
        }
        void DrawHelp(Graphics g)
        {
            System.Text.StringBuilder sb = new StringBuilder();
            sb.AppendLine("컨트롤 설정이 완료되지 않았습니다.\n");
            sb.AppendLine("이 메세지는 GRID COUNT가 설정되지 않았거나 ITEMS 항목이 없는 경우 표시됩니다.");
            sb.AppendLine("ITEMS 갯수가 GRID 갯수를 넘을 경우 페이지가 분리됩니다.\n");
            sb.AppendLine("현재 GRID 갯수는 : " + GridCount.ToString() + " = " + GridItemCount.ToString() + " 입니다.");
            sb.AppendLine("현재 ITEM 갯수는 : " + Slots.Count.ToString() + " 입니다.\n");
            sb.AppendLine("화면에 5x10 의 배열로 표시를 하려면 GridCount에 5x10을 설정하세요.");
            sb.AppendLine("ITEMS 는 코드상에서 입력하세요.\n");
            sb.AppendLine("# Example #");
            sb.AppendLine("var newitem = new CMSControl.Item();");
            sb.AppendLine("newitem.No = \"--\";");
            sb.AppendLine("newitem.Title = \"ItemName\"");
            sb.AppendLine("newitem.Contents = \"Model No\";");
            sb.AppendLine("cmsview1.items.Add(newitem);");

            g.DrawString(sb.ToString(), this.Font, Brushes.Red, 10f, 10f);

        }

        public Color slotColorUnUsed = Color.DimGray;
        public Color slotColorDisable = Color.Gray;
        public Color slotColorSelect = Color.Lime;

        void DrawSlot(Graphics g, Slot slot, IEnumerable<Item> items)
        {
            if (slot.Rect.IsEmpty) return;

            //fill background color
            g.FillRectangle(Brushes.Gray, slot.Rect);

            Color bdColor = Color.FromArgb(194, 192, 194);
            Color bColor = slot.BackColor;
            float bSize = 1.0f;
            if (slot.Selected)
            {
                bSize = 5.5f;
                //bColor = slotColorSelect;
                bdColor = Color.Lime;
            }
            else if (slot.Index == LastContactSlotIDX)
            {
                bdColor = Color.Yellow;
                bSize = 5.5f;
            }

            if (!slot.Enable) bColor = slotColorDisable;
            else if (items.Count() < 1) bColor = slotColorUnUsed;


            //no Color.FromArgb(231, 229, 231)
            byte R = bColor.R;
            byte G = bColor.G;
            byte B = bColor.B;
            if (R > 22) R -= 22; else R = 0;
            if (G > 22) G -= 22; else G = 0;
            if (B > 22) B -= 22; else B = 0;

            Color bgColor2 = Color.FromArgb(R, G, B);
            using (LinearGradientBrush brush = new LinearGradientBrush(slot.RectNo, bColor, bgColor2, LinearGradientMode.Vertical))
            {
                g.FillRectangle(brush, slot.RectNo);
            }
            g.DrawRectangle(new Pen(bColor), slot.RectNo);

            if (slot.Opend)
            {
                if (slot.BorderColor == Color.Yellow) bdColor = Color.Tomato;
                else bdColor = Color.Yellow;
                bSize = 5.0f;
            }

            Boolean ItemQtyManage = true;
            Boolean ItemQtySummary = false;
            Boolean ItemExpManage = false;

            if (items.Count() > 0)
            {
                var itemInfo = items.First();
                ItemQtyManage = itemInfo.QtyManage;
                ItemQtySummary = itemInfo.QtySummary;
                ItemExpManage = itemInfo.ExpManage;
            }

            //아이템이 여러개 있다면 우측 상단에 책갈피 처럼 표시한다.
            if (items.Count() > 1)
            {
                Rectangle openrect = new Rectangle(
                    (int)(slot.Rect.Right - 15),
                    (int)(slot.Rect.Top + 1),
                    15, 15);

                Point[] pts = new Point[4];
                pts[0] = new Point(slot.Rect.Right - 30, slot.Rect.Top + 1);
                pts[1] = new Point(slot.Rect.Right - 1, slot.Rect.Top + 1);
                pts[2] = new Point(slot.Rect.Right - 1, slot.Rect.Top + 30);
                pts[3] = new Point(slot.Rect.Right - 30, slot.Rect.Top + 1);
                g.FillPolygon(new SolidBrush(Color.FromArgb(40, 40, 40)), pts);

                using (Font f = new Font("맑은 고딕", 10f))
                    DrawString(g, f, items.Count().ToString(), openrect, Color.White, 0);
            }

            string slotnoStr = (slot.Index + 1).ToString();
            if (slot.No != "") slotnoStr = slot.No; //180607

            if (slot.Enable)
            {
                string StrT = slot.Name;
                string StrM = string.Empty;
                string StrBL = string.Empty;
                string StrBR = string.Empty;

                //값이없는 경우 세부항목에서 가져온다.
                var subItems = items.ToArray<Item>();
                if (StrT == "")
                {
                    StrT = ParserMessage(DisplayT, subItems); // subItems[0].ID1 + "\n" + subItems[0].VNAME;
                }
                if (subItems.Count() > 0)
                {
                    StrM = ParserMessage(DisplayM, subItems);// subItems[0].Name;
                    StrBL = ParserMessage(DisplayBL, subItems);// subItems[0].Model;
                    StrBR = ParserMessage(DisplayBR, subItems);// "[" + subItems[0].Qty.ToString() + subItems[0].Unit + "]";
                }

                //g.DrawRectangle(new Pen(Color.Magenta, 1.5f), RectT);
                //g.DrawRectangle(new Pen(Color.Red, 1.5f), RectM);
                //g.DrawRectangle(new Pen(Color.Yellow, 1.5f), RectB);
                //g.DrawRectangle(new Pen(Color.Yellow, 1.5f),);

                DrawString(g, Font_No, slotnoStr, slot.RectNo, color_font_no, HorizontalAlignment.Center, Padding_No);

                //title
                if (StrT != "")
                    DrawString(g, Font_Top, StrT, slot.RectT, color_font_top, TextAlignT, Padding_Top);
                if (StrM != "")
                    DrawString(g, Font_Middle, StrM, slot.RectM, color_font_middle, TextAlignM, Padding_Middle);
                if (StrBL != "")
                    DrawString(g, Font_Bottom, StrBL, slot.RectB, color_font_bottom_left, TextAlignBL, Padding_Bottom);
                if (StrBR != "" && ItemQtyManage)
                    DrawString(g, Font_Count, StrBR, slot.RectCnt, color_font_bottom_right, TextAlignBR, Padding_Count);
            }
            else
            {
                DrawString(g, this.Font_No, slotnoStr, slot.RectNo, color_font_no);
                DrawString(g, this.Font_Middle, "Disabled", slot.RectM, color_font_no);
                //DrawString(g, fConttent, "DISABLED", RectT, Color.Black, 0);
            }

            //g.DrawRectangle(Pens.White, slot.RectT);
            //g.DrawRectangle(Pens.White, slot.RectM);
            //g.DrawRectangle(Pens.White, slot.RectB);
            //g.DrawRectangle(Pens.White, slot.RectCnt);
            //g.DrawString(items.Count().ToString(), fNo, Brushes.Red, Rect.Left, Rect.Top);

            g.DrawLine(new Pen(Color.Black, 5f), slot.Rect.Left + 3, slot.Rect.Bottom + 1, slot.Rect.Right + 2, slot.Rect.Bottom + 1);
            g.DrawLine(new Pen(Color.Black, 5f), slot.Rect.Right + 1, slot.Rect.Top + 3, slot.Rect.Right + 1, slot.Rect.Bottom + 4);
            //g.DrawRectangle(Pens.Black, slot.Rect.Left + 1, slot.Rect.Top + 1, slot.Rect.Width - 2, slot.Rect.Height - 2);

            using (Pen p = new Pen(bdColor, bSize))
            {
                g.DrawRectangle(p, slot.Rect); //최종테두리
            }

            slot.BorderColor = bdColor;
            //g.DrawString(this.BackColor.ToString(), fID, Brushes.Black,RectNo.Left, RectNo.Top);

            if (slot.Expiration)
            {
                string msg = "Expiration";
                var fsize = g.MeasureString(msg, this.Font);
                var rectheight = (int)(fsize.Height * 1.5);
                Rectangle msgRect = new Rectangle(slot.Rect.Left + 1, slot.Rect.Bottom - rectheight, slot.Rect.Width - 1, rectheight);
                g.FillRectangle(new SolidBrush(Color.FromArgb(100, Color.Red)), msgRect);
                DrawString(g, this.Font, msg, msgRect, Color.White);
                //g.DrawString("expiration", this.Font, Brushes.White, msgRect.Left, msgRect.Top);
            }

        }

        string ParserMessage(string org, Item[] subItems)
        {
            org = org.Replace("\\n", "\n");
            if (subItems.Length > 0)
            {
                var item = subItems[0];
                org = org.Replace("{ID1}", item.ID1);
                org = org.Replace("{ID2}", item.ID2);
                org = org.Replace("{NAME}", item.Name);
                org = org.Replace("{MODEL}", item.Model);
                org = org.Replace("{SERIAL}", item.Serial);

                if (item.ScaleUnit != item.Unit && item.ScaleUnit != "")
                {
                    org = org.Replace("{QTY}", (item.Qty / item.Scale).ToString());
                    org = org.Replace("{UNIT}", item.ScaleUnit);
                }
                else
                {
                    org = org.Replace("{QTY}", item.Qty.ToString());
                    org = org.Replace("{UNIT}", item.Unit);
                }
            }
            else
            {
                org = org.Replace("{ID1}", string.Empty);
                org = org.Replace("{ID2}", string.Empty);
                org = org.Replace("{NAME}", string.Empty);
                org = org.Replace("{MODEL}", string.Empty);
                org = org.Replace("{SERIAL}", string.Empty);
                org = org.Replace("{QTY}", string.Empty);
                org = org.Replace("{UNIT}", string.Empty);
            }
            return org;
        }

        void DrawString(Graphics g, Font f, string data, Rectangle rect, Color fcolor, System.Windows.Forms.HorizontalAlignment align = HorizontalAlignment.Center, Padding pad = new Padding())
        {
            var fsize = g.MeasureString(data, f);
            float cx, cy;
            cx = cy = 0;
            switch (align)
            {
                case HorizontalAlignment.Left:
                    cx = pad.Left + rect.Left;
                    cy = pad.Top + rect.Top + (rect.Height - fsize.Height) / 2.0f;
                    break;
                case HorizontalAlignment.Center:
                    cx = pad.Left + rect.Left + (rect.Width - fsize.Width) / 2.0f;
                    cy = pad.Top + rect.Top + (rect.Height - fsize.Height) / 2.0f;
                    break;
                case HorizontalAlignment.Right:
                    cx = rect.Right - fsize.Width - pad.Right;
                    cy = pad.Top + rect.Top + (rect.Height - fsize.Height) / 2.0f;
                    break;
            }

            g.DrawString(data, f, new SolidBrush(fcolor), new PointF(cx + 1, cy + 1));
        }
    }
}
