//------------------------------------------------------------------------------
// <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 delegate void DataGridColumnWidthChangedEventHandler(object sender, EventArgs e);

  public enum DataGridColumnFrozenState
  {
    None, ToLeftSide, ToRightSide
  }

  [Designer("EhLib.Design.DataGridColumnDesigner" + EhLibUtils.EhLibDesignDesignerVersionInfo)]
  [DesignerCategory("Code")]
  [TypeConverter(typeof(ExpandableObjectConverter))]
  [DesignTimeVisible(false)]
  [ToolboxItem(false)]
  public class DataGridColumn : PropertyAxisBar, IGridLineHost, IMultiTitleNodeProvider
  //public class DataGridColumn
  {

    #region private consts
    //private static readonly object EventKeyDataCellCustomAreaMeasuresNeeded = new object();
    private static readonly object EventKeyDataCellObjectNeededEventHandler = new object();
    private static readonly object EventKeyDataCellContentClick = new object();
    private static readonly object EventKeyColumnWidthChanged = new object();
    private static readonly object EventKeyDataCellPaint = new object();
    private static readonly object EventKeyDataCellPaintCustomArea = new object();
    private static readonly object EventKeyDataCellMouseDown = new object();
    private static readonly object EventKeyDataCellMouseMove = new object();
    private static readonly object EventKeyDataCellMouseUp = new object();
    private static readonly object EventKeyDataCellMouseClick = new object();
    private static readonly object EventKeyDataCellMouseDoubleClick = new object();
    private static readonly object EventKeyDataCellMouseEnter = new object();
    private static readonly object EventKeyDataCellMouseLeave = new object();
    private static readonly object EventKeyDataCellMouseHover = new object();
    private static readonly object EventKeyDataCellQueryFillFormatParams = new object();
    private static readonly object EventKeyDataCellPullValue = new object();
    private static readonly object EventKeyDataCellPushValue = new object();
    private static readonly object EventKeyDataCellParseValue = new object();
    private static readonly object EventKeyDataCellToolTipInfo = new object();
    private static readonly object EventKeyDataCellContextMenuStripNeeded = new object();
    private static readonly object EventKeyDataCellClientAreaNeeded = new object();
    private static readonly object EventKeyDataCellOptimalWidthNeeded = new object();
    private static readonly object EventKeyDataCellValuesAreDuplicatesStateNeeded = new object();
    #endregion

    #region privates
    private int defaultWidth = 64;
    private readonly DataGridColumnFooter footer;
    private int width = -1;

    private readonly DataGridColumnRowCells rowCells;
    private int minWidth;
    private int maxWidth;

    //private Color backColor = Color.Empty;
    private DataGridColumnFrozenState frozen = DataGridColumnFrozenState.None;
    private readonly GridLine vertLine;
    //private DataGridColumnTitle title;

    internal bool WidthStored;
    internal bool SelectedInternal;
    internal float FillWeightInternal = 100;
    internal bool OmitFromWidthCalculation;
    private bool mergeDuplicates;
    private DataGridColumnMergeDuplicatesList mergeDuplicatesList;

    //internal int DisplayIndexQuery = -1;
    //internal int DisplayIndexQueryIndex = -1;
    #endregion

    public DataGridColumn()
    {
      //this.title = new DataGridColumnTitle(this);
      this.footer = new DataGridColumnFooter(this);
      //this.roFooters = new DataGridColumnFooters(footers);
      this.rowCells = new DataGridColumnRowCells(this);
      this.vertLine = new GridLine(this);
    }

    #region design-time properties
    [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
    public DataGridColumnFooter Footer
    {
      get { return footer; }
    }

    [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
    public new DataGridColumnTitle Title
    {
      get
      {
        return (DataGridColumnTitle)base.Title;
      }
    }

    public int Width
    {
      get
      {
        if (WidthStored)
          return width;
        else
          return DefaultWidth;
      }
      set
      {
        if ((WidthStored == false) || (width != value))
        {
          WidthStored = true;
          value = AdjustWidth(value);
          width = value;
          OnWidthChanged();
        }
      }
    }

    [DefaultValue(0)]
    public int MinWidth
    {
      get
      {
        return minWidth;
      }
      set
      {
        if (minWidth != value)
        {
          minWidth = value;
          if ((Grid != null) && (!Grid.InInitialization))
            width = AdjustWidth(value);
          OnWidthChanged();
        }
      }
    }

    [DefaultValue(0)]
    public int MaxWidth
    {
      get
      {
        return maxWidth;
      }
      set
      {
        if (maxWidth != value)
        {
          maxWidth = value;
          if ((Grid != null) && (!Grid.InInitialization))
            width = AdjustWidth(value);
          OnWidthChanged();
        }
      }
    }

    [DefaultValue(100F)]
    [Browsable(false)]
    public float FillWeight
    {
      get
      {
        return FillWeightInternal;
      }
      set
      {
        // ReSharper disable once CompareOfFloatsByEqualityOperator
        if (value != FillWeightInternal)
        {
          FillWeightInternal = value;
          FillWeightChanged();
        }
      }
    }

    [DefaultValue(DataGridColumnFrozenState.None)]
    public DataGridColumnFrozenState Frozen
    {
      get
      {
        return frozen;
      }

      set
      {
        if (value != frozen)
        {
          frozen = value;
          if (Grid != null)
            Grid.ColumnFrozenChanged(this, value);
        }
      }
    }

    [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
    public GridLine VertLine
    {
      get
      {
        return vertLine;
      }
    }

    [DefaultValue(false)]
    public bool MergeDuplicates
    {
      get
      {
        return mergeDuplicates;
      }
      set
      {
        if (value != mergeDuplicates)
        {
          mergeDuplicates = value;
          if (mergeDuplicates)
            MergeDuplicatesList.ListIsObsolete();
          if (Grid != null)
          {
            Grid.ColumnMergeDuplicatesChanged(this, value);
          }
        }
      }
    }

    DataGridTitleNodeType IMultiTitleNodeProvider.NodeType
    {
      get
      {
        return Title.TitleNode.NodeType;
      }
    }

    DataGridColumnTitle IMultiTitleNodeProvider.ColumnTitle
    {
      get
      {
        return GetMultiTitleColumnTitle();
      }
    }

    DataGridSuperTitle IMultiTitleNodeProvider.SuperTitle
    {
      get
      {
        return GetMultiTitleSuperTitle();
      }
    }
    #endregion

    #region events
    public event DataGridDataCellObjectNeededEventHandler DataCellObjectNeeded
    {
      add { this.Events.AddHandler(EventKeyDataCellObjectNeededEventHandler, value); }
      remove { this.Events.RemoveHandler(EventKeyDataCellObjectNeededEventHandler, value); }
    }

    public event DataGridDataCellEventHandler CellContentClick
    {
      add { this.Events.AddHandler(EventKeyDataCellContentClick, value); }
      remove { this.Events.RemoveHandler(EventKeyDataCellContentClick, value); }
    }

    public event DataGridDataCellObjectNeededEventHandler QueryDataCellObject
    {
      add { this.Events.AddHandler(EventKeyDataCellObjectNeededEventHandler, value); }
      remove { this.Events.RemoveHandler(EventKeyDataCellObjectNeededEventHandler, value); }
    }

    public event EventHandler<DataGridColumnEventArgs> WidthChanged
    {
      add
      {
        this.Events.AddHandler(EventKeyColumnWidthChanged, value);
      }

      remove
      {
        this.Events.RemoveHandler(EventKeyColumnWidthChanged, value);
      }
    }

    public event EventHandler<DataGridDataCellPaintEventArgs> DataCellPaint
    {
      add
      {
        this.Events.AddHandler(EventKeyDataCellPaint, value);
      }
      remove
      {
        this.Events.RemoveHandler(EventKeyDataCellPaint, value);
      }
    }

    public event EventHandler<DataGridDataCellPaintEventArgs> DataCellPaintCustomArea
    {
      add
      {
        this.Events.AddHandler(EventKeyDataCellPaintCustomArea, value);
      }
      remove
      {
        this.Events.RemoveHandler(EventKeyDataCellPaintCustomArea, value);
      }
    }

    //public event EventHandler<DataGridDataCellCustomAreaMeasuresNeededEventArgs> DataCellCustomAreaMeasuresNeeded
    //{
    //  add
    //  {
    //    this.Events.AddHandler(EventKeyDataCellCustomAreaMeasuresNeeded, value);
    //  }
    //  remove
    //  {
    //    this.Events.RemoveHandler(EventKeyDataCellCustomAreaMeasuresNeeded, value);
    //  }
    //}

    public event EventHandler<DataGridDataCellMouseEventArgs> DataCellMouseDown
    {
      add
      {
        this.Events.AddHandler(EventKeyDataCellMouseDown, value);
      }
      remove
      {
        this.Events.RemoveHandler(EventKeyDataCellMouseDown, value);
      }
    }

    public event EventHandler<DataGridDataCellMouseEventArgs> DataCellMouseMove
    {
      add
      {
        this.Events.AddHandler(EventKeyDataCellMouseMove, value);
      }
      remove
      {
        this.Events.RemoveHandler(EventKeyDataCellMouseMove, value);
      }
    }

    public event EventHandler<DataGridDataCellMouseEventArgs> DataCellMouseUp
    {
      add
      {
        this.Events.AddHandler(EventKeyDataCellMouseUp, value);
      }
      remove
      {
        this.Events.RemoveHandler(EventKeyDataCellMouseUp, value);
      }
    }

    public event EventHandler<DataGridDataCellMouseEventArgs> DataCellMouseClick
    {
      add
      {
        this.Events.AddHandler(EventKeyDataCellMouseClick, value);
      }
      remove
      {
        this.Events.RemoveHandler(EventKeyDataCellMouseClick, value);
      }
    }

    public event EventHandler<DataGridDataCellMouseEventArgs> DataCellMouseDoubleClick
    {
      add
      {
        this.Events.AddHandler(EventKeyDataCellMouseDoubleClick, value);
      }
      remove
      {
        this.Events.RemoveHandler(EventKeyDataCellMouseDoubleClick, value);
      }
    }

    public event EventHandler<DataGridDataCellEnterEventArgs> DataCellMouseEnter
    {
      add
      {
        this.Events.AddHandler(EventKeyDataCellMouseEnter, value);
      }
      remove
      {
        this.Events.RemoveHandler(EventKeyDataCellMouseEnter, value);
      }
    }

    public event EventHandler<DataGridDataCellLeaveEventArgs> DataCellMouseLeave
    {
      add
      {
        this.Events.AddHandler(EventKeyDataCellMouseLeave, value);
      }
      remove
      {
        this.Events.RemoveHandler(EventKeyDataCellMouseLeave, value);
      }
    }

    public event EventHandler<DataGridDataCellMouseEventArgs> DataCellMouseHover
    {
      add
      {
        this.Events.AddHandler(EventKeyDataCellMouseHover, value);
      }
      remove
      {
        this.Events.RemoveHandler(EventKeyDataCellMouseHover, value);
      }
    }

    public event EventHandler<DataGridDataCellFormatParamsEventArgs> DataCellQueryFillFormatParams
    {
      add
      {
        this.Events.AddHandler(EventKeyDataCellQueryFillFormatParams, value);
      }
      remove
      {
        this.Events.RemoveHandler(EventKeyDataCellQueryFillFormatParams, value);
      }
    }

    public event EventHandler<DataGridDataCellPullValueEventArgs> DataCellPullValue
    {
      add
      {
        this.Events.AddHandler(EventKeyDataCellPullValue, value);
      }
      remove
      {
        this.Events.RemoveHandler(EventKeyDataCellPullValue, value);
      }
    }

    public event EventHandler<DataGridDataCellPushValueEventArgs> DataCellPushValue
    {
      add
      {
        this.Events.AddHandler(EventKeyDataCellPushValue, value);
      }
      remove
      {
        this.Events.RemoveHandler(EventKeyDataCellPushValue, value);
      }
    }

    public event EventHandler<DataGridDataCellParseValueEventArgs> DataCellParseValue
    {
      add
      {
        this.Events.AddHandler(EventKeyDataCellParseValue, value);
      }
      remove
      {
        this.Events.RemoveHandler(EventKeyDataCellParseValue, value);
      }
    }

    public event EventHandler<DataGridDataCellToolTipInfoEventArgs> DataCellToolTipInfoNeeded
    {
      add
      {
        this.Events.AddHandler(EventKeyDataCellToolTipInfo, value);
      }
      remove
      {
        this.Events.RemoveHandler(EventKeyDataCellToolTipInfo, value);
      }
    }

    public event EventHandler<DataGridDataCellContextMenuStripNeededEventArgs> DataCellContextMenuStripNeeded
    {
      add
      {
        this.Events.AddHandler(EventKeyDataCellContextMenuStripNeeded, value);
      }
      remove
      {
        this.Events.RemoveHandler(EventKeyDataCellContextMenuStripNeeded, value);
      }
    }

    public event EventHandler<DataGridDataCellClientAreaNeededEventArgs> DataCellClientAreaNeeded
    {
      add
      {
        this.Events.AddHandler(EventKeyDataCellClientAreaNeeded, value);
      }
      remove
      {
        this.Events.RemoveHandler(EventKeyDataCellClientAreaNeeded, value);
      }
    }

    public event EventHandler<DataGridDataCellOptimalWidthNeededEventArgs> DataCellOptimalWidthNeeded
    {
      add
      {
        this.Events.AddHandler(EventKeyDataCellOptimalWidthNeeded, value);
      }
      remove
      {
        this.Events.RemoveHandler(EventKeyDataCellOptimalWidthNeeded, value);
      }
    }

    public event EventHandler<DataGridValuesAreDuplicatesStateNeededEventArgs> ValuesAreDuplicatesStateNeeded
    {
      add
      {
        this.Events.AddHandler(EventKeyDataCellValuesAreDuplicatesStateNeeded, value);
      }
      remove
      {
        this.Events.RemoveHandler(EventKeyDataCellValuesAreDuplicatesStateNeeded, value);
      }
    }
    #endregion

    #region runtime properties
    //[Browsable(false)]
    //[EditorBrowsable(EditorBrowsableState.Advanced)]
    //[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
    //public virtual DataGridBaseCell TemplateCell
    //{
    //  get { return this.dataCell; }
    //  set { this.dataCell = value; }
    //}

    [Browsable(false)]
    public new DataGridEh Grid
    {
      get
      {
        return (DataGridEh)base.Grid;
      }

      protected internal set
      {
        base.Grid = value;
      }
    }

    [Browsable(false)]
    public bool IsDataBound
    {
      get { return (PropDescr != null); }
    }

    [DefaultValue(false)]
    [Browsable(false)]
    public bool Selected
    {
      get
      {
        if ((Grid != null) &&
            (Grid.Selection.SelectionType == GridSelectionType.All))
          return true;
        else
          return SelectedInternal;
      }
      set
      {
        if (value != SelectedInternal)
        {
          if (Grid == null)
            SelectedInternal = value;
          else
            Grid.Selection.AddSelectedColumn(this, value);
        }
      }
    }

    [Browsable(false)]
    public DataGridColumnRowCells RowCells
    {
      get
      {
        return rowCells;
      }
    }

    /// <summary>
    /// The cell for a new virtual row.
    /// New virtual row - is a row that does not have an appropriate entry in the DatGrid.Rows collection.
    /// </summary>
    [Browsable(false)]
    public virtual BaseGridCellManager NewVirtualRowCell
    {
      get
      {
        return Grid.EmptyDataCell;
      }
    }

    [Browsable(false)]
    public virtual int DefaultWidth
    {
      get { return defaultWidth; }
      internal set { defaultWidth = value; }
    }
    #endregion

    #region internal fields and properties
    internal int WidthInternal
    {
      set
      {
        this.width = value;
      }
    }

    internal DataGridColumnMergeDuplicatesList MergeDuplicatesList
    {
      get
      {
        if (mergeDuplicatesList == null)
          mergeDuplicatesList = new DataGridColumnMergeDuplicatesList(this);
        return mergeDuplicatesList;
      }
    }
    #endregion

    #region Methods
    //Width
    private bool ShouldSerializeWidth()
    {
      return (WidthStored == true);
    }

    public void ResetWidth()
    {
      WidthStored = false;
      OnWidthChanged();
    }

    private void OnWidthChanged()
    {
      if (Grid != null)
        Grid.OnColumnWidthChanged(this);

      var eh = this.Events[EventKeyColumnWidthChanged] as EventHandler<DataGridColumnEventArgs>;
      if (eh != null)
      {
        eh(this, new DataGridColumnEventArgs(this));
      }
    }

    internal virtual int CalcDefaultWidth()
    {
      int dataRowIndex;
      int rowLength;
      int rowWidth, maxRowWidth;

      SizeF sf;

      if (Grid == null) return 100;

      sf = EhLibUtils.MeasureText(EhLibUtils.DisplayGraphicsCash, "0", Grid.Font);

      rowLength = 0;
      dataRowIndex = 0;

      if (Grid.AutoSizeColumnOptions.ConsiderTitle)
        maxRowWidth = Title.CalcDefaultWidth();
      else
        maxRowWidth = (int)EhLibUtils.MeasureText(EhLibUtils.DisplayGraphicsCash, "0", Grid.Font).Width;

      DataGridColumnAutoSizeConsiderRowsMode considerDataCell = Grid.AutoSizeColumnOptions.ConsiderRowsMode;
      int considerRowCount;
      if (considerDataCell == DataGridColumnAutoSizeConsiderRowsMode.ConsiderRowCount)
        considerRowCount = Grid.AutoSizeColumnOptions.ConsiderRowCount;
      else if (considerDataCell == DataGridColumnAutoSizeConsiderRowsMode.VisibleRows)
        considerRowCount = Grid.VisibleRowCount;
      else
        considerRowCount = Grid.Rows.Count;

      if (considerDataCell != DataGridColumnAutoSizeConsiderRowsMode.None)
      {
        foreach (DataGridRow row in Grid.VisibleRows)
        {
          int colIndex, rowIndex;

          BaseGridCellManager cell = GetRowCellMan(row);
          cell.AreaCellPosToGridCellPos(VisibleIndex, row.VisibleIndex, out colIndex, out rowIndex);

          DataAxisGridDataCellMan dataCell = cell as DataAxisGridDataCellMan;
          if (/*VisibleIndex >= 0 && */dataCell != null)
            rowWidth = dataCell.GetOptimalWidth(colIndex, rowIndex, VisibleIndex, row.VisibleIndex, this, row);
          else
          {
            string text = GetDisplayText(row);
            rowWidth = (int)EhLibUtils.MeasureText(EhLibUtils.DisplayGraphicsCash, text, Grid.Font).Width;
          }

          if (rowWidth > maxRowWidth)
            maxRowWidth = rowWidth;
          dataRowIndex++;

          if (dataRowIndex > considerRowCount) break;
        }

      }

      if ((Grid.AutoSizeColumnOptions.MaxAutoWidth > 0) &&
          (maxRowWidth > Grid.AutoSizeColumnOptions.MaxAutoWidth))
      {
        maxRowWidth = Grid.AutoSizeColumnOptions.MaxAutoWidth;
      }

      if (maxRowWidth == 0)
        return (int)sf.Width * rowLength;
      else
        return maxRowWidth;

      //return 100;
    }

    public int AdjustWidth(int value)
    {
      if (value < MinWidth)
        value = MinWidth;
      if ((MaxWidth > 0) && (value > MaxWidth))
        value = MaxWidth;
      return value;
    }

    //IGridLineHost
    void IGridLineHost.GridLineChanged(GridLine gl)
    {
      if (Grid != null)
        Grid.Invalidate();
    }

    protected virtual void GridLineChanged(GridLine gl)
    {
      if (Grid != null)
        Grid.Invalidate();
    }

    bool IGridLineHost.GridLineDefaultVisible(GridLine gl)
    {
      return Grid.ColumnOptions.VertLine.Visible;
    }

    Color IGridLineHost.GridLineDefaultColor(GridLine gl)
    {
      return Grid.ColumnOptions.VertLine.Color;
    }

    DashStyle IGridLineHost.GridLineDefaultStyle(GridLine gl)
    {
      return Grid.ColumnOptions.VertLine.Style;
    }

    //Mouse
    protected internal override void HandleMouseDownEvent(BaseGridCellMouseEventArgs e)
    {
      var eh = this.Events[EventKeyDataCellMouseDown] as EventHandler<DataGridDataCellMouseEventArgs>;
      if (eh != null)
        eh(this, (DataGridDataCellMouseEventArgs)e);
    }

    protected internal override void HandleMouseMoveEvent(BaseGridCellMouseEventArgs e)
    {
      var eh = this.Events[EventKeyDataCellMouseMove] as EventHandler<DataGridDataCellMouseEventArgs>;
      if (eh != null)
        eh(this, (DataGridDataCellMouseEventArgs)e);
    }

    protected internal override void HandleMouseUpEvent(BaseGridCellMouseEventArgs e)
    {
      var eh = this.Events[EventKeyDataCellMouseUp] as EventHandler<DataGridDataCellMouseEventArgs>;
      if (eh != null)
        eh(this, (DataGridDataCellMouseEventArgs)e);
    }

    protected internal override void HandleMouseClickEvent(BaseGridCellMouseEventArgs e)
    {
      var eh = this.Events[EventKeyDataCellMouseClick] as EventHandler<DataGridDataCellMouseEventArgs>;
      if (eh != null)
        eh(this, (DataGridDataCellMouseEventArgs)e);
    }

    protected internal override void HandleMouseDoubleClickEvent(BaseGridCellMouseEventArgs e)
    {
      var eh = this.Events[EventKeyDataCellMouseDoubleClick] as EventHandler<DataGridDataCellMouseEventArgs>;
      if (eh != null)
        eh(this, (DataGridDataCellMouseEventArgs)e);
    }

    protected internal override DataAxisGridDataCellEnterEventArgs CreateDataCellEnterEventArgs(
      int colIndex, int rowIndex, int areaColIndex, int areaRowIndex, Rectangle cellRect, int leaveColIndex, int leaveRowIndex,
      PropertyAxisBar propAxisBar, object listItemBar, DataAxisGridDataCellMan cell)
    {
      return new DataGridDataCellEnterEventArgs(colIndex, rowIndex, areaColIndex, areaRowIndex, cellRect, leaveColIndex, leaveRowIndex, propAxisBar, listItemBar, cell);
    }

    protected internal override void HandleMouseEnterEvent(BaseGridCellEnterEventArgs e)
    {
      var eh = this.Events[EventKeyDataCellMouseEnter] as EventHandler<DataGridDataCellEnterEventArgs>;
      if (eh != null)
      {
        var hea = (DataGridDataCellEnterEventArgs)e;
        eh(this, hea);
      }
    }

    protected internal override DataAxisGridDataCellLeaveEventArgs CreateDataCellLeaveEventArgs(
      int colIndex, int rowIndex, int areaColIndex, int areaRowIndex, Rectangle cellRect, int enterColIndex, int enterRowIndex,
      PropertyAxisBar propAxisBar, object listItemBar, DataAxisGridDataCellMan cell)
    {
      return new DataGridDataCellLeaveEventArgs(colIndex, rowIndex, areaColIndex, areaRowIndex, cellRect, enterColIndex, enterRowIndex, propAxisBar, listItemBar, cell);
    }

    protected internal override void HandleMouseLeaveEvent(BaseGridCellLeaveEventArgs e)
    {
      var eh = this.Events[EventKeyDataCellMouseLeave] as EventHandler<DataGridDataCellLeaveEventArgs>;
      if (eh != null)
      {
        var hea = (DataGridDataCellLeaveEventArgs)e;
        eh(this, hea);
      }
    }

    protected internal override void HandleMouseHoverEvent(BaseGridCellMouseEventArgs e)
    {
      var eh = this.Events[EventKeyDataCellMouseHover] as EventHandler<DataGridDataCellMouseEventArgs>;
      if (eh != null)
        eh(this, (DataGridDataCellMouseEventArgs)e);
    }

    //PullValue
    protected internal override DataAxisGridDataCellPullValueEventArgs CreatePullValueEventArgs(
      PropertyAxisBar propAxisBar, object listItemBar, DataAxisGridDataCellMan cellMan)
    {
      return new DataGridDataCellPullValueEventArgs(propAxisBar, listItemBar, cellMan);
    }

    protected internal override void OnPullValue(DataAxisGridDataCellPullValueEventArgs e)
    {
      DataGridRow row = (DataGridRow)e.ListItemBar;
      e.Value = InternalGetRowValue(row);
      e.Handled = true;
    }

    protected internal override void HandlePullValueEvent(DataAxisGridDataCellPullValueEventArgs e)
    {
      var eh = this.Events[EventKeyDataCellPullValue] as EventHandler<DataGridDataCellPullValueEventArgs>;
      if (eh != null)
        eh(this, (DataGridDataCellPullValueEventArgs)e);
    }

    //PushValue
    protected internal override DataAxisGridDataCellPushValueEventArgs CreatePushValueEventArgs(
      PropertyAxisBar propAxisBar, object listItemBar, DataAxisGridDataCellMan cellMan)
    {
      return new DataGridDataCellPushValueEventArgs(propAxisBar, listItemBar, cellMan);
    }

    protected internal override void OnPushValue(DataAxisGridDataCellPushValueEventArgs e)
    {
      DataGridRow row = (DataGridRow)e.ListItemBar;

      if (PropDescr == null)
        throw new InvalidOperationException("PropDescr == null");

      if (Grid.CurrentRow == row)
        Grid.DataLink.SetCurrentRowValue(PropDescr, e.Value);
      else
        PropDescr.SetValue(row.SourceItem, e.Value);
    }

    protected internal override void HandlePushValueEvent(DataAxisGridDataCellPushValueEventArgs e)
    {
      var eh = this.Events[EventKeyDataCellPushValue] as EventHandler<DataGridDataCellPushValueEventArgs>;
      if (eh != null)
        eh(this, (DataGridDataCellPushValueEventArgs)e);
    }

    //ToolTipInfo
    protected internal override DataAxisGridDataCellToolTipInfoEventArgs CreateToolTipInfoEventArgs(
      PropertyAxisBar propAxisBar, object listItemBar, DataAxisGridDataCellMan cellMan)
    {
      return new DataGridDataCellToolTipInfoEventArgs(propAxisBar, listItemBar, cellMan);
    }

    protected internal override void HandleToolTipInfoEvent(DataAxisGridDataCellToolTipInfoEventArgs e)
    {
      var eh = this.Events[EventKeyDataCellToolTipInfo] as EventHandler<DataGridDataCellToolTipInfoEventArgs>;
      if (eh != null)
        eh(this, (DataGridDataCellToolTipInfoEventArgs)e);
    }

    // DataCellContextMenuStripNeeded
    protected internal override DataAxisGridDataCellContextMenuStripNeededEventArgs CreateCellContextMenuStripNeededEventArgs(
      DataAxisGridDataCellMan cellMan, int colIndex, int rowIndex, int areaColIndex, int areaRowIndex, int inCellX, int inCellY,
      Rectangle cellRect, int MousePosX, int MousePosY, PropertyAxisBar propAxisBar, object listItemBar)
    {
      return new DataGridDataCellContextMenuStripNeededEventArgs(cellMan, colIndex, rowIndex, areaColIndex, areaRowIndex, inCellX, inCellY,
        cellRect, MousePosX, MousePosY, propAxisBar, listItemBar);
    }

    protected internal override void HandleMouseContextMenuStripNeededEvent(DataAxisGridDataCellContextMenuStripNeededEventArgs e)
    {
      var eh = this.Events[EventKeyDataCellContextMenuStripNeeded] as EventHandler<DataGridDataCellContextMenuStripNeededEventArgs>;
      if (eh != null)
        eh(this, (DataGridDataCellContextMenuStripNeededEventArgs)e);
    }


    //ValuesAreDuplicatesStateNeeded
    internal bool CheckValuesAreDuplicates(DataGridRow row1, DataGridRow row2)
    {
      var e = new DataGridValuesAreDuplicatesStateNeededEventArgs(this, row1, row2);
      ProcessValuesAreDuplicatesStateNeeded(e);
      return e.ValuesAreDuplicates;
    }

    internal void ProcessValuesAreDuplicatesStateNeeded(DataGridValuesAreDuplicatesStateNeededEventArgs e)
    {
      HandleValuesAreDuplicatesStateNeededEvent(e);
      if (!e.Handled)
        InternalOnValuesAreDuplicatesStateNeeded(e);
    }

    private void HandleValuesAreDuplicatesStateNeededEvent(DataGridValuesAreDuplicatesStateNeededEventArgs e)
    {
      var eh = this.Events[EventKeyDataCellValuesAreDuplicatesStateNeeded] as EventHandler<DataGridValuesAreDuplicatesStateNeededEventArgs>;
      if (eh != null)
      {
        eh(this, e);
      }
    }

    internal void InternalOnValuesAreDuplicatesStateNeeded(DataGridValuesAreDuplicatesStateNeededEventArgs e)
    {
      object value1 = GetValue(e.Row1);
      object value2 = GetValue(e.Row2);
      e.ValuesAreDuplicates = ValuesEqual(value1, value2);
    }

    public bool ValuesEqual(object value1, object value2)
    {
      if (value1 == null && value2 != null)
        return false;
      else if (value1 != null && value2 == null)
        return false;
      else if (value1 == null && value2 == null)
        return true;
      else
        return value1.Equals(value2);
    }

    //Other
    public void SetRowValue(DataGridRow row, object value)
    {
      SetValue(row, value);
    }

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

    protected internal override void HandleParseValueEvent(DataAxisGridDataCellParseValueEventArgs e)
    {
      var eh = this.Events[EventKeyDataCellParseValue] as EventHandler<DataGridDataCellParseValueEventArgs>;
      if (eh != null)
        eh(this, (DataGridDataCellParseValueEventArgs)e);
    }

    protected override DataAxisGridBarTitle CreateDataAxisGridBarTitle()
    {
      return new DataGridColumnTitle(this);
    }

    protected override void GridChanged()
    {
      base.GridChanged();
      UpdateDefaultPadding();
      UpdateFooterList();
    }

    public override BaseGridCellManager GetDataCellMan(object listItemBar)
    {
      return GetRowCellMan((DataGridRow)listItemBar);
    }

    public BaseGridCellManager GetRowCellMan(DataGridRow row)
    {
      return InternalGetRowCellMan(row);
    }

    protected internal BaseGridCellManager InternalGetRowCellMan(DataGridRow row)
    {
      DataGridDataCellObjectNeededEventArgs e = new DataGridDataCellObjectNeededEventArgs(this, row);
      OnGetRowCellMan(e);
      if (e.CellObject == null)
        e.CellObject = Grid.EmptyDataCell;
      return e.CellObject;
    }

    protected virtual void OnGetRowCellMan(DataGridDataCellObjectNeededEventArgs e)
    {
      DataGridDataCellObjectNeededEventHandler eh = this.Events[EventKeyDataCellObjectNeededEventHandler] as DataGridDataCellObjectNeededEventHandler;
      if (eh != null)
      {
        eh(this, e);
      }
    }

    protected virtual void FillWeightChanged()
    {
      if (Grid != null)
        Grid.UpdateFitColWidthsToClient();
    }

    private void DataPropertyNameChanged()
    {
      if (Grid != null)
        Grid.UpdateColumnsList();
    }

    protected internal virtual void GridFooterAdded(DataGridFooterRow footerRow, int index)
    {
      //DataGridColumnFooterItem colFooter = new DataGridColumnFooterItem
      //{
      //  Column = this,
      //  FooterRow = footerRow
      //};

      //if (index == Footer.Items.Count)
      //  Footer.Items.Add(colFooter);
      //else
      //  Footer.Items.Insert(index, colFooter);
    }

    protected internal virtual void GridFooterRemoved(DataGridFooterRow footerRow, int index)
    {
      //Footer.Items.RemoveAt(index);
    }

    internal void GridFooterRowMoved(int oldIndex, int newIndex)
    {
      DataGridColumnFooterItem footerItem = Footer.Items[oldIndex];
      Footer.Items.RemoveAt(oldIndex);
      Footer.Items.Insert(newIndex, footerItem);
    }

    protected internal void UpdateFooterList()
    {
      if (Grid == null) return;
      if (Grid.InInitialization) return;

      if (Footer.Items.Count < Grid.Footer.Rows.Count)
      {
        for (int i = Footer.Items.Count; i < Grid.Footer.Rows.Count; i++)
          GridFooterAdded(Grid.Footer.Rows[i], i);
      }
      else if (Footer.Items.Count > Grid.Footer.Rows.Count)
      {
        for (int i = Footer.Items.Count-1; i >= Grid.Footer.Rows.Count; i--)
          GridFooterRemoved(null, i);
      }

      //for(int i = 0; i < Grid.Footer.Rows.Count; i++)
      //{
      //  Footer.Items[i].FooterRow = Grid.Footer.Rows[i];
      //}
    }

    protected internal virtual int CalcDefaultRowHeight()
    {
      return 0;
    }

    protected internal virtual int CalcRowHeight(DataGridRow row)
    {
      BaseGridCellManager cell = GetRowCellMan(row);
      if (cell is DataAxisGridDataCellMan)
        return (cell as DataAxisGridDataCellMan).ProcessCalcCellHeight(this, row, Width);
      else
        return CalcDefaultRowHeight();
    }

    public virtual Collection<KeyDisplayValue> GetUniqueStringListValues()
    {
      var srcVals = new List<object>();
      var resVals = new List<KeyDisplayValue>();
      var resColl = new Collection<KeyDisplayValue>();
      object ats;

      Collection<DataGridColumn> fList = Grid.Title.Filter.GetFilterList(this);

      foreach (DataGridRow row in Grid.Rows)
      {
        if (Grid.Title.Filter.RowMatchColumnsFilter(row, fList))
          srcVals.Add(GetRowValue(row));
      }

      srcVals.Sort(EhLibUtils.DBCompareValues);

      if (srcVals.Count == 0)
        return resColl;

      ats = srcVals[0];
      resVals.Add(new KeyDisplayValue(ats, GetValueDisplayText(ats)));

      for (int i = 1; i < srcVals.Count; i++)
      {
        if (EhLibUtils.DBCompareValues(ats, srcVals[i])  != 0)
        {
          ats = srcVals[i];
          resVals.Add(new KeyDisplayValue(ats, GetValueDisplayText(ats)));
        }
      }

      resVals.Sort(CompareKeyDisplayValues);

      foreach (KeyDisplayValue v in resVals)
        resColl.Add(v);

      return resColl;
    }

    protected virtual int CompareKeyDisplayValues(KeyDisplayValue x, KeyDisplayValue y)
    {
      return EhLibUtilsInternal.DBCompareValues(x.KeyValue, y.KeyValue);
    }

    public virtual object GetRowValue(DataGridRow row)
    {
      return GetValue(row);
    }

    protected virtual object InternalGetRowValue(DataGridRow row)
    {
      if (DataValueSource == DataValueSource.ListItem)
      {
        return row.SourceItem;
      }
      else if (PropDescr == null)
      {
        return null;
      }
      else
      {
        object srcRow = row.SourceItem;
        return PropDescr.GetValue(srcRow);
      }
    }

    public virtual string GetRowDisplayText(DataGridRow row)
    {
      //object srcRow = row.srcRow;
      if (row == null) return null;

      object value = GetRowValue(row);
      return GetValueDisplayText(value);
    }

    public virtual string GetValueDisplayText(object value)
    {
      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 virtual object ParseValue(object formattedValue)
    {
      DataGridRow dataRow;

      if (Grid.Rows.Count > 0)
        dataRow = Grid.Rows[0];
      else
        dataRow = null;

      return ParseValue(dataRow, formattedValue);
    }

    public override void Invalidate()
    {
      if (Grid != null)
        Grid.InvalidateGrid();
    }

    public virtual string GetDisplayText(DataGridRow row)
    {
      BaseGridCellManager cell = InternalGetRowCellMan(row);
      DataAxisGridDataCellMan dataCell = (cell as DataAxisGridDataCellMan);
      if (dataCell != null)
        return dataCell.GetDisplayText(this, row);
      else
        return cell.GetDisplayText(VisibleIndex, row.VisibleIndex);
    }

    public virtual ContextMenuStrip GetContextMenuStripAtRow(DataGridRow row)
    {
      return null;
    }

    public virtual bool CanModifyValueAtRow(DataGridRow row)
    {
      return false;
    }

    protected internal override void OnDataCellContentClick(DataAxisGridDataCellEventArgs e)
    {
      DataGridDataCellEventHandler eh = this.Events[EventKeyDataCellContentClick] as DataGridDataCellEventHandler;
      if (eh != null)
      {
        eh(this, (DataGridDataCellEventArgs)e);
      }
    }

    DataGridTitleNode IMultiTitleNodeProvider.GetNode()
    {
      //if (Title.TitleNode.Parent == null)
      //  return null;
      //else
      return Title.TitleNode;
    }

    public DataGridColumnTitle GetMultiTitleColumnTitle()
    {
      return Title.TitleNode.ColumnTitle;
    }

    public DataGridSuperTitle GetMultiTitleSuperTitle()
    {
      return Title.TitleNode.SuperTitle;
    }

    protected internal override void UpdatedInList()
    {
      base.UpdatedInList();
      UpdateFooterList();
    }

    protected internal virtual void StartCellRectSelectionMode(BaseGridCellMouseEventArgs e)
    {
      Grid.StartCellRectSelectionMode(e.GridMouseArgs);
    }

    protected internal override void CellFontChanged()
    {
      if (Grid != null)
        Grid.UpdateRowHeights();
    }

    public override Font DefaultFont()
    {
      if (Grid != null)
        return Grid.ColumnOptions.Font;
      else
        return null;
    }

    public override Color DefaultForeColor()
    {
      if (Grid != null)
        return Grid.ColumnOptions.ForeColor;
      else
        return Color.Empty;
    }

    protected internal override void RowHeightAutoExpandChanged()
    {
      if (Grid != null)
        Grid.RowHeightAutoExpandChanged();
    }

    public override bool HeightOptionsDefaultAutoExpand(GridRowHeightOptions heightOptions)
    {
      if (Grid != null)
        return Grid.RowOptions.HeightOptions.AutoExpand;
      else
        return false;
    }

    public override int HeightOptionsDefaultContentHeight(GridRowHeightOptions heightOptions)
    {
      if (Grid != null)
        return Grid.RowOptions.HeightOptions.ContentHeight;
      else
        return 1;
    }

    public override int HeightOptionsDefaultMaxContentHeight(GridRowHeightOptions heightOptions)
    {
      if (Grid != null)
        return Grid.RowOptions.HeightOptions.MaxContentHeight;
      else
        return 0;
    }

    public override GridRowHeightUnit HeightOptionsDefaultUnit(GridRowHeightOptions heightOptions)
    {
      if (Grid != null)
        return Grid.RowOptions.HeightOptions.Unit;
      else
        return GridRowHeightUnit.TextLine;
    }

    protected internal override void AxisObjectsByDataColRowIndex(int dataColIndex, int dataRowIndex, out PropertyAxisBar propAxisBar, out object listItemBar)
    {
      if (dataColIndex >= 0 && dataColIndex < Grid.VisibleColumns.Count)
        propAxisBar = Grid.VisibleColumns[dataColIndex];
      else
        propAxisBar = null;

      if (dataRowIndex < Grid.VisibleRows.Count)
        listItemBar = Grid.VisibleRows[dataRowIndex];
      else
        listItemBar = null;
    }

    //protected internal override object GetValue(PropertyAxisBar propAxisBar, object listItemBar)
    //{
    //  return ((DataGridColumn)propAxisBar).GetRowValue((DataGridRow)listItemBar);
    //}

    protected internal override bool HandlePaintEvent(DataAxisGridDataCellPaintEventArgs e)
    {
      var eh = this.Events[EventKeyDataCellPaint] as EventHandler<DataGridDataCellPaintEventArgs>;
      if (eh != null)
      {
        eh(this, (DataGridDataCellPaintEventArgs)e);
        return e.Handled;
      }
      else
      {
        return false;
      }
    }

    protected internal override void HandleDataCellPaintCustomAreaEvent(DataAxisGridDataCellPaintEventArgs e)
    {
      var eh = this.Events[EventKeyDataCellPaintCustomArea] as EventHandler<DataGridDataCellPaintEventArgs>;
      if (eh != null)
        eh(this, (DataGridDataCellPaintEventArgs)e);
    }

    protected internal override void PaintCellBackground(DataAxisGridDataCellMan cellMan, DataAxisGridDataCellPaintEventArgs e)
    {
      Color baseColor = e.BackColor;
      int alpha = 255;
      bool drawSelection = false;

      if (e.ListItemBar != null)
      {
        bool isEvenRow = e.AreaRowIndex % 2 == 0;
        if (Grid.RowOptions.EvenColor != Color.Empty && isEvenRow)
          baseColor = Grid.RowOptions.EvenColor;
        else if (Grid.RowOptions.OddColor != Color.Empty && !isEvenRow)
          baseColor = Grid.RowOptions.OddColor;
      }

      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);

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

      if ((Grid.Selection.SelectionType != GridSelectionType.None))
      {
        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;
        }
        else if ((BasePaintCellStates.Selected & e.State) != 0)
        {
          alpha = 255 / 6;
          drawSelection = true;
        }
      }
      else 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;
      }
      else if (Grid.Selection.RowHighlight &&
          ((BasePaintCellStates.Current & e.State) == 0) &&
          ((BasePaintCellStates.CurrentRow & e.State) != 0))
      {
        alpha = 255 / 6;
        drawSelection = true;
      }

      if (drawSelection)
      {

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

        e.BackFilledColor = Color.FromArgb(alpha, baseColor);

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

    protected internal override void OnGetDataCellBorderParams(BaseGridCellBorderEventArgs e)
    {
      if (e.BorderType == GridCellBorderType.Right)
      {
        if (e.AreaColIndex < Grid.VisibleColumns.Count)
        {
          GridLine gl = Grid.Columns[e.AreaColIndex].VertLine;
          e.Visible = gl.Visible;
          e.Color = gl.Color;
          e.Style = gl.Style;
          e.IsExtent = true;
        }
      }
      else if (e.BorderType == GridCellBorderType.Bottom)
      {
        e.Visible = Grid.RowOptions.HorzLine.Visible;
        e.IsExtent = true;
        e.Color = Grid.RowOptions.HorzLine.Color;
        e.Style = Grid.RowOptions.HorzLine.Style;

        DataGridColumn column = null;
        DataGridRow row = null;

        if (e.AreaColIndex < Grid.VisibleColumns.Count)
          column = Grid.VisibleColumns[e.AreaColIndex];
        if (e.AreaRowIndex < Grid.VisibleRows.Count)
          row = Grid.VisibleRows[e.AreaRowIndex];

        var hlpe = new DataGridHorzLineParamsNeededEventArgs(column, row)
        {
          Visible = e.Visible,
          Color = e.Color,
          Style = e.Style
        };

        Grid.OnHorzLineParamsNeeded(hlpe);

        e.Visible = hlpe.Visible;
        e.Color = hlpe.Color;
        e.Style = hlpe.Style;
      }

      if (e.Visible && Grid.Background.Visible)
        e.Color = Color.FromArgb(Grid.Background.GridOpacityOptions.LinesOpacity, e.Color);
    }

    protected internal override bool IsPaintEditItemBackground(EditButton editButton, DataAxisGridDataCellPaintEventArgs e, Rectangle itemRect)
    {

      DataGridEditItemOptions eiOpts = Grid.ColumnOptions.EditItemOptions;

      if (eiOpts.PaintBackgroundTime == DataGridCellItemPaintTime.Always)
        return true;
      else if (eiOpts.PaintBackgroundTime == DataGridCellItemPaintTime.Never)
        return false;
      else if (eiOpts.PaintBackgroundTime == DataGridCellItemPaintTime.WhenHot)
        return false;
      else if (eiOpts.PaintBackgroundTime == DataGridCellItemPaintTime.WhenAreaHot)
      {
        if (eiOpts.ActiveArea == DataGridActiveArea.Row)
          return ((e.State & BasePaintCellStates.RowHotTrack) != 0);
        else
          return ((e.State & BasePaintCellStates.HotTrack) != 0);
      }
      else if (eiOpts.PaintBackgroundTime == DataGridCellItemPaintTime.WhenAreaHotOrActive)
      {
        if (eiOpts.ActiveArea == DataGridActiveArea.Row)
          return ((e.State & BasePaintCellStates.RowHotTrack) != 0 && Grid.IsDrawHotState()) ||
                 (e.RowIndex == Grid.Row);
        else
          return ((e.State & BasePaintCellStates.HotTrack) != 0) ||
                 (e.ColIndex == Grid.Col && e.RowIndex == Grid.Row);
      }
      else
        return false;
    }

    protected internal override bool IsPaintEditItemForeground(EditButton editButton, DataAxisGridDataCellPaintEventArgs e, Rectangle itemRect)
    {
      DataGridEditItemOptions eiOpts = Grid.ColumnOptions.EditItemOptions;

      if (eiOpts.PaintTime == DataGridCellItemPaintTime.Always)
        return true;
      else if (eiOpts.PaintTime == DataGridCellItemPaintTime.Never)
        return false;
      else if (eiOpts.PaintTime == DataGridCellItemPaintTime.WhenHot)
        return false;
      else if (eiOpts.PaintTime == DataGridCellItemPaintTime.WhenAreaHot)
      {
        if (eiOpts.ActiveArea == DataGridActiveArea.Row)
          return ((e.State & BasePaintCellStates.RowHotTrack) != 0);
        else
          return ((e.State & BasePaintCellStates.HotTrack) != 0);
      }
      else if (eiOpts.PaintTime == DataGridCellItemPaintTime.WhenAreaHotOrActive)
      {
        if (eiOpts.ActiveArea == DataGridActiveArea.Row)
          return ((e.State & BasePaintCellStates.RowHotTrack) != 0) ||
                 (e.RowIndex == Grid.Row);
        else
          return ((e.State & BasePaintCellStates.HotTrack) != 0) ||
                 (e.ColIndex == Grid.Col && e.RowIndex == Grid.Row);
      }
      else
        return false;
    }

    protected internal override void GridCellPosToDataCellPos(int gridColIndex, int gridRowIndex, out int areaColIndex, out int areaRowIndex)
    {
      areaColIndex = gridColIndex - Grid.StartDataColIndex;
      areaRowIndex = gridRowIndex - Grid.FixedRowCount;
    }

    protected internal override void DataCellPosToGridCellPos(int areaColIndex, int areaRowIndex, out int gridColIndex, out int gridRowIndex)
    {
      gridColIndex = areaColIndex + Grid.StartDataColIndex;
      gridRowIndex = areaRowIndex + Grid.FixedRowCount;
    }

    protected internal override bool IsDataCellSelected(int dataColIndex, int dataRowIndex)
    {
      if (Grid.Selection.SelectionType == GridSelectionType.Columns)
        return Grid.VisibleColumns[dataColIndex].Selected;
      else if (Grid.Selection.SelectionType == GridSelectionType.Rows && dataRowIndex < Grid.VisibleRows.Count)
        return Grid.VisibleRows[dataRowIndex].Selected;
      else if (Grid.Selection.SelectionType == GridSelectionType.CellsBox)
        return Grid.Selection.CellsRectContains(dataColIndex, dataRowIndex);
      else if (Grid.Selection.SelectionType == GridSelectionType.All)
        return true;
      else
        return false;
    }

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

    //protected internal override void OnCellCustomAreaMeasuresNeeded(BaseGridCellCustomAreaMeasuresEventArgs e)
    //{
    //  var eh = this.Events[EventKeyDataCellCustomAreaMeasuresNeeded] as EventHandler<DataGridDataCellCustomAreaMeasuresNeededEventArgs>;
    //  if (eh != null)
    //  {
    //    eh(this, (DataGridDataCellCustomAreaMeasuresNeededEventArgs)e);
    //  }
    //}

    protected internal override void OnFillFormatParams(DataAxisGridDataCellFormatParamsEventArgs e)
    {
      var eh = this.Events[EventKeyDataCellQueryFillFormatParams] as EventHandler<DataGridDataCellFormatParamsEventArgs>;
      if (eh != null)
      {
        eh(this, (DataGridDataCellFormatParamsEventArgs)e);
      }
    }

    protected internal override BaseGridCellMouseEventArgs CreateDataCellMouseEventArgs(
      int colIndex, int rowIndex, int areaColIndex, int areaRowIndex,
      PropertyAxisBar propAxisBar, object listItemBar, DataAxisGridDataCellMan cell,
      int inCellX, int inCellY, Rectangle cellRect, MouseEventArgs gridMouseArgs)
    {
      return new DataGridDataCellMouseEventArgs(
        cell, colIndex, rowIndex, areaColIndex, areaRowIndex, propAxisBar, listItemBar, inCellX, inCellY, cellRect, gridMouseArgs);
    }

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

    protected internal override DataAxisGridDataCellPaintEventArgs GetDataCellPaintParams(BaseGridCellManager cellManager, Graphics graphics,
      int colIndex, int rowIndex, Rectangle paintRect, BasePaintCellStates state, int areaColIndex, int areaRowIndex,
      Point inCellMousePos, PropertyAxisBar propAxisBar, object listItemBar)
    {
      return new DataGridDataCellPaintEventArgs(cellManager, graphics, colIndex, rowIndex, paintRect, state, areaColIndex, areaRowIndex, 
        inCellMousePos, propAxisBar, listItemBar);
    }

    protected internal override DataAxisGridDataCellClientAreaNeededEventArgs CreateDataCellClientAreaNeededEventArgs(PropertyAxisBar propAxisBar,
        object listItemBar, Rectangle cellRect, DataAxisGridDataCellMan cellMan)
    {
      return new DataGridDataCellClientAreaNeededEventArgs(propAxisBar, listItemBar, cellRect, cellMan);
    }

    protected override void HandleDataCellClientAreaNeededEvent(DataAxisGridDataCellClientAreaNeededEventArgs e)
    {
      var eh = this.Events[EventKeyDataCellClientAreaNeeded] as EventHandler<DataGridDataCellClientAreaNeededEventArgs>;
      if (eh != null)
      {
        eh(this, (DataGridDataCellClientAreaNeededEventArgs)e);
      }
    }

    protected internal override DataAxisGridDataCellOptimalWidthNeededEventArgs CreateDataCellOptimalWidthNeededEventArgs(
      PropertyAxisBar propAxisBar, object listItemBar, DataAxisGridDataCellMan cellMan)
    {
      return new DataGridDataCellOptimalWidthNeededEventArgs(propAxisBar, listItemBar, cellMan);
    }

    protected internal override void HandleCellOptimalWidthNeededEvent(DataAxisGridDataCellOptimalWidthNeededEventArgs e)
    {
      var eh = this.Events[EventKeyDataCellOptimalWidthNeeded] as EventHandler<DataGridDataCellOptimalWidthNeededEventArgs>;
      if (eh != null)
      {
        eh(this, (DataGridDataCellOptimalWidthNeededEventArgs)e);
      }
    }

    internal protected virtual void RollPosChanged()
    {
    }

    internal protected virtual bool IsFullInvalidateOnVertScroll()
    {
      if (MergeDuplicates)
        return true;
      else
        return false;
    }

    internal protected virtual void CurrencyManagerChanged(object sender, ListChangedEventArgs e)
    {
      if (MergeDuplicates)
        MergeDuplicatesList.ListIsObsolete();
    }
    #endregion

  }

  public class DataGridColumnDataCellList : Collection<BaseGridCellManager>
  {
    private readonly DataGridDynaCellColumn column;

    public DataGridColumnDataCellList(DataGridDynaCellColumn column)
    {
      this.column = column;
    }

    public new void Add(BaseGridCellManager item)
    {
      base.Add(item);
      item.Grid = column.Grid;
      DataAxisGridDataCellMan itemAsPropertyBar = item as DataAxisGridDataCellMan;
      if (itemAsPropertyBar != null)
        itemAsPropertyBar.PropAxisBar = column;
    }
  }

  [DataAxisGridPropBarDesignTimeVisibleAttribute(true)]
  public class DataGridDynaCellColumn : DataGridColumn
  {
    private readonly DataGridColumnDataCellList cells;

    public DataGridDynaCellColumn()
    {
      cells = new DataGridColumnDataCellList(this);
    }

    #region run-time properties
    #endregion

    #region design-time properties
    [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
    [Editor("EhLib.Design.DataGridDynaColumnCellsEditor" + EhLibUtils.EhLibDesignDesignerVersionInfo, "System.Drawing.Design.UITypeEditor, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a")]
    public DataGridColumnDataCellList Cells
    {
      get { return cells; }
    }
    #endregion

    protected override void GridChanged()
    {
      base.GridChanged();
      foreach (DataAxisGridDataCellMan c in Cells)
        c.Grid = Grid;
    }
  }

  [DataAxisGridPropBarDesignTimeVisibleAttribute(false)]
  public class DataGridMonoCellColumn : DataGridColumn
  {

    #region privates
    private DataAxisGridDataCellMan dataCell;
    #endregion

    public DataGridMonoCellColumn()
    {
    }

    #region internal properties
    [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
    protected EditButton EditButton
    {
      get
      {
        return DataCell.EditButton;
      }

      set
      {
        DataCell.EditButton = value;
      }
    }
    #endregion

    #region runtime properties
    [Browsable(false)]
    public DataAxisGridDataCellMan DataCell
    {
      get
      {
        if (dataCell == null)
        {
          dataCell = CreateTemplateCell();
          dataCell.PropAxisBar = this;
          //dataCell.CellHolder = this;
        }
        return dataCell;
      }
    }

    [Browsable(false)]
    public override BaseGridCellManager NewVirtualRowCell
    {
      get
      {
        return DataCell;
      }
    }

    public Padding Padding
    {
      get { return DataCell.Padding; }
      set { DataCell.Padding = value; }
    }

    public HorizontalAlignment HorzAlign
    {
      get { return DataCell.HorzAlign; }
      set { DataCell.HorzAlign = value; }
    }

    public VerticalAlignment VertAlign
    {
      get { return DataCell.VertAlign; }
      set { DataCell.VertAlign = value; }
    }

    [DefaultValue(null)]
    public virtual ContextMenuStrip ContextMenuStrip
    {
      get { return DataCell.ContextMenuStrip; }
      set { DataCell.ContextMenuStrip = value; }
    }

    //[DefaultValue(true)]
    //bool ContextMenuIsCompound
    //{
    //  get { return DataCell.ContextMenuIsCompound; }
    //  set { DataCell.ContextMenuIsCompound = value; }
    //}

    public Color ForeColor
    {
      get { return DataCell.ForeColor; }
      set { DataCell.ForeColor = value; }
    }

    public Font Font
    {
      get { return DataCell.Font; }
      set { DataCell.Font = value; }
    }

    [DefaultValue(false)]
    public virtual bool ReadOnly
    {
      get { return DataCell.ReadOnly; }
      set { DataCell.ReadOnly = value; }
    }

    [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
    public GridRowHeightOptions HeightOptions
    {
      get
      {
        return DataCell.HeightOptions;
      }
    }

    //public bool HeightAutoExpand
    //{
    //  get { return DataCell.HeightAutoExpand; }
    //  set { DataCell.HeightAutoExpand = value; }
    //}
    #endregion

    #region methods

    //Padding
    protected virtual void PaddingChanged()
    {
      if (Grid != null)
        Grid.UpdateBaseFixedBands();
    }

    protected virtual Padding DefaultPadding()
    {
      return DataCell.DefaultPadding();
    }

    protected virtual bool ShouldSerializePadding()
    {
      return DataCell.ShouldSerializePadding();
    }

    public virtual void ResetPadding()
    {
      DataCell.ResetPadding();
    }

    //HorzAlign
    protected virtual HorizontalAlignment DefaultHorzAlign()
    {
      return DataCell.DefaultHorzAlign();
    }

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

    protected virtual bool ShouldSerializeHorzAlign()
    {
      return DataCell.ShouldSerializeHorzAlign();
    }

    public virtual void ResetHorzAlign()
    {
      DataCell.ResetHorzAlign();
    }

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

    public virtual VerticalAlignment DefaultVertAlign()
    {
      return DataCell.DefaultVertAlign();
    }

    public virtual bool ShouldSerializeVertAlign()
    {
      return DataCell.ShouldSerializeVertAlign();
    }

    public virtual void ResetVertAlign()
    {
      DataCell.ResetVertAlign();
    }

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

    public override Color DefaultForeColor()
    {
      if (Grid != null)
        return Grid.ColumnOptions.ForeColor;
      else
        return SystemColors.WindowText;
    }

    protected virtual bool ShouldSerializeForeColor()
    {
      return DataCell.ShouldSerializeForeColor();
    }

    public virtual void ResetForeColor()
    {
      DataCell.ResetForeColor();
    }

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

    public override Font DefaultFont()
    {
      if (Grid != null)
        return Grid.ColumnOptions.Font;
      else
        return null;
    }

    protected virtual bool ShouldSerializeFont()
    {
      return DataCell.ShouldSerializeFont();
    }

    public virtual void ResetFont()
    {
      DataCell.ResetFont();
    }

    //Other
    protected override void GridChanged()
    {
      base.GridChanged();
      DataCell.Grid = Grid;
    }

    protected virtual DataAxisGridDataCellMan CreateTemplateCell()
    {
      return null;
    }

    protected override void OnGetRowCellMan(DataGridDataCellObjectNeededEventArgs e)
    {
      base.OnGetRowCellMan(e);
      if (e.CellObject == null)
        e.CellObject = DataCell;
    }

    //public override void UpdateDefaultPadding()
    //{
    //  DataCell.UpdateDefaultPadding();
    //}

    protected internal override int CalcDefaultRowHeight()
    {
      int th;

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

    public override ContextMenuStrip GetContextMenuStripAtRow(DataGridRow row)
    {
      return DataCell.ContextMenuStrip;
    }

    public override bool CanModifyValueAtRow(DataGridRow row)
    {
      return !DataCell.ReadOnly;
    }

    //internal override int CalcDefaultWidth()
    //{
    //  int dataRowIndex;
    //  int rowLength;
    //  int rowWidth, maxRowWidth;

    //  SizeF sf;

    //  if (Grid == null) return 100;

    //  sf = EhLibUtils.MeasureText(EhLibUtils.DisplayGraphicsCash, "0", Font);

    //  rowLength = 0;
    //  dataRowIndex = 0;

    //  if (Grid.AutoSizeColumnOptions.ConsiderTitle)
    //    maxRowWidth = Title.CalcDefaultWidth();
    //  else
    //    maxRowWidth = (int)EhLibUtils.MeasureText(EhLibUtils.DisplayGraphicsCash, "0", Font).Width;

    //  DataGridColumnAutoSizeConsiderRowsMode considerDataCell = Grid.AutoSizeColumnOptions.ConsiderRowsMode;
    //  int considerRowCount;
    //  if (considerDataCell == DataGridColumnAutoSizeConsiderRowsMode.ConsiderRowCount)
    //    considerRowCount = Grid.AutoSizeColumnOptions.ConsiderRowCount;
    //  else if (considerDataCell == DataGridColumnAutoSizeConsiderRowsMode.VisibleRows)
    //    considerRowCount = Grid.VisibleRowCount;
    //  else
    //    considerRowCount = Grid.Rows.Count;

    //  if (considerDataCell != DataGridColumnAutoSizeConsiderRowsMode.None)
    //  {
    //    foreach (DataGridRow row in Grid.VisibleRows)
    //    {
    //      int colIndex, rowIndex;

    //      BaseGridCellManager cell = GetRowCellMan(row);
    //      cell.AreaCellPosToGridCellPos(VisibleIndex, row.VisibleIndex, out colIndex, out rowIndex);

    //      DataAxisGridDataCellMan dataCell = cell as DataAxisGridDataCellMan;
    //      if (VisibleIndex >= 0 && dataCell != null)
    //        rowWidth = dataCell.GetOptimalWidth(colIndex, rowIndex, VisibleIndex, row.VisibleIndex, row);
    //      else
    //      {
    //        string text = GetDisplayText(row);
    //        rowWidth = (int)EhLibUtils.MeasureText(EhLibUtils.DisplayGraphicsCash, text, Font).Width;
    //      }

    //      if (rowWidth > maxRowWidth)
    //        maxRowWidth = rowWidth;
    //      dataRowIndex++;

    //      if (dataRowIndex > considerRowCount) break;
    //    }

    //    maxRowWidth = maxRowWidth + Padding.Left + Padding.Right + Math.Max(Padding.Left, Padding.Right);
    //  }

    //  if ((Grid.AutoSizeColumnOptions.DefaultMaxWidth > 0) &&
    //      (maxRowWidth > Grid.AutoSizeColumnOptions.DefaultMaxWidth))
    //  {
    //    maxRowWidth = Grid.AutoSizeColumnOptions.DefaultMaxWidth;
    //  }

    //  if (maxRowWidth == 0)
    //    return (int)sf.Width * rowLength;
    //  else
    //    return maxRowWidth;
    //}
    #endregion
  }

}
