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

using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Diagnostics;
using System.Drawing;
using System.Drawing.Design;
using System.Drawing.Drawing2D;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Windows.Forms.VisualStyles;

namespace EhLib
{
  [DesignerCategory("Code")]
  [Designer("EhLib.Design.DataVertGridDesigner" + EhLibUtils.EhLibDesignDesignerVersionInfo)]
  [ToolboxItem(true)]
  [ToolboxBitmap(typeof(DataVertGridEh), "ToolboxBitmaps.EhLib_DataVertGrid.bmp")]
  //[ToolboxBitmap(typeof(DataGridEh))]
  [ComplexBindingProperties("DataSource", "DataMember")]
  [Description("Displays rows and columns of data in a grid you can customize where properties of a list is shown as rows and list items as columns")]
  public class DataVertGridEh : DataAxisGrid
  {
    #region private consts
    #endregion private consts

    #region privates
    private DataAxisGridDataCellMan emptyDataCell;
    internal readonly DataVertGridTitleColumnCellMan titleCell;
    private bool gridIsEmpty;
    private int internalCurrentColumnIndex;

    private DataVertGridIndicatorTitle indicatorTitle;
    private readonly DataVertGridIndicatorTitleCellMan titleIndicatorCell;
    private DataVertGridIndicatorRow indicatorRow;
    private readonly DataVertGridIndicatorDataCellMan indicatorRowCell;

    protected List<object> listItems;
    private ReadOnlyCollection<object> visibleColumns;

    private Padding leftAlignDefaultPadding;
    private Padding centerAlignDefaultPadding;
    private Padding rightAlignDefaultPadding;

    private readonly DataVertGridRowOptions rowOptions;
    private readonly DataVertGridColumnOptions columnOptions;

    public int TitleColumnBaseColIndex { get; internal set; }
    public int StartDataColumnBaseColIndex { get; internal set; }
    public int StartDataRowBaseRowIndex { get; internal set; }
    public int EmptyDataColumnBaseColIndex { get; internal set; }

    protected internal int DataColumnWidth;
    private DataVertGridManager manager;
    #endregion

    public DataVertGridEh()
    {
      Options = GridOptions.DrawFocusSelected | GridOptions.Editing |
                GridOptions.ColSizing |
                //GridOptions.RowSizing | GridOptions.ColSizing |
                //GridOption.RowMoving | //GridOption.ColMoving | 
                GridOptions.Tabs |
                GridOptions.ContraHorzBoundaryLine | GridOptions.ContraVertBoundaryLine;

      this.ColCount = 2;
      this.FixedRowCount = 0;
      this.RowCount = 1;

      emptyDataCell = new DataVertGridEmptyCellManager();
      emptyDataCell.Grid = this;

      titleCell = new DataVertGridTitleColumnCellMan();
      titleCell.Grid = this;

      titleIndicatorCell = new DataVertGridIndicatorTitleCellMan();
      titleIndicatorCell.Grid = this;
      indicatorRowCell = new DataVertGridIndicatorDataCellMan();
      indicatorRowCell.Grid = this;

      indicatorTitle = CreateIndicatorTitle();
      indicatorRow = CreateIndicatorRow();

      listItems = new List<object>();
      visibleColumns = new ReadOnlyCollection<object>(listItems);

      rowOptions = new DataVertGridRowOptions(this);
      columnOptions = new DataVertGridColumnOptions(this);
      UpdatePaddingsForSidePadding();

      InitData();

      UpdateBaseFixedBands();
      UpdateRowsList();
    }

    internal void InitData()
    {
      UpdateGridState();
    }

    #region design-time properties
    public bool AutoGenerateRows
    {
      get { return base.AutoGeneratePropBars; }
      set { base.AutoGeneratePropBars = value; }
    }

