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

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Windows.Forms;
using System.Windows.Forms.VisualStyles;
using System.Xml.Serialization;

namespace EhLib
{

  public delegate void MouseDownRepeatEventHandler(object sender, EventArgs e);

  [ToolboxItem(false)]
  [System.ComponentModel.DesignerCategory("Code")]
  public class DataGridSearchBoxControl : ContainerControl
  {

    private readonly DataGridEh grid;

    internal SearchBoxTextEditor FindEditor;
    internal ButtonEh FilterBtn;
    internal ButtonEh FindNextBtn;
    internal ButtonEh FindPrevBtn;
    internal ButtonEh DropDownMenuBtn;

    private readonly List<ButtonEh> searchBtns = new List<ButtonEh>();

    public DataGridSearchBoxControl(DataGridEh grid)
    {

      SetStyle(ControlStyles.ResizeRedraw, true);
      SetStyle(ControlStyles.Opaque, true);
      SetStyle(ControlStyles.Selectable, false);

      this.grid = grid;

      FindEditor = new SearchBoxTextEditor(this);
      Controls.Add(FindEditor);

      FilterBtn = new ButtonEh();
      FilterBtn.Image = Properties.Resources.SearchBoxFilter;
      FilterBtn.Focusable = false;
      FilterBtn.Click += FilterBtn_Click;
      Controls.Add(FilterBtn);
      searchBtns.Add(FilterBtn);

      FindNextBtn = new ButtonEh();
      FindNextBtn.Image = Properties.Resources.SearchBoxFindNext;
      FindNextBtn.Focusable = false;
      FindNextBtn.Click += FindNextBtn_Click;
      Controls.Add(FindNextBtn);
      searchBtns.Add(FindNextBtn);

      FindPrevBtn = new ButtonEh();
      FindPrevBtn.Image = Properties.Resources.SearchBoxFindPrev;
      FindPrevBtn.Focusable = false;
      FindPrevBtn.Click += FindPrevBtn_Click;
      Controls.Add(FindPrevBtn);
      searchBtns.Add(FindPrevBtn);

      DropDownMenuBtn = new ButtonEh();
      DropDownMenuBtn.Image = Properties.Resources.SearchBoxEllipsis;
      DropDownMenuBtn.Focusable = false;
      DropDownMenuBtn.MouseDown += DropDownMenuBtn_MouseDown;
      Controls.Add(DropDownMenuBtn);
      searchBtns.Add(DropDownMenuBtn);
    }

    #region properties

    [Browsable(false)]
    public DataGridEh Grid
    {
      get { return grid; }
    }

    public bool SearchEditMode { get; private set; }

    public bool FilterEnabled
    {
      get
      {
        return Grid.SearchBox.FilterEnabled;
      }
    }

    public bool FilterOnTyping
    {
      get
      {
        return Grid.SearchBox.FilterOnTyping;
      }
    }

    #endregion properties

    #region Methods
    private void FilterBtn_Click(object sender, EventArgs e)
    {
      if ((!String.IsNullOrEmpty(FindEditor.Text)) &&
          (FindEditor.Text != Grid.SearchBox.FilterText))
      {
        Grid.SearchBox.ApplyFilter(FindEditor.Text);
      }
      else
      {
        Grid.SearchBox.CancelFilter();
      }
    }

    private void FindNextBtn_Click(object sender, EventArgs e)
    {
      Grid.SearchBox.FindNext();
    }

    private void FindPrevBtn_Click(object sender, EventArgs e)
    {
      Grid.SearchBox.FindPrev();
    }

    protected virtual void DropDownMenuBtn_MouseDown(object sender, MouseEventArgs e)
    {
      Point ddmPos = DropDownMenuBtn.PointToScreen(new Point(0, DropDownMenuBtn.Height));

      BuildAndShowToolMenu(ddmPos);
    }

    protected internal virtual void BuildAndShowToolMenu(Point menuPos)
    {
      ToolStripDropDown popupMenu = null;

      DataGridManager.DefaultManager.BuildSearchBoxToolMenu(Grid, ref popupMenu);

      if (popupMenu != null)
      {
        popupMenu.Show(menuPos);
      }
    }

    protected override void OnResize(EventArgs e)
    {

      base.OnResize(e);
      RealignControls();
    }

    protected override void OnPaint(PaintEventArgs e)
    {
      Rectangle fillRect;
      using (
        SolidBrush fillBrush = new SolidBrush(SystemColors.Control))
      {

        fillRect = ClientRectangle;

        e.Graphics.FillRectangle(fillBrush, fillRect);

        using (Pen pen = new Pen(Grid.LineOptions.DarkColor))
        {
          e.Graphics.DrawLine(pen, new Point(fillRect.Left, fillRect.Bottom - 1), new Point(fillRect.Right - 1, fillRect.Bottom - 1));
          e.Graphics.DrawLine(pen, new Point(fillRect.Right - 1, fillRect.Bottom - 1), new Point(fillRect.Right - 1, fillRect.Top));
        }
      }
    }

