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

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

namespace EhLib
{
  public enum DataGridTitleNodeType
  {
    ColumnTitle,
    SuperTitle
  }

  public interface IMultiTitleNodeProvider
  {
    DataGridTitleNode GetNode();
    DataGridTitleNodeType NodeType { get; }
    DataGridColumnTitle ColumnTitle { get; }
    DataGridSuperTitle SuperTitle { get; }
  }

  public class ColumnTitleNodeProviders : List<IMultiTitleNodeProvider>
  {

  }

  [TypeConverter(typeof(ExpandableObjectConverter))]
  [DesignerCategory("Code")]
  [ToolboxItem(false)]
  public class DataGridMultiTitle : Component
  {
    #region private consts
    private static readonly object EventKeyCustomAreaNeeded = new object();
    private static readonly object EventKeyMouseDown = 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 EventKeySuperTitlePaint = new object();
    private static readonly object EventKeySuperTitleClientRectNeeded = new object();

    #endregion private consts

    #region privates
    private readonly DataGridTitle title;
    private bool active;
    private int fullHeight;

    private DataGridMultiTitleTreeList titleTree;

    internal DataGridTitleNode TitleMovingFromNode { get; set; }
    internal int TitleMovingBaseMouseY { get; set; }
    #endregion

    #region constructor
    public DataGridMultiTitle(DataGridTitle title)
    {
      this.title = title;
      titleTree = new DataGridMultiTitleTreeList(this);
    }
    #endregion

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

      set
      {
        if (active != value)
        {
          active = value;
          if (active)
          {
            TitleTree.RefreshColumnsNode();
          }
          else
          {
            DeleteAllSuperTitles();
            //Grid.MultiTitleChanged();
          }
        }
      }
    }

