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

using System;
using System.ComponentModel;
using System.Drawing;
using System.Windows.Forms;
using System.Windows.Forms.VisualStyles;
using System.Drawing.Drawing2D;

namespace EhLib
{

  [TypeConverter(typeof(ExpandableObjectConverter))]
  [ToolboxItem(false)]
  [DesignerCategory("Code")]
  public class DataGridIndicatorColumn : DataGridBaseComponent, IDisposable, IGridLineHost, ICellBackFillerOwner
  {

    #region private consts
    //private static readonly object EventKeyCustomAreaMeasuresNeeded = new object();
    private static readonly object EventKeyCellPaint = new object();
    private static readonly object EventCellQueryCursor = new object();
    private static readonly object EventCellMouseDown = new object();
    private static readonly object EventKeyMouseMove = new object();
    private static readonly object EventKeyMouseUp = new object();
    private static readonly object EventKeyMouseClick = new object();
    private static readonly object EventKeyMouseDoubleClick = new object();
    private static readonly object EventKeyMouseEnter = new object();
    private static readonly object EventKeyMouseLeave = new object();
    private static readonly object EventKeyMouseHover = new object();
    private static readonly object EventKeyCellWidthNeeded = new object();
    private static readonly object EventKeyCellHeightNeeded = new object();

    #endregion private consts

    #region privates
    private bool showRowIndicator = true;
    private Font font;
    private Font defaultFont;
    private bool showRecNo = true;
    private int recNoShowStep = 5;
    private bool visible = true;
    private readonly CellBackFiller backFiller;

    private readonly GridLine vertLine;
    private readonly GridLine horzLine;

    private bool disposed;
    private bool showRowErrors;
    #endregion

    public DataGridIndicatorColumn(DataGridEh grid) : base(grid)
    {
      ShowRowselCheckboxes = false;
      vertLine = new GridLine(this);
      horzLine = new GridLine(this);
      backFiller = new CellBackFiller(this);
    }

    ~DataGridIndicatorColumn()
    {
      Dispose(false);
    }

    protected override void Dispose(bool disposing)
    {
      if (disposed)
        return;
      if (disposing)
      {
        if (font != null) font.Dispose();
        if (defaultFont != null) defaultFont.Dispose();
      }
      disposed = true;
    }

    #region design-time properties

    [DefaultValue(true)]
    public bool Visible
    {
      get
      {
        return visible;
      }
      set
      {
        if (visible != value)
        {
          visible = value;
          Grid.UpdateColumnsList();
        }
      }
    }

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