    internal int CalcAutoHeight()
    {
      return FindEditor.PreferredHeight + 6 + 1;
    }

    public void RealignControls()
    {
      int editorTop;
      int btnWidth;
      int x;
      ButtonEh btn;

      btnWidth = ClientSize.Height - 4;
      x = ClientSize.Width - 3;

      FilterBtn.Visible = Grid.SearchBox.VisibleButtons.ApplyFilterClear;
      FindNextBtn.Visible = Grid.SearchBox.VisibleButtons.FindNext;
      FindPrevBtn.Visible = Grid.SearchBox.VisibleButtons.FindPrior;
      DropDownMenuBtn.Visible = Grid.SearchBox.VisibleButtons.OptionsPopupMenu &&
                                Grid.SearchBox.OptionsPopupMenuItems.HasVisibleItem();

      for (int i = searchBtns.Count - 1; i >= 0; i--)
      {
        btn = searchBtns[i];
        btn.UseVisualStyleBackColor = true;
        btn.SetBounds(x - btnWidth, 2, btnWidth, btnWidth);
        if (btn.Visible)
          x = x - btnWidth;
      }

      editorTop = (FindEditor.Height + Height) / 2 - FindEditor.Height;
      FindEditor.SetBounds(3, editorTop, x - 6, FindEditor.Height);
      FindEditor.Border.Style = ControlBorderStyle.Custom;
      FindEditor.Border.NormalColor = Grid.LineOptions.DarkColor;

      if (FindEditor.Text != Grid.SearchBox.FilterText)
        FilterBtn.Image = Properties.Resources.SearchBoxFilter;
      else
        FilterBtn.Image = Properties.Resources.SearchBoxCancelFilter;

      if (String.IsNullOrEmpty(FindEditor.Text) && 
          String.IsNullOrEmpty(Grid.SearchBox.FilterText))
        FilterBtn.Enabled = false;
      else
        FilterBtn.Enabled = true;
    }

    internal void FindEditorGotFocus()
    {
      Grid.InvalidateGrid();
      Grid.SearchBox.HighlightSearchingText = true;
    }

    internal void FindEditorLostFocus()
    {
      Grid.InvalidateGrid();
      Grid.SearchBox.HighlightSearchingText = false;
    }

    internal void TextEditorTextChanged()
    {
      if (String.IsNullOrEmpty(FindEditor.Text))
      {
        if (FilterEnabled && FilterOnTyping)
          Grid.SearchBox.CancelFilter();
      }
      else
      {
        if (FilterEnabled && FilterOnTyping)
          Grid.SearchBox.ApplyFilter(FindEditor.Text);
        Grid.SearchBox.RestartFind();
      }
      Grid.InvalidateGrid();
      RealignControls();
    }

    protected internal virtual void TextEditorKeyDown(KeyEventArgs e)
    {

      switch (e.KeyData)
      {
        case Keys.Down:
          {
            Grid.SearchBox.FindNext();
            e.Handled = true;
            break;
          }
        case Keys.Up:
          {
            Grid.SearchBox.FindPrev();
            e.Handled = true;
            break;
          }
        case Keys.Tab:
          {
            SearchEditMode = false;
            e.Handled = true;
            break;
          }
      }

    }

    protected internal virtual void TextEditorKeyUp(KeyEventArgs e)
    {
    }

    protected internal virtual void TextEditorKeyPress(KeyPressEventArgs e)
    {
      switch (e.KeyChar)
      {
        case (char)Keys.Enter:
          {
            Grid.SearchBox.ApplyFilter(FindEditor.Text);
            e.Handled = true;
            break;
          }
        case (char)Keys.Escape:
          {
            if (String.IsNullOrEmpty(Text) &&
                String.IsNullOrEmpty(Grid.SearchBox.FilterText))
            {
              Grid.Focus();
              Grid.SearchBox.UpdateVisibleState();
            }
            else
              Grid.SearchBox.CancelFilter();
            e.Handled = true;
            break;
          }
      }
    }

    protected override void OnGotFocus(EventArgs e)
    {
      base.OnGotFocus(e);
    }
    #endregion Methods
  }

  [ToolboxItem(false)]
  [System.ComponentModel.DesignerCategory("Code")]
  public class DataGridScrollBarPanelControl : BaseGridScrollBarPanelControl
  {
    #region privates
    private readonly DataGridHorzScrollExtraBarControl extraBar;
    #endregion privates

    public DataGridScrollBarPanelControl(BaseGridControl grid, Orientation kind) : base(grid, kind)
    {
      extraBar = new DataGridHorzScrollExtraBarControl(this);
      extraBar.Parent = this;
    }

    #region properties
    public new DataGridEh Grid
    {
      get { return (DataGridEh)base.Grid; }
    }

    public string SelectionAggrInfoText
    {
      get;
      internal set;
    }
    #endregion properties

    #region methods
    protected internal virtual void GridDataChanged()
    {
      RealignControls(); 
    }