    [Browsable(true)]
    [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
    public MultiTitleNodeProviderList Subtitles
    {
      get { return TitleTree.Root.Subtitles; }
    }

    public DataGridMultiTitleTreeList TitleTree
    {
      get { return titleTree; }
    }
    #endregion

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

    [Browsable(false)]
    [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
    public DataGridTitleNode Root
    {
      get { return TitleTree.Root; }
    }

    [Browsable(false)]
    public int FullHeight
    {
      get { return fullHeight; }
    }
    #endregion

    #region events

    //public event EventHandler<DataGridSuperTitleCellCustomAreaNeededEventArgs> CustomAreaNeeded
    //{
    //  add
    //  {
    //    this.Events.AddHandler(EventKeyCustomAreaNeeded, value);
    //  }
    //  remove
    //  {
    //    this.Events.RemoveHandler(EventKeyCustomAreaNeeded, value);
    //  }
    //}

    public event EventHandler<DataGridSuperTitleCellMouseEventArgs> MouseDown
    {
      add
      {
        this.Events.AddHandler(EventKeyMouseDown, value);
      }
      remove
      {
        this.Events.RemoveHandler(EventKeyMouseDown, value);
      }
    }

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

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

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

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

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

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

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

    public event EventHandler<SuperTitlePaintEventArgs> SuperTitlePaint
    {
      add
      {
        this.Events.AddHandler(EventKeySuperTitlePaint, value);
      }
      remove
      {
        this.Events.RemoveHandler(EventKeySuperTitlePaint, value);
      }
    }

    public event EventHandler<DataGridSuperTitleCellClientAreaNeededEventArgs> SuperTitleClientRectNeeded
    {
      add
      {
        this.Events.AddHandler(EventKeySuperTitleClientRectNeeded, value);
      }
      remove
      {
        this.Events.RemoveHandler(EventKeySuperTitleClientRectNeeded, value);
      }
    }
    #endregion

    #region methods
    private void DeleteAllSuperTitles()
    {
      BeginUpdate();
      try
      {
        DeleteSuperTitlesNodes(Root);
      }
      finally
      {
        EndUpdate();
      }
    }

    private void DeleteSuperTitlesNodes(DataGridTitleNode superTitleNode)
    {
      DataGridTitleNode[] nodes = superTitleNode.Items.ToArray();

      foreach (DataGridTitleNode node in nodes)
      {
        if (node.NodeType == DataGridTitleNodeType.SuperTitle)
        {
          DeleteSuperTitlesNodes(node);
          node.SuperTitle.Dispose();
        }
      }
    }

    public void BeginUpdate()
    {
      TitleTree.BeginUpdate();
    }

    public void EndUpdate()
    {
      TitleTree.EndUpdate();
    }

    protected internal virtual void PaintTitleTree(Graphics graphics, Rectangle rect, Point shift)
    {
      PaintTitleTree(Root, graphics, rect, shift);
    }

    protected internal virtual void PaintTitleTree(DataGridTitleNode node,
      Graphics graphics, Rectangle rect, Point shift)
    {
      node.Paint(graphics, rect, shift);
      for (int i = 0; i < node.VisibleItems.Count; i++)
      {
        PaintTitleTree(node.VisibleItems[i], graphics, rect, shift);
      }
    }

    internal DataGridTitleNode GetNodeAtGridAtPos(Point pos, out Point inCellPos, out Rectangle cellRect)
    {
      inCellPos = new Point(-1, -1);
      cellRect = new Rectangle(-1, -1, -1, -1);

      if (Active == true)
      {
        Point mtStartPos = Point.Empty;

        mtStartPos.X = (int)(Grid.HorzAxis.FixedBoundary - Grid.HorzAxis.RollStartVisPos);
        mtStartPos.Y = Grid.VertAxis.GridClientStart;

        mtStartPos.X = pos.X - mtStartPos.X;
        mtStartPos.Y = pos.Y - mtStartPos.Y;

        DataGridTitleNode tn = TitleTree.GetNodeAtPos(mtStartPos);
        if (tn == null) return null;
        //Debug.Assert(tn != null, "tn != null");

        cellRect = tn.Bounds;
        cellRect.Offset((int)(Grid.HorzAxis.FixedBoundary - Grid.HorzAxis.RollStartVisPos), Grid.VertAxis.GridClientStart);

        inCellPos = new Point(pos.X - cellRect.X, pos.Y - cellRect.Y);

        return tn;
      }
      else
      {
        return null;
      }
    }

    internal bool CheckBeginColumnDrag(ref int moveFromIndex, ref int moveToIndex, Point mousePos)
    {
      Point inCellPos;
      Rectangle cellRect;

      DataGridTitleNode tn = GetNodeAtGridAtPos(mousePos, out inCellPos, out cellRect);
      if (tn == null) return false;
      //TitleMovingFromNode = tn;
      //TitleMovingBaseMouseY = tn.Bounds.Top + Grid.VertAxis.GridClientStart;

      DataGridTitleNode lbn = TitleTree.GetFirstBottomVisibleNode(tn);
      DataGridColumn dgc = lbn.ColumnTitle.Column;
      moveFromIndex = dgc.VisibleIndex + Grid.StartDataColIndex;

      if (inCellPos.X > cellRect.Width / 2)
      {
        lbn = TitleTree.GetLastBottomVisibleNode(tn);
        dgc = lbn.ColumnTitle.Column;
        moveToIndex = dgc.VisibleIndex + 1 + Grid.StartDataColIndex;
      }
      else
      {
        lbn = TitleTree.GetFirstBottomVisibleNode(tn);
        dgc = lbn.ColumnTitle.Column;
        moveToIndex = dgc.VisibleIndex + Grid.StartDataColIndex;
      }

      return true;
    }

    public virtual void ReadStorableSettings(Dictionary<string, object> settings)
    {
      TitleTree.BeginUpdate();
      try
      {
        ReadSettingsForNode(settings, Root);
      }
      finally
      {
        TitleTree.EndUpdate();
      }
    }

    private void ReadSettingsForNode(Dictionary<string, object> nodeSettings, DataGridTitleNode node)
    {
      foreach (DataGridTitleNode childNode in node.Items)
      {
        if (childNode.NodeType == DataGridTitleNodeType.SuperTitle)
        {
          DataGridSuperTitle st = childNode.SuperTitle;
          object superTitleSettingsObj;
          Dictionary<string, object> superTitleSettings = null;

          if (nodeSettings.TryGetValue(st.Name, out superTitleSettingsObj))
            superTitleSettings = superTitleSettingsObj as Dictionary<string, object>;
          if (superTitleSettings != null)
          {
            DataGridManager.DefaultManager.ReadMultiTitleSuperTitleNodeSettings(Grid, childNode, superTitleSettings);

            object itemsObj;
            Dictionary<string, object> itemsSettings;
            if (superTitleSettings.TryGetValue("Items", out itemsObj))
            {
              itemsSettings = itemsObj as Dictionary<string, object>;
              if (itemsSettings != null)
                ReadSettingsForNode(itemsSettings, childNode);
            }
          }
        }
        else
        {
          DataGridColumn col = childNode.ColumnTitle.Column;
          object columnTitleSettingsObj;
          Dictionary<string, object> columnTitleSettings = null;

          if (nodeSettings.TryGetValue(col.Name, out columnTitleSettingsObj))
            columnTitleSettings = columnTitleSettingsObj as Dictionary<string, object>;
          if (columnTitleSettings != null)
            DataGridManager.DefaultManager.ReadMultiTitleColumnTitleNodeSettings(Grid, childNode, columnTitleSettings);
        }
      }
    }

    internal protected virtual Dictionary<string, object> GetStorableSettings()
    {
      return GetSettingsForNode(Root);
    }

    internal protected virtual Dictionary<string, object> GetSettingsForNode(DataGridTitleNode node)
    {
      var nodeSettings = new Dictionary<string, object>();

      foreach (DataGridTitleNode childNode in node.Items)
      {
        string keyValue;

        if (childNode.NodeType == DataGridTitleNodeType.SuperTitle)
        {
          DataGridSuperTitle st = childNode.SuperTitle;
          keyValue = st.Name;

          var stSettings = new Dictionary<string, object>();
          DataGridManager.DefaultManager.WriteMultiTitleSuperTitleNode(Grid, childNode, stSettings);

          var stChildSettings = GetSettingsForNode(childNode);
          stSettings.Add("Items", stChildSettings);

          nodeSettings.Add(keyValue, stSettings);
        }
        else
        {
          DataGridColumn col = childNode.ColumnTitle.Column;
          if (!String.IsNullOrEmpty(col.Name))
            keyValue = col.Name;
          else if (!String.IsNullOrEmpty(col.DataPropertyName))
            keyValue = col.DataPropertyName;
          else
            keyValue = col.Index.ToString();

          var colTitleSettings = new Dictionary<string, object>();
          DataGridManager.DefaultManager.WriteMultiTitleColumnTitleNode(Grid, childNode, colTitleSettings);
          nodeSettings.Add(keyValue, colTitleSettings);
        }
      }

      return nodeSettings;
    }

    internal void FillColumnsViewList(List<PropertyAxisBar> columnsViewList)
    {
      DataGridTitleNode node = TitleTree.GetFirst();
      while (node != null)
      {
        if (node.NodeType == DataGridTitleNodeType.ColumnTitle)
        {
          columnsViewList.Add(node.ColumnTitle.Column);
        }
        node = TitleTree.GetNext(node);
      }
    }

    internal void MoveColumn(int dataFromColIndex, int dataToColIndex)
    {
      int additive = 0;
      DataGridTitleNode parentNode = TitleMovingFromNode.Parent;
      DataGridColumn column;

      if (dataToColIndex == Grid.VisibleColumns.Count)
      {
        dataToColIndex = dataToColIndex - 1;
        additive = 1;
      }

      column = Grid.VisibleColumns[dataToColIndex];
      DataGridTitleNode inParentToNode = TitleTree.GetNodeForParent(parentNode, column.Title.TitleNode);
      if (inParentToNode == null && dataToColIndex > 0)
      {
        dataToColIndex = dataToColIndex - 1;
        additive = 1;
        column = Grid.VisibleColumns[dataToColIndex];
        inParentToNode = TitleTree.GetNodeForParent(parentNode, column.Title.TitleNode);
      }

      if (inParentToNode == null || inParentToNode == TitleMovingFromNode) return;

      if (parentNode.TreeList != null)
        parentNode.TreeList.BeginUpdate();

      try
      {
        parentNode.Items.Remove(TitleMovingFromNode);

        parentNode.Items.Insert(inParentToNode.Index + additive, TitleMovingFromNode);
      }
      finally
      {
        if (parentNode.TreeList != null)
          parentNode.TreeList.EndUpdate();
      }
    }

    internal bool CheckColumnDrag(ref int moveFromIndex, ref int moveToIndex, Point mousePos)
    {
      Point inCellPos;
      Rectangle cellRect;
      if (mousePos.X <= Grid.HorzAxis.FixedBoundary)
        mousePos.X = Grid.HorzAxis.FixedBoundary + 1;
      else if (mousePos.X >= Grid.HorzAxis.RollInClientBoundary)
        mousePos.X = Grid.HorzAxis.RollInClientBoundary - 1;

      Point fixedMousePos = new Point(mousePos.X, TitleMovingBaseMouseY);

      DataGridTitleNode tn = GetNodeAtGridAtPos(fixedMousePos, out inCellPos, out cellRect);
      if (tn != null && tn.Parent == TitleMovingFromNode.Parent)
      {
        if (inCellPos.X > cellRect.Width / 2)
        {
          DataGridTitleNode lbn = TitleTree.GetLastBottomVisibleNode(tn);
          DataGridColumn dgc = lbn.ColumnTitle.Column;
          moveToIndex = dgc.VisibleIndex + 1 + Grid.StartDataColIndex;
        }
        else
        {
          DataGridTitleNode lbn = TitleTree.GetFirstBottomVisibleNode(tn);
          DataGridColumn dgc = lbn.ColumnTitle.Column;
          moveToIndex = dgc.VisibleIndex + Grid.StartDataColIndex;
        }
        return true;
      }
      else
        return false;
    }

    internal void ColumnWidthsChanged()
    {
      ResetNodesBound();
    }

    public virtual void ResetNodesBound()
    {
      CalcSetAllNodesSize(Root);
    }

    public virtual void CalcSetAllNodesSize(DataGridTitleNode rootNode)
    {
      SetNodeWidthAndLeft(rootNode, 0);
      fullHeight = SetNodeHeight(rootNode);
      SetNodeTop(rootNode, 0);
    }

    public virtual int SetNodeWidthAndLeft(DataGridTitleNode titleNode, int startPos)
    {
      int sumWidth = 0;
      Rectangle tnBounds = titleNode.Bounds;

      if (titleNode.NodeType == DataGridTitleNodeType.SuperTitle)
      {
        for (int i = 0; i < titleNode.VisibleItems.Count; i++)
        {
          sumWidth = sumWidth + SetNodeWidthAndLeft(titleNode.VisibleItems[i], sumWidth + startPos);
        }
        tnBounds.Width = sumWidth;
        tnBounds.X = startPos;
        titleNode.Bounds = tnBounds;
      }
      else
      {
        sumWidth = titleNode.ColumnTitle.Column.Width + Grid.LineOptions.HorzLineSpace;
        tnBounds.Width = sumWidth;
        tnBounds.X = startPos;
        titleNode.Bounds = tnBounds;
      }
      return sumWidth;
    }

    public virtual int SetNodeHeight(DataGridTitleNode titleNode)
    {
      int maxHeight = 0;
      int[] subTreesHeight = new int[titleNode.VisibleItems.Count];
      int resultHeight;

      if (titleNode.NodeType == DataGridTitleNodeType.SuperTitle)
      {
        for (int i = 0; i < titleNode.VisibleItems.Count; i++)
        {
          subTreesHeight[i] = SetNodeHeight(titleNode.VisibleItems[i]);

          if (subTreesHeight[i] > maxHeight)
            maxHeight = subTreesHeight[i];
        }

        for (int i = 0; i < titleNode.VisibleItems.Count; i++)
        {
          titleNode.VisibleItems[i].BoundsInternal.Height =
            titleNode.VisibleItems[i].BoundsInternal.Height + (maxHeight - subTreesHeight[i]);
        }

        titleNode.BoundsInternal.Height = titleNode.CalcNodeHeight();
        resultHeight = maxHeight + titleNode.BoundsInternal.Height;
      }
      else
      {
        resultHeight = titleNode.CalcNodeHeight();
        titleNode.BoundsInternal.Height = resultHeight;
      }

      return resultHeight;
    }

    public virtual void SetNodeTop(DataGridTitleNode titleNode, int newTop)
    {
      titleNode.BoundsInternal.Y = newTop;
      newTop = newTop + titleNode.BoundsInternal.Height;
      if (titleNode.Items.Count == 0)
      {
        if (newTop < fullHeight)
          titleNode.BoundsInternal.Height = titleNode.BoundsInternal.Height + (fullHeight - newTop);
      }
      else
      {
        for (int i = 0; i < titleNode.Items.Count; i++)
          SetNodeTop(titleNode.Items[i], newTop);
      }
    }

    internal void FixSizingLineBound(ref int startPos, ref int finishPos, DataGridColumn column)
    {
      DataGridTitleNode node = TitleTree.FindNodeByColumnTitle(column.Title, null);
      DataGridTitleNode upNode = node;
      int stHeight = 0;
      while (true)
      {
        stHeight = stHeight + upNode.Bounds.Height;
        upNode = upNode.Parent;
        if (upNode == Root) break;
        if (node.Bounds.Right != upNode.Bounds.Right) break;
      }
      startPos = startPos + FullHeight - stHeight;
    }

    internal void SynchroniseWithGridColumns()
    {
      TitleTree.SynchroniseWithGridColumns();
    }

    protected internal virtual bool ColumnCanBeVisible(DataGridColumn column)
    {
      return column.Title.TitleNode.NodePathIsVisible();
    }

    protected virtual bool ShouldSerializeSubtitles()
    {
      return (Active == true);
    }

    protected internal virtual DataGridSuperTitleCellEventArgs CreateCellEventArgs(BaseGridCellEventArgs e, DataGridSuperTitle superTitle)
    {
      return new DataGridSuperTitleCellEventArgs(e, superTitle);
    }

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

    protected internal virtual void ProcessMouseMove(DataGridSuperTitleCellMouseEventArgs e)
    {
      HandleMouseMoveEvent(e);
    }

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

    protected internal virtual void ProcessMouseUp(DataGridSuperTitleCellMouseEventArgs e)
    {
      HandleMouseUpEvent(e);
    }

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

    protected internal virtual void ProcessMouseClick(DataGridSuperTitleCellMouseEventArgs e)
    {
      HandleMouseClickEvent(e);
    }

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

    protected internal virtual void ProcessMouseDoubleClick(DataGridSuperTitleCellMouseEventArgs e)
    {
      HandleMouseDoubleClickEvent(e);
    }

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

    protected internal virtual void ProcessMouseEnter(DataGridSuperTitleCellEventArgs e)
    {
      HandleMouseEnter(e);
    }

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

    protected internal virtual void ProcessMouseLeave(DataGridSuperTitleCellEventArgs e)
    {
      HandleMouseLeave(e);
    }

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

    protected internal virtual void ProcessMouseHover(DataGridSuperTitleCellMouseEventArgs e)
    {
      HandleMouseHoverEvent(e);
    }

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

    //internal void HandleCellCustomAreaNeededEvent(DataGridSuperTitleCellCustomAreaNeededEventArgs e)
    //{
    //  var eh = this.Events[EventKeyCustomAreaNeeded] as EventHandler<DataGridSuperTitleCellCustomAreaNeededEventArgs>;
    //  if (eh != null)
    //  {
    //    eh(this, e);
    //  }
    //}

    internal void HandlePaintEvent(SuperTitlePaintEventArgs e)
    {
      var eh = this.Events[EventKeySuperTitlePaint] as EventHandler<SuperTitlePaintEventArgs>;
      if (eh != null /*&& !this.IsDisposed*/)
      {
        eh(this, e);
      }
    }

    internal void HandleClientRectNeededEvent(DataGridSuperTitleCellClientAreaNeededEventArgs e)
    {
      var eh = this.Events[EventKeySuperTitleClientRectNeeded] as EventHandler<DataGridSuperTitleCellClientAreaNeededEventArgs>;
      if (eh != null /*&& !this.IsDisposed*/)
      {
        eh(this, e);
      }
    }
    #endregion

  }

  //  [TypeConverter(typeof(ExpandableObjectConverter))]
  public class DataGridMultiTitleTreeList : TreeListGeneric<DataGridTitleNode>
  {
    #region privates
    private DataGridMultiTitle multiTitle;
    private int updateCount;
    private bool treeListChanged;
    private bool nodeVisibleChanged;

    //private bool titleMovingMode;
    //private int titleMovingFromIndex;
    //private int titleMovingToIndex;
    #endregion

    #region constructor
    public DataGridMultiTitleTreeList(DataGridMultiTitle multiTitle)
    {
      this.multiTitle = multiTitle;
    }
    #endregion

    #region run-time properties
    public DataGridMultiTitle MultiTitle
    {
      get { return multiTitle; }
    }

    [Browsable(false)]
    [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
    public BaseTreeNodeItemsGeneric<DataGridTitleNode> TitleNodes
    {
      get { return Root.Items; }
    }

    [Browsable(false)]
    public bool Updating
    {
      get
      {
        if (MultiTitle.Grid.InInitialization || updateCount > 0)
          return true;
        return false;
      }
    }

    #endregion

    #region methods
    internal DataGridTitleNode FindNodeByColumnTitle(DataGridColumnTitle dataGridColumnTitle, DataGridTitleNode startNode)
    {
      DataGridTitleNode result;
      
      if (startNode == null) startNode = Root;
      for (int i = 0; i < startNode.Items.Count; i++)
      {
        if (startNode.Items[i].ColumnTitle == dataGridColumnTitle)
          return startNode.Items[i];
        result = FindNodeByColumnTitle(dataGridColumnTitle, startNode.Items[i]);
        if (result != null)
          return result;
      }
      return null;
    }

    internal void RefreshColumnsNode()
    {
      BeginUpdate();
      try
      {
        Clear();
        foreach (DataGridColumn col in MultiTitle.Grid.Columns)
        {
          if (FindNodeByColumnTitle(col.Title, Root) == null)
            Root.Subtitles.Add(col);
        }
      }
      finally
      {
        EndUpdate();
      }
    }

    public override DataGridTitleNode CreateNodeApart()
    {
      DataGridTitleNode colNode = base.CreateNodeApart();
      //colNode.Data = new DataGridTitleNodeData();
      return colNode;
    }

    public virtual int FixNodeHeight(DataGridTitleNode titleNode)
    {
      int itemsHeight;
      int resultHeight = 0;

      if (titleNode.NodeType == DataGridTitleNodeType.SuperTitle)
      {
        for (int i = 0; i < titleNode.Items.Count; i++)
        {
          itemsHeight = FixNodeHeight(titleNode.Items[i]);

          titleNode.BoundsInternal.Height = titleNode.BoundsInternal.Height - itemsHeight;
          resultHeight = itemsHeight + titleNode.BoundsInternal.Height;
        }
      }
      else
      {
        resultHeight = titleNode.BoundsInternal.Height;
      }

      return resultHeight;
    }

    public DataGridTitleNode GetNodeAtPos(Point pos)
    {
      foreach (DataGridTitleNode tn in Root.VisibleItems)
      {
        if (tn.Bounds.Contains(pos))
          return tn;
        if (tn.VisibleItems.Count > 0)
        {
          DataGridTitleNode hitNode = GetNodeAtPos(tn, pos);
          if (hitNode != null)
            return hitNode;
        }
      }
      return null;
    }

    private DataGridTitleNode GetNodeAtPos(DataGridTitleNode titleNode, Point pos)
    {
      foreach (DataGridTitleNode tn in titleNode.VisibleItems)
      {
        if (tn.Bounds.Contains(pos))
          return tn;
        if (tn.VisibleItems.Count > 0)
        {
          DataGridTitleNode hitNode = GetNodeAtPos(tn, pos);
          if (hitNode != null)
            return hitNode;
        }
      }
      return null;
    }

    public void BeginUpdate()
    {
      updateCount++;
    }

    public void EndUpdate()
    {
      EndUpdate(true);
    }

    internal void EndUpdate(bool updateChanges)
    {
      updateCount--;
      if (updateCount < 0)
        throw new InvalidOperationException(@"EhLib.DataGridMultiTitle.EndUpdate() updateCount < 0");
      if (updateCount == 0 && updateChanges && (treeListChanged || nodeVisibleChanged))
      {
        if (treeListChanged)
          CheckNodesConsistency();
        MultiTitle.ResetNodesBound();
        CheckUpdateChildIndexFromNewIndex(Root);
        MultiTitle.Grid.MultiTitleChanged();
        treeListChanged = false;
        nodeVisibleChanged = false;
      }
    }

    protected override void TreeChanged(DataGridTitleNode node, TreeListNotification operation, int oldIndex, DataGridTitleNode oldParentNode)
    {
      if (!Updating)
      {
        CheckNodesConsistency();
        MultiTitle.ResetNodesBound();
        MultiTitle.Grid.MultiTitleChanged();
      }
      else
      {
        treeListChanged = true;
      }
    }

    private void CheckNodesConsistency()
    {
      HashSet<DataGridTitleNode> hashNodeList = new HashSet<DataGridTitleNode>();
      HashSet<object> hashDataList = new HashSet<object>();
      object val;

      DataGridTitleNode node = GetFirst();
      while (node != null)
      {
        if (hashNodeList.Contains(node))
          throw new InvalidOperationException("node already included in the TreeList: " + node.ToString());
        hashNodeList.Add(node);

        if (node.NodeType == DataGridTitleNodeType.ColumnTitle)
        {
          val = node.ColumnTitle;
          if (MultiTitle.Grid.Columns.IndexOf(node.ColumnTitle.Column) < 0)
            throw new InvalidOperationException("Column is not in the Grid.Columns: " + node.ColumnTitle.Column.ToString());
        }
        else
          val = node.SuperTitle;

        if (hashDataList.Contains(val))
          throw new InvalidOperationException("node value already included in the TreeList: " + val.ToString());
        hashDataList.Add(val);

        node = GetNext(node);
      }

      foreach(DataGridColumn col in MultiTitle.Grid.Columns)
      {
        if (FindNodeByColumnTitle(col.Title, Root) == null)
          throw new InvalidOperationException("column is not in the MultiTitleTreeList: " + col.ToString());
      }
    }

    internal void SynchroniseWithGridColumns()
    {
      BeginUpdate();
      try
      {
        DataGridTitleNode node;

        //Delete deleted
        while (true)
        {
          node = FindNodeNotInGridColumns();
          if (node == null)
            break;
          else
            DeleteNodeAndEmptyUpNodes(node);
        }

        //Add added
        foreach (DataGridColumn col in MultiTitle.Grid.Columns)
        {
          if (FindNodeByColumnTitle(col.Title, Root) == null)
          {
            MultiTitle.Subtitles.Add(col);
          }
        }
      }
      finally
      {
        EndUpdate();
      }
    }

    internal DataGridTitleNode FindNodeNotInGridColumns()
    {
      DataGridTitleNode node = GetFirst();
      while (node != null)
      {
        if (node.NodeType == DataGridTitleNodeType.ColumnTitle)
        {
          if (MultiTitle.Grid.Columns.IndexOf(node.ColumnTitle.Column) < 0)
            return node;
        }
        node = GetNext(node);
      }
      return null;
    }

    private void DeleteNodeAndEmptyUpNodes(DataGridTitleNode node)
    {
      DataGridTitleNode parent = node.Parent;
      parent.Delete(node.Index);
      if (parent.Items.Count == 0 && parent != Root)
      {
        DeleteNodeAndEmptyUpNodes(parent);
      }
    }

    protected override void OnAddingAdoptedNode(DataGridTitleNode node)
    {
      node.TreeList.ExtractNode(node, true);
      //if (node.NodeType == DataGridTitleNodeType.ColumnTitle)
      //  node.TreeList.ExtractNode(node, true);
      //else
      //  base.OnAddingAdoptedNode(node);
    }

    protected override void NodeVisibleChanged(DataGridTitleNode node)
    {
      if (!Updating)
      {
        MultiTitle.Grid.MultiTitleChanged();
      }
      else
      {
        nodeVisibleChanged = true;
      }
    }

    internal DataGridTitleNode GetLastBottomVisibleNode(DataGridTitleNode node)
    {
      if (node.VisibleItems.Count > 0)
        return GetLastBottomVisibleNode(node.VisibleItems[node.VisibleItems.Count - 1]);
      else
        return node;
    }

    internal DataGridTitleNode GetFirstBottomVisibleNode(DataGridTitleNode node)
    {
      if (node.VisibleItems.Count > 0)
        return GetFirstBottomVisibleNode(node.VisibleItems[0]);
      else
        return node;
    }

    internal void CheckUpdateChildIndexFromNewIndex(DataGridTitleNode parentNode)
    {
      if (parentNode.childNewIndexChanged)
        parentNode.SetChildPositionsFromNewIndex(false);

      foreach (DataGridTitleNode chNode in parentNode.Items)
      {
        CheckUpdateChildIndexFromNewIndex(chNode);
      }
    }

    internal DataGridTitleNode GetNodeForParent(DataGridTitleNode parentNode, DataGridTitleNode lowChildNode)
    {
      if (lowChildNode.Parent == null)
      {
        return null;
      }
      else if (lowChildNode.Parent == parentNode)
      {
        return lowChildNode;
      }
      else
      {
        return GetNodeForParent(parentNode, lowChildNode.Parent);
      }
    }

    //internal void UpdateNodesVisibility()
    //{
    //  {
    //    BeginUpdate();
    //    try
    //    {
    //      foreach (DataGridColumn col in Grid.ViewOrderedColumns)
    //        col.Title.TitleNode.Visible = col.Visible;
    //    }
    //    finally
    //    {
    //      treeListChanged = false;
    //      EndUpdate();
    //      ResetNodesBound();
    //    }
    //  }
    //}

    internal DataGridTitleNode GetNodeByDisplayIndex(int displayIndex)
    {
      if (displayIndex >= 0 && displayIndex < MultiTitle.Grid.ViewOrderedColumns.Count)
      {
        DataGridTitleNode titleNode = MultiTitle.Grid.ViewOrderedColumns[displayIndex].Title.TitleNode;
        DataGridTitleNode inRootNode = titleNode;

        while (inRootNode.Parent != Root)
        {
          inRootNode = inRootNode.Parent;
        }

        return inRootNode;
      }
      else
      {
        return null;
      }
    }
    #endregion
  }

  public class DataGridTitleNode : BaseTreeNode
  {
    private DataGridTitleNodeType nodeType = DataGridTitleNodeType.SuperTitle;
    private readonly DataGridColumnTitle columnTitle;
    private readonly DataGridSuperTitle superTitle;
    internal Rectangle BoundsInternal;
    private readonly MultiTitleNodeProviderList subtitles;
    private bool newIndexStored;
    private int newIndex;
    internal bool childNewIndexChanged;

    public DataGridTitleNode()
    {
      subtitles = new MultiTitleNodeProviderList(this);
      newIndex = -1;
    }

    public DataGridTitleNode(DataGridTitleNodeType nodeType, DataGridColumnTitle columnTitle, DataGridSuperTitle superTitle)
    {
      this.nodeType = nodeType;
      this.columnTitle = columnTitle;
      this.superTitle = superTitle;
      subtitles = new MultiTitleNodeProviderList(this);
    }

    // base data
    public new DataGridTitleNodes Items
    {
      get
      {
        return (DataGridTitleNodes)base.Items;
      }
    }

    public new DataGridTitleNodes VisibleItems
    {
      get
      {
        return (DataGridTitleNodes)base.VisibleItems;
      }
    }

    public new DataGridTitleNode Parent
    {
      get
      {
        return (DataGridTitleNode)base.Parent;
      }
      set
      {
        base.Parent = value;
      }
    }

    public new DataGridMultiTitleTreeList TreeList
    {
      get
      {
        return (DataGridMultiTitleTreeList)base.TreeList;
      }
    }

    public override bool Visible
    {
      get
      {
        if (NodeType == DataGridTitleNodeType.ColumnTitle)
          return ColumnTitle.Column.Visible;
        else
          return base.Visible;
      }

      set
      {
        if (NodeType == DataGridTitleNodeType.ColumnTitle)
          Debug.Fail("Set Visible for NodeType == DataGridTitleNodeType.ColumnTitle");
        else
          base.Visible = value;
      }
    }

    public int NewIndex
    {
      get
      {
        if (newIndexStored)
          return newIndex;
        else
          return Index;
      }

      set
      {
        newIndexStored = true;
        newIndex = value;
        if (Parent != null)
          Parent.childNewIndexChanged = true;
        if (TreeList != null)
          TreeList.NodeVisibleChanged(this);
      }
    }

    protected override BaseTreeNodeItems CreateVisibleItemsList()
    {
      return new DataGridTitleNodes(this);
    }

    protected override BaseTreeNodeItems CreateItemsList()
    {
      return new DataGridTitleNodes(this);
    }

    //other
    public MultiTitleNodeProviderList Subtitles
    {
      get
      {
        return subtitles;
      }
    }

    public DataGridEh Grid
    {
      get
      {
        if (columnTitle != null)
          return columnTitle.Column.Grid;
        if (superTitle != null)
          return superTitle.Grid;
        return null;
      }
    }

    public string Caption
    {
      get
      {
        if (NodeType == DataGridTitleNodeType.SuperTitle)
          if (SuperTitle != null)
            return SuperTitle.Text;
          else
            return "";
        return ColumnTitle.Text;
      }
    }

    public DataGridTitleNodeType NodeType
    {
      get { return nodeType; }
      protected internal set { nodeType = value; }
    }

    public DataGridColumnTitle ColumnTitle
    {
      get { return columnTitle; }
    }

    public DataGridSuperTitle SuperTitle
    {
      get { return superTitle; }
    }

    public Rectangle Bounds
    {
      get { return BoundsInternal; }
      protected internal set {BoundsInternal = value; }
    }

    public virtual string Text
    {
      get
      {
        bool first = true;
        string result;
        if (NodeType == DataGridTitleNodeType.ColumnTitle)
          result = ColumnTitle.Text;
        else if (SuperTitle != null)
          result = SuperTitle.Text;
        else
          result = "Root";

        result = result + " {";

        foreach (DataGridTitleNode v in Items)
        {
          if (!first)
            result = result + ", ";
          result = result + v.Text;
          first = false;
        }

        result = result + "}";

        return result;
      }
    }

    //methods
    public IMultiTitleNodeProvider GetAsMultiTitleNodeProviderInterface()
    {
      if (nodeType == DataGridTitleNodeType.SuperTitle)
        return SuperTitle;
      return ColumnTitle.Column;
    }

    public int CalcNodeHeight()
    {
      int result;

      if (NodeType == DataGridTitleNodeType.SuperTitle)
        if (SuperTitle != null)
          result = SuperTitle.CalcDataHeight();
        else
          return 0;
      else
        result = ColumnTitle.CalcHeight();

      result = result + Grid.Title.HorzLineSpace;
      return result;
    }

    public override string ToString()
    {
      return base.ToString() + " - " + Text;
    }

    public DataGridTitleNode[] GetUpChain()
    {
      List<DataGridTitleNode> nodesChain = new List<DataGridTitleNode>();

      DataGridTitleNode loopNode = this;

      while (loopNode.Parent != null)
      {
        nodesChain.Add(loopNode);
        loopNode = loopNode.Parent;
      }

      return nodesChain.ToArray();
    }

    protected internal virtual void Paint(Graphics gr, Rectangle rect, Point shift)
    {
      if (Grid == null) return;
      Rectangle paintRect = Bounds;
      if (paintRect.Width == 0) return;
      paintRect.Offset(shift);

      CheckPaintCellBorderLines(gr, ref paintRect);
      PaintCell(gr, paintRect);
    }

    protected internal virtual void PaintCell(Graphics gr, Rectangle rect)
    {
      if (NodeType == DataGridTitleNodeType.SuperTitle)
      {
        if (SuperTitle != null)
        {

          Point inCellMousePos = new Point(-1, -1);

          SuperTitlePaintEventArgs pea = SuperTitle.GetCellPaintParams(gr, rect, inCellMousePos);
          SuperTitle.ProcessPaint(pea);
          //SuperTitle.Paint(gr, rect);
        }
      }
      else
      {
        int row = Grid.TitleRowIndex;
        int col = Grid.DataToBaseColIndex(ColumnTitle.Column.VisibleIndex);
        DataGridBaseCellMan cell = Grid.titleCellMan;

        BaseGridCellPaintEventArgs pea = cell.GetCellPaintParams(gr, col, row, rect, 0, ColumnTitle.Column.VisibleIndex, Grid.TitleRowIndex, new Point(-1, -1));
        cell.ProcessPaint(pea);
      }
    }

    protected internal virtual void CheckPaintCellBorderLines(Graphics gr, ref Rectangle rect)
    {
      bool isDrawVertLines = Grid.Title.VertLine.Visible;
      bool isDrawHorzLines = Grid.Title.HorzLine.Visible;
      Color vertLinesColor = Grid.Title.VertLine.Color;
      Color horzLinesColor = Grid.Title.HorzLine.Color;
      Grid.DrawBordersForRect(gr, ref rect, isDrawVertLines, isDrawHorzLines, vertLinesColor, horzLinesColor, DashStyle.Solid, DashStyle.Solid, true, true);
    }

    protected internal virtual void Print(PrintServiceEventArgs e, Rectangle rowRect)
    {
      if (Grid == null) return;
      Rectangle printRect = Bounds;
      if (printRect.Width == 0) return;
      printRect.Offset(rowRect.Location);

      CheckPrintCellBorderLines(e, printRect);
      PrintCell(e, printRect);
    }

    protected internal virtual void CheckPrintCellBorderLines(PrintServiceEventArgs e, Rectangle rect)
    {
      bool isDrawVertLines = Grid.Title.VertLine.Visible;
      bool isDrawHorzLines = Grid.Title.HorzLine.Visible;
      Color vertLinesColor = Color.Black;
      Color horzLinesColor = Color.Black;
      Grid.PrintBordersForRect(e, ref rect, isDrawVertLines, isDrawHorzLines, vertLinesColor, horzLinesColor, DashStyle.Solid, DashStyle.Solid, true, true);
      //Grid.DrawBordersForRect(e.Graphics, ref rect, isDrawVertLines, isDrawHorzLines, vertLinesColor, horzLinesColor, DashStyle.Solid, DashStyle.Solid, true, true);
    }

    protected internal virtual void PrintCell(PrintServiceEventArgs e, Rectangle rect)
    {
      if (NodeType == DataGridTitleNodeType.SuperTitle)
      {
        if (SuperTitle != null)
        {

          Point inCellMousePos = new Point(-1, -1);

          SuperTitlePaintEventArgs pea = SuperTitle.GetCellPaintParams(e.Graphics, rect, inCellMousePos);
          SuperTitle.Print(e, rect);
          //SuperTitle.Paint(gr, rect);
        }
      }
      else
      {
        int row = Grid.TitleRowIndex;
        int col = Grid.DataToBaseColIndex(ColumnTitle.Column.VisibleIndex);
        DataGridBaseCellMan cell = Grid.titleCellMan;

        BaseGridCellPaintEventArgs pea = cell.GetCellPaintParams(e.Graphics, col, row, rect, 0, ColumnTitle.Column.VisibleIndex, Grid.TitleRowIndex, new Point(-1, -1));
        cell.PrintCell(e, rect, ColumnTitle.Column.VisibleIndex, Grid.TitleRowIndex, null);
      }
    }

    protected internal override void OnAddingAdoptedNode(BaseTreeNode node)
    {
      if (((DataGridTitleNode)node).NodeType == DataGridTitleNodeType.ColumnTitle)
        node.Parent.Items.Remove(node);
      else
        base.OnAddingAdoptedNode(node);
    }

    internal bool NodePathIsVisible()
    {
      if (Visible && Parent != null)
        return Parent.NodePathIsVisible();
      else
        return Visible;
    }

    internal void ResetChildNewIndex(bool processChilds)
    {
      newIndexStored = false;
      newIndex = -1;

      if (processChilds == false) return;

      foreach (DataGridTitleNode childNode in Items)
      {
        childNode.ResetChildNewIndex(false);
      }
    }

    internal void SetChildPositionsFromNewIndex(bool processChilds)
    {
      Items.Sort((item1, item2) => ((DataGridTitleNode)item1).NewIndex - ((DataGridTitleNode)item2).NewIndex);
      BuildVisibleItems();

      childNewIndexChanged = false;
      foreach (DataGridTitleNode childNode in Items)
      {
        childNode.newIndexStored = false;
        childNode.newIndex = -1;
      }

      if (processChilds)
      {
        foreach (DataGridTitleNode childNode in Items)
        {
          childNode.SetChildPositionsFromNewIndex(true);
        }
      }
    }
  }

  public class DataGridTitleNodes : BaseTreeNodeItemsGeneric<DataGridTitleNode>
  {
    public DataGridTitleNodes(DataGridTitleNode ownerNode) : base(ownerNode)
    {
    }

    public int Add(IMultiTitleNodeProvider item)
    {
      return base.Add(item.GetNode()); 
    }

    public void Insert(int position, IMultiTitleNodeProvider item)
    {
      base.Insert(position, item.GetNode());
    }

    public void MoveIn(int position, IMultiTitleNodeProvider item)
    {
      DataGridTitleNode node = item.GetNode();

      if (OwnerNode.TreeList != null)
        OwnerNode.TreeList.BeginUpdate();

      try
      {
        if (node.Parent != null)
          node.Parent.Items.Remove(node);

        Insert(position, item);
      }
      finally
      {
        if (OwnerNode.TreeList != null)
          OwnerNode.TreeList.EndUpdate();
      }
    }

    public void Remove(IMultiTitleNodeProvider item)
    {
      DataGridTitleNode tn = item.GetNode();
      int tnIndex = IndexOf(tn);
      if (tnIndex < 0)
        throw new InvalidOperationException("Item: " + item.ToString() + " is not in the list of Parent: " + this.ToString());
      if (Count == 1 && tn.NodeType == DataGridTitleNodeType.ColumnTitle)
        throw new InvalidOperationException(this.ToString() + " can't have zero items of ColumnTitle type");
      //if (tn.NodeType == DataGridTitleNodeType.ColumnTitle)
      //  throw new InvalidOperationException("Node: " + tn.ToString() + " of ColumnTitle can't be deleted");

      DataGridMultiTitle tl = null;
      if (OwnerNode.TreeList != null)
        tl = OwnerNode.TreeList.MultiTitle;
      if (tl != null)
        tl.TitleTree.BeginUpdate();
      try
      {
        base.Remove(tn);

        for (int i = tn.Items.Count-1; i >= 0; i--)
        {
          DataGridTitleNode tnc = tn.Items[i];
          tn.Items.RemoveAt(i);
          Insert(tnIndex, tnc);
        }
      }
      finally
      {
        if (tl != null)
          tl.TitleTree.EndUpdate();
      }
    }
  }

  [Designer("EhLib.Design.DataGridSuperTitleDesigner" + EhLibUtils.EhLibDesignDesignerVersionInfo)]
  [System.ComponentModel.DesignerCategory("Code")]
  [TypeConverter(typeof(ExpandableObjectConverter))]
  [DesignTimeVisible(false)]
  [ToolboxItem(false)]
  public class DataGridSuperTitle : Component, IMultiTitleNodeProvider, ICellBackFillerOwner, ICellImageBoxOwner, IDisposable
  //public class DataGridSuperTitle : object, IMultiTitleNodeProvider, ICellBackFillerOwner, IDisposable
  {

    #region private consts
    private static readonly object EventKeyPaint = new object();
    private static readonly object EventKeyPaintCustomArea = new object();
    private static readonly object EventCellMouseDown = new object();
    private static readonly object EventCellMouseMove = new object();
    private static readonly object EventCellMouseUp = new object();
    private static readonly object EventCellMouseClick = new object();
    private static readonly object EventCellMouseDoubleClick = new object();
    private static readonly object EventKeyCellMouseEnter = new object();
    private static readonly object EventKeyCellMouseLeave = new object();
    private static readonly object EventKeyCellMouseHover = new object();
    private static readonly object EventKeyMouseContextMenuStripNeeded = new object();
    private static readonly object EventKeyClientRectNeeded = new object();
    #endregion private consts

    #region privates
    //private DataGridSuperTitlePaintingEventArgs paintingEventArgs;
    private DataGridSuperTitleContentRectNeededEventArgs contentRectNeededEventArgs;
    private DataGridSuperTitleFittedHeightNeededEventArgs fittedHeightNeededEventArgs;

    private bool textStored;
    private string text = string.Empty;

    //private DataGridEh grid;
    //private int width;

    private bool horzAlignStored;
    private HorizontalAlignment horzAlign;
    private bool vertAlignStored;
    private VerticalAlignment vertAlign;
    private Padding padding = new Padding(0);
    private readonly Padding defaultPadding = new Padding(4, 2, 4, 2);

    private bool paddingStored;
    private Font font;
    private bool backColorStored;
    //private Color backColor = Color.Empty;
    private bool foreColorStored;
    private Color foreColor = Color.Empty;
    DataGridTitleNode titleNode;

    private readonly CellBackFiller backFiller;
    private bool visible = true;
    private bool disposed;
    private object tag;
    private string name;
    private readonly CellImageBox imageBox;

    //private int DisplayIndex = -1;
    #endregion

    public DataGridSuperTitle()
    {
      backFiller = new CellBackFiller(this);
      imageBox = new CellImageBox(this);
    }

    #region IDisposable Support
    protected override void Dispose(bool disposing)
    {
      if (!disposed)
      {
        if (disposing)
        {
          if (TitleNode.Parent != null)
            TitleNode.Parent.Items.Remove(this);
          //TitleNode.Parent.Items.Remove(TitleNode);
        }
        disposed = true;
      }

      base.Dispose(disposing);
    }
    //public void Dispose()
    //{
    //  Dispose(true);
    //}
    #endregion

    #region design-time properties
    //[Browsable(false)]
    //[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
    //public int DisplayIndex
    //{
    //  get
    //  {
    //    return this.DisplayIndex;
    //  }
    //  set
    //  {
    //    if (Grid == null)
    //      this.DisplayIndex = value;
    //    else
    //      Grid.SetColumnDisplayIndex(this, value);
    //  }
    //}

    // design-time properties
    public string Text
    {
      get
      {
        if (textStored)
          return text;
        return DefaultText();
      }
      set
      {
        if ((textStored == false) || (text != value))
        {
          textStored = true;
          text = value;
          if (text == null) text = string.Empty;
          TextChanged();
        }
      }
    }

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

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

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

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

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

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

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

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

    [DefaultValue(true)]
    public bool Visible
    {
      get
      {
        return visible;
      }

      set
      {
        if (value != visible)
        {
          visible = value;
          VisibleChanged();
        }
      }
    }

    [Bindable(true)]
    //[SRDescription(SR.ControlTagDescr)]
    [DefaultValue(null)]
    [TypeConverter(typeof(StringConverter))]
    public object Tag
    {
      get { return tag; }
      set { tag = value; }
    }

    [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
    public CellImageBox ImageBox
    {
      get
      {
        return imageBox;
      }
    }
    #endregion

    #region runtime properties
    // run-time properties
    [Browsable(false)]
    public string Name
    {
      get
      {
        if (Site != null)
          name = Site.Name;
        return name;
      }

      set
      {
        if (string.Equals(this.name, value, StringComparison.Ordinal)) return;

        //if (Site != null)
        //  Site.Name = value;

        this.name = value;

        if (this.Grid != null)
        {
          this.Grid.OnSuperTitleNameChanged(this);
        }
      }
    }

    [Browsable(false)]
    [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
    public DataGridTitleNode TitleNode
    {
      get
      {
        if (titleNode == null)
        {
          titleNode = new DataGridTitleNode(DataGridTitleNodeType.SuperTitle, null, this);
        }
        return titleNode;
      }
    }

    [Browsable(false)]
    [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
    public DataGridEh Grid
    {
      get
      {
        if (TitleNode.TreeList != null)
          return TitleNode.TreeList.MultiTitle.Grid;
        return null;
      }
    }

    [Browsable(true)]
    [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
    public MultiTitleNodeProviderList Subtitles
    {
      get { return TitleNode.Subtitles; }
    }

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

    DataGridColumnTitle IMultiTitleNodeProvider.ColumnTitle
    {
      get
      {
        return TitleNode.ColumnTitle;
      }
    }

    DataGridSuperTitle IMultiTitleNodeProvider.SuperTitle
    {
      get
      {
        return TitleNode.SuperTitle;
      }
    }

    //protected virtual DataGridSuperTitlePaintingEventArgs PaintingEventArgs
    //{
    //  get
    //  {
    //    if (paintingEventArgs == null)
    //      paintingEventArgs = new DataGridSuperTitlePaintingEventArgs(Grid);
    //    return paintingEventArgs;
    //  }
    //}

    protected virtual DataGridSuperTitleContentRectNeededEventArgs ContentRectNeededEventArgs
    {
      get
      {
        if (contentRectNeededEventArgs == null)
          contentRectNeededEventArgs = new DataGridSuperTitleContentRectNeededEventArgs(Grid);
        return contentRectNeededEventArgs;
      }
    }

    protected virtual DataGridSuperTitleFittedHeightNeededEventArgs FittedHeightNeededEventArgs
    {
      get
      {
        if (fittedHeightNeededEventArgs == null)
          fittedHeightNeededEventArgs = new DataGridSuperTitleFittedHeightNeededEventArgs(Grid);
        return fittedHeightNeededEventArgs;
      }
    }
    
    #endregion

    #region event
    public event EventHandler<SuperTitlePaintEventArgs> Paint
    {
      add
      {
        this.Events.AddHandler(EventKeyPaint, value);
      }
      remove
      {
        this.Events.RemoveHandler(EventKeyPaint, value);
      }
    }

    public event EventHandler<SuperTitlePaintEventArgs> PaintCustomArea
    {
      add
      {
        this.Events.AddHandler(EventKeyPaintCustomArea, value);
      }
      remove
      {
        this.Events.RemoveHandler(EventKeyPaintCustomArea, value);
      }
    }
    
    //public event EventHandler<DataGridSuperTitleCellCustomAreaMeasuresNeededEventArgs> CustomAreaMeasuresNeeded
    //{
    //  add
    //  {
    //    this.Events.AddHandler(EventKeylCustomAreaMeasuresNeeded, value);
    //  }
    //  remove
    //  {
    //    this.Events.RemoveHandler(EventKeylCustomAreaMeasuresNeeded, value);
    //  }
    //}

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

    public event EventHandler<DataGridSuperTitleCellMouseEventArgs> MouseMove
    {
      add
      {
        this.Events.AddHandler(EventCellMouseMove, value);
      }
      remove
      {
        this.Events.RemoveHandler(EventCellMouseMove, value);
      }
    }

    public event EventHandler<DataGridSuperTitleCellMouseEventArgs> MouseUp
    {
      add
      {
        this.Events.AddHandler(EventCellMouseUp, value);
      }
      remove
      {
        this.Events.RemoveHandler(EventCellMouseUp, value);
      }
    }

    public event EventHandler<DataGridSuperTitleCellMouseEventArgs> MouseClick
    {
      add
      {
        this.Events.AddHandler(EventCellMouseClick, value);
      }
      remove
      {
        this.Events.RemoveHandler(EventCellMouseClick, value);
      }
    }

    public event EventHandler<DataGridSuperTitleCellMouseEventArgs> MouseDoubleClick
    {
      add
      {
        this.Events.AddHandler(EventCellMouseDoubleClick, value);
      }
      remove
      {
        this.Events.RemoveHandler(EventCellMouseDoubleClick, value);
      }
    }

    public event EventHandler<DataGridSuperTitleCellEventArgs> MouseEnter
    {
      add
      {
        this.Events.AddHandler(EventKeyCellMouseEnter, value);
      }
      remove
      {
        this.Events.RemoveHandler(EventKeyCellMouseEnter, value);
      }
    }

    public event EventHandler<DataGridSuperTitleCellEventArgs> MouseLeave
    {
      add
      {
        this.Events.AddHandler(EventKeyCellMouseLeave, value);
      }
      remove
      {
        this.Events.RemoveHandler(EventKeyCellMouseLeave, value);
      }
    }

    public event EventHandler<DataGridSuperTitleCellMouseEventArgs> MouseHover
    {
      add
      {
        this.Events.AddHandler(EventKeyCellMouseHover, value);
      }
      remove
      {
        this.Events.RemoveHandler(EventKeyCellMouseHover, value);
      }
    }

    public event EventHandler<DataGridSuperTitleCellContextMenuStripNeededEventArgs> MouseContextMenuStripNeeded
    {
      add
      {
        this.Events.AddHandler(EventKeyMouseContextMenuStripNeeded, value);
      }
      remove
      {
        this.Events.RemoveHandler(EventKeyMouseContextMenuStripNeeded, value);
      }
    }

    public event EventHandler<DataGridSuperTitleCellClientAreaNeededEventArgs> ClientRectNeeded
    {
      add
      {
        this.Events.AddHandler(EventKeyClientRectNeeded, value);
      }
      remove
      {
        this.Events.RemoveHandler(EventKeyClientRectNeeded, value);
      }
    }
    #endregion

    #region Methods
    // methods

    //ICellBackFillerOwner
    protected virtual CellBackFiller CreateFixedBackFiller()
    {
      return new CellBackFiller(this);
    }

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

    Color ICellBackFillerOwner.BackFillerDefaultColor(CellBackFiller backFiller)
    {
      if (Grid != null)
        return Grid.Title.BackFiller.Color;
      return SystemColors.ButtonFace;
    }

    Color ICellBackFillerOwner.BackFillerDefaultSecondColor(CellBackFiller backFiller)
    {
      if (Grid != null)
        return Grid.Title.BackFiller.SecondColor;
      return SystemColors.Window;
    }

    CellFillStyle ICellBackFillerOwner.BackFillerDefaultFillStyle(CellBackFiller backFiller)
    {
      if (Grid != null)
        return Grid.Title.BackFiller.FillStyle;
      return CellFillStyle.VisualStyles;
    }

    CellInnerBorderStyle ICellBackFillerOwner.BackFillerDefaultInnerBorder(CellBackFiller backFiller)
    {
      if (Grid != null)
        return Grid.Title.BackFiller.InnerBorder;
      return CellInnerBorderStyle.RaisedTopLeft;
    }

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

    protected virtual Padding DefaultPadding()
    {
      if (Grid != null)
        return Grid.Title.Padding;
      return defaultPadding;
    }

    protected virtual bool ShouldSerializePadding()
    {
      return paddingStored;
    }

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

    //Visible
    protected virtual void VisibleChanged()
    {
      TitleNode.Visible = Visible;
      //if (Grid != null)
      //  Grid.Title.MultiTitle.UpdateNodesVisibility();
    }

    //MouseDown
    protected internal virtual void ProcessMouseDown(DataGridSuperTitleCellMouseEventArgs e)
    {
      Grid.Title.MultiTitle.HandleMouseDownEvent(e);
      if (!e.Handled)
        HandleMouseDownEvent(e);
      if (e.Handled) return;
      OnMouseDown(e);
    }

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

    protected virtual void OnMouseDown(DataGridSuperTitleCellMouseEventArgs e)
    {
      if (e.BaseEventArgs.GridMouseArgs.Button == MouseButtons.Left)
      {
        if (Grid.ColumnOptions.AllowMoveColumns)
        {
          CheckStartColMoving(e.BaseEventArgs);
        }
      }
    }

    //MouseMove
    protected internal virtual void ProcessMouseMove(DataGridSuperTitleCellMouseEventArgs e)
    {
      Grid.Title.MultiTitle.ProcessMouseMove(e);
      if (!e.Handled)
        HandleMouseMoveEvent(e);
      if (e.Handled) return;
      OnMouseMove(e);
    }

    protected virtual void HandleMouseMoveEvent(DataGridSuperTitleCellMouseEventArgs e)
    {
      var eh = this.Events[EventCellMouseMove] as EventHandler<DataGridSuperTitleCellMouseEventArgs>;
      if (eh != null)
        eh(this, e);
    }

    protected virtual void OnMouseMove(DataGridSuperTitleCellMouseEventArgs e)
    {
    }

    //MouseUp
    protected internal virtual void ProcessMouseUp(DataGridSuperTitleCellMouseEventArgs e)
    {
      Grid.Title.MultiTitle.ProcessMouseUp(e);
      if (!e.Handled)
        HandleMouseUpEvent(e);
      if (e.Handled) return;
      OnMouseUp(e);
    }

    protected virtual void HandleMouseUpEvent(DataGridSuperTitleCellMouseEventArgs e)
    {
      var eh = this.Events[EventCellMouseUp] as EventHandler<DataGridSuperTitleCellMouseEventArgs>;
      if (eh != null)
        eh(this, e);
    }

    protected virtual void OnMouseUp(DataGridSuperTitleCellMouseEventArgs e)
    {
    }

    //MouseClick
    protected internal virtual void ProcessMouseClick(DataGridSuperTitleCellMouseEventArgs e)
    {
      Grid.Title.MultiTitle.ProcessMouseClick(e);
      if (!e.Handled)
        HandleMouseClickEvent(e);
      if (e.Handled) return;
      OnMouseClick(e);
    }

    protected virtual void HandleMouseClickEvent(DataGridSuperTitleCellMouseEventArgs e)
    {
      var eh = this.Events[EventCellMouseClick] as EventHandler<DataGridSuperTitleCellMouseEventArgs>;
      if (eh != null)
        eh(this, e);
    }

    protected virtual void OnMouseClick(DataGridSuperTitleCellMouseEventArgs e)
    {
    }

    //MouseDoubleClick
    protected internal virtual void ProcessMouseDoubleClick(DataGridSuperTitleCellMouseEventArgs e)
    {
      Grid.Title.MultiTitle.ProcessMouseDoubleClick(e);
      if (!e.Handled)
        HandleMouseDoubleClickEvent(e);
      if (e.Handled) return;
      OnMouseDoubleClick(e);
    }

    protected virtual void HandleMouseDoubleClickEvent(DataGridSuperTitleCellMouseEventArgs e)
    {
      var eh = this.Events[EventCellMouseDoubleClick] as EventHandler<DataGridSuperTitleCellMouseEventArgs>;
      if (eh != null)
        eh(this, e);
    }

    protected virtual void OnMouseDoubleClick(DataGridSuperTitleCellMouseEventArgs e)
    {
    }

    //MouseEnter
    internal void ProcessMouseEnter(DataGridSuperTitleCellEventArgs e)
    {
      Grid.Title.MultiTitle.ProcessMouseEnter(e);
      if (!e.Handled)
        HandleMouseEnterEvent(e);
      if (e.Handled) return;
      OnMouseEnter(e);
    }

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

    protected virtual void OnMouseEnter(DataGridSuperTitleCellEventArgs e)
    {
      Grid.Title.Invalidate();
    }

    //MouseLeave
    internal void ProcessMouseLeave(DataGridSuperTitleCellEventArgs e)
    {
      Grid.Title.MultiTitle.ProcessMouseLeave(e);
      if (!e.Handled)
        HandleMouseLeaveEvent(e);
      if (e.Handled) return;
      OnMouseLeave(e);
    }

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

    protected virtual void OnMouseLeave(DataGridSuperTitleCellEventArgs e)
    {
      Grid.Title.Invalidate();
    }

    //MouseHover
    internal void ProcessMouseHover(DataGridSuperTitleCellMouseEventArgs e)
    {
      Grid.Title.MultiTitle.ProcessMouseHover(e);
      if (!e.Handled)
        HandleMouseHoverEvent(e);
      if (e.Handled) return;
      OnMouseHover(e);
    }

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

    protected virtual void OnMouseHover(DataGridSuperTitleCellMouseEventArgs e)
    {
    }

    //SetCursor
    protected internal virtual void SetCursor(DataGridSuperTitleCellMouseEventArgs e, ref Cursor cursor)
    {
    }

    //Painting
    protected internal virtual SuperTitlePaintEventArgs GetCellPaintParams(Graphics graphics, Rectangle rect, Point inCellMousePos)
    {
      var result = new SuperTitlePaintEventArgs(this, graphics, rect, inCellMousePos);
      result.CellClientRect = GetCellClientRect(result.CellRect);
      OnFillPaintParams(result);
      return result;
    }

    private void OnFillPaintParams(SuperTitlePaintEventArgs e)
    {
      e.FillStyle = BackFiller.FillStyle;
      e.InnerBorder = BackFiller.InnerBorder;
      e.FillColor = BackFiller.Color;
      e.SecondFillColor = BackFiller.SecondColor;
      e.Text = Text;
      e.Font = Font;
      e.ForeColor = ForeColor;
    }

    internal void ProcessPaint(SuperTitlePaintEventArgs e)
    {
      bool handled = HandlePaintEvent(e);
      if (handled) return;
      OnPaint(e);

      if (Grid.DesignMode)
      {
        IDesignerHost idh = (IDesignerHost)Grid.GetService(typeof(IDesignerHost));
        Debug.Assert(idh != null, "idh != null");
        var grd = idh.GetDesigner(Grid) as IDataGridDesigner;
        if (grd != null)
          grd.PaintSuperTitleCellDesignData(Grid, this, e.Graphics, e.CellClientRect);
      }
    }

    protected internal virtual bool HandlePaintEvent(SuperTitlePaintEventArgs e)
    {
      var eh = this.Events[EventKeyPaint] as EventHandler<SuperTitlePaintEventArgs>;

      if (eh != null)
        eh(this, e);

      if (!e.Handled)
        Grid.Title.MultiTitle.HandlePaintEvent(e);
      //Grid.Title.ProcessSuperTitlePaintingEvent(e);

      return e.Handled;
    }

    protected internal virtual void OnPaint(SuperTitlePaintEventArgs e)
    {
      OnPaintBackground(e);
      OnPaintForeground(e);
    }

    protected internal virtual void OnPaintBackground(SuperTitlePaintEventArgs e)
    {
      BaseGridFillFixedCellEventArgs drPrms = new BaseGridFillFixedCellEventArgs
      {
        CellRect = e.CellRect,
        Graphics = e.Graphics,
        IsHot = false,
        IsPressed = false,
        BackColor = BackFiller.Color,
        FillStyle = BackFiller.FillStyle,
        InnerBorder = BackFiller.InnerBorder,
        FillColor = BackFiller.Color,
        SecondFillColor = BackFiller.SecondColor
      };

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

    protected internal virtual void OnPaintForeground(SuperTitlePaintEventArgs e)
    {
      OnPaintClientRect(e);
      OnPaintCustomArea(e);
    }

    protected internal virtual void OnPaintClientRect(SuperTitlePaintEventArgs e)
    {
      OnPaintSurround(e);
      OnPaintContent(e);
    }

    protected internal virtual void OnPaintSurround(SuperTitlePaintEventArgs e)
    {
      e.CellClientRect = EhLibUtils.TrimPadding(e.CellClientRect, Padding);

      if (e.SuperTitle.ImageBox.Visible)
      {
        Rectangle imageRect;
        Rectangle textRect;

        TextLayoutParams tlp = new TextLayoutParams()
        {
          Text = e.SuperTitle.Text,
          Font = e.SuperTitle.Font,
          HorzAlign = e.SuperTitle.HorzAlign,
          VertAlign = e.SuperTitle.VertAlign,
          WrapMode = Grid.Title.WrapMode
        };
        e.SuperTitle.ImageBox.LayoutImageAndText(e.CellClientRect, tlp, out imageRect, out textRect);

        CellImageBoxPaintEventArgs ibe = new CellImageBoxPaintEventArgs(e.SuperTitle.ImageBox, e.Graphics, imageRect, e);
        e.SuperTitle.ImageBox.OnPaint(ibe);

        e.CellClientRect = textRect;
      }
    }

    protected internal virtual void OnPaintContent(SuperTitlePaintEventArgs e)
    {
      //TextFormatFlags aligntFlags;
      Font fnt;
      Color fColor;
      bool endEllipsis;
      Rectangle paintRect = e.CellClientRect;
      bool wordWrap = false;
      //Rectangle dataRect = e.CellClientRect;

      //aligntFlags = EhLibUtils.TranslateAlignmentToTextFormatFlags(HorzAlign, VertAlign);
      fnt = e.Font;
      fColor = e.ForeColor;
      endEllipsis = Grid.Title.EndEllipsis;

      //TextFormatFlags fmtFlags =
      //  aligntFlags |
      //  TextFormatFlags.PreserveGraphicsClipping |
      //  TextFormatFlags.NoPadding;
      if (EhLibUtils.CanDrawWordBreak(e.Graphics, paintRect, fnt, padding))
        wordWrap = true;
        //fmtFlags |= TextFormatFlags.WordBreak;
      //if (endEllipsis)
      //  fmtFlags |= TextFormatFlags.EndEllipsis;

      string s = Text;
      Grid.PaintingDrawText(e.Graphics, s, fnt, paintRect, fColor, HorzAlign, VertAlign, wordWrap);
      //TextRenderer.DrawText(e.Graphics, s, fnt, paintRect, fColor, fmtFlags);
    }

    protected internal virtual void OnPaintCustomArea(SuperTitlePaintEventArgs e)
    {
      HandlePaintCustomAreaEvent(e);
    }

    protected void HandlePaintCustomAreaEvent(SuperTitlePaintEventArgs e)
    {
      var eh = this.Events[EventKeyPaintCustomArea] as EventHandler<SuperTitlePaintEventArgs>;

      if (eh != null)
        eh(this, e);
    }

    internal void Print(PrintServiceEventArgs e, Rectangle rect)
    {
      string s = Text;
      //TextFormatFlags aligntFlags = EhLibUtils.TranslateAlignmentToTextFormatFlags(HorzAlign, VertAlign);

      //TextFormatFlags fmtFlags =
      //  aligntFlags |
      //  TextFormatFlags.PreserveGraphicsClipping |
      //  TextFormatFlags.NoPadding;

      //TextRenderer.DrawText(gr, s, Font, rect, Color.Black, fmtFlags);

      e.PrintText(s, Font, rect, Color.Black, HorzAlign, VertAlign, TextFormatFlagsEh.WordBreak);
      //EhLibUtils.DrawText(e.Graphics, s, Font, rect, Color.Black, HorzAlign, VertAlign, TextFormatFlagsEh.WordBreak, UsedGraphicEngine.WinFormsGDIPlus);
    }

    //CustomAreaMeasures
    //protected internal virtual DataGridSuperTitleCellCustomAreaMeasuresNeededEventArgs CreateCellCustomAreaMeasuresEventArgs(CellCustomAreaMeasures areaMeasures)
    //{
    //  return new DataGridSuperTitleCellCustomAreaMeasuresNeededEventArgs(areaMeasures, this);
    //}

    //protected internal virtual void OnCellCustomAreaMeasuresNeeded(DataGridSuperTitleCellCustomAreaMeasuresNeededEventArgs e)
    //{
    //  Grid.Title.MultiTitle.HandleCellCustomAreaMeasuresNeededEvent(e);
    //  HandleCellCustomAreaMeasuresNeededEvent(e);
    //}

    //protected internal virtual void SetCellCustomAreaMeasures(CellCustomAreaMeasures areaMeasures)
    //{
    //  var e = CreateCellCustomAreaMeasuresEventArgs(areaMeasures);
    //  OnCellCustomAreaMeasuresNeeded(e);
    //}

    //internal void HandleCellCustomAreaMeasuresNeededEvent(DataGridSuperTitleCellCustomAreaMeasuresNeededEventArgs e)
    //{
    //  var eh = this.Events[EventKeylCustomAreaMeasuresNeeded] as EventHandler<DataGridSuperTitleCellCustomAreaMeasuresNeededEventArgs>;
    //  if (eh != null)
    //  {
    //    eh(this, e);
    //  }
    //}

    // ContextMenuStripNeeded
    protected internal virtual ContextMenuStrip GetMouseContextMenuStrip(DataGridSuperTitleCellContextMenuStripNeededEventArgs e)
    {
      if (ContextMenuStrip != null)
        e.ContextMenuStrip = ContextMenuStrip;
      else if (Grid.Title.ContextMenuStrip != null)
        e.ContextMenuStrip = Grid.Title.ContextMenuStrip;
      else
        e.ContextMenuStrip = Grid.GetDefaultContextMenuStrip();

      //Grid.Title.OnCellMouseContextMenuStripNeeded(e);
      return e.ContextMenuStrip;
    }

    protected internal virtual void HandleMouseContextMenuStripNeededEvent(DataGridSuperTitleCellContextMenuStripNeededEventArgs e)
    {
      var eh = this.Events[EventKeyMouseContextMenuStripNeeded] as EventHandler<DataGridSuperTitleCellContextMenuStripNeededEventArgs>;
      if (eh != null)
      {
        eh(this, e);
      }
    }

    //Other
    void ICellImageBoxOwner.CellImageBoxChanged(CellImageBox imageBox)
    {
      if (Grid != null)
        Grid.UpdateBaseFixedBands();
    }

    protected internal virtual bool CheckStartColMoving(BaseGridCellMouseEventArgs e)
    {
      int moveFromIndex = e.ColIndex;
      int moveToIndex = e.ColIndex;
      bool result = Grid.CheckBeginColumnDrag(ref moveFromIndex, ref moveToIndex, new Point(e.GridMouseArgs.X, e.GridMouseArgs.Y));
      if (result)
        Grid.StartColMoving(moveFromIndex, moveToIndex, e.GridMouseArgs.X, e.GridMouseArgs.Y);
      return result;
    }

    public virtual string DefaultText()
    {
      return "";
    }

    protected virtual void TextChanged()
    {
      if (Grid != null)
        Grid.UpdateColumnsList();
    }

    //public virtual System.Drawing.ContentAlignment DefaultTextAlign()
    //{
    //  return Grid.Title.TextAlign;
    //}

    private HorizontalAlignment DefaultHorzAlign()
    {
      if (Grid != null)
        return Grid.Title.HorzAlign;
      return HorizontalAlignment.Left;
    }

    protected virtual bool ShouldSerializeHorzAlign()
    {
      return horzAlignStored;
    }

    public void ResetHorzAlign()
    {
      horzAlignStored = false;
      TextAlignChanged();
    }

    private VerticalAlignment DefaultVertAlign()
    {
      if (Grid != null)
        return Grid.Title.VertAlign;
      return VerticalAlignment.Top;
    }

    protected virtual bool ShouldSerializeVertAlign()
    {
      return vertAlignStored;
    }

    public void ResetVertAlign()
    {
      vertAlignStored = false;
      TextAlignChanged();
    }

    protected virtual void TextAlignChanged()
    {
      if (Grid != null)
        Grid.InvalidateGrid();
    }

    protected virtual void BackColorChanged()
    {
      if (Grid != null)
        Grid.InvalidateGrid();
    }

    public virtual Color DefaultBackColor()
    {
      if (Grid != null)
        return Grid.Title.BackFiller.Color;
      return SystemColors.ButtonFace;
    }

    protected virtual bool ShouldSerializeBackColor()
    {
      return backColorStored;
    }

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

    protected virtual void ForeColorChanged()
    {
      if (Grid != null)
        Grid.InvalidateGrid();
    }

    public virtual Color DefaultForeColor()
    {
      if (Grid != null)
        return Grid.Title.ForeColor;
      return SystemColors.WindowText;
    }

    protected virtual bool ShouldSerializeForeColor()
    {
      return foreColorStored;
    }

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

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

    private Font DefaultFont()
    {
      if (Grid != null)
        return Grid.Title.Font;
      return null;
    }

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

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

    public virtual int CalcDataHeight()
    {
      Size sz;
      int th;
      int th1;

      sz = TextRenderer.MeasureText(EhLibUtils.DisplayGraphicsCash, "0", Font);
      th = sz.Height * Grid.Title.HeightOptions.ContentHeight;
      th = th + Padding.Top + Padding.Bottom;

      if (Grid.Title.HeightOptions.AutoExpand)
      {
        Size sz1;
        //TextFormatFlags fmtFlags = TextFormatFlags.Left |
        //                            TextFormatFlags.VerticalCenter |
        //                            TextFormatFlags.PreserveGraphicsClipping |
        //                            TextFormatFlags.WordBreak |
        //                            TextFormatFlags.NoPadding;

        Rectangle clientRect = GetCellClientRect(TitleNode.Bounds);
        clientRect.Width = clientRect.Width - Padding.Left - Padding.Right;
        if (ImageBox.Visible &&
              (ImageBox.TextImageRelation == TextImageRelation.ImageBeforeText ||
               ImageBox.TextImageRelation == TextImageRelation.TextBeforeImage ||
               ImageBox.TextImageRelation == TextImageRelation.Overlay)
           )
        {
          clientRect.Width = clientRect.Width - ImageBox.Size.Width;
        }

        //sz1 = TextRenderer.MeasureText(EhLibUtils.DisplayGraphicsCash, Text, Font, clientRect.Size, fmtFlags);
        sz1 = EhLibUtils.MeasureText(EhLibUtils.DisplayGraphicsCash, Text, Font, clientRect.Size, DataGridTextWrapMode.WordWrap);
        th1 = sz1.Height;
        th1 = th1 + Padding.Top + Padding.Bottom;
        if (th1 > th)
          th = th1;
      }

      if (ImageBox.Visible)
      {
        int imageHeight = ImageBox.Size.Height + Padding.Top + Padding.Bottom;
        if (ImageBox.TextImageRelation == TextImageRelation.ImageBeforeText ||
            ImageBox.TextImageRelation == TextImageRelation.TextBeforeImage ||
            ImageBox.TextImageRelation == TextImageRelation.Overlay)
        {
          if (imageHeight > th)
            th = imageHeight;
        }
        else
        {
          th = th + imageHeight;
        }
      }

      th = th + 1; //Horz line size

      return th;
    }

    protected virtual Rectangle GetCellClientRect(Rectangle cellRect)
    {
      //Rectangle result = TitleNode.Bounds;

      var e = new DataGridSuperTitleCellClientAreaNeededEventArgs(this, cellRect);

      ProcessClientRectNeeded(e);
      return e.CellClientRect;
    }

    private void ProcessClientRectNeeded(DataGridSuperTitleCellClientAreaNeededEventArgs e)
    {
      Grid.Title.MultiTitle.HandleClientRectNeededEvent(e);
      HandleClientRectNeededEvent(e);
    }

    private void HandleClientRectNeededEvent(DataGridSuperTitleCellClientAreaNeededEventArgs e)
    {
      var eh = this.Events[EventKeyClientRectNeeded] as EventHandler<DataGridSuperTitleCellClientAreaNeededEventArgs>;
      if (eh != null /*&& !this.IsDisposed*/)
      {
        eh(this, e);
      }
    }

    DataGridTitleNode IMultiTitleNodeProvider.GetNode()
    {
      return TitleNode;
    }
    #endregion
  }

  public class MultiTitleNodeProviderList : object, IList
  {
    private readonly DataGridTitleNode ownerNode;

    public MultiTitleNodeProviderList(DataGridTitleNode ownerNode)
    {
      this.ownerNode = ownerNode;
    }

    //props
    public int Count
    {
      get { return ownerNode.Items.Count; }
    }

    public IMultiTitleNodeProvider this[int index]
    {
      get
      {
        DataGridTitleNode tn = ownerNode.Items[index];
        return tn.GetAsMultiTitleNodeProviderInterface();
      }
    }

    //methods
    public int Add(IMultiTitleNodeProvider item)
    {
      return ownerNode.Items.Add(item);
    }

    public void Insert(int position, IMultiTitleNodeProvider item)
    {
      ownerNode.Items.Insert(position, item);
    }

    public void MoveIn(int position, IMultiTitleNodeProvider item)
    {
      ownerNode.Items.MoveIn(position, item);
    }

    //IList
    bool IList.IsFixedSize
    {
      get
      {
        return false;
      }
    }

    object IList.this[int index]
    {
      get
      {
        return this[index];
      }

      set
      {
        throw new ArgumentException("Assign BaseTreeNodeItems IList.this[int index] is not supported");
      }
    }

    int IList.Add(object node)
    {
      return Add((IMultiTitleNodeProvider)node);
    }

    bool IList.Contains(object node)
    {
      return ownerNode.Items.Contains(((IMultiTitleNodeProvider)node).GetNode());
    }

    int IList.IndexOf(object node)
    {
      return ownerNode.Items.IndexOf(((IMultiTitleNodeProvider)node).GetNode());
    }

    void IList.Insert(int index, object node)
    {
      ownerNode.Items.Insert(index, ((IMultiTitleNodeProvider)node).GetNode());
    }

    void IList.Remove(object node)
    {
      ownerNode.Items.Remove(((IMultiTitleNodeProvider)node).GetNode());
    }

    void IList.RemoveAt(int index)
    {
      ownerNode.Items.RemoveAt(index);
    }

    void IList.Clear()
    {
      ownerNode.Items.Clear();
    }

    void ICollection.CopyTo(Array array, int index)
    {
      for (int i = 0; i < Count; i++)
        array.SetValue(this[i], index + i);
    }

    public void CopyTo(IMultiTitleNodeProvider[] array, int index)
    {
      ((ICollection)this).CopyTo(array, index);
    }

    IEnumerator IEnumerable.GetEnumerator()
    {
      IMultiTitleNodeProvider[] arr = new IMultiTitleNodeProvider[Count];
      ((ICollection)this).CopyTo(arr, 0);
      return arr.GetEnumerator();
    }

    //ICollection
    bool ICollection.IsSynchronized
    {
      get
      {
        return false;
      }
    }

    object ICollection.SyncRoot
    {
      get
      {
        return this;
      }
    }

    bool IList.IsReadOnly
    {
      get { return ownerNode.Items.IsReadOnly;  }
    }

    int ICollection.Count
    {
      get { return ownerNode.Items.Count; }
    }
  }

}