    [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
    public DataVertGridTitleColumn TitleColumn
    {
      get { return (DataVertGridTitleColumn)base.TitleBar; }
    }

    [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
    public DataVertGridLineOptions LineOptions
    {
      get { return (DataVertGridLineOptions)GridLineColors; }
    }

    [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
    public DataVertGridRowOptions RowOptions
    {
      get { return rowOptions; }
    }

    [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
    public DataVertGridColumnOptions ColumnOptions
    {
      get { return columnOptions; }
    }

    [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
    [Editor("EhLib.Design.DataVertGridRowsEditor" + EhLibUtils.EhLibDesignDesignerVersionInfo, "System.Drawing.Design.UITypeEditor, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a")]
    public DataVertGridStaticRowsCollection StaticRows
    {
      get { return (DataVertGridStaticRowsCollection)base.StaticPropBars; }
    }

    [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
    public new DataVertGridKeyboardOptions KeyboardOptions
    {
      get
      {
        return (DataVertGridKeyboardOptions)base.KeyboardOptions;
      }
    }

    [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
    public DataVertGridIndicatorTitle IndicatorTitle
    {
      get { return indicatorTitle; }
    }

    [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
    public DataVertGridIndicatorRow IndicatorRow
    {
      get { return indicatorRow; }
    }
    #endregion 

    #region run-time properties
    [Browsable(false)]
    [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
    public ReadOnlyCollection<object> VisibleColumns
    {
      get { return visibleColumns; }
    }

    [Browsable(false)]
    [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
    public bool GridIsEmpty
    {
      get { return gridIsEmpty; }
    }

    [Browsable(false)]
    [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
    public DataAxisGridDataCellMan EmptyDataCell
    {
      get { return emptyDataCell; }
    }

    [Browsable(false)]
    [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
    public DataVertGridTitleColumnCellMan TitleCell
    {
      get { return titleCell; }
    }

    [Browsable(false)]
    public override int CurrentDataColIndex
    {
      get { return Col - FixedColCount; }
    }

    [Browsable(false)]
    public override int CurrentDataRowIndex
    {
      get { return Row - FixedRowCount; }
    }

    [Browsable(false)]
    [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
    protected internal int InternalCurrentColumnIndex
    {
      get
      {
        return internalCurrentColumnIndex;
      }

      set
      {
        if (internalCurrentColumnIndex != value)
        {
          internalCurrentColumnIndex = value;
          if (internalCurrentColumnIndex != -1)
            Col = internalCurrentColumnIndex + FixedColCount;
          else
            InvalidateCol(Col);
        }
      }
    }

    [Browsable(false)]
    [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
    public DataVertGridReadOnlyRowCollection DynamicRows
    {
      get { return (DataVertGridReadOnlyRowCollection)base.DynamicPropBars; }
    }

    [Browsable(false)]
    [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
    public DataVertGridMainRowCollection Rows
    {
      get { return (DataVertGridMainRowCollection)base.PropBars; }
    }

    [Browsable(false)]
    [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
    public DataVertGridReadOnlyRowCollection ViewOrderedRows
    {
      get { return (DataVertGridReadOnlyRowCollection)base.ViewOrderedPropBars; }
    }

    [Browsable(false)]
    [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
    public DataVertGridReadOnlyRowCollection VisibleRows
    {
      get { return (DataVertGridReadOnlyRowCollection)base.VisiblePropBars; }
    }

    [Browsable(false)]
    [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
    public int CurrentRowIndex
    {
      get { return Row - FixedRowCount; }
      set { Row = value + FixedRowCount; }
    }

    protected override PropertyAxisBar CurrentPropBar
    {
      get
      {
        if (CurrentRowIndex < VisibleRows.Count)
          return VisibleRows[CurrentRowIndex];
        else
          return null;
      }
    }

    protected override object CurrentListItemBar
    {
      get
      {
        if (VisibleColumns.Count > 0)
          return VisibleColumns[CurrentDataColIndex];
        else
          return null;
      }
    }

    [Browsable(false)]
    [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
    protected virtual DataVertGridManager DefaultManager
    {
      get
      {
        return DataVertGridManager.DefaultManager;
      }
    }

    [Browsable(false)]
    [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
    public DataVertGridManager Manager
    {
      get
      {
        if (manager != null)
          return manager;
        else
          return DefaultManager;
      }
      set
      {
        manager = Manager;
      }
    }
    #endregion 

    #region public methods
    public virtual DataVertGridDrawStyle GetDrawStyle()
    {
      return EhLibDrawStyle.DefaultDataVertGridDrawStyle;
    }

    public void GetColumnRowByDataColRowIndex(int areaColIndex, int areaRowIndex,
      out DataVertGridRow row, out object listItem)
    {
      if (areaRowIndex < VisibleRows.Count)
        row = VisibleRows[areaRowIndex];
      else
        row = null;

      if (areaColIndex < VisibleColumns.Count)
        listItem = VisibleColumns[areaColIndex];
      else
        listItem = null;
    }
    #endregion 

    #region nopublic methods

    //AutoGenerateRows
    protected virtual bool DefaultAutoGenerateRows()
    {
      return DefaultAutoGeneratePropBars();
    }

    protected virtual bool ShouldSerializeAutoGenerateRows()
    {
      return ShouldSerializeAutoGeneratePropBars();
    }

    public virtual void ResetAutoGenerateRows()
    {
      ResetAutoGeneratePropBars();
    }

    //Keyboard handling
    protected override void OnKeyDown(KeyEventArgs e)
    {
      base.OnKeyDown(e);
      if (e.Handled) return;

      switch (e.KeyData & Keys.KeyCode)
      {
        case Keys.F2:
          {
            e.Handled = ProcessF2Key(e.KeyData);
            return;
          }
      }
    }

    protected override bool ProcessDialogKey(Keys keyData)
    {
      Keys key = (keyData & Keys.KeyCode);

      switch (key)
      {
        case Keys.Enter:
          {
            if (ProcessEnterKey(keyData))
              return true;
            else
              break;
          }

        case Keys.Escape:
          {
            if (ProcessEscapeKey(keyData))
              return true;
            else
              break;
          }
      }

      return base.ProcessDialogKey(keyData);
    }

    protected override bool IsInputKey(Keys keyData)
    {
      switch (keyData & Keys.KeyCode)
      {
        case Keys.Tab:
          {
            Keys altData = (keyData & (Keys.Control | Keys.Shift | Keys.Alt));
            if ((altData == 0 || altData == Keys.Shift) && ((GridOptions.Tabs & Options) != 0))
              return (KeyboardOptions.TabKeyAction != GridKeyboardAction.None);
            else
              break;
          }
      }
      return base.IsInputKey(keyData);
    }

    //Other
    protected override GridKeyboardOptions CreateKeyboardOptions()
    {
      return new DataVertGridKeyboardOptions(this);
    }

    public override void InteractiveFocusCell(int col, int row, InteractiveActionSource actionSource)
    {
      if ((col == Col) && (row == Row)) return;
      if (!PrepareChangeCellPos()) return;
      //if ((ModifierKeys & Keys.Shift) != 0) return;
      if (!DataLink.Active) return;

      if ((col - FixedColCount) == visibleColumns.Count)
        DataLink.AddNew();
      else
        DataLink.Position = col - FixedColCount;

      FocusCell(Col, row, false);
    }

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

    protected override GridLineColors CreateGridLineColors()
    {
      return new DataVertGridLineOptions(this);
    }

    protected internal override void CurrencyManagerListChanged(object sender, ListChangedEventArgs e)
    {
      switch (e.ListChangedType)
      {
        case ListChangedType.Reset:
          UpdateRowsList();
          CheckPropBarsPropDescr();
          UpdateDataColumns();
          UpdateRowHeights();
          if (CurrencyManager != null)
            CurrencyManagerPositionChanged(null, null);
          break;

        case ListChangedType.ItemMoved:
          UpdateDataColumns();
          break;

        case ListChangedType.ItemAdded:
          //object row = CurrencyManager.List[e.NewIndex];
          //if ((e.NewIndex < Rows.Count) && (addedSrcRow == row))
          //  EhLibUtils.DoNothing();//Do nothing. It is second time
          //else
          //{
          //  AddDataRow(e.NewIndex);
          //  addedSrcRow = row;
          //}
          UpdateDataColumns();
          UpdateRowHeights();
          break;

        case ListChangedType.ItemChanged:
          //UpdateDataRow(e.NewIndex);
          UpdateDataColumns();
          UpdateRowHeights();
          break;

        case ListChangedType.ItemDeleted:
          //DeleteItem(e.NewIndex);
          UpdateDataColumns();
          UpdateRowHeights();
          break;

        default:
          UpdateRowsList();
          UpdateDataColumns();
          break;
      }
    }

    protected internal override void CurrencyManagerPositionChanged(object sender, EventArgs e)
    {
      UpdateGridColumnIndexFromCurrencyManagerPosition();

      //TODO: return this code for DataPropertyGrid
      //UpdateDataColumns();
      //UpdateRowHeights();
    }

    internal void UpdateGridColumnIndexFromCurrencyManagerPosition()
    {
      if (CurrencyManager.Position >= 0 && CurrencyManager.Position < VisibleColumns.Count)
      {
        InternalCurrentColumnIndex = CurrencyManager.Position;
      }
    }

    protected internal virtual void UpdateRowsView()
    {
      UpdatePropBarsView();
    }

    protected internal override void UpdatePropBarsView()
    {
      base.UpdatePropBarsView();
      UpdateGridState();
      UpdateBaseGridRows();
      //TODO ?
      //UpdateFitColWidthsToClient();
    }

    protected internal void UpdateRowsList()
    {
      UpdatePropBarsList();
    }

    protected internal virtual void UpdateDataColumns()
    {
      UpdateListItems();

      UpdateBaseGridRows();
      //UpdateDataColumnWidths();

      UpdateBaseColCount();
      UpdateBaseColWidths();
      InvalidateGrid();
    }

    protected internal virtual void UpdateListItems()
    {
      listItems.Clear();
      if (CurrencyManager != null && CurrencyManager.Count > 0)
      {
        //listItems.Add(CurrencyManager.Current);
        for (int i = 0; i < CurrencyManager.Count; i++)
        {
          listItems.Add(CurrencyManager.List[i]);
        }
      }
    }

    public override PropertyAxisBar CreatePropBarFromType(Type type)
    {
      return Manager.GetDataGridRowFromType(type);
    }

    public override Type GetAxisBarTypeForDataType(Type type)
    {
      return Manager.GetDataGridRowTypeForDataType(type);
    }

    internal virtual void UpdateGridState()
    {
      gridIsEmpty = (Rows.Count == 0) && (CurrencyManager == null);
    }

    protected override DataAxisGridReadOnlyPropBarCollection CreatePropBarReadOnlyCollection(IList<PropertyAxisBar> list)
    {
      return new DataVertGridReadOnlyRowCollection(this, list);
    }

    protected override DataAxisGridMainPropBarCollection CreatePropBarMainCollection(IList<PropertyAxisBar> list)
    {
      return new DataVertGridMainRowCollection(this, list);
    }

    protected override DataAxisGridStaticPropBarCollection CreateStaticPropBarCollection()
    {
      return new DataVertGridStaticRowsCollection(this);
    }

    protected internal virtual bool RowCanBeVisible(DataVertGridRow dataVertGridRow)
    {
      return true;
    }

    protected internal override DataAxisGridTitleBar CreateTitleBar()
    {
      return new DataVertGridTitleColumn(this);
    }

    internal void UpdateRowHeights()
    {
      foreach (DataVertGridRow row in Rows)
      {
        row.Height = row.CalcHeight();
      }

      UpdateBaseGridRows();
    }

    internal void UpdateBaseGridRows()
    {
      if ((InInitialization) || Rows.Updating) return;

      int newFixedRowCount = 0;
      int newRowCount;
      bool vertLayoutChanged = false;

      if (IndicatorRow.Visible)
        newFixedRowCount = 1;

      if (FixedRowCount != newFixedRowCount)
      {
        FixedRowCount = newFixedRowCount;
        vertLayoutChanged = true;
      }

      StartDataRowBaseRowIndex = FixedRowCount;

      newRowCount = FixedRowCount + VisibleRows.Count;
      if (VisibleRows.Count == 0)
        newRowCount = FixedRowCount + 1;

      if (RowCount != newRowCount)
      {
        RowCount = newRowCount;
        vertLayoutChanged = true;
      }

      for (int i = 0; i < VisibleRows.Count; i++)
      {
        DataVertGridRow row = VisibleRows[i];

        int newRowHeight = row.Height + LineOptions.VertLineSpace;
        if (newRowHeight != this.RowHeights[i + FixedRowCount])
        {
          this.RowHeights[i + FixedRowCount] = newRowHeight;
          vertLayoutChanged = true;
        }
      }

      if (vertLayoutChanged)
        UpdateBaseColWidths();
      Invalidate();
    }

    internal void UpdateBaseColCount()
    {
      int newColCount;
      if (VisibleColumns.Count == 0)
        newColCount = FixedColCount + 1;
      else
        newColCount = FixedColCount + VisibleColumns.Count;

      TitleColumnBaseColIndex = 0;
      if (VisibleColumns.Count == 0)
      {
        StartDataColumnBaseColIndex = -1;
        EmptyDataColumnBaseColIndex = 1;
      }
      else
      {
        StartDataColumnBaseColIndex = 1;
        EmptyDataColumnBaseColIndex = -1;
      }

      this.ColCount = newColCount;
    }

    internal protected virtual void UpdateBaseColWidths()
    {
      //int width = HorzAxis.GridClientLen;

      int titleColWidth = TitleColumn.Width;
      //if (titleColWidth > width - 4)
      //  titleColWidth = width - 4;
      //if (titleColWidth < 0)
      //  titleColWidth = width / 2;
      //DataColumnWidth = width - titleColWidth;

      ColWidths[0] = titleColWidth;
      if (VisibleColumns.Count == 0)
      {
        ColWidths[1] = ColumnOptions.Width;
      }
      else
      {
        for (int i = 0; i < VisibleColumns.Count; i++)
        {
          ColWidths[i + StartDataColumnBaseColIndex] = ColumnOptions.Width;
        }
      }
    }

    protected internal override void UpdatePaddingsForSidePadding()
    {
      leftAlignDefaultPadding = new Padding(2);
      leftAlignDefaultPadding.Right = 0;

      centerAlignDefaultPadding = new Padding(2);
      centerAlignDefaultPadding.Right = 0;
      centerAlignDefaultPadding.Left = 0;

      rightAlignDefaultPadding = new Padding(2);
      rightAlignDefaultPadding.Left = 0;
    }

    protected internal override Padding GetDataCellSidePadding()
    {
      return RowOptions.SidePadding;
    }

    protected internal override void SidePaddingChanged()
    {
      UpdatePaddingsForSidePadding();
      UpdateRowHeights();
    }

    protected internal override Padding GetDefaultPaddingForAlign(HorizontalAlignment horzAlign, VerticalAlignment vertAlign)
    {
      switch (horzAlign)
      {
        case HorizontalAlignment.Left:
          return leftAlignDefaultPadding;

        case HorizontalAlignment.Center:
          return centerAlignDefaultPadding;

        case HorizontalAlignment.Right:
          return rightAlignDefaultPadding;

        default:
          return Padding.Empty;
      }
    }

    protected internal override VerticalAlignment DefaultVertAlign()
    {
      return VerticalAlignment.Top;
    }

    internal void RowHeightAutoExpandChanged()
    {
      if (!InInitialization)
        UpdateRowHeights();
    }

    public override BaseGridCellManager CellByColRow(int colIndex, int rowIndex)
    {
      if (rowIndex >= 0 && rowIndex < FixedRowCount)
      {
        if (colIndex < FixedRowCount)
          return titleIndicatorCell;
        else
          return indicatorRowCell;
      }
      else if (colIndex >= 0 && colIndex < FixedColCount)
      {
        if (gridIsEmpty)
          return emptyDataCell;
        else if (VisibleRows.Count > 0)
          return titleCell;
        else
          return emptyDataCell;
      }
      else
      {
        if (gridIsEmpty || colIndex == -1)
          return emptyDataCell;
        else if (VisibleRows.Count == 0)
          return emptyDataCell;
        else
        {
          if (VisibleRows.Count > 0)
          {
            DataVertGridRow dataRowIndex = VisibleRows[rowIndex - FixedRowCount];
            if (colIndex - FixedColCount < VisibleColumns.Count)
              return dataRowIndex.InternalGetColumnCell(colIndex - FixedColCount);
            else
              return dataRowIndex.NewVirtualRowCell;
          }
          else
            return emptyDataCell;
        }
      }
    }

    protected override void OnEndInitialization()
    {
      UpdateBaseFixedBands();
      UpdateRowsList();
      UpdateDataColumns();
      UpdateRowHeights();
      UpdateGridState();
    }

    protected internal override bool FixedColsSizingAllowed()
    {
      return true;
    }

    protected override bool CanResizeCol(int colIndex, int rowIndex, int xPos, int yPos, int inCellXPos, int inCellYPos)
    {
      bool result = base.CanResizeCol(colIndex, rowIndex, xPos, yPos, inCellXPos, inCellYPos);
      if (colIndex != FixedColCount - 1)
        return false;
      else
        return result;
    }

    protected override void InteractiveSetColWidths(int colIndex, int newSize)
    {
      if (colIndex == FixedColCount - 1)
        TitleColumn.Width = newSize;
      else
        base.InteractiveSetColWidths(colIndex, newSize);
    }

    internal void TitleColumnWidthChanged()
    {
      if ((InInitialization) || Rows.Updating) return;
      UpdateBaseColWidths();
      UpdateRowHeights();
    }

    protected internal override HorizontalAlignment DefaultHorzAlignForType(Type dataType)
    {
      return HorizontalAlignment.Left;
    }

    protected internal override void RowHeightAffectPropertyChanged()
    {
      if (!InInitialization)
        UpdateRowHeights();
    }

    protected override void OnHandleCreated(EventArgs e)
    {
      base.OnHandleCreated(e);
      UpdateBaseColWidths();
    }

    protected internal override bool CanShowEditor()
    {
      return !EditorBanned && RowOptions.CanShowEditor();
    }

    protected internal override void OnDataCellContextMenuStripNeeded(DataAxisGridDataCellContextMenuStripNeededEventArgs age)
    {
      if (RowOptions.ContextMenuStrip != null)
        age.ContextMenuStrip = RowOptions.ContextMenuStrip;
      else
        age.ContextMenuStrip = ContextMenuStrip;
    }

    protected virtual DataVertGridIndicatorTitle CreateIndicatorTitle()
    {
      return new DataVertGridIndicatorTitle(this);
    }

    protected virtual DataVertGridIndicatorRow CreateIndicatorRow()
    {
      return new DataVertGridIndicatorRow(this);
    }
    #endregion
  }

  public class DataVertGridBaseCellManager : BaseGridCellManager
  {

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

    protected internal override void OnGetCellBorderParams(BaseGridCellBorderEventArgs e)
    {
      e.Style = DashStyle.Solid;

      if ((e.BorderType == GridCellBorderType.Left) || (e.BorderType == GridCellBorderType.Right))
      {
        if ((e.ColIndex < Grid.FixedColCount) || (e.RowIndex < Grid.FixedRowCount))
          e.Visible = Grid.LineOptions.VertLines;
        else
          e.Visible = Grid.LineOptions.VertLines;
        e.IsExtent = true;
      }
      else
      {
        if ((e.ColIndex < Grid.FixedColCount) || (e.RowIndex < Grid.FixedRowCount))
          e.Visible = Grid.LineOptions.HorzLines;
        else
          e.Visible = Grid.RowOptions.HorzLine.Visible;
        e.IsExtent = true;
      }

      if ((e.BorderType == GridCellBorderType.Top || e.BorderType == GridCellBorderType.Left) &&
          ((e.ColIndex == Grid.ColCount) || (e.RowIndex == Grid.RowCount))
      )
        e.Color = Grid.GridLineColors.DarkColor;
      else if ((e.ColIndex < Grid.FixedColCount - Grid.FrozenColCount) || (e.RowIndex < Grid.FixedRowCount - Grid.FrozenRowCount))
        e.Color = Grid.LineOptions.DarkColor;
      else if ((e.ColIndex == Grid.FixedColCount - 1) && (e.BorderType == GridCellBorderType.Right))
        e.Color = Grid.LineOptions.DarkColor;
      else if ((e.RowIndex == Grid.FixedRowCount - 1) && (e.BorderType == GridCellBorderType.Bottom))
        e.Color = Grid.LineOptions.DarkColor;
      else
        e.Color = Grid.LineOptions.BrightColor;
    }
  }

  [DataAxisGridDataCellDesignTimeVisibleAttribute(false)]
  public class DataVertGridEmptyCellManager : DataAxisGridDataCellMan
  {
    public override string GetDisplayText(int areaColIndex, int areaRowIndex)
    {
      return null;
    }

    protected internal override void OnPaintBackground(BaseGridCellPaintEventArgs e)
    {
      using (
        SolidBrush fillBrush = new SolidBrush(Grid.BackColor))
      {
        if ((BasePaintCellStates.Selected & e.State) != 0)
        {
          if (Grid.IsActiveControl())
            fillBrush.Color = SystemColors.Highlight;
          else
            fillBrush.Color = SystemColors.ButtonShadow;
        }

        Grid.PaintingFillRectangle(e.Graphics, fillBrush, e.CellClientRect);
      }
    }
  }

  [TypeConverter(typeof(ExpandableObjectConverter))]
  public class DataVertGridLineOptions : GridLineColors
  {
    #region privates
    private bool horzLines = true;
    private bool vertLines = true;
    #endregion privates

    public DataVertGridLineOptions(BaseGridControl grid) : base(grid)
    {
    }

    #region design-time properties
    public new Color DarkColor
    {
      get { return base.DarkColor; }
      set { base.DarkColor = value; }
    }

    public new Color BrightColor
    {
      get { return base.BrightColor; }
      set { base.BrightColor = value; }
    }

    [DefaultValue(true)]
    public bool HorzLines
    {
      get { return horzLines; }
      set
      {
        if (horzLines != value)
        {
          horzLines = value;
          HorzLinesChanged();
        }
      }
    }

    [DefaultValue(true)]
    public bool VertLines
    {
      get { return vertLines; }
      set
      {
        if (vertLines != value)
        {
          vertLines = value;
          VertLinesChanged();
        }
      }
    }
    #endregion

    #region run-time properties
    [Browsable(false)]
    protected new DataVertGridEh Grid
    {
      get { return (DataVertGridEh)base.Grid; }
    }

    [Browsable(false)]
    public int VertLineSpace
    {
      get
      {
        if (VertLines)
          return Grid.GridLineWidth;
        else
          return 0;
      }
    }

    [Browsable(false)]
    public int HorzLineSpace
    {
      get
      {
        if (HorzLines)
          return Grid.GridLineWidth;
        else
          return 0;
      }
    }
    #endregion

    #region methods
    protected virtual void VertEmptySpaceStyleChanged()
    {
      Grid.InvalidateGrid();
    }

    protected virtual void HorzEmptySpaceStyleChanged()
    {
      Grid.InvalidateGrid();
    }

    protected virtual void GridBoundariesChanged()
    {
      Grid.InvalidateGrid();
    }

    protected virtual void HorzLinesChanged()
    {
      if (HorzLines)
        Grid.Options = Grid.Options | GridOptions.HorzLines;
      else
        Grid.Options = Grid.Options & ~GridOptions.HorzLines;

      Grid.UpdateRowsView();
    }

    protected virtual void VertLinesChanged()
    {
      Grid.UpdateBaseColWidths();
    }
    #endregion methods

  }

  public class DataVertGridObject : object
  {
    private readonly DataVertGridEh grid;

    public DataVertGridObject(DataVertGridEh grid)
    {
      this.grid = grid;
    }

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

  }

  [TypeConverter(typeof(ExpandableObjectConverter))]
  public class DataVertGridRowOptions : DataVertGridObject, IGridLineHost, IGridRowHeightOptionsOwner
  {

    #region privates
    private bool allowShowEditor = true;
    private bool foreColorStored;
    private Color foreColor = Color.Empty;
    private Padding sidePadding = new Padding(2, 2, 2, 2);
    private bool sidePaddingStored;
    private Font font;
    private DataGridTextWrapMode wrapMode = DataGridTextWrapMode.Auto;
    private VerticalAlignment vertAlign = VerticalAlignment.Top;
    private readonly GridLine horzLine;
    private readonly GridRowHeightOptions heightOptions;
    #endregion privates

    public DataVertGridRowOptions(DataVertGridEh grid) : base(grid)
    {
      this.horzLine = new GridLine(this);
      this.heightOptions = new GridRowHeightOptions(this);
    }

    #region properties
    [DefaultValue(true)]
    public bool AllowShowEditor
    {
      get
      {
        return allowShowEditor;
      }
      set
      {
        if ((allowShowEditor != value))
        {
          allowShowEditor = value;
        }
      }
    }

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

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

    public Padding SidePadding
    {
      get
      {
        if (sidePaddingStored)
          return sidePadding;
        else
          return DefaultSidePadding();
      }
      set
      {
        if ((sidePaddingStored == false) || (sidePadding != value))
        {
          sidePaddingStored = true;
          sidePadding = value;
          SidePaddingChanged();
        }
      }
    }

    [DefaultValue(DataGridTextWrapMode.Auto)]
    public DataGridTextWrapMode WrapMode
    {
      get
      {
        return wrapMode;
      }
      set
      {
        if (wrapMode != value)
        {
          wrapMode = value;
          WrapModeChanged();
        }
      }
    }

    [DefaultValue(VerticalAlignment.Top)]
    public VerticalAlignment VertAlign
    {
      get
      {
        return vertAlign;
      }
      set
      {
        if (vertAlign != value)
        {
          vertAlign = value;
          VertAlignChanged();
        }
      }
    }

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

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

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

    #region methods

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

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

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

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

    //IGridLineHost
    void IGridLineHost.GridLineChanged(GridLine gl)
    {
      GridLineChanged(gl);
    }

    protected virtual void GridLineChanged(GridLine gl)
    {
      Grid.Invalidate();
    }

    public virtual bool GridLineDefaultVisible(GridLine gl)
    {
      return Grid.LineOptions.VertLines;
    }

    public virtual Color GridLineDefaultColor(GridLine gl)
    {
      return Grid.LineOptions.BrightColor;
    }

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

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

    bool IGridRowHeightOptionsOwner.HeightOptionsDefaultAutoExpand(GridRowHeightOptions heightOptions)
    {
      return false;
    }

    int IGridRowHeightOptionsOwner.HeightOptionsDefaultContentHeight(GridRowHeightOptions heightOptions)
    {
      return 1;
    }

    int IGridRowHeightOptionsOwner.HeightOptionsDefaultMaxContentHeight(GridRowHeightOptions heightOptions)
    {
      return 0;
    }

    GridRowHeightUnit IGridRowHeightOptionsOwner.HeightOptionsDefaultUnit(GridRowHeightOptions heightOptions)
    {
      return GridRowHeightUnit.TextLine;
    }

    //Others
    protected virtual void VertAlignChanged()
    {
      Grid.Invalidate();
    }

    private void WrapModeChanged()
    {
      Grid.UpdateRowHeights();
    }

    protected virtual void ForeColorChanged()
    {
      Grid.InvalidateGrid();
    }

    public virtual Color DefaultForeColor()
    {
      return Grid.ForeColor;
    }

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

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

    protected virtual void SidePaddingChanged()
    {
      Grid.SidePaddingChanged();
    }

    private Padding DefaultSidePadding()
    {
      return Grid.GetDrawStyle().GetColumnOptionsSidePadding();
    }

    protected virtual bool ShouldSerializeSidePadding()
    {
      return (sidePaddingStored == true);
    }

    public virtual void ResetSidePadding()
    {
      sidePaddingStored = false;
      SidePaddingChanged();
    }

    protected virtual void HeightTextLinesChanged()
    {
      Grid.UpdateRowHeights();
    }

    public virtual bool CanShowEditor()
    {
      if (AllowShowEditor && Grid.Options.HasFlag(GridOptions.Editing))
        return true;
      else
        return false;
    }

    internal void EditItemOptionsChanged()
    {
      Grid.Invalidate();
    }
    #endregion methods

  }

  [TypeConverter(typeof(ExpandableObjectConverter))]
  public class DataVertGridColumnOptions : DataVertGridObject
  {
    #region privates
    private bool fitWidthToWinClient = false;
    private int width = 200;
    #endregion

    public DataVertGridColumnOptions(DataVertGridEh grid) : base(grid)
    {
    }

    #region properties
    [DefaultValue(false)]
    public bool FitWidthToWinClient
    {
      get
      {
        return fitWidthToWinClient;
      }
      set
      {
        if (fitWidthToWinClient != value)
        {
          fitWidthToWinClient = value;
        }
      }
    }

    [DefaultValue(200)]
    public int Width
    {
      get
      {
        return width;
      }
      set
      {
        if (width != value)
        {
          width = value;
        }
      }
    }
    #endregion

    #region methods

    //Others
    #endregion

  }


  [TypeConverter(typeof(ExpandableObjectConverter))]
  public class DataVertGridKeyboardOptions : GridKeyboardOptions
  {

    public DataVertGridKeyboardOptions(DataAxisGrid grid) : base(grid)
    {
      base.TabKeyAction = GridKeyboardAction.NextRowCell;
    }

    [DefaultValue(GridKeyboardAction.NextRowCell)]
    public override GridKeyboardAction TabKeyAction
    {
      get { return base.TabKeyAction; }
      set { base.TabKeyAction = value; }
    }
  }
}