    protected internal virtual void GridSelectionChanged()
    {
      if (extraBar.Visible)
      {
        extraBar.StartAggrInfoTextCaluclationTimer();
        RealignControls();
        Invalidate(true);
      }
    }

    public override void RealignControls()
    {
      int newSbWidth;
      int newSbHeight;
      int newSbVWidth;
      int extraBarWidth;

      if (extraBar == null) return;

      if (!Grid.HorzScrollBar.ExtraBar.Visible)
      {
        extraBar.Visible = false;
        base.RealignControls();
      }
      else
      {
        extraBar.Visible = true;
        extraBar.Height = this.Height;
        extraBar.ResetWidth();
        extraBarWidth = extraBar.Width;

        newSbVWidth = Grid.VertScrollBar.ActualScrollBarBoxSize();
        newSbHeight = Grid.HorzScrollBar.ActualScrollBarBoxSize();
        newSbWidth = this.Width - extraBarWidth;
        newSbHeight = Math.Min(newSbHeight, newSbVWidth);

        ScrollBar.SetBounds(this.Width - newSbWidth, this.Height - newSbHeight, newSbWidth, newSbHeight);
        extraBar.SetBounds(0, 0, extraBarWidth, this.Height);
      }
      extraBar.Invalidate(true);
    }
    #endregion methods
  }

  [ToolboxItem(false)]
  [System.ComponentModel.DesignerCategory("Code")]
  public class DataGridHorzScrollExtraBarControl : Control
  {
    #region privates
    private readonly DataGridScrollBarPanelControl scrollBarControl;
    private readonly Control recordsInfoBox;
    private readonly Control selectionAggrInfoBox;
    private readonly DataGridAggregator dataAggregator;

    private readonly ButtonEh navButtonFirst;
    private readonly ButtonEh navButtonPrior;
    private readonly ButtonEh navButtonNext;
    private readonly ButtonEh navButtonLast;
    private readonly ButtonEh navButtonAppend;
    private readonly ButtonEh navButtonDelete;

    private readonly List<Control> activeBarControls;
    private readonly Timer timer;
    private string selectionAggrInfoText;

    #endregion privates

    public DataGridHorzScrollExtraBarControl(DataGridScrollBarPanelControl scrollBarControl)
    {
      this.scrollBarControl = scrollBarControl;
      this.SetStyle(ControlStyles.Selectable, false);

      activeBarControls = new List<Control>();
      //var navButtons = new List<ButtonEh>();

      recordsInfoBox = new Control();
      recordsInfoBox.Paint += RecordsInfoBox_Paint;
      recordsInfoBox.Parent = this;
      recordsInfoBox.Enabled = false;

      selectionAggrInfoBox = new Control();
      selectionAggrInfoBox.Paint += SelectionAggrInfoBox_Paint;
      selectionAggrInfoBox.Parent = this;
      selectionAggrInfoBox.Enabled = false;
      dataAggregator = new DataGridAggregator();

      navButtonFirst = new ButtonEh();
      navButtonFirst.Image = Properties.Resources.NavigatorFirst;
      navButtonFirst.Focusable = false;
      navButtonFirst.MouseDown += NavButtonFirst_Click;
      Controls.Add(navButtonFirst);
      //navButtons.Add(navButtonFirst);

      navButtonPrior = new ButtonEh();
      navButtonPrior.Image = Properties.Resources.NavigatorPrev;
      navButtonPrior.Focusable = false;
      navButtonPrior.AutoRepeat = true;
      navButtonPrior.MouseDown += NavButtonPrior_Click;
      navButtonPrior.MouseDownRepeat += NavButtonPrior_Click;
      Controls.Add(navButtonPrior);
      //navButtons.Add(navButtonPrior);

      navButtonNext = new ButtonEh();
      navButtonNext.Image = Properties.Resources.NavigatorNext;
      navButtonNext.Focusable = false;
      navButtonNext.AutoRepeat = true;
      navButtonNext.MouseDown += NavButtonNext_Click;
      navButtonNext.MouseDownRepeat += NavButtonNext_Click;
      Controls.Add(navButtonNext);
      //navButtons.Add(navButtonNext);

      navButtonLast = new ButtonEh();
      navButtonLast.Image = Properties.Resources.NavigatorLast;
      navButtonLast.Focusable = false;
      navButtonLast.MouseDown += NavButtonLast_Click;
      Controls.Add(navButtonLast);
      //navButtons.Add(navButtonLast);

      navButtonAppend = new ButtonEh();
      navButtonAppend.Image = Properties.Resources.NavigatorNew;
      navButtonAppend.Focusable = false;
      navButtonAppend.Click += NavButtonAppend_Click;
      Controls.Add(navButtonAppend);
      //navButtons.Add(navButtonAppend);

      navButtonDelete = new ButtonEh();
      navButtonDelete.Image = Properties.Resources.NavigatorDelete;
      navButtonDelete.Focusable = false;
      navButtonDelete.Click += NavButtonDelete_Click;
      Controls.Add(navButtonDelete);
      //navButtons.Add(navButtonDelete);

      timer = new Timer();
      timer.Tick += Timer_Elapsed;
      timer.Interval = 300;
      timer.Enabled = false;
    }

