//------------------------------------------------------------------------------
// <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.Data;
using System.Diagnostics;
using System.Drawing.Design;
using System.Drawing.Drawing2D;
using System.Collections.ObjectModel;

namespace EhLib
{
  public enum DataAxisGridDataCellFormatApplying
  {
    DisplayValue, EditValue
  }

  public class DataAxisGridDataCellMan : BaseGridCellManager, IGridRowHeightOptionsOwner
  {

    #region privates
    private PropertyAxisBar propAxisBar;

    private EditButton editButton;
    private bool paddingStored;
    private Padding padding = new Padding(0);
    //private Padding defaultPadding = new Padding(2, 2, 0, 0);
    private bool horzAlignStored;
    private HorizontalAlignment horzAlign;
    private bool vertAlignStored;
    private VerticalAlignment vertAlign;
    private Color foreColor = Color.Empty;
    private bool foreColorStored;
    private bool readOnly;
    private bool readOnlyStored;
    private Font font;
    private Color backColor = Color.Empty;
    private bool backColorStored;
    private readonly GridRowHeightOptions heightOptions;
    //private DataAxisGridDataCellPaintEventArgs paintEventArgs;
    #endregion

    public DataAxisGridDataCellMan()
    {
      heightOptions = new GridRowHeightOptions(this);
      //ContextMenuIsCompound = true;
    }

    #region properties
    [Browsable(false)]
    [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
    public PropertyAxisBar PropAxisBar
    {
      get
      {
        return propAxisBar;
      }
      set
      {
        propAxisBar = value;
      }
    }

    [Browsable(false)]
    [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
    public new DataAxisGrid Grid
    {
      get { return (DataAxisGrid)base.Grid; }
      set { base.Grid = value; }
    }

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

        return editButton;
      }

      set
      {
        if (editButton != value)
        {
          if (editButton != null)
          {
            editButton.EditItemChanged -= EditItemChanged;
            editButton.DefaultVisibleStateRequested -= EditButtonDefaultVisibleStateRequested;
          }

          editButton = value;

          if (editButton != null)
          {
            editButton.EditItemChanged += EditItemChanged;
            editButton.DefaultVisibleStateRequested += EditButtonDefaultVisibleStateRequested;
          }

          EditButtonChanged();
        }
      }
    }

    public Padding Padding
    {
      get
      {
        if (paddingStored)
          return padding;
        else
          return DefaultPadding();
      }
      set
      {
        padding = value;
        paddingStored = true;
        PaddingChanged();
      }
    }

    public HorizontalAlignment HorzAlign
    {
      get
      {
        if (horzAlignStored)
          return horzAlign;
        else
          return DefaultHorzAlign();
      }
      set
      {
        if ((horzAlignStored == false) || (horzAlign != value))
        {
          horzAlignStored = true;
          horzAlign = value;
          HorzAlignChanged();
        }
      }
    }

    public VerticalAlignment VertAlign
    {
      get
      {
        if (vertAlignStored)
          return vertAlign;
        else
          return DefaultVertAlign();
      }
      set
      {
        if ((vertAlignStored == false) || (vertAlign != value))
        {
          vertAlignStored = true;
          vertAlign = value;
          VertAlignChanged();
        }
      }
    }

    [DefaultValue(null)]
    public virtual ContextMenuStrip ContextMenuStrip { get; set; }

    //[DefaultValue(true)]
    //public bool ContextMenuIsCompound { get; set; }

    public Color BackColor
    {
      get
      {
        if (backColorStored)
          return backColor;
        else
          return DefaultBackColor();
      }
      set
      {
        if ((backColorStored == false) || (backColor != value))
        {
          backColorStored = true;
          backColor = value;
          BackColorChanged();
        }
      }
    }

    public Color ForeColor
    {
      get
      {
        if (foreColorStored)
          return foreColor;
        else
          return DefaultForeColor();
      }
      set
      {
        if ((foreColorStored == false) || (foreColor != value))
        {
          foreColorStored = true;
          foreColor = value;
          ForeColorChanged();
        }
      }
    }

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

    [DefaultValue(false)]
    public virtual bool ReadOnly
    {
      get
      {
        if (readOnlyStored)
          return readOnly;
        else
          return DefaultReadOnly();
      }
      set
      {
        if ((readOnlyStored == false) || (readOnly != value))
        {
          readOnlyStored = true;
          readOnly = value;
          OnReadOnlyChanged();
        }
      }
    }