    [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
    public GridLine HorzLine
    {
      get
      {
        return horzLine;
      }
    }

    [DefaultValue(5)]
    public int RecNoShowStep
    {
      get { return recNoShowStep; }
      set
      {
        if (recNoShowStep != value)
        {
          recNoShowStep = value;
          Grid.InvalidateGrid();
        }
      }
    }

    [DefaultValue(true)]
    public bool ShowRowIndicator
    {
      get
      {
        return showRowIndicator;
      }
      set
      {
        if (showRowIndicator != value)
        {
          showRowIndicator = value;
          Grid.UpdateColumnsList();
        }
      }
    }

    [DefaultValue(true)]
    public bool ShowRecNo
    {
      get
      {
        return showRecNo;
      }
      set
      {
        if (showRecNo != value)
        {
          showRecNo = value;
          Grid.UpdateColumnsList();
        }
      }
    }

    [DefaultValue(false)]
    public bool ShowRowselCheckboxes { get; set; }

    //[DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
    public Font Font
    {
      get
      {
        if (font != null)
          return font;
        else
          return DefaultFont();
      }
      set
      {
        font = value;
        FontChanged();
      }
    }

    [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
    public CellBackFiller BackFiller
    {
      get
      {
        return backFiller;
      }
    }

    [DefaultValue(false)]
    public bool ShowRowErrors
    {
      get
      {
        return showRowErrors;
      }
      set
      {
        if (showRowErrors != value)
        {
          showRowErrors = value;
          if (Grid != null)
            Grid.UpdateColumnsList();
        }
      }
    }
    
    #endregion design-time properties

    #region events
    //public event EventHandler<CustomAreaMeasuresNeededEventArgs> CellCustomAreaMeasuresNeeded
    //{
    //  add
    //  {
    //    this.Events.AddHandler(EventKeyCustomAreaMeasuresNeeded, value);
    //  }
    //  remove
    //  {
    //    this.Events.RemoveHandler(EventKeyCustomAreaMeasuresNeeded, value);
    //  }
    //}

    public event EventHandler<DataGridIndicatorCellPaintEventArgs> CellPaint
    {
      add
      {
        this.Events.AddHandler(EventKeyCellPaint, value);
      }
      remove
      {
        this.Events.RemoveHandler(EventKeyCellPaint, value);
      }
    }

    public event EventHandler<BaseGridCellQueryCursorEventArgs> CellQueryCursor
    {
      add
      {
        this.Events.AddHandler(EventCellQueryCursor, value);
      }
      remove
      {
        this.Events.RemoveHandler(EventCellQueryCursor, value);
      }
    }

    public event EventHandler<DataGridIndicatorCellMouseEventArgs> CellMouseDown
    {
      add
      {
        this.Events.AddHandler(EventCellMouseDown, value);
      }
      remove
      {
        this.Events.RemoveHandler(EventCellMouseDown, value);
      }
    }

    public event EventHandler<DataGridIndicatorCellMouseEventArgs> CellMouseMove
    {
      add
      {
        this.Events.AddHandler(EventKeyMouseMove, value);
      }
      remove
      {
        this.Events.RemoveHandler(EventKeyMouseMove, value);
      }
    }

    public event EventHandler<DataGridIndicatorCellMouseEventArgs> CellMouseUp
    {
      add
      {
        this.Events.AddHandler(EventKeyMouseUp, value);
      }
      remove
      {
        this.Events.RemoveHandler(EventKeyMouseUp, value);
      }
    }

    public event EventHandler<DataGridIndicatorCellMouseEventArgs> CellMouseClick
    {
      add
      {
        this.Events.AddHandler(EventKeyMouseClick, value);
      }
      remove
      {
        this.Events.RemoveHandler(EventKeyMouseClick, value);
      }
    }

    public event EventHandler<DataGridIndicatorCellMouseEventArgs> CellMouseDoubleClick
    {
      add
      {
        this.Events.AddHandler(EventKeyMouseDoubleClick, value);
      }
      remove
      {
        this.Events.RemoveHandler(EventKeyMouseDoubleClick, value);
      }
    }

    public event EventHandler<DataGridIndicatorCellEnterEventArgs> CellMouseEnter
    {
      add
      {
        this.Events.AddHandler(EventKeyMouseEnter, value);
      }
      remove
      {
        this.Events.RemoveHandler(EventKeyMouseEnter, value);
      }
    }

    public event EventHandler<DataGridIndicatorCellLeaveEventArgs> CellMouseLeave
    {
      add
      {
        this.Events.AddHandler(EventKeyMouseLeave, value);
      }
      remove
      {
        this.Events.RemoveHandler(EventKeyMouseLeave, value);
      }
    }

    public event EventHandler<DataGridIndicatorCellMouseEventArgs> CellMouseHover
    {
      add
      {
        this.Events.AddHandler(EventKeyMouseHover, value);
      }
      remove
      {
        this.Events.RemoveHandler(EventKeyMouseHover, value);
      }
    }

    public event EventHandler<DataGridIndicatorCellWidthNeededEventArgs> CellWidthNeeded
    {
      add
      {
        this.Events.AddHandler(EventKeyCellWidthNeeded, value);
      }
      remove
      {
        this.Events.RemoveHandler(EventKeyCellWidthNeeded, value);
      }
    }

    public event EventHandler<DataGridIndicatorCellHeightNeededEventArgs> CellHeightNeeded
    {
      add
      {
        this.Events.AddHandler(EventKeyCellHeightNeeded, value);
      }
      remove
      {
        this.Events.RemoveHandler(EventKeyCellHeightNeeded, value);
      }
    }
    #endregion

    #region methods

    //Font
    protected virtual Font DefaultFont()
    {
      if (defaultFont == null)
      {
        defaultFont = new Font(Grid.Font.Name,
                               Grid.Font.Size / 100 * 80,
                               FontStyle.Regular,
                               Grid.Font.Unit,
                               Grid.Font.GdiCharSet);
      }
      return defaultFont;
    }

    protected virtual bool ShouldSerializeFont()
    {
      return (!ReferenceEquals(Font, defaultFont));
    }

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

    protected virtual void FontChanged()
    {
      if (Grid != null)
        Grid.UpdateBaseFixedBands();
    }

    public virtual void UpdateDefaultFont()
    {
      defaultFont = new Font(Grid.Font.Name,
                             Grid.Font.Size / 100 * 80,
                             FontStyle.Regular,
                             Grid.Font.Unit,
                             Grid.Font.GdiCharSet);
      ResetFont();
    }

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

    bool IGridLineHost.GridLineDefaultVisible(GridLine gl)
    {
      if (Grid == null) return false;

      if (gl == vertLine)
        return Grid.LineOptions.VertLines;
      else if (gl == horzLine)
        return Grid.LineOptions.HorzLines;
      else
        return false;
    }

    Color IGridLineHost.GridLineDefaultColor(GridLine gl)
    {
      if (Grid != null)
        return Grid.LineOptions.DarkColor;
      else
        return Color.Empty;
    }

    DashStyle IGridLineHost.GridLineDefaultStyle(GridLine gl)
    {
      return DashStyle.Solid;
    }

    //ICellBackFillerOwner
    void ICellBackFillerOwner.BackFillerChanged(CellBackFiller backFiller)
    {
      if (Grid != null)
        Grid.Invalidate();
    }

    Color ICellBackFillerOwner.BackFillerDefaultColor(CellBackFiller backFiller)
    {
      return Grid.FixedBackFiller.Color;
    }

    Color ICellBackFillerOwner.BackFillerDefaultSecondColor(CellBackFiller backFiller)
    {
      return Grid.FixedBackFiller.SecondColor;
    }

    CellFillStyle ICellBackFillerOwner.BackFillerDefaultFillStyle(CellBackFiller backFiller)
    {
      return Grid.FixedBackFiller.FillStyle;
    }

    CellInnerBorderStyle ICellBackFillerOwner.BackFillerDefaultInnerBorder(CellBackFiller backFiller)
    {
      return Grid.FixedBackFiller.InnerBorder;
    }

    //Other
    public virtual int RecordStateSignAreaWidth()
    {
      return 10;
    }

    public virtual int CalcWidth()
    {
      int result = 0;
      if (Visible)
      {
        int fixWidth = 0;
        int newWidth = 0;

        if (ShowRowIndicator)
          fixWidth = fixWidth + RecordStateSignAreaWidth();

        if (ShowRecNo)
          fixWidth = fixWidth + CalcRowAreaWidth();

        if (ShowRowErrors)
          fixWidth = fixWidth + CalcRowErrorsWidth();

        if (ShowRowselCheckboxes)
          fixWidth = fixWidth + CalcRowselCheckboxesWidth();

        newWidth = fixWidth;
        foreach (DataGridRow row in Grid.VisibleRows)
        {
          var e = new DataGridIndicatorCellWidthNeededEventArgs(0, 0, 0, 0, Rectangle.Empty, row, fixWidth);
          OnGetCellWidth(e);
          if (e.CellWidth > newWidth)
            newWidth = e.CellWidth;
        }
        result = newWidth;

        //int defaultHeight = 16;

        //var custAreaMeasures = new CellCustomAreaMeasures();
        //SetCellCustomAreaMeasures(custAreaMeasures);

        //Size indicSize = new Size(newWidth, defaultHeight);
        //Size newSize = EhLibUtils.FixSizeByCellCustomAreaMeasures(indicSize, custAreaMeasures);
        //result = newSize.Width;
      }
      return result;
    }

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

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

    public virtual int CalcRowErrorsWidth()
    {
      int result = Properties.Resources.DataGridEhRowError.Width;
      result = (result / 2 + result % 2) * 2;
      result = result + 4;
      return result;
    }

    public virtual int CalcRowAreaWidth()
    {
      string rowCountStr;

      if (!Grid.GridIsEmpty)
      {
        rowCountStr = Convert.ToString(Grid.Rows.Count + 1);
        rowCountStr = "0" + rowCountStr + "0";
      }
      else
        rowCountStr = "0";

      Size sz = TextRenderer.MeasureText(EhLibUtils.DisplayGraphicsCash, rowCountStr, Font);
      return sz.Width;
    }

    public virtual int CalcRowselCheckboxesWidth()
    {
      Size cbSize = CheckBoxRenderer.GetGlyphSize(EhLibUtils.DisplayGraphicsCash, CheckBoxState.CheckedNormal);
      return cbSize.Width + 4;
    }

    public virtual int CalcHeight(DataGridRow row)
    {
      int result = Grid.DefaultRowHeight;

      var e = new DataGridIndicatorCellHeightNeededEventArgs(0, 0, 0, 0, Rectangle.Empty, row, result);
      OnGetCellHeight(e);
      
      return e.CellHeight;
    }


    internal void HandlePaintEvent(DataGridIndicatorCellPaintEventArgs e)
    {
      var eh = this.Events[EventKeyCellPaint] as EventHandler<DataGridIndicatorCellPaintEventArgs>;
      if (eh != null)
        eh(this, e);
    }

    internal void HandleQueryCursorEvent(BaseGridCellQueryCursorEventArgs e)
    {
      var eh = this.Events[EventCellQueryCursor] as EventHandler<BaseGridCellQueryCursorEventArgs>;
      if (eh != null)
      {
        eh(this, e);
      }
    }

    internal void HandleMouseDownEvent(DataGridIndicatorCellMouseEventArgs e)
    {
      var eh = this.Events[EventCellMouseDown] as EventHandler<DataGridIndicatorCellMouseEventArgs>;
      if (eh != null)
        eh(this, e);
    }

    internal void HandleMouseMoveEvent(DataGridIndicatorCellMouseEventArgs e)
    {
      var eh = this.Events[EventKeyMouseMove] as EventHandler<DataGridIndicatorCellMouseEventArgs>;
      if (eh != null)
        eh(this, e);
    }

    internal void HandleMouseUpEvent(DataGridIndicatorCellMouseEventArgs e)
    {
      var eh = this.Events[EventKeyMouseUp] as EventHandler<DataGridIndicatorCellMouseEventArgs>;
      if (eh != null)
        eh(this, e);
    }

    internal void HandleMouseClickEvent(DataGridIndicatorCellMouseEventArgs e)
    {
      var eh = this.Events[EventKeyMouseClick] as EventHandler<DataGridIndicatorCellMouseEventArgs>;
      if (eh != null)
        eh(this, e);
    }

    internal void HandleMouseDoubleClickEvent(DataGridIndicatorCellMouseEventArgs e)
    {
      var eh = this.Events[EventKeyMouseDoubleClick] as EventHandler<DataGridIndicatorCellMouseEventArgs>;
      if (eh != null)
        eh(this, e);
    }

    internal void HandleMouseEnterEvent(DataGridIndicatorCellEnterEventArgs e)
    {
      var eh = this.Events[EventKeyMouseEnter] as EventHandler<DataGridIndicatorCellEnterEventArgs>;
      if (eh != null)
        eh(this, e);
    }

    internal void HandleMouseLeaveEvent(DataGridIndicatorCellLeaveEventArgs e)
    {
      var eh = this.Events[EventKeyMouseLeave] as EventHandler<DataGridIndicatorCellLeaveEventArgs>;
      if (eh != null)
      {
        eh(this, e);
      }
    }

    internal void HandleMouseHoverEvent(DataGridIndicatorCellMouseEventArgs e)
    {
      var eh = this.Events[EventKeyMouseHover] as EventHandler<DataGridIndicatorCellMouseEventArgs>;
      if (eh != null)
        eh(this, e);
    }
    #endregion

  }

  public class DataGridIndicatorDataCellMan : DataGridBaseIndicatorCellMan
  {
    //Painting
    public override BaseGridCellPaintEventArgs GetCellPaintParams(
        Graphics graphics,
        int colIndex, int rowIndex,
        Rectangle paintRect,
        BasePaintCellStates state,
        int areaColIndex, int areaRowIndex,
        Point inCellMousePos
      )
    {
      DataGridRow row;
      if (areaRowIndex < Grid.VisibleRows.Count)
        row = Grid.VisibleRows[areaRowIndex];
      else
        row = null;
      return new DataGridIndicatorCellPaintEventArgs(this, graphics, colIndex, rowIndex, paintRect, state, areaColIndex, areaRowIndex, inCellMousePos, row);
    }

    protected internal override void HandlePaintEvent(BaseGridCellPaintEventArgs e)
    {
      Grid.IndicatorColumn.HandlePaintEvent((DataGridIndicatorCellPaintEventArgs)e);
    }

    protected internal override void OnPaintBackground(BaseGridCellPaintEventArgs e)
    {
      Color backColor = Grid.IndicatorColumn.BackFiller.Color;

      StyledPaintArgs.CellRect = e.CellRect;
      StyledPaintArgs.Graphics = e.Graphics;
      StyledPaintArgs.IsHot = false;
      StyledPaintArgs.IsPressed = false;
      StyledPaintArgs.IsSelected = (e.State & BasePaintCellStates.Selected) != 0;
      StyledPaintArgs.BackColor = backColor;
      StyledPaintArgs.FillColor = Grid.IndicatorColumn.BackFiller.Color;
      StyledPaintArgs.SecondFillColor = Grid.IndicatorColumn.BackFiller.SecondColor;
      StyledPaintArgs.FillStyle = Grid.IndicatorColumn.BackFiller.FillStyle;
      StyledPaintArgs.InnerBorder = Grid.IndicatorColumn.BackFiller.InnerBorder;

      Grid.GetDrawStyle().FillTitleCell(Grid, StyledPaintArgs);
    }

    protected internal override void OnPaintForeground(BaseGridCellPaintEventArgs e)
    {
      int widthReducer = 0;
      Rectangle sectRect;
      Rectangle restRect;

      if (Grid.IndicatorColumn.ShowRowErrors)
      {
        sectRect = e.CellClientRect;
        sectRect.Width = Grid.IndicatorColumn.CalcRowAreaWidth();
        sectRect.X = e.CellClientRect.Right - sectRect.Width;
        PaintRowError(e.Graphics, sectRect, e.State, e.AreaColIndex, e.AreaRowIndex);
        widthReducer = sectRect.Width;
      }

      if (Grid.IndicatorColumn.ShowRowIndicator)
      {
        sectRect = e.CellClientRect;
        sectRect.Width = e.CellClientRect.Width - widthReducer;
        PaintRecordStateSign(e.Graphics, e.ColIndex, e.RowIndex, sectRect, e.State, e.AreaColIndex, e.AreaRowIndex);
        widthReducer = widthReducer + Grid.IndicatorColumn.RecordStateSignAreaWidth();
      }

      restRect = e.CellClientRect;
      if (Grid.IndicatorColumn.ShowRowselCheckboxes)
      {
        sectRect = restRect;
        sectRect.Width = Grid.IndicatorColumn.CalcRowselCheckboxesWidth();
        PaintRowselCheckbox(e.Graphics, sectRect, e.State, e.AreaColIndex, e.AreaRowIndex);
        restRect.X = restRect.X + sectRect.Width;
        restRect.Width = restRect.Width - sectRect.Width;
      }

      if (Grid.IndicatorColumn.ShowRecNo)
      {
        sectRect = restRect;
        sectRect.Width = e.CellClientRect.Width - widthReducer;
        PaintRowNum(e.Graphics, sectRect, e.State, e.AreaColIndex, e.AreaRowIndex);
      }

    }

    protected internal virtual void PaintRecordStateSign(Graphics graphics, int colIndex, int rowIndex,
      Rectangle paintRect, BasePaintCellStates state, int areaColIndex, int areaRowIndex)
    {
      Bitmap bmp = null;
      RowEditState rowState = Grid.DataLink.CurrentListItemState;
      Rectangle bmpRect = paintRect;
      Rectangle centerRect = new Rectangle(0, 0, 10, 10);

      //if (dataRowIndex == Grid.Row - Grid.FixedRowCount)
      if (areaRowIndex == Grid.CurrentDataRowIndex)
      {
        bmpRect.Width = Grid.IndicatorColumn.RecordStateSignAreaWidth();
        bmpRect.X = paintRect.Right - bmpRect.Width;

        if (Grid.DataLink.EditorHasValueToPush)
          bmp = DataGridManager.DefaultManager.GetEditRecordIndicatorRightImage();
        else if (rowState == RowEditState.Edit)
          bmp = DataGridManager.DefaultManager.GetEditRecordIndicatorRightImage();
        else if (rowIndex == Grid.NewRowIndex && rowState == RowEditState.Add)
          bmp = DataGridManager.DefaultManager.GetEditRecordIndicatorRightImage();
        else
          bmp = Properties.Resources.CurRecordIndicatorRight;

        bmpRect.X = bmpRect.Right - 10;
        bmpRect.Width = 10;

        centerRect.Offset(
          new Point((bmpRect.Width - centerRect.Width) / 2,
                    (bmpRect.Height - centerRect.Height) / 2));
        centerRect.Offset(bmpRect.Left, bmpRect.Top);
      }
      else if (areaRowIndex == Grid.VisibleRows.Count && Grid.AllowedOperations.AllowAdd)
      {
        bmp = Properties.Resources.NavigatorNew;

        centerRect = EhLibUtils.RectCenter(centerRect, paintRect);
        centerRect.Y = centerRect.Y + 1;
      }

      if (bmp != null)
      {
        Grid.PaintingDrawImage(graphics, bmp, centerRect);
      }
    }

    protected internal virtual void PaintRowNum(Graphics graphics,
                                          Rectangle paintRect,
                                          BasePaintCellStates state,
                                          int areaColIndex,
                                          int areaRowIndex)
    {
      //TextFormatFlags aligntFlags;

      //aligntFlags = TextFormatFlags.Left | TextFormatFlags.VerticalCenter;
      Font font = Grid.IndicatorColumn.Font;
      Color foreColor = Grid.ForeColor;

      if ((state & BasePaintCellStates.Selected) != 0)
        foreColor = Grid.GetDrawStyle().GetFixedSelectedForeColor(Grid, Grid.FixedBackFiller.Color, foreColor);

      Rectangle dataRect = paintRect;

      string text = GetDisplayText(areaColIndex, areaRowIndex);
      Grid.PaintingDrawText(graphics, text, font, dataRect, foreColor, 
        HorizontalAlignment.Center, VerticalAlignment.Center, false);

    }

    protected internal virtual void PaintRowError(Graphics graphics,
                                          Rectangle paintRect,
                                          BasePaintCellStates state,
                                          int areaColIndex,
                                          int areaRowIndex)
    {
      if (areaRowIndex >= Grid.VisibleRows.Count) return;

      DataGridRow row = Grid.VisibleRows[areaRowIndex];
      string errorText = Grid.DataLink.GetRowError(row.Index);
      if (!String.IsNullOrEmpty(errorText))
      {
        Bitmap image = Properties.Resources.DataGridEhRowError;

        Rectangle imageArea = new Rectangle(Point.Empty, image.Size);
        imageArea = EhLibUtils.RectCenter(imageArea, paintRect);

        graphics.DrawImage(image, imageArea);
      }
    }

    protected internal virtual void PaintRowselCheckbox(Graphics graphics,
                                          Rectangle paintRect,
                                          BasePaintCellStates state,
                                          int areaColIndex,
                                          int areaRowIndex)
    {
      if (areaRowIndex >= Grid.VisibleRows.Count) return;

      DataGridRow row = Grid.VisibleRows[areaRowIndex];

      Rectangle chRect = new Rectangle();
      bool isHot = false;
      bool isDown = false;
      GridCoord mouseHolderCellCoord = Grid.MouseHolderCellCoord;
      CheckBoxState cbState;
      int gridColIndex;
      int gridRowIndex;

      if (row.Selected)
        cbState = CheckBoxState.CheckedNormal;
      else
        cbState = CheckBoxState.UncheckedNormal;

      Size cbSize = CheckBoxRenderer.GetGlyphSize(graphics, cbState);
      chRect.Size = cbSize;
      chRect = EhLibUtils.RectCenter(chRect, paintRect);
      cbState = EhLibUtilsInternal.FixCheckBoxStateByState(cbState, isHot, isDown, true);

      AreaCellPosToGridCellPos(areaColIndex, areaRowIndex, out gridColIndex, out gridRowIndex);

      if (mouseHolderCellCoord.X == gridColIndex &&
          mouseHolderCellCoord.Y == gridRowIndex)
      {
        isHot = true;
      }

      cbState = EhLibUtilsInternal.FixCheckBoxStateByState(cbState, isHot, isDown, true);

      Grid.GetDrawStyle().DrawRowselCheckBox(graphics, chRect.Location, cbState, true, true);
    }

    //Handle Mouse 
    protected internal override BaseGridCellMouseEventArgs CreateMouseEventArgs(
      int colIndex, int rowIndex, int areaColIndex, int areaRowIndex, int inCellX, int inCellY,
      Rectangle cellRect, MouseEventArgs gridMouseArgs)
    {
      DataGridRow row;
      if (areaRowIndex < Grid.VisibleRows.Count)
        row = Grid.VisibleRows[areaRowIndex];
      else
        row = null;

      return new DataGridIndicatorCellMouseEventArgs(this, colIndex, rowIndex, areaColIndex, areaRowIndex, inCellX, inCellY, cellRect, gridMouseArgs, row);
    }

    protected internal override void HandleMouseDownEvent(BaseGridCellMouseEventArgs e)
    {
      Grid.IndicatorColumn.HandleMouseDownEvent((DataGridIndicatorCellMouseEventArgs)e);
    }

    protected internal override void OnMouseDown(BaseGridCellMouseEventArgs e)
    {
      if (e.GridMouseArgs.Button == MouseButtons.Left)
      {
        if (Grid.Selection.RowsSelectionIsAllowed)
        {
          bool addToSelection = ((Control.ModifierKeys & Keys.Control) != 0) ||
                                Grid.Selection.KeepSelect;
          Grid.StartRowSelection(Grid.VisibleRows[e.AreaRowIndex], addToSelection, true, (Control.ModifierKeys & Keys.Shift) != 0);
        }
      }
    }

    protected internal override void HandleMouseMoveEvent(BaseGridCellMouseEventArgs e)
    {
      Grid.IndicatorColumn.HandleMouseMoveEvent((DataGridIndicatorCellMouseEventArgs)e);
    }

    protected internal override void HandleMouseUpEvent(BaseGridCellMouseEventArgs e)
    {
      Grid.IndicatorColumn.HandleMouseUpEvent((DataGridIndicatorCellMouseEventArgs)e);
    }

    protected internal override void HandleMouseClickEvent(BaseGridCellMouseEventArgs e)
    {
      Grid.IndicatorColumn.HandleMouseClickEvent((DataGridIndicatorCellMouseEventArgs)e);
    }

    protected internal override void HandleMouseDoubleClickEvent(BaseGridCellMouseEventArgs e)
    {
      Grid.IndicatorColumn.HandleMouseDoubleClickEvent((DataGridIndicatorCellMouseEventArgs)e);
    }

    protected internal override BaseGridCellEnterEventArgs CreateCellEnterEventArgs(
      int colIndex, int rowIndex, int areaColIndex, int areaRowIndex, Rectangle cellRect, int leaveColIndex, int leaveRowIndex)
    {
      DataGridRow row;
      if (areaRowIndex < Grid.VisibleRows.Count)
        row = Grid.VisibleRows[areaRowIndex];
      else
        row = null;

      var de = new DataGridIndicatorCellEnterEventArgs(colIndex, rowIndex, areaColIndex, areaRowIndex, cellRect, leaveColIndex, leaveRowIndex, row);
      return de;
    }

    protected override void HandleMouseEnterEvent(BaseGridCellEnterEventArgs e)
    {
      Grid.IndicatorColumn.HandleMouseEnterEvent((DataGridIndicatorCellEnterEventArgs)e);
    }

    protected internal override BaseGridCellLeaveEventArgs CreateCellLeaveEventArgs(
      int colIndex, int rowIndex, int areaColIndex, int areaRowIndex, Rectangle cellRect, int enterColIndex, int enterRowIndex)
    {
      DataGridRow row;
      if (areaRowIndex < Grid.VisibleRows.Count)
        row = Grid.VisibleRows[areaRowIndex];
      else
        row = null;

      var de = new DataGridIndicatorCellLeaveEventArgs(colIndex, rowIndex, areaColIndex, areaRowIndex, cellRect, enterColIndex, enterRowIndex, row);
      return de;
    }

    protected override void HandleMouseLeaveEvent(BaseGridCellLeaveEventArgs e)
    {
      Grid.IndicatorColumn.HandleMouseLeaveEvent((DataGridIndicatorCellLeaveEventArgs)e);
    }

    protected override void HandleMouseHoverEvent(BaseGridCellMouseEventArgs e)
    {
      Grid.IndicatorColumn.HandleMouseHoverEvent((DataGridIndicatorCellMouseEventArgs)e);
    }

    //Other
    protected internal override BaseGridCellEventArgs CreateCellEventArgs(
      int colIndex, int rowIndex, int areaColIndex, int areaRowIndex, Rectangle cellRect)
    {
      DataGridRow row;
      if (areaRowIndex < Grid.VisibleRows.Count)
        row = Grid.VisibleRows[areaRowIndex];
      else
        row = null;

      return new DataGridIndicatorCellEventArgs(colIndex, rowIndex, areaColIndex, areaRowIndex, cellRect, row);
    }

    public override void GridCellPosToAreaCellPos(int gridColIndex, int gridRowIndex, out int areaColIndex, out int areaRowIndex)
    {
      areaColIndex = gridColIndex;
      areaRowIndex = gridRowIndex - Grid.FixedRowCount;
    }

    protected internal override void OnQueryCursor(BaseGridCellQueryCursorEventArgs e)
    {
      if (Grid.Selection.RowsSelectionIsAllowed &&
          !Grid.IndicatorColumn.ShowRowselCheckboxes)
      {
        if ((e.AreaRowIndex >= 0) && (e.AreaRowIndex < Grid.VisibleRows.Count))
          e.Cursor = Grid.GetDrawStyle().RightArrowSelectCursor();
      }
    }

    protected internal override void HandleQueryCursorEvent(BaseGridCellQueryCursorEventArgs e)
    {
      Grid.IndicatorColumn.HandleQueryCursorEvent(e);
    }

    public override string GetDisplayText(int areaColIndex, int areaRowIndex)
    {
      DataGridIndicatorColumn indCol = Grid.IndicatorColumn;

      if ((areaRowIndex >= Grid.VisibleRows.Count) || (areaRowIndex < 0))
        return "";
      else if (((indCol.RecNoShowStep > 0) && (areaRowIndex % indCol.RecNoShowStep == 0)) ||
            (areaRowIndex == 0) ||
            (areaRowIndex == Grid.VisibleRows.Count - 1) ||
            (areaRowIndex == Grid.CurrentRowIndex)
         )
      {
        areaRowIndex = areaRowIndex + 1;
        return areaRowIndex.ToString();
      }
      else if ((indCol.RecNoShowStep % 2 == 0) &&
                ((areaRowIndex % indCol.RecNoShowStep) == (indCol.RecNoShowStep / 2))
              )
      {
        return "-";
      }
      else
        return ((char)(0xB7)).ToString();

    }

    protected internal override bool IsSelected(int areaColIndex, int areaRowIndex)
    {
      if ((Grid.Selection.SelectionType == GridSelectionType.Rows) &&
          (areaRowIndex >= 0) &&
          (areaRowIndex < Grid.VisibleRows.Count))
      {
        return Grid.VisibleRows[areaRowIndex].Selected;
      }
      else if (Grid.Selection.SelectionType == GridSelectionType.All)
        return true;
      else
        return false;
    }

    public override void AreaCellPosToGridCellPos(int areaColIndex, int areaRowIndex, out int gridColIndex, out int gridRowIndex)
    {
      gridColIndex = areaColIndex;
      gridRowIndex = areaRowIndex + Grid.FixedRowCount;
    }
  }

}