    #region properties
    public DataGridScrollBarPanelControl ScrollBarControl
    {
      get { return scrollBarControl; }
    }

    public DataGridHorzScrollBar ScrollBar
    {
      get { return scrollBarControl.Grid.HorzScrollBar; }
    }
    #endregion properties

    #region methods
    protected virtual void NavButtonNext_Click(object sender, EventArgs e)
    {
      scrollBarControl.Grid.PutFocus();
      scrollBarControl.Grid.EditActions.MoveCurrentToNextRow();
    }

    protected virtual void NavButtonPrior_Click(object sender, EventArgs e)
    {
      scrollBarControl.Grid.PutFocus();
      scrollBarControl.Grid.EditActions.MoveCurrentToPriorRow();
    }

    protected virtual void NavButtonFirst_Click(object sender, EventArgs e)
    {
      scrollBarControl.Grid.PutFocus();
      scrollBarControl.Grid.EditActions.MoveCurrentToFirstRow();
    }

    protected virtual void NavButtonLast_Click(object sender, EventArgs e)
    {
      scrollBarControl.Grid.PutFocus();
      scrollBarControl.Grid.EditActions.MoveCurrentToLastRow();
    }

    protected virtual void NavButtonAppend_Click(object sender, EventArgs e)
    {
      scrollBarControl.Grid.PutFocus();
      scrollBarControl.Grid.EditActions.MoveCurrentToNewRow();
    }

    protected virtual void NavButtonDelete_Click(object sender, EventArgs e)
    {
      scrollBarControl.Grid.PutFocus();
      DataGridEditActions editActions = scrollBarControl.Grid.EditActions;
      bool deleteConfirmed;
      if (editActions.ConfirmDelete)
        deleteConfirmed = editActions.ShowConfirmDeleteDialog();
      else
        deleteConfirmed = true;

      if (!deleteConfirmed) return;

      if (scrollBarControl.Grid.Selection.SelectionType == GridSelectionType.None)
        editActions.DeleteCurrentRow();
      else
        editActions.Delete();
    }

    private void RecordsInfoBox_Paint(object sender, PaintEventArgs e)
    {
      string text = scrollBarControl.Grid.VisibleRows.Count.ToString();

      if (ScrollBarControl.Grid.Selection.SelectedRowCount > 0)
        text = text + " (" + ScrollBarControl.Grid.Selection.SelectedRowCount.ToString() + ")";

      EhLibUtils.DrawText(e.Graphics,
                          text,
                          recordsInfoBox.Font,
                          new Rectangle(Point.Empty, recordsInfoBox.Size),
                          scrollBarControl.Grid.ForeColor,
                          HorizontalAlignment.Center,
                          VerticalAlignment.Center,
                          TextFormatFlagsEh.None);
    }

    private void SelectionAggrInfoBox_Paint(object sender, PaintEventArgs e)
    {
      string text = selectionAggrInfoText;

      EhLibUtils.DrawText(e.Graphics,
                          text,
                          selectionAggrInfoBox.Font,
                          new Rectangle(Point.Empty, selectionAggrInfoBox.Size),
                          scrollBarControl.Grid.ForeColor,
                          HorizontalAlignment.Center,
                          VerticalAlignment.Center,
                          TextFormatFlagsEh.None);
    }

    protected internal virtual string CalcSelectionAggrInfoText()
    {
      if (scrollBarControl.Grid.Selection.SelectionType == GridSelectionType.None)
        return "";

      dataAggregator.Grid = scrollBarControl.Grid;
      dataAggregator.ImportArea = DataGridExportArea.SelectedArea;
      dataAggregator.BuildExportObject();

      return "Sum: " + dataAggregator.SumValue + 
             "  Count: " + dataAggregator.CountValue + 
             "  Average: " + dataAggregator.AverageValue;
    }

    internal void StartAggrInfoTextCaluclationTimer()
    {
      if (!ScrollBar.ExtraBar.VisibleItems.SelectAggregationInfo) return;
      if (timer.Enabled == true)
        timer.Stop();
      timer.Start();
    }

    protected virtual void Timer_Elapsed(object value, EventArgs args)
    {
      timer.Stop();
      if (ScrollBar.Grid.IsDisposed) return;
      if (!ScrollBar.ExtraBar.VisibleItems.SelectAggregationInfo) return;
      selectionAggrInfoText = CalcSelectionAggrInfoText();
      ResetWidth();
    }

    protected internal virtual void ResetWidth()
    {
      int nextPos = 0;
      //selectionAggrInfoText = CalcSelectionAggrInfoText();
      Width = CalcOptimalWidth();

      foreach (Control c in activeBarControls)
      {
        c.SetBounds(nextPos, 0, c.Width, Height);
        nextPos = nextPos + c.Width;
      }
    }