    [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
    public GridRowHeightOptions HeightOptions
    {
      get
      {
        return heightOptions;
      }
    }
    #endregion

    #region methods
    //Padding
    public virtual void PaddingChanged()
    {
      if (Grid != null)
        Grid.UpdateBaseFixedBands();
    }

    public virtual Padding DefaultPadding()
    {
      if (Grid != null)
        return Grid.GetDefaultPaddingForAlign(HorzAlign, VertAlign);
      else
        return Padding.Empty;
    }

    public virtual bool ShouldSerializePadding()
    {
      return (paddingStored == true);
    }

    public virtual void ResetPadding()
    {
      paddingStored = false;
      PaddingChanged();
    }

    //HorzAlign
    public virtual HorizontalAlignment DefaultHorzAlign()
    {
      if ((PropAxisBar != null) && (Grid != null))
        return Grid.DefaultHorzAlignForType(PropAxisBar.DataType);
      else
        return HorizontalAlignment.Left;
    }

    protected virtual void HorzAlignChanged()
    {
      if (Grid != null)
        Grid.Invalidate();
    }

    public virtual bool ShouldSerializeHorzAlign()
    {
      return (horzAlignStored == true);
    }

    public virtual void ResetHorzAlign()
    {
      horzAlignStored = false;
      HorzAlignChanged();
    }

    //VertAlign
    public virtual VerticalAlignment DefaultVertAlign()
    {
      if (Grid != null)
        return Grid.DefaultVertAlign();
      else
        return VerticalAlignment.Top;
    }

    protected internal virtual void VertAlignChanged()
    {
      if (Grid != null)
        Grid.Invalidate();
    }

    public virtual bool ShouldSerializeVertAlign()
    {
      return (vertAlignStored == true);
    }

    public virtual void ResetVertAlign()
    {
      vertAlignStored = false;
      VertAlignChanged();
    }

    //ReadOnly
    private bool DefaultReadOnly()
    {
      if ((PropAxisBar != null) && (PropAxisBar.PropDescr != null))
        return PropAxisBar.PropDescr.IsReadOnly;
      else
        return false;
    }

    private void OnReadOnlyChanged()
    {
    }

    protected virtual bool ShouldSerializeReadOnly()
    {
      return (readOnlyStored == true);
    }

    public virtual void ResetReadOnly()
    {
      readOnlyStored = false;
      OnReadOnlyChanged();
    }

    //BackColor
    protected virtual void BackColorChanged()
    {
      if (Grid != null)
        Grid.Invalidate();
    }

    public virtual Color DefaultBackColor()
    {
      if (PropAxisBar != null)
        return PropAxisBar.BackColor;
      if (Grid != null)
        return Grid.BackColor;
      else
        return Color.Empty;
    }

    protected virtual bool ShouldSerializeBackColor()
    {
      return (backColorStored == true);
    }

    public virtual void ResetBackColor()
    {
      backColorStored = false;
      BackColorChanged();
    }

    //ForeColor
    protected virtual void ForeColorChanged()
    {
      if (Grid != null)
        Grid.Invalidate();
    }

    public virtual Color DefaultForeColor()
    {
      if (PropAxisBar != null)
        return PropAxisBar.DefaultForeColor();
      else
        return Color.Empty;
    }

    protected internal virtual bool ShouldSerializeForeColor()
    {
      return (foreColorStored == true);
    }

    public virtual void ResetForeColor()
    {
      foreColorStored = false;
      ForeColorChanged();
    }

    //Font
    protected virtual void FontChanged()
    {
      if (PropAxisBar != null)
        PropAxisBar.CellFontChanged();
    }

    public virtual Font DefaultFont()
    {
      if (PropAxisBar != null)
        return PropAxisBar.DefaultFont();
      else
        return null;
    }

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

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

    //IGridRowHeightOptionsOwner

    void IGridRowHeightOptionsOwner.HeightOptionsChanged(GridRowHeightOptions heightOptions)
    {
      if (PropAxisBar != null)
        PropAxisBar.RowHeightAutoExpandChanged();
    }

    bool IGridRowHeightOptionsOwner.HeightOptionsDefaultAutoExpand(GridRowHeightOptions heightOptions)
    {
      if (PropAxisBar != null)
        return PropAxisBar.HeightOptionsDefaultAutoExpand(heightOptions);
      else
        return false;
    }

    int IGridRowHeightOptionsOwner.HeightOptionsDefaultContentHeight(GridRowHeightOptions heightOptions)
    {
      if (PropAxisBar != null)
        return PropAxisBar.HeightOptionsDefaultContentHeight(heightOptions);
      else
        return 1;
    }

    int IGridRowHeightOptionsOwner.HeightOptionsDefaultMaxContentHeight(GridRowHeightOptions heightOptions)
    {
      if (PropAxisBar != null)
        return PropAxisBar.HeightOptionsDefaultMaxContentHeight(heightOptions);
      else
        return 0;
    }

    GridRowHeightUnit IGridRowHeightOptionsOwner.HeightOptionsDefaultUnit(GridRowHeightOptions heightOptions)
    {
      if (PropAxisBar != null)
        return PropAxisBar.HeightOptionsDefaultUnit(heightOptions);
      else
        return GridRowHeightUnit.TextLine;
    }

    //Paint
    protected internal override void HandlePaintEvent(BaseGridCellPaintEventArgs e)
    {
      if (PropAxisBar != null)
        PropAxisBar.HandlePaintEvent((DataAxisGridDataCellPaintEventArgs)e);
      else
        base.HandlePaintEvent(e);
    }

    public override BaseGridCellPaintEventArgs GetCellPaintParams(
        Graphics graphics,
        int colIndex, int rowIndex,
        Rectangle paintRect,
        BasePaintCellStates state,
        int areaColIndex, int areaRowIndex,
        Point inCellMousePos
      )
    {
      DataAxisGridDataCellPaintEventArgs result;
      PropertyAxisBar propAxisBar;
      object listItemBar;
      AxisObjectsByDataColRowIndex(areaColIndex, areaRowIndex, out propAxisBar, out listItemBar);

      if (PropAxisBar != null)
        result = PropAxisBar.GetDataCellPaintParams(this, graphics, colIndex, rowIndex, paintRect, state, areaColIndex, areaRowIndex, inCellMousePos, propAxisBar, listItemBar);
      else
        result = new DataAxisGridDataCellPaintEventArgs(this, graphics, colIndex, rowIndex, paintRect, state, areaColIndex, areaRowIndex, inCellMousePos, propAxisBar, listItemBar);

      var formatParams = CreateDataCellFormatParamsEventArgs(colIndex, rowIndex, areaColIndex, areaRowIndex, paintRect, propAxisBar, listItemBar, 
        DataAxisGridDataCellFormatApplying.DisplayValue);
      OnGetFormatParams(formatParams);
      FillPaintParamsFromFormatParams(result, formatParams);

      result.CellClientRect = GetCellClientRect(propAxisBar, listItemBar, result.CellRect);

      return result;
    }

    protected virtual DataAxisGridDataCellFormatParamsEventArgs CreateDataCellFormatParamsEventArgs(
      int colIndex, int rowIndex, int areaColIndex, int areaRowIndex, Rectangle cellRect, PropertyAxisBar propAxisBar, object listItemBar, 
      DataAxisGridDataCellFormatApplying formatApplying)
    {
      if (PropAxisBar != null)
        return PropAxisBar.CreateDataCellFormatParamsEventArgs(colIndex, rowIndex, areaColIndex, areaRowIndex, cellRect,
          propAxisBar, listItemBar, this, formatApplying);
      else
        return new DataAxisGridDataCellFormatParamsEventArgs(colIndex, rowIndex, areaColIndex, areaRowIndex, cellRect,  
          propAxisBar, listItemBar, this, formatApplying);
    }

    protected virtual void OnGetFormatParams(DataAxisGridDataCellFormatParamsEventArgs formatParams)
    {
      formatParams.HorzAlign = HorzAlign;
      formatParams.VertAlign = VertAlign;
      formatParams.Font = Font;
      formatParams.BackColor = BackColor;
      formatParams.ForeColor = ForeColor;
      formatParams.Padding = Padding;

      if (Grid != null)
        Grid.OnFillDataCellFormatParams(formatParams);
      if (PropAxisBar != null)
        PropAxisBar.OnFillFormatParams(formatParams);
    }

    protected virtual void FillPaintParamsFromFormatParams(DataAxisGridDataCellPaintEventArgs paintParams, DataAxisGridDataCellFormatParamsEventArgs formatParams)
    {
      paintParams.HorzAlign = formatParams.HorzAlign;
      paintParams.VertAlign = formatParams.VertAlign;
      paintParams.Font = formatParams.Font;
      paintParams.BackColor = formatParams.BackColor;
      paintParams.ForeColor = formatParams.ForeColor;
      paintParams.Padding = formatParams.Padding;
    }

    protected internal override void OnPaint(BaseGridCellPaintEventArgs e)
    {
      //base.OnPaint(e);

      var de = (DataAxisGridDataCellPaintEventArgs)e;

      if (de.ListItemBar == null)
        OnPaintVirtualNewCell(de);
      else
        OnPaint(de);
    }

    protected virtual void OnPaintVirtualNewCell(DataAxisGridDataCellPaintEventArgs e)
    {
      PaintBackground(e);
    }

    protected virtual void OnPaint(DataAxisGridDataCellPaintEventArgs e)
    {
      PaintBackground(e);
      PaintForeground(e);
    }

    protected internal override void OnPaintBackground(BaseGridCellPaintEventArgs e)
    {
      PaintBackground((DataAxisGridDataCellPaintEventArgs)e);
    }

    protected virtual void PaintBackground(DataAxisGridDataCellPaintEventArgs e)
    {
      if (!e.IsPaintBackground) return;

      if (PropAxisBar != null)
        PropAxisBar.PaintCellBackground(this, e);
      else
        InternalPaintCellBackground(e);
    }

    internal void InternalPaintCellBackground(DataAxisGridDataCellPaintEventArgs e)
    {
      Color baseColor;

      if (PropAxisBar != null)
        baseColor = PropAxisBar.BackColor;
      else
        baseColor = Grid.BackColor;

      int alpha = 255;
      bool drawSelection = false;

      if (Grid.Background.Visible && baseColor == Grid.BackColor)
      {
        // Paint nothing
      }
      else
      {
        if (Grid.Background.Visible && baseColor.A == 255)
          baseColor = Color.FromArgb(Grid.Background.GridOpacityOptions.CellsOpacity, baseColor);

        using (
          SolidBrush fillBrush = new SolidBrush(baseColor))
        {
          Grid.PaintingFillRectangle(e.Graphics, fillBrush, e.CellRect);
        }
      }

      if (((BasePaintCellStates.Current & e.State) != 0) ||
                ((BasePaintCellStates.RowSelected & e.State) != 0))
      {
        if (Grid.Background.Visible)
          alpha = Grid.Background.GridOpacityOptions.FocusCellOpacity;
        else
          alpha = 255;
        drawSelection = true;
      }

      if (drawSelection)
      {

        if (Grid.IsActiveControl())
          baseColor = SystemColors.Highlight;
        else
          baseColor = SystemColors.ButtonShadow;

        using (
          SolidBrush fillBrush = new SolidBrush(Color.FromArgb(alpha, baseColor)))
        {
          Grid.PaintingFillRectangle(e.Graphics, fillBrush, e.CellRect);
        }
      }
    }

    protected internal override void OnPaintForeground(BaseGridCellPaintEventArgs e)
    {
      PaintForeground((DataAxisGridDataCellPaintEventArgs)e);
    }

    protected virtual void PaintForeground(DataAxisGridDataCellPaintEventArgs e)
    {
      if (!e.IsPaintForeground) return;

      OnPaintClientRect(e);
      OnPaintCustomArea(e);
    }

    private void OnPaintClientRect(DataAxisGridDataCellPaintEventArgs e)
    {
      Rectangle paintRect = e.CellClientRect;
      DataAxisGridDataCellContentPaintEventArgs ce;
      PaintSurround(e, ref paintRect);

      ce = new DataAxisGridDataCellContentPaintEventArgs(e, paintRect);
      PaintContent(ce);
    }

    protected internal virtual void OnPaintCustomArea(DataAxisGridDataCellPaintEventArgs e)
    {
      if (PropAxisBar != null)
        PropAxisBar.HandleDataCellPaintCustomAreaEvent(e);
    }

    protected virtual void PaintSurround(DataAxisGridDataCellPaintEventArgs e, ref Rectangle paintRect)
    {
      PaintLeftEditItems(e, ref paintRect);
      PaintRightEditItems(e, ref paintRect);
    }

    protected virtual void PaintLeftEditItems(DataAxisGridDataCellPaintEventArgs e, ref Rectangle paintRect)
    {

    }

    protected virtual void PaintRightEditItems(DataAxisGridDataCellPaintEventArgs e, ref Rectangle paintRect)
    {
      if (EditButtonAccessible() && EditButton.Visible)
      {
        Rectangle ebRect = paintRect;
        ebRect.X = ebRect.Right - EditButton.Width;
        ebRect.Width = EditButton.Width;
        if (ebRect.Height > EditButton.MaxHeight)
          ebRect.Height = EditButton.MaxHeight;

        bool paintBackground = IsPaintEditItemBackground(EditButton, e, ebRect);
        bool paintForeground = IsPaintEditItemForeground(EditButton, e, ebRect);

        EditItemContextPaintEventArgs eItArg = new EditItemContextPaintEventArgs(ebRect, false, false, false,
          paintBackground, paintForeground, false, e.Graphics, Rectangle.Empty);
        EditButton.Paint(eItArg);
        paintRect.Width = paintRect.Width - ebRect.Width;
      }
    }

    protected virtual bool IsPaintEditItemBackground(EditButton editButton, DataAxisGridDataCellPaintEventArgs e, Rectangle itemRect)
    {
      if (PropAxisBar != null)
        return PropAxisBar.IsPaintEditItemBackground(editButton, e, itemRect);
      else
        return true;
    }

    protected virtual bool IsPaintEditItemForeground(EditButton editButton, DataAxisGridDataCellPaintEventArgs e, Rectangle itemRect)
    {
      if (PropAxisBar != null)
        return PropAxisBar.IsPaintEditItemBackground(editButton, e, itemRect);
      else
        return true;
    }

    protected virtual void PaintContent(DataAxisGridDataCellContentPaintEventArgs e)
    {
      Color fForeColor;

      if ((BasePaintCellStates.Current & e.State) != 0)
        fForeColor = SystemColors.HighlightText;
      else
        fForeColor = Grid.ForeColor;

      string text = GetDisplayText(e.DataColIndex, e.DataRowIndex);
      if (text != null)
      {
        Grid.PaintingDrawText(e.Graphics, text, Grid.Font, e.CellContentRect, fForeColor, HorizontalAlignment.Left, VerticalAlignment.Top, false);
      }
    }

    protected internal override void PrintCell(PrintServiceEventArgs e,
      Rectangle paintRect, int areaColIndex,
      int areaRowIndex,
      PrintServiceEventArgs printContext
        )
    {
      Font drawFont;
      Rectangle textRect;
      Color fForeColor = Color.Black;
      bool wordWrap;
      //DataGridColumn column = Grid.VisibleColumns[dataColIndex];

      string text = GetDisplayText(areaColIndex, areaRowIndex);
      if (text != null)
      {
        drawFont = Font;
        TextFormatFlagsEh flags = TextFormatFlagsEh.None;
        textRect = EhLibUtils.TrimPadding(paintRect, Padding);

        wordWrap = CheckWordWrap(textRect);
        if (wordWrap)
          flags = flags | TextFormatFlagsEh.WordBreak;

        e.PrintText(text, drawFont, textRect, fForeColor, HorzAlign, VertAlign, flags);
      }
    }

    // CellClientRect
    protected internal Rectangle GetCellClientRect(PropertyAxisBar propAxisBar, object listItemBar, Rectangle cellRect)
    {
      DataAxisGridDataCellClientAreaNeededEventArgs de;
      if (PropAxisBar != null)
      {
        de = PropAxisBar.CreateDataCellClientAreaNeededEventArgs(propAxisBar, listItemBar, cellRect, this);
        PropAxisBar.OnDataCellClientAreaNeeded(de);
        return de.CellClientRect;
      }
      else
      {
        return cellRect;
      }
    }

    // Handle mouse
    protected internal override void HandleMouseDownEvent(BaseGridCellMouseEventArgs e)
    {
      if (PropAxisBar != null)
        PropAxisBar.HandleMouseDownEvent(e);
      else
        base.HandleMouseDownEvent(e);
    }

    protected internal virtual void OnMouseDown(DataAxisGridDataCellMouseEventArgs e)
    {
      //if (PropAxisBar != null)
      //  PropAxisBar.OnDataCellMouseDown(this, e);
      //else
      if (IsSelected(e.AreaColIndex, e.AreaRowIndex) &&
          e.Button == MouseButtons.Right
         )
        EhLibUtils.DoNothing();
      else
        base.OnMouseDown(e);
    }

    protected internal override void OnMouseDown(BaseGridCellMouseEventArgs e)
    {
      DataAxisGridDataCellMouseEventArgs de = (DataAxisGridDataCellMouseEventArgs)e;
      Grid.OnDataCellMouseDownEvent(de);
      if (!de.Handled)
        de.Handled = CheckPassMouseDownToEditor(de);
      if (!de.Handled)
        OnMouseDown(de);
    }

    protected internal override void HandleMouseMoveEvent(BaseGridCellMouseEventArgs e)
    {
      if (PropAxisBar != null)
        PropAxisBar.HandleMouseMoveEvent(e);
      else
        base.HandleMouseMoveEvent(e);
    }

    protected internal override void OnMouseMove(BaseGridCellMouseEventArgs e)
    {
      base.OnMouseMove(e);
    }

    protected internal override void HandleMouseUpEvent(BaseGridCellMouseEventArgs e)
    {
      if (PropAxisBar != null)
        PropAxisBar.HandleMouseUpEvent(e);
      else
        base.HandleMouseUpEvent(e);
    }

    protected internal override void HandleMouseClickEvent(BaseGridCellMouseEventArgs e)
    {
      if (PropAxisBar != null)
        PropAxisBar.HandleMouseClickEvent(e);
      else
        base.HandleMouseUpEvent(e);
    }

    protected internal override void HandleMouseDoubleClickEvent(BaseGridCellMouseEventArgs e)
    {
      if (PropAxisBar != null)
        PropAxisBar.HandleMouseDoubleClickEvent(e);
      else
        base.HandleMouseUpEvent(e);
    }

    protected override void HandleMouseEnterEvent(BaseGridCellEnterEventArgs e)
    {
      if (PropAxisBar != null)
        PropAxisBar.HandleMouseEnterEvent(e);
      else
        base.HandleMouseEnterEvent(e);
    }

    protected internal override void OnMouseEnter(BaseGridCellEnterEventArgs e)
    {
      base.OnMouseEnter(e);

      string toolTipText = GetCellToolTipText(e);
      if (!string.IsNullOrEmpty(toolTipText))
      {
        Grid.ShowCellHintTooltip(toolTipText, -1);
      }
    }

    protected override void HandleMouseLeaveEvent(BaseGridCellLeaveEventArgs e)
    {
      if (PropAxisBar != null)
        PropAxisBar.HandleMouseLeaveEvent(e);
      else
        base.HandleMouseLeaveEvent(e);
    }

    protected internal override void OnMouseLeave(BaseGridCellLeaveEventArgs e)
    {
      base.OnMouseLeave(e);
      Grid.HideCellHintToolTip();
    }

    protected override void HandleMouseHoverEvent(BaseGridCellMouseEventArgs e)
    {
      if (PropAxisBar != null)
        PropAxisBar.HandleMouseHoverEvent(e);
      else
        base.HandleMouseHoverEvent(e);
    }

    protected virtual void OnContentClick(DataAxisGridDataCellEventArgs e)
    {
      Grid.OnDataCellContentClick(e);
      if (PropAxisBar != null)
        PropAxisBar.OnDataCellContentClick(e);
    }

    protected virtual bool CheckPassMouseDownToEditor(DataAxisGridDataCellMouseEventArgs de)
    {
      bool result = false;
      bool isInEditItemsRect = false;
      Rectangle editItemsRect;

      editItemsRect = GetLeftEditItemsRect(de.PropAxisBar, de.ListItemBar, de.CellRect);
      if (editItemsRect.Contains(de.InCellX, de.InCellY))
        isInEditItemsRect = true;

      editItemsRect = GetRightEditItemsRect(de.PropAxisBar, de.ListItemBar, de.CellRect);
      if (editItemsRect.Contains(de.InCellX, de.InCellY))
        isInEditItemsRect = true;

      if (isInEditItemsRect)
      {
        Grid.InteractiveFocusCell(de.ColIndex, de.RowIndex, InteractiveActionSource.Mouse);
        if (Grid.EditorMode)
          Grid.HideEditor(true);
        Grid.ShowEditor(true);
        if (Grid.EditorMode)
        {
          Control inEditItem = EhLibUtils.ControlFromScreenPoint(Grid.PointToScreen(de.GridMouseArgs.Location));
          if (inEditItem != null)
          {
            Point mousePos = Grid.PointToScreen(de.GridMouseArgs.Location);
            mousePos = inEditItem.PointToClient(mousePos);
            EhLibUtils.SendMouseDownMessage(inEditItem, mousePos, de.GridMouseArgs.Button);
            result = true;
          }
        }
      }

      return result;
    }

    protected internal override BaseGridCellMouseEventArgs CreateMouseEventArgs(
      int colIndex, int rowIndex, int areaColIndex, int areaRowIndex, int inCellX, int inCellY,
      Rectangle cellRect, MouseEventArgs gridMouseArgs)
    {
      BaseGridCellMouseEventArgs de = null;
      PropertyAxisBar propAxisBar;
      object listItemBar;

      AxisObjectsByDataColRowIndex(areaColIndex, areaRowIndex, out propAxisBar, out listItemBar);

      if (PropAxisBar != null)
        de = PropAxisBar.CreateDataCellMouseEventArgs(
          colIndex, rowIndex, areaColIndex, areaRowIndex, propAxisBar, listItemBar, this, inCellX, inCellY, cellRect, gridMouseArgs);
      else
        de = base.CreateMouseEventArgs(colIndex, rowIndex, areaColIndex, areaRowIndex, inCellX, inCellY, cellRect, gridMouseArgs);

      return de;
    }

    protected internal override BaseGridCellEnterEventArgs CreateCellEnterEventArgs(
      int colIndex, int rowIndex, int areaColIndex, int areaRowIndex, Rectangle cellRect, int leaveColIndex, int leaveRowIndex)
    {
      BaseGridCellEnterEventArgs de = null;
      PropertyAxisBar propAxisBar;
      object listItemBar;

      AxisObjectsByDataColRowIndex(areaColIndex, areaRowIndex, out propAxisBar, out listItemBar);

      if (PropAxisBar != null)
        de = PropAxisBar.CreateDataCellEnterEventArgs(
          colIndex, rowIndex, areaColIndex, areaRowIndex, cellRect, leaveColIndex, leaveRowIndex, propAxisBar, listItemBar, this);
      else
        de = base.CreateCellEnterEventArgs(colIndex, rowIndex, areaColIndex, areaRowIndex, cellRect, leaveColIndex, leaveRowIndex);

      return de;
    }

    protected internal override BaseGridCellLeaveEventArgs CreateCellLeaveEventArgs(
      int colIndex, int rowIndex, int areaColIndex, int areaRowIndex, Rectangle cellRect, int enterColIndex, int enterRowIndex)
    {
      BaseGridCellLeaveEventArgs de = null;
      PropertyAxisBar propAxisBar;
      object listItemBar;

      AxisObjectsByDataColRowIndex(areaColIndex, areaRowIndex, out propAxisBar, out listItemBar);

      if (PropAxisBar != null)
        de = PropAxisBar.CreateDataCellLeaveEventArgs(
          colIndex, rowIndex, areaColIndex, areaRowIndex, cellRect, enterColIndex, enterRowIndex, propAxisBar, listItemBar, this);
      else
        de = base.CreateCellLeaveEventArgs(colIndex, rowIndex, areaColIndex, areaRowIndex, cellRect, enterColIndex, enterRowIndex);

      return de;
    }

    //PullValue
    internal object ProcessPullValue(PropertyAxisBar propAxisBar, object listItemBar)
    {
      DataAxisGridDataCellPullValueEventArgs e;
      if (PropAxisBar != null)
      {
        e = PropAxisBar.CreatePullValueEventArgs(propAxisBar, listItemBar, this);
        PropAxisBar.HandlePullValueEvent(e);
      }
      else
      {
        e = CreatePullValueEventArgs(propAxisBar, listItemBar, this);
      }
      if (!e.Handled)
        OnPullValue(e);

      return e.Value;
    }

    protected virtual void OnPullValue(DataAxisGridDataCellPullValueEventArgs e)
    {
      e.PropAxisBar.OnPullValue(e);
    }

    protected internal virtual DataAxisGridDataCellPullValueEventArgs CreatePullValueEventArgs(
      PropertyAxisBar propAxisBar, object listItemBar, DataAxisGridDataCellMan cellMan)
    {
      return new DataAxisGridDataCellPullValueEventArgs(propAxisBar, listItemBar, cellMan);
    }

    //PushValue
    internal object ProcessPushValue(PropertyAxisBar propAxisBar, object listItemBar, object dataValue)
    {
      DataAxisGridDataCellPushValueEventArgs e;

      if (PropAxisBar != null)
      {
        e = PropAxisBar.CreatePushValueEventArgs(propAxisBar, listItemBar, this);
        e.Value = dataValue;
        PropAxisBar.HandlePushValueEvent(e);
      }
      else
      {
        e = CreatePushValueEventArgs(propAxisBar, listItemBar, this);
        e.Value = dataValue;
      }

      if (!e.Handled)
        OnPushValue(e);

      return e.Value;
    }

    protected virtual void OnPushValue(DataAxisGridDataCellPushValueEventArgs e)
    {
      e.PropAxisBar.OnPushValue(e);
    }

    protected internal virtual DataAxisGridDataCellPushValueEventArgs CreatePushValueEventArgs(
      PropertyAxisBar propAxisBar, object listItemBar, DataAxisGridDataCellMan cellMan)
    {
      return new DataAxisGridDataCellPushValueEventArgs(propAxisBar, listItemBar, cellMan);
    }

    //ParseValue
    internal object ProcessParseValue(PropertyAxisBar propAxisBar, object listItemBar, object value)
    {
      DataAxisGridDataCellParseValueEventArgs e;

      if (PropAxisBar != null)
      {
        e = PropAxisBar.CreateParseValueEventArgs(propAxisBar, listItemBar, this, value);
        PropAxisBar.HandleParseValueEvent(e);
      }
      else
      {
        e = CreateParseValueEventArgs(propAxisBar, listItemBar, this, value);
      }

      if (!e.Handled)
        OnParseValue(e);

      return e.OutValue;
    }

    protected virtual void OnParseValue(DataAxisGridDataCellParseValueEventArgs e)
    {
      e.PropAxisBar.OnParseValue(e);
    }

    protected internal virtual DataAxisGridDataCellParseValueEventArgs CreateParseValueEventArgs(
      PropertyAxisBar propAxisBar, object listItemBar, DataAxisGridDataCellMan cellMan, object inValue)
    {
      return new DataAxisGridDataCellParseValueEventArgs(propAxisBar, listItemBar, cellMan, inValue);
    }

    //Other 
    protected internal virtual DataAxisGridDataCellEventArgs CreateDataCellEventArgs(
      int colIndex, int rowIndex, int areaColIndex, int areaRowIndex, Rectangle cellRect,
      PropertyAxisBar propAxisBar, object listItemBar, DataAxisGridDataCellMan cell
      )
    {
      return new DataAxisGridDataCellEventArgs(colIndex, rowIndex, areaColIndex, areaRowIndex, cellRect, propAxisBar, listItemBar, cell);
    }

    protected internal override BaseGridCellEventArgs CreateCellEventArgs(
      int colIndex, int rowIndex, int areaColIndex, int areaRowIndex, Rectangle cellRect)
    {
      BaseGridCellEventArgs de = null;
      PropertyAxisBar propAxisBar;
      object listItemBar;

      AxisObjectsByDataColRowIndex(areaColIndex, areaRowIndex, out propAxisBar, out listItemBar);

      if (PropAxisBar != null)
        de = PropAxisBar.CreateDataCellEventArgs(colIndex, rowIndex, areaColIndex, areaRowIndex, cellRect, propAxisBar, listItemBar, this);
      else
        de = CreateDataCellEventArgs(colIndex, rowIndex, areaColIndex, areaRowIndex, cellRect, propAxisBar, listItemBar, this);

      return de;
    }

    public virtual void AxisObjectsByDataColRowIndex(int dataColIndex, int dataRowIndex, out PropertyAxisBar propAxisBar, out object listItemBar)
    {
      if (PropAxisBar != null)
        PropAxisBar.AxisObjectsByDataColRowIndex(dataColIndex, dataRowIndex, out propAxisBar, out listItemBar);
      else
      {
        propAxisBar = null;
        listItemBar = null;
      }
    }

    protected internal virtual int CalcDefaultRowHeight()
    {
      int th;

      th = EhLibUtils.GetFontHeight(Font);
      th = th + Padding.Top + Padding.Bottom;
      return th;
    }

    protected internal virtual int CalcCellHeight(PropertyAxisBar propAxisBar, object listItemBar, int cellWidth)
    {
      int th;

      if (HeightOptions.Unit == GridRowHeightUnit.TextLine)
      {
        th = EhLibUtils.GetFontHeight(Font) * HeightOptions.ContentHeight;
        th = th + Padding.Top + Padding.Bottom;
      }
      else
      {
        th = HeightOptions.ContentHeight;
        th = th + Padding.Top + Padding.Bottom;
      }

      return th;
    }

    protected internal virtual int ProcessCalcCellHeight(PropertyAxisBar propAxisBar, object listItemBar, int cellWidth)
    {
      int th;
      int rowMaxHeight;

      th = CalcCellHeight(propAxisBar, listItemBar, cellWidth);

      if (HeightOptions.MaxContentHeight > 0)
      {
        if (HeightOptions.Unit == GridRowHeightUnit.TextLine)
        {
          int fh = EhLibUtils.GetFontHeight(Font);
          rowMaxHeight = fh * HeightOptions.MaxContentHeight;
          rowMaxHeight = rowMaxHeight + Padding.Top + Padding.Bottom;
        }
        else
        {
          rowMaxHeight = HeightOptions.MaxContentHeight;
          rowMaxHeight = rowMaxHeight + Padding.Top + Padding.Bottom;
        }

        if (th > rowMaxHeight)
          th = rowMaxHeight;
      }

      return th;
    }

    public override string GetDisplayText(int areaColIndex, int areaRowIndex)
    {
      PropertyAxisBar propAxisBar;
      object listItemBar;
      AxisObjectsByDataColRowIndex(areaColIndex, areaRowIndex, out propAxisBar, out listItemBar);

      return GetDisplayText(propAxisBar, listItemBar);
    }

    public virtual string GetDisplayText(PropertyAxisBar propAxisBar, object listItemBar)
    {
      if (PropAxisBar != null && listItemBar != null)
      {
        object val = PropAxisBar.GetValue(listItemBar);
        return GetValueDisplayText(propAxisBar, val);
      }
      else
        return null;
    }

    public virtual string GetValueDisplayText(PropertyAxisBar propAxisBar, object value)
    {
      Type dataType;

      if (propAxisBar != null)
        dataType = propAxisBar.DataType;
      else
        dataType = null;

      TypeConverter srcConverter = null;
      TypeConverter targetConverter = TypeDescriptor.GetConverter(typeof(string));
      if (dataType != null)
        srcConverter = TypeDescriptor.GetConverter(dataType);
      object result = EhLibManager.DefaultEhLibManager.ValueConverter.FormatValue(
        value, typeof(string), srcConverter, targetConverter, "", null, "", null);
      return result.ToString();
    }

    public bool CanModify(int areaColIndex, int areaRowIndex)
    {
      PropertyAxisBar propAxisBar;
      object listItemBar;
      AxisObjectsByDataColRowIndex(areaColIndex, areaRowIndex, out propAxisBar, out listItemBar);

      return CanModify(propAxisBar, listItemBar);
    }

    public virtual bool CanModify(PropertyAxisBar propAxisBar, object listItemBar)
    {
      if (PropAxisBar != null && listItemBar != null)
      {
        return !ReadOnly && !Grid.ReadOnly;
      }
      else
        return false;
    }

    protected internal override void OnGetCellBorderParams(BaseGridCellBorderEventArgs e)
    {
      base.OnGetCellBorderParams(e);
      if (PropAxisBar != null)
        PropAxisBar.OnGetDataCellBorderParams(e);
    }

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

    private void EditItemChanged(object sender, EventArgs e)
    {
      EditButtonChanged();
    }

    protected virtual void EditButtonChanged()
    {
      if (Grid != null)
        Grid.Invalidate();
    }

    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 virtual EditButton CreateDropDownButton()
    {
      return new EditButton();
    }

    public override void GridCellPosToAreaCellPos(int gridColIndex, int gridRowIndex, out int areaColIndex, out int areaRowIndex)
    {
      areaColIndex = gridColIndex;
      areaRowIndex = gridRowIndex;

      if (PropAxisBar != null)
        PropAxisBar.GridCellPosToDataCellPos(gridColIndex, gridRowIndex, out areaColIndex, out areaRowIndex);
    }

    public override void AreaCellPosToGridCellPos(int areaColIndex, int areaRowIndex, out int gridColIndex, out int gridRowIndex)
    {
      gridColIndex = areaColIndex;
      gridRowIndex = areaRowIndex;

      if (PropAxisBar != null)
        PropAxisBar.DataCellPosToGridCellPos(areaColIndex, areaRowIndex, out gridColIndex, out gridRowIndex);
    }

    protected virtual Rectangle GetLeftEditItemsRect(PropertyAxisBar propAxisBar, object listItemBar, Rectangle cellRect)
    {
      return Rectangle.Empty;
    }

    protected virtual Rectangle GetRightEditItemsRect(PropertyAxisBar propAxisBar, object listItemBar, Rectangle cellRect)
    {
      Rectangle result = Rectangle.Empty;

      if (EditButtonAccessible() && EditButton.Visible)
      {
        result.X = cellRect.Width - EditButton.Width;
        result.Width = EditButton.Width;
        result.Y = 0;
        result.Height = cellRect.Height;
      }

      return result;
    }

    protected internal override bool IsSelected(int areaColIndex, int areaRowIndex)
    {
      if (PropAxisBar != null)
        return PropAxisBar.IsDataCellSelected(areaColIndex, areaRowIndex);
      else
        return false;
    }

    //protected internal override BaseGridCellCustomAreaMeasuresEventArgs CreateCellCustomAreaMeasuresEventArgs(
    //  int colIndex, int rowIndex, int areaColIndex, int areaRowIndex, CellCustomAreaMeasures areaMeasures)
    //{
    //  PropertyAxisBar propAxisBar;
    //  object listItemBar;

    //  AxisObjectsByDataColRowIndex(areaColIndex, areaRowIndex, out propAxisBar, out listItemBar);

    //  if (PropAxisBar != null)
    //    return PropAxisBar.CreateCellCustomAreaMeasuresEventArgs(colIndex, rowIndex, areaColIndex, areaRowIndex, propAxisBar, listItemBar, areaMeasures);
    //  else 
    //    return base.CreateCellCustomAreaMeasuresEventArgs(colIndex, rowIndex, areaColIndex, areaRowIndex, areaMeasures);
    //}

    //protected internal override void OnCellCustomAreaMeasuresNeeded(BaseGridCellCustomAreaMeasuresEventArgs e)
    //{
    //  if (PropAxisBar != null)
    //    PropAxisBar.OnCellCustomAreaMeasuresNeeded(e);
    //}

    protected internal override BaseGridCellContextMenuStripNeededEventArgs CreateCellContextMenuStripNeededEventArgs(
      int colIndex, int rowIndex, int areaColIndex, int areaRowIndex, int inCellX, int inCellY,
      Rectangle cellRect, int MousePosX, int MousePosY)
    {
      DataAxisGridDataCellContextMenuStripNeededEventArgs de = null;
      PropertyAxisBar propAxisBar;
      object listItemBar;

      AxisObjectsByDataColRowIndex(areaColIndex, areaRowIndex, out propAxisBar, out listItemBar);

      if (PropAxisBar != null)
        de = PropAxisBar.CreateCellContextMenuStripNeededEventArgs(this, colIndex, rowIndex, areaColIndex, areaRowIndex, inCellX, inCellY, cellRect, MousePosX, MousePosY, propAxisBar, listItemBar);
      else
        de = CreateCellContextMenuStripNeededEventArgs(colIndex, rowIndex, areaColIndex, areaRowIndex, inCellX, inCellY, cellRect, MousePosX, MousePosY, propAxisBar, listItemBar);

      return de;
    }

    protected virtual DataAxisGridDataCellContextMenuStripNeededEventArgs CreateCellContextMenuStripNeededEventArgs(
      int colIndex, int rowIndex, int areaColIndex, int areaRowIndex, int inCellX, int inCellY,
      Rectangle cellRect, int MousePosX, int MousePosY, PropertyAxisBar propAxisBar, object listItemBar)
    {
      return new DataAxisGridDataCellContextMenuStripNeededEventArgs(this, colIndex, rowIndex, areaColIndex, areaRowIndex, inCellX, inCellY,
        cellRect, MousePosX, MousePosY, propAxisBar, listItemBar);
    }

    protected internal override void OnContextMenuStripNeeded(BaseGridCellContextMenuStripNeededEventArgs e)
    {
      var age = e as DataAxisGridDataCellContextMenuStripNeededEventArgs;
      if (age != null)
      {
        Grid.OnDataCellContextMenuStripNeeded(age);
      }
      else
      {
        base.OnContextMenuStripNeeded(e);
      }
    }

    protected internal override void HandleMouseContextMenuStripNeededEvent(BaseGridCellContextMenuStripNeededEventArgs e)
    {
      var age = e as DataAxisGridDataCellContextMenuStripNeededEventArgs;

      Grid.HandleDataCellMouseContextMenuStripNeededEvent(age);

      if (age.PropAxisBar != null)
        PropAxisBar.HandleMouseContextMenuStripNeededEvent(age);
      else
        base.HandleMouseContextMenuStripNeededEvent(e);
    }

    protected internal virtual int GetOptimalWidth(int colIndex, int rowIndex, int dataColIndex, int dataRowIndex, PropertyAxisBar propAxisBar, object listItemBar)
    {
      //int result;
      //result = GetOptimalCellStandartAreaWidth(colIndex, rowIndex, dataColIndex, dataRowIndex, listItemBar) +
      //         GetOptimalCellCustomAreaWidth(colIndex, rowIndex, dataColIndex, dataRowIndex, listItemBar);
      //return result;

      var e = CreateDataDataCellOptimalWidthNeededEventArgs(propAxisBar, listItemBar);
      ProcessCellOptimalWidthNeeded(e);
      return e.OptimalWidth;
    }

    protected virtual DataAxisGridDataCellOptimalWidthNeededEventArgs CreateDataDataCellOptimalWidthNeededEventArgs(
      PropertyAxisBar propAxisBar, object listItemBar)
    {
      if (propAxisBar != null)
        return propAxisBar.CreateDataCellOptimalWidthNeededEventArgs(propAxisBar, listItemBar, this);
      else
        return new DataAxisGridDataCellOptimalWidthNeededEventArgs(propAxisBar, listItemBar, this);
    }

    private void ProcessCellOptimalWidthNeeded(DataAxisGridDataCellOptimalWidthNeededEventArgs e)
    {
      OnCellOptimalWidthNeeded(e);
      HandleCellOptimalWidthNeededEvent(e);
    }

    private void HandleCellOptimalWidthNeededEvent(DataAxisGridDataCellOptimalWidthNeededEventArgs e)
    {
      if (e.PropAxisBar != null)
        e.PropAxisBar.HandleCellOptimalWidthNeededEvent(e);
    }

    protected virtual void OnCellOptimalWidthNeeded(DataAxisGridDataCellOptimalWidthNeededEventArgs e)
    {
      e.OptimalWidth = GetOptimalCellStandartAreaWidth(0, 0, 0, 0, e.ListItemBar);
    }

    protected internal virtual int GetOptimalCellContentWidth(int colIndex, int rowIndex, int dataColIndex, int dataRowIndex, object listItemBar)
    {
      int result;
      string text = GetDisplayText(PropAxisBar, listItemBar);
      result = (int)EhLibUtils.MeasureText(EhLibUtils.DisplayGraphicsCash, text, Font).Width;
      return result;
    }

    protected internal virtual int GetOptimalCellStandartAreaWidth(int colIndex, int rowIndex, int dataColIndex, int dataRowIndex, object listItemBar)
    {
      int result = GetOptimalCellContentWidth(colIndex, rowIndex, dataColIndex, dataRowIndex, listItemBar);
      result = result + Padding.Left + Padding.Right + Math.Max(Padding.Left, Padding.Right);
      if (EditButton.Visible)
        result = result + EditButton.Width;
      return result;
    }

    //protected internal virtual int GetOptimalCellCustomAreaWidth(int colIndex, int rowIndex, int dataColIndex, int dataRowIndex, object listItemBar)
    //{
    //  var custAreaMeasures = new CellCustomAreaMeasures();
    //  SetCellCustomAreaMeasures(colIndex, rowIndex, dataColIndex, dataRowIndex, custAreaMeasures);
    //  return custAreaMeasures.LeftSide.Width + custAreaMeasures.RightSide.Width;
    //}

    protected virtual string GetCellToolTipText(BaseGridCellEventArgs e)
    {
      PropertyAxisBar propAxisBar;
      object listItemBar;
      AxisObjectsByDataColRowIndex(e.AreaColIndex, e.AreaRowIndex, out propAxisBar, out listItemBar);

      DataAxisGridDataCellToolTipInfoEventArgs de = null;
      if (PropAxisBar != null && listItemBar != null)
      {
        de = PropAxisBar.CreateToolTipInfoEventArgs(propAxisBar, listItemBar, this);
        PropAxisBar.HandleToolTipInfoEvent(de);
        return de.ToolTipText;
      }
      else
      {
        return null;
      }

    }

    protected internal virtual bool CheckWordWrap(Rectangle paintRect)
    {
      return false;
    }
    #endregion

  }
}
