//------------------------------------------------------------------------------
// <copyright file=”BaseEditBox.cs” company=”EhLib Team”>
//     Copyright (c) 2017 Dmitry V. Bolshakov   
// </copyright>
//------------------------------------------------------------------------------

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Drawing;
using System.Drawing.Design;
using System.Runtime.InteropServices;
using System.Windows.Forms;
using System.Windows.Forms.VisualStyles;

namespace EhLib
{

  [DesignerCategory("Code")]
  [Designer("EhLib.Design.BaseEditBoxDesigner" + EhLibUtils.EhLibDesignDesignerVersionInfo)]
  [ToolboxItem(false)]
  public class BaseEditBoxEh : Control, ISupportInitialize
  {

    #region internal fields
    internal Control EditControl;
    private EditItem inEditControl;

    private BoundLabel boundLabel;

    //private Padding defaultPadding = new Padding(0, 0, 0, 0);
    //private BorderStyle borderStyle = BorderStyle.Fixed3D;
    private bool mouseOver;
    private int requestedHeight;
    private bool internalHeightAdjust;
    private bool initializing;
    private bool backColorStored;
    private EditButton editButton;
    private EditBoxBorder border;

    #endregion internal fields

    #region constructor
    public BaseEditBoxEh()
    {
      initializing = true;
      try

      {
        InitData();
        EditControl.Parent = this;
        TabStop = false;
        border = new EditBoxBorder();
        border.BorderStateChanged += BorderStateChanged;
      }
      finally
      {
        initializing = false;
      }
      //System.Diagnostics.Trace.WriteLine("BaseEditBox's constructor is called.");
    }

    private void InitData()
    {
      EditControl = CreateEditControl();
    }

    protected override void Dispose(bool disposing)
    {
      if (disposing)
      {
        EditControl.Dispose();
        if (inEditControl != null)
          inEditControl.Dispose();
        if (BoundLabel != null)
          BoundLabel.Dispose();
        if (EditButtonAccessible())
        {
          editButton.DisconnectFromEditor();
          editButton.EditItemChanged -= EditItemChanged;
          editButton.DefaultVisibleStateRequested -= EditButtonDefaultVisibleStateRequested;
          editButton.Dispose();
        }
      }
      base.Dispose(disposing);
    }
    #endregion

    #region design-time properties
    public override Color BackColor
    {
      get
      {
        if (ShouldSerializeBackColor())
        {
          return base.BackColor;
        }
        else if (this.ReadOnly)
        {
          return SystemColors.Control;
        }
        else
        {
          return SystemColors.Window;
        }
      }
      set
      {
        base.BackColor = value;
        backColorStored = true;
      }
    }

    //[DefaultValue(BorderStyle.Fixed3D)]
    //public BorderStyle BorderStyle
    //{
    //  get
    //  {
    //    return borderStyle;
    //  }
    //  set
    //  {
    //    if (borderStyle != value)
    //    {
    //      borderStyle = value;
    //      AdjustHeight(false);
    //      RealignControls();
    //      Invalidate();
    //    }
    //  }
    //}

    [DefaultValue(false)]
    [RefreshProperties(RefreshProperties.Repaint)]
    public virtual bool ReadOnly
    {
      get; set; 
    }