    protected internal virtual int CalcOptimalWidth()
    {
      int result = 0;

      activeBarControls.Clear();

      if (ScrollBar.ExtraBar.VisibleItems.RecordsInfo)
      {
        recordsInfoBox.Visible = true;
        recordsInfoBox.Width = CalcWidthForRecordsInfoPanel();
        activeBarControls.Add(recordsInfoBox);
      }
      else
      {
        recordsInfoBox.Visible = false;
      }

      if (ScrollBar.ExtraBar.VisibleItems.Navigator)
      {
        navButtonFirst.Visible = true;
        navButtonFirst.Width = Height;
        navButtonFirst.UseVisualStyleBackColor = true;
        navButtonFirst.Enabled = scrollBarControl.Grid.EditActions.CanMoveCurrentToFirstRow();
        activeBarControls.Add(navButtonFirst);

        navButtonPrior.Visible = true;
        navButtonPrior.Width = Height;
        navButtonPrior.UseVisualStyleBackColor = true;
        navButtonPrior.Enabled = scrollBarControl.Grid.EditActions.CanMoveCurrentToPriorRow();
        activeBarControls.Add(navButtonPrior);

        navButtonNext.Visible = true;
        navButtonNext.Width = Height;
        navButtonNext.UseVisualStyleBackColor = true;
        navButtonNext.Enabled = scrollBarControl.Grid.EditActions.CanMoveCurrentToNextRow();
        activeBarControls.Add(navButtonNext);

        navButtonLast.Visible = true;
        navButtonLast.Width = Height;
        navButtonLast.UseVisualStyleBackColor = true;
        navButtonLast.Enabled = scrollBarControl.Grid.EditActions.CanMoveCurrentToLastRow();
        activeBarControls.Add(navButtonLast);

        navButtonAppend.Visible = true;
        navButtonAppend.Width = Height;
        navButtonAppend.UseVisualStyleBackColor = true;
        navButtonAppend.Enabled = scrollBarControl.Grid.EditActions.CanMoveCurrentToNewRow();
        activeBarControls.Add(navButtonAppend);

        navButtonDelete.Visible = true;
        navButtonDelete.Width = Height;
        navButtonDelete.UseVisualStyleBackColor = true;
        navButtonDelete.Enabled = scrollBarControl.Grid.EditActions.CanDeleteCurrentRow();
        activeBarControls.Add(navButtonDelete);

      }
      else
      {
        navButtonFirst.Visible = false;
        navButtonPrior.Visible = false;
        navButtonNext.Visible = false;
        navButtonLast.Visible = false;
        navButtonAppend.Visible = false;
        navButtonDelete.Visible = false;
      }

      if (ScrollBar.ExtraBar.VisibleItems.SelectAggregationInfo)
      {
        selectionAggrInfoBox.Visible = true;
        selectionAggrInfoBox.Width = CalcWidthForSelectionAggrInfoBox();
        activeBarControls.Add(selectionAggrInfoBox);
      }
      else
      {
        selectionAggrInfoBox.Visible = false;
      }

      foreach (Control c in activeBarControls)
        result = result + c.Width;

      return result;
    }

    protected internal virtual int CalcWidthForRecordsInfoPanel()
    {
      int result;
      string text;

      recordsInfoBox.Font = ScrollBarControl.Grid.IndicatorColumn.Font;

      text = ScrollBarControl.Grid.VisibleRows.Count.ToString();
      if (ScrollBarControl.Grid.Selection.SelectedRowCount > 0)
        text = text + " (" + ScrollBarControl.Grid.Selection.SelectedRowCount.ToString() + ")";

      result = EhLibUtils.MeasureText(EhLibUtils.DisplayGraphicsCash, " " + text + " ", recordsInfoBox.Font).Width;

      if (ScrollBarControl.Grid.IndicatorColumn.Visible && ScrollBarControl.Grid.IndicatorColumn.CalcWidth() > result)
        result = ScrollBarControl.Grid.IndicatorColumn.CalcWidth();

      return result;
    }

    protected internal virtual int CalcWidthForSelectionAggrInfoBox()
    {
      int result;
      string text;

      if (String.IsNullOrEmpty(selectionAggrInfoText)) return 0;

      recordsInfoBox.Font = ScrollBarControl.Grid.IndicatorColumn.Font;
      text = selectionAggrInfoText;
      result = EhLibUtils.MeasureText(EhLibUtils.DisplayGraphicsCash, " " + text + " ", selectionAggrInfoBox.Font).Width;
      return result;
    }

    #endregion methods
  }

  [ToolboxItem(false)]
  [System.ComponentModel.DesignerCategory("Code")]
  [TypeConverter(typeof(ExpandableObjectConverter))]
  public class GridEmptyDataInfo : Component
  {

    #region privates
    private bool active;
    private Font font;
    private DataGridEh grid;
    private string text;
    #endregion privates

    public GridEmptyDataInfo(DataGridEh grid)
    {
      this.grid = grid;
    }

    #region design-time properties
    [DefaultValue(false)]
    public virtual bool Active
    {
      get
      {
        return active;
      }

      set
      {
        if (active != value)
        {
          active = value;
          Grid.Invalidate();
        }
      }
    }

    public Font Font
    {
      get
      {
        if (font != null)
          return font;
        else
          return DefaultFont();
      }
      set
      {
        font = value;
        FontChanged();
      }
    }

    public string Text
    {
      get
      {
        return text;
      }

      set
      {
        if (text != value)
        {
          text = value;
          Grid.Invalidate();
        }
      }
    }

    #endregion

    #region run-time properties
    [Browsable(false)]
    [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
    public DataGridEh Grid
    {
      get { return grid; }
    }

    public bool Showing
    {
      get
      {
        //bool result = Active && (string.IsNullOrEmpty(Text));
        if (Active &&
            !string.IsNullOrEmpty(Text) &&
            Grid.VisibleRows.Count == 0
           )
        {
          return true;
        }
        else
        {
          return false;
        }
      }
    }
    #endregion

    #region methods
    //Font
    protected virtual Font DefaultFont()
    {
      return Grid.Font;
    }

    protected virtual bool ShouldSerializeFont()
    {
      return (font != null);
    }

    public virtual void ResetFont()
    {
      font = null;
      FontChanged();
    }

    protected virtual void FontChanged()
    {
      Grid.Invalidate();
    }

    //Text
    protected virtual bool ShouldSerializeText()
    {
      return !String.IsNullOrEmpty(text);
    }

    public virtual void ResetText()
    {
      text = null;
      Grid.Invalidate();
    }

    //Other
    public virtual void GetDrawRect(Graphics graphics, ref Rectangle drawRect)
    {
      Size ts;
      string text;
      Rectangle boundRect = Rectangle.Empty;
      text = Text;
      ts = EhLibUtils.MeasureText(graphics, text, Font);
      ts.Height = ts.Height + 2;
      boundRect.X = Grid.HorzAxis.FixedBoundary - Grid.HorzAxis.FrozenLen + 10;
      boundRect.Y = Grid.VertAxis.FixedBoundary - Grid.VertAxis.FrozenLen + 10;
      boundRect.Width = Grid.HorzAxis.ContraStart - 10 - boundRect.X;
      boundRect.Height = Grid.VertAxis.ContraStart - 10 - boundRect.Y;

      if (ts.Width > boundRect.Width)
      {
        drawRect = boundRect;
        Size drawSize = EhLibUtils.MeasureText(graphics, text, Font, new Size(boundRect.Width, ts.Height), DataGridTextWrapMode.WordWrap);
        drawRect.Size = drawSize;
      }
      else
      {
        drawRect = new Rectangle(0, 0, ts.Width, ts.Height);
      }

      drawRect = EhLibUtils.RectCenter(drawRect, boundRect);
    }

    public void PaintEmptyDataInfo(Graphics graphics)
    {
      string aText;
      Rectangle ADrawRect = Rectangle.Empty;
      aText = Text;
      GetDrawRect(graphics, ref ADrawRect);
      ADrawRect.Inflate(5, 5);
      if (Grid.LineOptions.VertEmptySpaceStyle != DataGridPaintEmptySpaceStyle.NoPaint)
      {
        graphics.FillRectangle(new SolidBrush(Grid.BackColor), ADrawRect);
        //ADrawRect.Inflate(1, 1);
        graphics.DrawRectangle(new Pen(Grid.LineOptions.BrightColor), ADrawRect);
      }
      EhLibUtils.DrawText(graphics, aText, Font, ADrawRect, Grid.ForeColor,
        HorizontalAlignment.Center, VerticalAlignment.Center, TextFormatFlagsEh.WordBreak);
    }
    #endregion
  }

  [AttributeUsage(AttributeTargets.Class)]
  public sealed class DataAxisGridPropBarDesignTimeVisibleAttribute : Attribute
  {
    private bool visible;

    public DataAxisGridPropBarDesignTimeVisibleAttribute(bool visible)
    {
      this.visible = visible;
    }

    public DataAxisGridPropBarDesignTimeVisibleAttribute()
    {
      this.visible = true;
    }

    public bool Visible
    {
      get
      {
        return visible;
      }
    }

    public static readonly DataGridViewColumnDesignTimeVisibleAttribute Default = new DataGridViewColumnDesignTimeVisibleAttribute(true);

    public override bool Equals(object obj)
    {
      if (obj == this)
      {
        return true;
      }

      DataGridViewColumnDesignTimeVisibleAttribute other = obj as DataGridViewColumnDesignTimeVisibleAttribute;
      return other != null && other.Visible == visible;
    }

    public override int GetHashCode()
    {
      return typeof(DataGridViewColumnDesignTimeVisibleAttribute).GetHashCode() ^ (visible ? -1 : 0);
    }

    public override bool IsDefaultAttribute()
    {
      return (this.Visible == true);
    }
  }

  [AttributeUsage(AttributeTargets.Class)]
  public sealed class DataAxisGridDataCellDesignTimeVisibleAttribute : Attribute
  {
    private bool visible;