    [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
    [Editor("EhLib.Design.InEditControlEditor" + EhLibUtils.EhLibDesignDesignerVersionInfo, "System.Drawing.Design.UITypeEditor, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a")]
    public EditItem InEditControl
    {
      get
      {
        return inEditControl;
      }
      set
      {
        if (inEditControl != value)
        {
          EditItem oldInEditControl = inEditControl;

          inEditControl = value;

          if (oldInEditControl != null)
          {
            oldInEditControl.InEditWinControl.Parent = null;
            oldInEditControl.EditControl = null;
          }

          if (inEditControl != null)
            inEditControl.EditControl = this;
          //inEditControl.Parent = this;
          RealignControls();
        }
      }
    }

    [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
    public EditButton EditButton
    {
      get
      {
        if (editButton == null)
        {
          InitEditButton();
        }

        return editButton;
      }

      // TODO: Tmp comment
      //set
      //{
      //  if (editButton != value)
      //  {
      //    SuspendLayout();
      //    try
      //    {
      //      if (editButton != null)
      //      {
      //        editButton.DisconnectFromEditor();
      //        editButton.EditItemChanged -= EditItemChanged;
      //        editButton.DefaultVisibleStateRequested -= EditButtonDefaultVisibleStateRequested;
      //      }

      //      editButton = value;

      //      if (editButton != null)
      //      {
      //        editButton.ConnectToEditor(this);
      //        editButton.EditItemChanged += EditItemChanged;
      //        editButton.DefaultVisibleStateRequested += EditButtonDefaultVisibleStateRequested;
      //      }
      //    }
      //    finally
      //    {
      //      ResumeLayout();
      //    }
      //    RealignControls();
      //  }
      //}
    }

    [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
    [Editor("EhLib.Design.BoundLabelEditor" + EhLibUtils.EhLibDesignDesignerVersionInfo, "System.Drawing.Design.UITypeEditor, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a")]
    //[DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
    public BoundLabel BoundLabel
    {
      get
      {
        return boundLabel;
      }
      set
      {
        if (boundLabel != value)
        {
          BoundLabel oldBoundLabel = boundLabel;

          boundLabel = value;

          if (oldBoundLabel != null)
          {
            oldBoundLabel.BaseEditBox = null;
            //?oldBoundLabel.Dispose();
          }

          if (boundLabel != null)
          {
            boundLabel.BaseEditBox = this;
            if (!initializing)
              boundLabel.Parent = Parent;
          }

          CheckUpdateBoundLabelControlPosition();
        }
      }
    }

    [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
    public EditBoxBorder Border
    {
      get { return border; }
    }
    #endregion design-time properties

    #region run-time properties
    public new string Name
    {
      get
      {
        return base.Name;
      }
      set
      {
        base.Name = value;
        //NameChanged();
      }
    }

    protected override Padding DefaultPadding
    {
      get
      {
        if (Border.Style != ControlBorderStyle.None)
          return Padding.Empty;
        else
          return new Padding(1, 1, 1, 2);
      }
    }

    [Browsable(false)]
    [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
    public override bool Focused
    {
      get
      {
        return EditControl.Focused;
      }
    }

    [Browsable(false)]
    [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
    [EditorBrowsable(EditorBrowsableState.Advanced)]
    public virtual int PreferredHeight
    {
      get
      {
        int fontHeight = base.FontHeight;
        if (this.Border.Style != ControlBorderStyle.None)
        {
            fontHeight += (SystemInformation.BorderSize.Height * 4) + 3;
        }
        return fontHeight;
      }
    }

    [Browsable(false)]
    public bool MouseOver
    {
      get
      {
        return mouseOver;
      }
      protected set
      {
        if (value != mouseOver)
        {
          mouseOver = value;
          Invalidate();
        }
      }
    }

    [Browsable(false)]
    public virtual bool SupportButtonBorderMerging
    {
      get
      {
        if (Border.Style != ControlBorderStyle.Fixed3D)
          return true;
        else
          return false;
      }
    }
    #endregion run-time properties

    #region public methods
    public void BeginInit()
    {
      initializing = true;
    }

    public void EndInit()
    {
      initializing = false;
      CheckUpdateBoundLabelControlPosition();
      RealignControls();
    }

    public virtual void Clear()
    {
    }

    public virtual void Copy()
    {
    }

    public virtual void Cut()
    {
    }

    public virtual void Paste()
    {
    }

    public virtual void HandleInEditControlDownAction(EditItem inEditControl, DownEventArgs e)
    {
      if (inEditControl.DefaultAction || inEditControl.IsDropDown())
        InEditButtonDownDefaultAction(inEditControl, e);
    }

    public virtual void HandleInEditControlClickAction(EditItem inEditControl, ClickEventArgs e)
    {
      //if (inEditControl.DefaultAction || !inEditControl.IsDropDown())
      //  InEditButtonClickDefaultAction(inEditControl, e);
    }

    public virtual void InEditButtonDownDefaultAction(EditItem inEditControl, DownEventArgs e)
    {
    }

    public bool ShouldSerializeBackColor()
    {
      return backColorStored;
    }

    public override void ResetBackColor()
    {
      backColorStored = false;
      Invalidate(true);
    }
    #endregion

    #region internal methos

    #region internal methos.Paddings
    protected override void OnPaddingChanged(EventArgs e)
    {
      base.OnPaddingChanged(e);
      RealignControls();
    }
    #endregion

    private void BorderStateChanged(object sender, EventArgs e)
    {
      if (!initializing)
        RealignControls();
    }

    protected override void OnLayout(LayoutEventArgs levent)
    {
      RealignControls();
      base.OnLayout(levent);
    }

    protected override void OnPaint(PaintEventArgs e)
    {
      Rectangle bounds = ClientRectangle;
      base.OnPaint(e);

      if (e == null)
        throw new ArgumentNullException("e");

      using (SolidBrush bkBrush = new SolidBrush(BackColor))
      {
        e.Graphics.FillRectangle(bkBrush, bounds);
      }

      TextBoxState state = EhLibDrawStyle.DefaultTextBoxDrawStyle.GetTextBoxState(mouseOver, ContainsFocus, !Enabled, ReadOnly);
      border.Paint(e.Graphics, bounds, state);
      //EhLibDrawStyle.DefaultTextBoxDrawStyle.DrawTextBoxFrame(e.Graphics, bounds, state, this, BorderStyle);
    }

    protected override void OnParentChanged(EventArgs e)
    {
      base.OnParentChanged(e);
      if (boundLabel != null && !initializing)
        boundLabel.Parent = this.Parent;
    }

    protected override void OnResize(EventArgs e)
    {
      base.OnResize(e);
      CheckUpdateBoundLabelControlPosition();
    }

    protected override void OnLocationChanged(EventArgs e)
    {
      base.OnLocationChanged(e);
      CheckUpdateBoundLabelControlPosition();
    }

    protected override void OnVisibleChanged(EventArgs e)
    {
      base.OnVisibleChanged(e);
      if (IsHandleCreated)
        Update();
    }

    protected override void WndProc(ref Message m)
    {
      switch (m.Msg)
      {
        case NativeMethods.WM_SETFOCUS:
          if (EditControl.CanFocus)
          {
            NativeMethods.SetFocus(new HandleRef(EditControl, EditControl.Handle));
          }
          base.WndProc(ref m);
          break;
        case NativeMethods.WM_KILLFOCUS:
          DefWndProc(ref m);
          break;
        default:
          base.WndProc(ref m);
          break;
      }
    }

    protected virtual bool AutoHeight()
    {
      return AutoSize;
    }

    protected override void SetBoundsCore(int x, int y, int width, int height, BoundsSpecified specified)
    {

      if (!internalHeightAdjust && height != Height)
        requestedHeight = height;

      if (AutoHeight())
        height = PreferredHeight;

      base.SetBoundsCore(x, y, width, height, specified);
    }

    internal class ControlBounds 
    {
      //public ControlBounds()
      //{
      //  Bounds = Rectangle.Empty;
      //  Control = null;
      //}
      public Rectangle Bounds;
      public EditItem InEditControl;
    }

    protected virtual void RealignControls()
    {
      //if (initializing || !IsHandleCreated) return;
      if (initializing) return;

      //bool themed = Application.RenderWithVisualStyles;
      ControlBounds btnBnds;
      List<ControlBounds> btnBndsList = new List<ControlBounds>();
      Rectangle clientArea = new Rectangle(Point.Empty, ClientSize);
      ControlBorderStyle brdrStyle = Border.Style;
      //int borderFixup = (themed) ? 1 : 0;
      
      int borderWidth = (brdrStyle == ControlBorderStyle.None) ? 0 : 2;
      clientArea.Inflate(-borderWidth, -borderWidth);

      if (EditControl != null)
      {
        EditControl.Size = new Size(clientArea.Width, clientArea.Height);
      }

      Rectangle editControlAreaBound = clientArea;

      if (inEditControl != null && inEditControl.Visible)
      {
        if (inEditControl.Visible)
        {
          btnBnds = new ControlBounds
          {
            Bounds = new Rectangle(0, 0, inEditControl.Width, clientArea.Height),
            InEditControl = inEditControl
          };

          btnBndsList.Add(btnBnds);
        }
        else
        {
          inEditControl.InEditWinControl.Visible = false;
        }
      }

      if (EditButtonAccessible() && EditButton.Visible)
      {
        btnBnds = new ControlBounds
        {
          Bounds = new Rectangle(0, 0, EditButton.Width, clientArea.Height),
          InEditControl = EditButton
        };
        btnBndsList.Add(btnBnds);
      }
      else
      {
        if (EditButtonAccessible())
          EditButton.InEditWinControl.Visible = false;
      }

      int toSetHeight = 0;
      foreach(ControlBounds b in btnBndsList)
      {
        if (b.InEditControl.MaxHeight > toSetHeight)
          toSetHeight = b.InEditControl.MaxHeight;
      }
      if (toSetHeight > clientArea.Height)
        toSetHeight = clientArea.Height;

      int leftPos = clientArea.Right;
      for (int i = btnBndsList.Count-1; i >= 0; i--)
      {
        btnBnds = btnBndsList[i];

        btnBnds.Bounds.Y = clientArea.Top;
        leftPos = leftPos - btnBnds.Bounds.Width;
        btnBnds.Bounds.X = leftPos;

        if (i == btnBndsList.Count - 1 &&
            SupportButtonBorderMerging &&
            btnBnds.InEditControl.SupportInControlBorderMerging)
        {

          btnBnds.Bounds.X = btnBnds.Bounds.X + borderWidth;
          btnBnds.Bounds.Y = btnBnds.Bounds.Y - borderWidth;
          btnBnds.Bounds.Height = btnBnds.Bounds.Height + borderWidth * 2;
          btnBnds.InEditControl.InEditWinControl.InControlBorderMerging = true;
        }
        else
        {
          btnBnds.InEditControl.InEditWinControl.InControlBorderMerging = false;
          btnBnds.Bounds.Height = toSetHeight;
        }

        btnBnds.InEditControl.InEditWinControl.Bounds = btnBnds.Bounds;
        btnBnds.InEditControl.InEditWinControl.Parent = this;
        btnBnds.InEditControl.InEditWinControl.Visible = true;
      }

      //txtBnds.Width = txtBnds.Width - (clientArea.Right - leftPos);
      editControlAreaBound.Width = editControlAreaBound.Width - (clientArea.Right - leftPos);
      SetEditControlBounds(editControlAreaBound);
    }

    protected virtual void SetEditControlBounds(Rectangle editControlAreaBound)
    {
      Rectangle txtBnds = EhLibUtils.TrimPadding(editControlAreaBound, Padding);
      EditControl.Bounds = txtBnds;
    }

    protected virtual Control CreateEditControl()
    {
      return null;
    }

    protected virtual EditButton CreateDropDownButton()
    {
      return new EditButton();
    }

    public virtual void InitEditButton()
    {
      editButton = CreateDropDownButton();
      editButton.ConnectToEditor(this);
      editButton.EditItemChanged += EditItemChanged;
      editButton.DefaultVisibleStateRequested += EditButtonDefaultVisibleStateRequested;
    }

    private void EditItemChanged(object sender, EventArgs e)
    {
      InEditControlChanged(sender as EditItem);
    }

    internal void InEditControlChanged(EditItem inEditControl)
    {
      RealignControls();
      Invalidate(true);
    }

    private void EditButtonDefaultVisibleStateRequested(object sender, VisibleStateRequestedEventArgs e)
    {
      e.Visible = EditButtonDefaultVisible();
    }

    protected virtual bool EditButtonDefaultVisible()
    {
      return false;
    }

    protected virtual bool EditButtonAccessible()
    {
      if (editButton != null || EditButtonDefaultVisible())
        return true;
      else
        return false;
    }

    protected internal virtual bool IsInEditControlDefaultVisible(EditItem inEditControl)
    {
      if (inEditControl == editButton)
        return false;
      else
        return true;
    }

    protected override void OnMouseEnter(EventArgs e)
    {
      base.OnMouseEnter(e);
      mouseOver = true;
      Invalidate(true);
    }

    protected override void OnMouseLeave(EventArgs e)
    {
      base.OnMouseLeave(e);
      if (this.ClientRectangle.Contains(this.PointToClient(MousePosition)))
        return;
      else
      {
        mouseOver = false;
      }
      Invalidate(true);
    }

    protected override void OnLostFocus(EventArgs e)
    {
      base.OnLostFocus(e);
      Invalidate(true);
    }

    protected override void OnGotFocus(EventArgs e)
    {
      base.OnGotFocus(e);
      Invalidate(true);
    }

    protected virtual void AdjustHeight(bool returnIfAnchored)
    {

      // If we're anchored to two opposite sides of the form, don't adjust the size because
      // we'll lose our anchored size by resetting to the requested width.
      //
      if (returnIfAnchored && 
         (this.Anchor & (AnchorStyles.Top | AnchorStyles.Bottom)) == (AnchorStyles.Top | AnchorStyles.Bottom))
      {
        return;
      }

      int saveHeight = requestedHeight;
      try
      {
        //if (AutoSize && !Multiline)
        if (AutoHeight())
        {
          Height = PreferredHeight;
        }
        else
        {

          //int curHeight = Height;

          //// Changing the font of a multi-line textbox can sometimes cause a painting problem
          //// The only workaround I can find is to size the textbox big enough for the font, and
          //// then restore its correct size.
          ////
          //if (Multiline)
          //{
          //  Height = Math.Max(saveHeight, PreferredHeight + 2); // 2 = fudge factor
          //}

          internalHeightAdjust = true;
          try
          {
            Height = saveHeight;
          }
          finally
          {
            internalHeightAdjust = false;
          }
        }
      }
      finally
      {
        requestedHeight = saveHeight;
      }
    }

    protected internal virtual void OnProcessInEditUpDownButton(UpDownEventArgs e)
    {
    }

    internal void BoundLabelPositionChanged()
    {
    }

    internal void BoundLabelRelativePositionChanged()
    {
      CheckUpdateBoundLabelControlPosition();
    }

    //private void BoundLabelControlSizeChanged(object sender, EventArgs e)
    //{
    //  CheckUpdateBoundLabelControlPosition();
    //}

    internal void CheckUpdateBoundLabelControlPosition()
    {
      if (IsHandleCreated && boundLabel != null)
      {
        Debug.Assert(boundLabel.Parent == Parent, "boundLabel.Parent != Parent");
        Point newPos;
        boundLabel.CalcLabelPosForControl(boundLabel.Width, boundLabel.Height, out newPos);
        SetBoundLabelBounds(newPos.X, newPos.Y, boundLabel.Width, boundLabel.Height);
        //boundLabel.Text = Name;
      }
    }

    internal int GetControlTextBaseLine()
    {
      return FontHeight;
    }

    internal void SetBoundLabelBounds(int x, int y, int width, int height)
    {
      boundLabel.SetBounds(x, y, width, height);
    }

    internal void SetExternalEditButton(EditButton newEdditButton)
    {
      if (editButton != newEdditButton)
      {
        SuspendLayout();
        try
        {
          if (editButton != null)
          {
            editButton.DisconnectFromEditor();
            editButton.EditItemChanged -= EditItemChanged;
            editButton.DefaultVisibleStateRequested -= EditButtonDefaultVisibleStateRequested;
          }

          this.editButton = newEdditButton;

          if (editButton != null)
          {
            editButton.ConnectToEditor(this);
            editButton.EditItemChanged += EditItemChanged;
            editButton.DefaultVisibleStateRequested += EditButtonDefaultVisibleStateRequested;
          }
        }
        finally
        {
          ResumeLayout();
        }
        RealignControls();
      }
    }
    #endregion internal methos

  }

  public enum SpacingBound
  {
    NearBound, FarBound
  }

  public enum LabelPosition
  {
    AboveLeft, AboveCenter, AboveRight,
    BelowLeft, BelowCenter, BelowRight,
    LeftTop, LeftTextBaseline, LeftCenter, LeftBottom,
    //- LeftTopFromLabelLeft, LeftCenterFromLabelLeft, LeftBottomFromLabelLeft,
    RightTop, RightTextBaseline, RightCenter, RightBottom
  }

  //  public class BoundLabel : Component
  //  {
  //    private BaseEditBox baseEditBox;
  //    private bool visible = false;
  //    private int spacing = 3;
  //    private int offset = 0;
  //    private bool textStored = false;
  //    private bool foreColorStored = false;
  //    private bool backColorStored = false;
  //    private bool fontStored = false;

  //    private LabelPosition position = LabelPosition.AboveLeft;
  //    private SpacingBound labelSpacingBound = SpacingBound.NearBound;

  //    public BoundLabel(BaseEditBox baseEditBox)
  //    {
  //      this.baseEditBox = baseEditBox;
  //    }

  //    #region properties
  //    public string Text
  //    {
  //      get
  //      {
  //        return baseEditBox.boundLabelControl.Text;
  //      }
  //      set
  //      {
  //        baseEditBox.boundLabelControl.Text = value;
  //        textStored = true;
  //      }
  //    }

  //    public Color ForeColor
  //    {
  //      get
  //      {
  //        return baseEditBox.boundLabelControl.ForeColor;
  //      }
  //      set
  //      {
  //        baseEditBox.boundLabelControl.ForeColor = value;
  //        foreColorStored = true;
  //      }
  //    }

  //    public Font Font
  //    {
  //      get
  //      {
  //        return baseEditBox.boundLabelControl.Font;
  //      }
  //      set
  //      {
  //        baseEditBox.boundLabelControl.Font = value;
  //        fontStored = true;
  //      }
  //    }

  //    public Color BackColor
  //    {
  //      get
  //      {
  //        return baseEditBox.boundLabelControl.BackColor;
  //      }
  //      set
  //      {
  //        baseEditBox.boundLabelControl.BackColor = value;
  //        backColorStored = true;
  //      }
  //    }

  //    [DefaultValue(false)]
  //    public bool Visible
  //    {
  //      get
  //      {
  //        return visible;
  //      }
  //      set
  //      {
  //        if (value != visible)
  //        {
  //          visible = value;
  //          baseEditBox.BoundLabelVisibleChanged();
  //        }
  //      }
  //    }

  //    [DefaultValue(SpacingBound.NearBound)]
  //    public SpacingBound LabelSpacingBound
  //    {
  //      get
  //      {
  //        return labelSpacingBound;
  //      }
  //      set
  //      {
  //        if (value != labelSpacingBound)
  //        {
  //          labelSpacingBound = value;
  //          baseEditBox.BoundLabelPositionChanged();
  //        }
  //      }
  //    }

  //    [DefaultValue(3)]
  //    public int Spacing
  //    {
  //      get
  //      {
  //        return spacing;
  //      }
  //      set
  //      {
  //        if (value != spacing)
  //        {
  //          spacing = value;
  //          baseEditBox.BoundLabelPositionChanged();
  //        }
  //      }
  //    }

  //    [DefaultValue(0)]
  //    public int Offset
  //    {
  //      get
  //      {
  //        return offset;
  //      }
  //      set
  //      {
  //        if (value != offset)
  //        {
  //          offset = value;
  //          baseEditBox.BoundLabelPositionChanged();
  //        }
  //      }
  //    }

  //    [DefaultValue(LabelPosition.AboveLeft)]
  //    public LabelPosition Position
  //    {
  //      get
  //      {
  //        return position;
  //      }
  //      set
  //      {
  //        if (value != position)
  //        {
  //          position = value;
  //          baseEditBox.BoundLabelPositionChanged();
  //        }
  //      }
  //    }
  //    #endregion properties

  //    #region methods
  //    public bool ShouldSerializeText()
  //    {
  //      return textStored;
  //    }

  //    public void ResetText()
  //    {
  //      textStored = false;
  //      baseEditBox.ResetBoundLabelText();
  //    }

  //    internal virtual bool ShouldSerializeForeColor()
  //    {
  //      return foreColorStored;
  //    }

  //    public virtual void ResetForeColor()
  //    {
  //      foreColorStored = false;
  //      baseEditBox.boundLabelControl.ResetForeColor();
  //    }

  //    internal virtual bool ShouldSerializeBackColor()
  //    {
  //      return backColorStored;
  //    }

  //    public virtual void ResetBackColor()
  //    {
  //      backColorStored = false;
  //      baseEditBox.boundLabelControl.ResetBackColor();
  //    }

  //    internal virtual bool ShouldSerializeFont()
  //    {
  //      return fontStored;
  //    }

  //    public virtual void ResetFont()
  //    {
  //      fontStored = false;
  //      baseEditBox.boundLabelControl.ResetFont();
  //    }

  //    internal void CalcLabelPosForControl(int LabelWidth, int LabelHeight, out Point LabelPos)
  //    {
  //      int ExtraSpacing;
  //      LabelPos = new Point(0, 0);

  //      if (LabelSpacingBound == SpacingBound.NearBound)
  //        ExtraSpacing = 0;
  //      else if (Position == LabelPosition.AboveLeft ||
  //               Position == LabelPosition.AboveCenter || 
  //               Position == LabelPosition.AboveRight ||
  //               Position == LabelPosition.BelowLeft || 
  //               Position == LabelPosition.BelowCenter || 
  //               Position == LabelPosition.BelowRight)
  //        ExtraSpacing = LabelHeight;
  //      else
  //        ExtraSpacing = LabelWidth;

  //      if (Position == LabelPosition.AboveLeft)
  //      {
  //        LabelPos.Y = baseEditBox.Top - LabelHeight - Spacing + ExtraSpacing;
  //        LabelPos.X = baseEditBox.Left + Offset;

  //      } else if (Position == LabelPosition.AboveCenter)
  //      {
  //        LabelPos.Y = baseEditBox.Top - LabelHeight - Spacing + ExtraSpacing;
  //        LabelPos.X = baseEditBox.Left + (baseEditBox.Width - LabelWidth) / 2 + Offset;

  //      } else if (Position == LabelPosition.AboveRight)
  //      {
  //        LabelPos.Y = baseEditBox.Top - LabelHeight - Spacing + ExtraSpacing;
  //        LabelPos.X = baseEditBox.Left + baseEditBox.Width - LabelWidth + Offset;

  //      } else if (Position == LabelPosition.BelowLeft)
  //      {
  //        LabelPos.Y = baseEditBox.Top + baseEditBox.Height + Spacing + ExtraSpacing;
  //        LabelPos.X = baseEditBox.Left + Offset;

  //      } else if (Position == LabelPosition.BelowCenter)
  //      {
  //        LabelPos.Y = baseEditBox.Top + baseEditBox.Height + Spacing + ExtraSpacing;
  //        LabelPos.X = baseEditBox.Left + (baseEditBox.Width - LabelWidth) / 2 + Offset;

  //      } else if (Position == LabelPosition.BelowRight)
  //      {
  //        LabelPos.Y = baseEditBox.Top + baseEditBox.Height + Spacing + ExtraSpacing;
  //        LabelPos.X = baseEditBox.Left + baseEditBox.Width  - LabelWidth + Offset;

  //      } else if (Position == LabelPosition.LeftTop)
  //      {
  //        LabelPos.Y = baseEditBox.Top + Offset;
  //        LabelPos.X = baseEditBox.Left - LabelWidth - Spacing + ExtraSpacing;

  //      } else if (Position == LabelPosition.LeftTextBaseline)
  //      {
  //        LabelPos.Y = baseEditBox.Top + baseEditBox.GetControlTextBaseLine() - LabelHeight + Offset;
  //        LabelPos.X = baseEditBox.Left - LabelWidth - Spacing + ExtraSpacing;

  //      } else if (Position == LabelPosition.LeftCenter)
  //      {
  //        LabelPos.Y = baseEditBox.Top + (baseEditBox.Height - LabelHeight) / 2 + Offset;
  //        LabelPos.X = baseEditBox.Left - LabelWidth - Spacing + ExtraSpacing;

  //      } else if (Position == LabelPosition.LeftBottom)
  //      {
  //        LabelPos.Y = baseEditBox.Top + baseEditBox.Height - LabelHeight + Offset;
  //        LabelPos.X = baseEditBox.Left - LabelWidth - Spacing + ExtraSpacing;

  //      } else if (Position == LabelPosition.RightTop)
  //      {
  //        LabelPos.Y = baseEditBox.Top + Offset;
  //        LabelPos.X = baseEditBox.Left + baseEditBox.Width + Spacing + ExtraSpacing;

  //      } else if (Position == LabelPosition.RightTextBaseline)
  //      {
  //        LabelPos.Y = baseEditBox.Top + baseEditBox.GetControlTextBaseLine() - LabelHeight + Offset;
  //        LabelPos.X = baseEditBox.Left + baseEditBox.Width + Spacing + ExtraSpacing;

  //      } else if (Position == LabelPosition.RightCenter)
  //      {
  //        LabelPos.Y = baseEditBox.Top + (baseEditBox.Height - LabelHeight) / 2 + Offset;
  //        LabelPos.X = baseEditBox.Left + baseEditBox.Width + Spacing + ExtraSpacing;

  //      } else if (Position == LabelPosition.RightBottom)
  //      {
  //        LabelPos.Y = baseEditBox.Top + baseEditBox.Height - LabelHeight + Offset;
  //        LabelPos.X = baseEditBox.Left + baseEditBox.Width + Spacing + ExtraSpacing;
  //      }
  //    }

  //  #endregion methods

  //}


  [Designer("EhLib.Design.BoundLabelDesigner" + EhLibUtils.EhLibDesignDesignerVersionInfo)]
  [ToolboxItem(false)]
  public class BoundLabel : Label
  {
    internal BaseEditBoxEh BaseEditBox;
    private int spacing = 3;
    private int offset;

    private LabelPosition position = LabelPosition.AboveLeft;
    private SpacingBound labelSpacingBound = SpacingBound.NearBound;
    private bool textStored;

    public BoundLabel()
    {
      InitData();
    }

    private void InitData()
    {
      AutoSize = true;
    }

    #region properties
    public override string Text
    {
      get
      {
        if (textStored)
          return base.Text;
        else
          return DefaultText();
      }
      set
      {
        base.Text = value;
        textStored = true;
      }
    }

    [DefaultValue(SpacingBound.NearBound)]
    public SpacingBound LabelSpacingBound
    {
      get
      {
        return labelSpacingBound;
      }
      set
      {
        if (value != labelSpacingBound)
        {
          labelSpacingBound = value;
          if (BaseEditBox != null)
            BaseEditBox.BoundLabelRelativePositionChanged();
        }
      }
    }

    [DefaultValue(3)]
    public int Spacing
    {
      get
      {
        return spacing;
      }
      set
      {
        if (value != spacing)
        {
          spacing = value;
          if (BaseEditBox != null)
            BaseEditBox.BoundLabelRelativePositionChanged();
        }
      }
    }

    [DefaultValue(0)]
    public int Offset
    {
      get
      {
        return offset;
      }
      set
      {
        if (value != offset)
        {
          offset = value;
          if (BaseEditBox != null)
            BaseEditBox.BoundLabelRelativePositionChanged();
        }
      }
    }

    [DefaultValue(LabelPosition.AboveLeft)]
    public LabelPosition Position
    {
      get
      {
        return position;
      }
      set
      {
        if (value != position)
        {
          position = value;
          if (BaseEditBox != null)
            BaseEditBox.BoundLabelRelativePositionChanged();
        }
      }
    }
    #endregion properties

    #region methods
    internal void CalcLabelPosForControl(int labelWidth, int labelHeight, out Point labelPos)
    {
      int extraSpacing;
      labelPos = new Point(0, 0);

      if (LabelSpacingBound == SpacingBound.NearBound)
        extraSpacing = 0;
      else if (Position == LabelPosition.AboveLeft ||
               Position == LabelPosition.AboveCenter ||
               Position == LabelPosition.AboveRight ||
               Position == LabelPosition.BelowLeft ||
               Position == LabelPosition.BelowCenter ||
               Position == LabelPosition.BelowRight)
        extraSpacing = labelHeight;
      else
        extraSpacing = labelWidth;

      if (Position == LabelPosition.AboveLeft)
      {
        labelPos.Y = BaseEditBox.Top - labelHeight - Spacing + extraSpacing;
        labelPos.X = BaseEditBox.Left + Offset;

      }
      else if (Position == LabelPosition.AboveCenter)
      {
        labelPos.Y = BaseEditBox.Top - labelHeight - Spacing + extraSpacing;
        labelPos.X = BaseEditBox.Left + (BaseEditBox.Width - labelWidth) / 2 + Offset;

      }
      else if (Position == LabelPosition.AboveRight)
      {
        labelPos.Y = BaseEditBox.Top - labelHeight - Spacing + extraSpacing;
        labelPos.X = BaseEditBox.Left + BaseEditBox.Width - labelWidth + Offset;

      }
      else if (Position == LabelPosition.BelowLeft)
      {
        labelPos.Y = BaseEditBox.Top + BaseEditBox.Height + Spacing + extraSpacing;
        labelPos.X = BaseEditBox.Left + Offset;

      }
      else if (Position == LabelPosition.BelowCenter)
      {
        labelPos.Y = BaseEditBox.Top + BaseEditBox.Height + Spacing + extraSpacing;
        labelPos.X = BaseEditBox.Left + (BaseEditBox.Width - labelWidth) / 2 + Offset;

      }
      else if (Position == LabelPosition.BelowRight)
      {
        labelPos.Y = BaseEditBox.Top + BaseEditBox.Height + Spacing + extraSpacing;
        labelPos.X = BaseEditBox.Left + BaseEditBox.Width - labelWidth + Offset;

      }
      else if (Position == LabelPosition.LeftTop)
      {
        labelPos.Y = BaseEditBox.Top + Offset;
        labelPos.X = BaseEditBox.Left - labelWidth - Spacing + extraSpacing;

      }
      else if (Position == LabelPosition.LeftTextBaseline)
      {
        labelPos.Y = BaseEditBox.Top + BaseEditBox.GetControlTextBaseLine() - labelHeight + Offset;
        labelPos.X = BaseEditBox.Left - labelWidth - Spacing + extraSpacing;

      }
      else if (Position == LabelPosition.LeftCenter)
      {
        labelPos.Y = BaseEditBox.Top + (BaseEditBox.Height - labelHeight) / 2 + Offset;
        labelPos.X = BaseEditBox.Left - labelWidth - Spacing + extraSpacing;

      }
      else if (Position == LabelPosition.LeftBottom)
      {
        labelPos.Y = BaseEditBox.Top + BaseEditBox.Height - labelHeight + Offset;
        labelPos.X = BaseEditBox.Left - labelWidth - Spacing + extraSpacing;

      }
      else if (Position == LabelPosition.RightTop)
      {
        labelPos.Y = BaseEditBox.Top + Offset;
        labelPos.X = BaseEditBox.Left + BaseEditBox.Width + Spacing + extraSpacing;

      }
      else if (Position == LabelPosition.RightTextBaseline)
      {
        labelPos.Y = BaseEditBox.Top + BaseEditBox.GetControlTextBaseLine() - labelHeight + Offset;
        labelPos.X = BaseEditBox.Left + BaseEditBox.Width + Spacing + extraSpacing;

      }
      else if (Position == LabelPosition.RightCenter)
      {
        labelPos.Y = BaseEditBox.Top + (BaseEditBox.Height - labelHeight) / 2 + Offset;
        labelPos.X = BaseEditBox.Left + BaseEditBox.Width + Spacing + extraSpacing;

      }
      else if (Position == LabelPosition.RightBottom)
      {
        labelPos.Y = BaseEditBox.Top + BaseEditBox.Height - labelHeight + Offset;
        labelPos.X = BaseEditBox.Left + BaseEditBox.Width + Spacing + extraSpacing;
      }
    }

    protected override void OnResize(EventArgs e)
    {
      base.OnResize(e);
      if (BaseEditBox != null)
        BaseEditBox.BoundLabelRelativePositionChanged();
    }

    protected override void OnLocationChanged(EventArgs e)
    {
      base.OnLocationChanged(e);
      if (BaseEditBox != null)
        BaseEditBox.BoundLabelRelativePositionChanged();
    }

    private string DefaultText()
    {
      if (BaseEditBox != null)
        return BaseEditBox.Name;
      else
        return base.Text;
    }

    public bool ShouldSerializeText()
    {
      return textStored;
    }

    public override void ResetText()
    {
      textStored = false;
      Invalidate();
    }

    #endregion methods

  }

}