    public DataAxisGridDataCellDesignTimeVisibleAttribute(bool visible)
    {
      this.visible = visible;
    }

    public DataAxisGridDataCellDesignTimeVisibleAttribute()
    {
      this.visible = true;
    }

    public bool Visible
    {
      get
      {
        return visible;
      }
    }

    public static readonly DataGridViewColumnDesignTimeVisibleAttribute Default = new DataGridViewColumnDesignTimeVisibleAttribute(true);

    public override bool Equals(object obj)
    {
      if (obj == this)
      {
        return true;
      }

      DataGridViewColumnDesignTimeVisibleAttribute other = obj as DataGridViewColumnDesignTimeVisibleAttribute;
      return other != null && other.Visible == visible;
    }

    public override int GetHashCode()
    {
      return typeof(DataGridViewColumnDesignTimeVisibleAttribute).GetHashCode() ^ (visible ? -1 : 0);
    }

    public override bool IsDefaultAttribute()
    {
      return (this.Visible == true);
    }
  }

  public class DataGridTitleDragWin : GridDragWin
  {
    private static DataGridTitleDragWin _titleDragWin;
    private object drawObject;
    private MovePoint movePoint;
    private DataGridEh grid;
    private int movePointPos;
    private int movePointSize;

    public DataGridEh Grid
    {
      get
      {
        return grid;
      }
    }

    public DataGridTitleDragWin()
    {
      SetStyle(ControlStyles.ResizeRedraw, true);
      SetStyle(ControlStyles.OptimizedDoubleBuffer, true);
      SetStyle(ControlStyles.DoubleBuffer, true);
      SetStyle(ControlStyles.Opaque, true);
      movePoint = new MovePoint();
      movePoint.Size = new Size(7, 4);
      movePointPos = 5;
      movePointSize = 4;
    }

    protected override CreateParams CreateParams
    {
      //[EnvironmentPermissionAttribute(SecurityAction.LinkDemand, Unrestricted = true)]
      get
      {

        CreateParams baseParams = base.CreateParams;
        baseParams.ClassStyle |= NativeMethods.CS_DROPSHADOW;
        return baseParams;
      }
    }

    protected override void OnVisibleChanged(EventArgs e)
    {
      base.OnVisibleChanged(e);
      UpdateMovePointPos();
      movePoint.ForePaintColor = SystemColors.ControlDarkDark;

      DataGridColumnTitle title = (drawObject as DataGridColumnTitle);
      DataGridTitleNode titleNode = (drawObject as DataGridTitleNode);
      if (title != null)
        movePoint.BackPaintColor = title.BackFiller.Color;
      else
      {
        if (titleNode.NodeType == DataGridTitleNodeType.ColumnTitle)
          movePoint.BackPaintColor = titleNode.ColumnTitle.BackFiller.Color;
        else
          movePoint.BackPaintColor = titleNode.SuperTitle.BackFiller.Color;
      }

      movePoint.LineColor = SystemColors.ControlDarkDark;
      movePoint.Visible = Visible;
    }

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

    private void UpdateMovePointPos()
    {
      //Point scMovePoint = PointToScreen(new Point(movePointPos, Height));
      Point scMovePoint = new Point(movePointPos, Top + Height);
      scMovePoint.X = scMovePoint.X - 3;
      movePoint.Location = scMovePoint;
      movePoint.Height = movePointSize + 5;
    }

    public static DataGridTitleDragWin GetTitleDragWin()
    {
      if (_titleDragWin == null)
      {
        _titleDragWin = new DataGridTitleDragWin();
      }
      return _titleDragWin;
    }

    public void StartShow(Control control, object drawObject,
      Point pos, int width, int height, int movePointPos, int moveSize)
    {
      this.movePointPos = movePointPos;
      this.movePointSize = moveSize;
      this.drawObject = drawObject;

      DataGridColumnTitle title = (drawObject as DataGridColumnTitle);
      DataGridTitleNode titleNode = (drawObject as DataGridTitleNode);
      if (title != null)
        grid = title.Grid;
      else
        grid = titleNode.Grid;

      Show();
      SetBounds(pos.X, pos.Y, width, height);
    }

    public void StartShowAnimated(Control control, object drawObject, 
      Rectangle sourceBounds, Rectangle bounds, int movePointPos, int moveSize)
    {
      this.movePointPos = movePointPos;
      this.movePointSize = moveSize;
      this.drawObject = drawObject;

      DataGridColumnTitle title = (drawObject as DataGridColumnTitle);
      DataGridTitleNode titleNode = (drawObject as DataGridTitleNode);
      if (title != null)
        grid = title.Grid;
      else
        grid = titleNode.Grid;

      int startTime = Environment.TickCount;
      int curTime = Environment.TickCount;
      int finishTime = startTime + DataGridManager.DefaultManager.TitleStartColumnMovingAnimationTime;
      double opacityFactor;
      Rectangle stepBounds = Rectangle.Empty;

      Opacity = 0;

      Show();         
      SetBounds(sourceBounds.X, sourceBounds.Y, sourceBounds.Width, sourceBounds.Height);

      while (curTime < finishTime)
      {
        opacityFactor = (double)(curTime - startTime) / (double)(finishTime - startTime);
        stepBounds = EhLibUtils.ApproximateRectangle(sourceBounds, bounds, opacityFactor);
        SetBounds(stepBounds.Left, stepBounds.Top, stepBounds.Width, stepBounds.Height, movePointPos, moveSize);
        Opacity = opacityFactor;
        Refresh();

        curTime = Environment.TickCount;
      }

      Opacity = 1;
      SetBounds(bounds.Left, bounds.Top, bounds.Width, bounds.Height, movePointPos, moveSize);
    }

    public void HideAnimated(Rectangle distantBounds)
    {
      int startTime = Environment.TickCount;
      int curTime = Environment.TickCount;
      int finishTime = startTime + DataGridManager.DefaultManager.TitleFinishColumnMovingAnimationTime;
      double opacityFactor;
      Rectangle sourceBounds = Bounds;
      Rectangle stepBounds = Rectangle.Empty;

      Opacity = 1;

      while (curTime < finishTime)
      {
        opacityFactor = (double)(curTime - startTime) / (double)(finishTime - startTime);
        stepBounds = EhLibUtils.ApproximateRectangle(sourceBounds, distantBounds, opacityFactor);
        SetBounds(stepBounds.Left, stepBounds.Top, stepBounds.Width, stepBounds.Height, movePointPos, movePointSize);
        Opacity = 1 - opacityFactor;
        Refresh();

        curTime = Environment.TickCount;
      }

      Hide();
    }

    public void SetBounds(int x, int y, int width, int height, int movePointPos, int moveSize)
    {
      Point oldLocation = Location;
      this.movePointPos = movePointPos;
      this.movePointSize = moveSize;

      SetBounds(x, y, width, height);
      if (oldLocation != Location)
        Invalidate();
    }

    protected override void OnPaint(PaintEventArgs e)
    {
      Color backColor;
      DataGridColumnTitle title = (drawObject as DataGridColumnTitle);
      DataGridTitleNode titleNode = (drawObject as DataGridTitleNode);
      if (title != null)
        backColor = title.BackFiller.Color;
      else
      {
        if (titleNode.NodeType == DataGridTitleNodeType.ColumnTitle)
          backColor = titleNode.ColumnTitle.BackFiller.Color;
        else
          backColor = titleNode.SuperTitle.BackFiller.Color;
      }

      Rectangle rect = ClientRectangle;
      rect.Width = rect.Width - 1;
      rect.Height = rect.Height - 1;
      e.Graphics.DrawRectangle(SystemPens.ControlDarkDark, rect);
      rect.Offset(1, 1);
      rect.Size = new Size(rect.Width - 1, rect.Height - 1);
      //e.Graphics.FillRectangle(new SolidBrush(Grid.Title.BackFiller.Color), rect);

      if (title != null)
      {
        int dataIndex = title.Column.VisibleIndex;
        int Index = Grid.DataToRawCol(dataIndex);

        BaseGridCellPaintEventArgs pea = Grid.Title.CellMan.GetCellPaintParams(e.Graphics, Index, 0, rect, 0, dataIndex, 0, new Point(-1, -1));
        Grid.Title.CellMan.OnPaint(pea);
      }
      else
      {
        titleNode.PaintCell(e.Graphics, rect);
      }

      Point locMovePointPos = PointToClient(new Point(movePointPos, 0));
      locMovePointPos.Y = Height - 1;
      Point p1 = locMovePointPos;
      p1.X = p1.X - 2;
      Point p2 = locMovePointPos;
      p2.X = p2.X + 2;
      e.Graphics.DrawLine(new Pen(backColor), p1, p2);

      if (title != null && title.Column.Selected)
      {
        int selCols = 0;
        foreach (DataGridColumn col in Grid.VisibleColumns)
        {
          if (col.Selected)
            selCols = selCols + 1;
        }

        string s = selCols.ToString();
        Font font = new Font(title.Font.FontFamily, 6F, GraphicsUnit.Point);
        Size size = EhLibUtils.MeasureText(e.Graphics, s, font);
        size.Height = size.Height + 4;
        size.Width = size.Width + 4;

        Rectangle colsRect = new Rectangle(new Point(0, 0), size);

        colsRect.X = rect.Width - size.Width - 1;
        colsRect.Y = 2;

        e.Graphics.DrawRectangle(new Pen(Grid.LineOptions.DarkColor), colsRect);

        colsRect.X = colsRect.Left + 1;
        colsRect.Y = colsRect.Top + 1;
        colsRect.Width = colsRect.Width - 1;
        colsRect.Height = colsRect.Height - 1;
        e.Graphics.FillRectangle(new SolidBrush(Color.White), colsRect);

        EhLibUtils.DrawText(e.Graphics, s, font, colsRect, SystemColors.WindowText,
          HorizontalAlignment.Center, VerticalAlignment.Center, 0);
      }

    }

  }

}
