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

using System;
using System.Collections;
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.Globalization;
using System.Reflection;
using System.Windows.Forms;
using System.Windows.Forms.VisualStyles;

namespace EhLib
{

  public enum DataGridFooterValueFunction
  {
    Non, Sum, Count, Average, Min, Max, CollectionItemValue, StaticText, Custom
  }

  [DesignerCategory("Code")]
  [ToolboxItem(false)]
  [TypeConverter(typeof(ExpandableObjectConverter))]
  public class DataGridFooter : Component, IGridLineHost, ICellBackFillerOwner
  {

    #region private consts
    private static readonly object EventKeyFooterCellPaint = new object();
    private static readonly object EventKeyInitCalculation = new object();
    private static readonly object EventKeyRowStepCalculation = new object();
    private static readonly object EventKeyFinalizeCalculation = new object();
    private static readonly object EventKeyFormatValue = new object();
    private static readonly object EventKeyCellMouseDown = new object();
    private static readonly object EventKeyCellMouseMove = new object();
    private static readonly object EventKeyCellMouseUp = new object();
    private static readonly object EventKeyCellMouseClick = new object();
    private static readonly object EventKeyCellMouseDoubleClick = new object();
    private static readonly object EventKeyCellMouseEnter = new object();
    private static readonly object EventKeyCellMouseLeave = new object();
    private static readonly object EventKeyCellMouseHover = new object();
    #endregion

    #region privates
    private DataGridEh grid;
    private readonly DataGridFooterRows rows;
    private Font font;
    private bool foreColorStored;
    private Color foreColor = Color.Empty;
    private Padding padding = new Padding(0);
    private bool paddingStored;
    private readonly Padding defaultPadding = new Padding(3, 2, 3, 4);

    private readonly GridLine vertLine;
    private readonly GridLine horzLine;
    private CellBackFiller backFiller;

    private VerticalAlignment vertAlign = VerticalAlignment.Center;
    #endregion

    public DataGridFooter(DataGridEh grid)
    {
      this.grid = grid;
      this.rows = new DataGridFooterRows(this);
      this.vertLine = new GridLine(this);
      this.horzLine = new GridLine(this);
    }

    #region properties
    [Browsable(false)]
    public DataGridEh Grid
    {
      get { return grid; }
    }

    [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
    //    [Editor(typeof(DataGridColumnsEditor), typeof(UITypeEditor))]
    public DataGridFooterRows Rows
    {
      get { return rows; }
    }

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

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

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

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

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

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

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

    #region events
    public event EventHandler<DataGridFooterCellPaintEventArgs> CellPaint
    {
      add
      {
        this.Events.AddHandler(EventKeyFooterCellPaint, value);
      }
      remove
      {
        this.Events.RemoveHandler(EventKeyFooterCellPaint, value);
      }
    }

    public event EventHandler<DataGridFooterCalculationEventArgs> InitCalculation
    {
      add
      {
        this.Events.AddHandler(EventKeyInitCalculation, value);
      }
      remove
      {
        this.Events.RemoveHandler(EventKeyInitCalculation, value);
      }
    }

    public event EventHandler<DataGridFooterCalculationEventArgs> RowStepCalculation
    {
      add
      {
        this.Events.AddHandler(EventKeyRowStepCalculation, value);
      }
      remove
      {
        this.Events.RemoveHandler(EventKeyRowStepCalculation, value);
      }
    }

    public event EventHandler<DataGridFooterCalculationEventArgs> FinalizeCalculation
    {
      add
      {
        this.Events.AddHandler(EventKeyFinalizeCalculation, value);
      }
      remove
      {
        this.Events.RemoveHandler(EventKeyFinalizeCalculation, value);
      }
    }

    public event EventHandler<DataGridFooterCellFormatValueEventArgs> CellFormatValue
    {
      add
      {
        this.Events.AddHandler(EventKeyFormatValue, value);
      }
      remove
      {
        this.Events.RemoveHandler(EventKeyFormatValue, value);
      }
    }

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

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

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

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

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

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

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

    public event EventHandler<DataGridFooterCellMouseEventArgs> CellMouseHover
    {
      add
      {
        this.Events.AddHandler(EventKeyCellMouseHover, value);
      }
      remove
      {
        this.Events.RemoveHandler(EventKeyCellMouseHover, value);
      }
    }
    #endregion

    #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.UpdateBaseFixedBands();
    }

    //BackColor
    public virtual Color DefaultBackColor()
    {
      Color c = Grid.FixedBackColor;
      float h = c.GetHue();
      float s = c.GetSaturation();
      float b = c.GetBrightness();
      Color result = EhLibUtils.ColorFromAHSB(255, h, s, b + ((1 - b) / 2));
      return result;
    }

    //ForeColor
    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();
    }

    //Padding
    protected virtual void PaddingChanged()
    {
      //MessageBox.Show("DataGridTitle.PaddingChanged");
      Grid.UpdateBaseFixedBands();
    }

    protected virtual Padding DefaultPadding()
    {
      return defaultPadding;
    }

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

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

    //Lines
    private void HorzLinesChanged()
    {
      Grid.InvalidateGrid();
    }

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

    //IGridLineHost
    void IGridLineHost.GridLineChanged(GridLine gl)
    {
      if (gl == vertLine)
        VertLinesChanged();
      else if (gl == horzLine)
        HorzLinesChanged();
    }

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

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

    Color IGridLineHost.GridLineDefaultColor(GridLine gl)
    {
      if (Grid == null) return Color.Empty;

      if (gl == vertLine)
        return Grid.LineOptions.DarkColor;
      else if (gl == horzLine)
        return Grid.LineOptions.DarkColor;
      else
        return Color.Empty;
    }

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

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

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

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

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

    CellFillStyle ICellBackFillerOwner.BackFillerDefaultFillStyle(CellBackFiller backFiller)
    {
      return CellFillStyle.Solid;
    }

    CellInnerBorderStyle ICellBackFillerOwner.BackFillerDefaultInnerBorder(CellBackFiller backFiller)
    {
      return CellInnerBorderStyle.None;
    }

    private void VertAlignChanged()
    {
      Grid.InvalidateGrid();
    }

    protected internal virtual void UpdateDefaults()
    {
      throw new InvalidOperationException(@"NotImplemented");
    }

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

    internal bool HandleInitCalculationEvent(DataGridFooterCalculationEventArgs e)
    {
      var eh = this.Events[EventKeyInitCalculation] as EventHandler<DataGridFooterCalculationEventArgs>;
      if (eh != null)
      {
        eh(this, e);
        return e.Handled;
      }
      else
      {
        return false;
      }
    }

    internal bool HandleRowStepCalculationEvent(DataGridFooterCalculationEventArgs e)
    {
      var eh = this.Events[EventKeyRowStepCalculation] as EventHandler<DataGridFooterCalculationEventArgs>;
      if (eh != null)
      {
        eh(this, e);
        return e.Handled;
      }
      else
      {
        return false;
      }
    }

    internal bool HandleFinalizeCalculationEvent(DataGridFooterCalculationEventArgs e)
    {
      var eh = this.Events[EventKeyFinalizeCalculation] as EventHandler<DataGridFooterCalculationEventArgs>;
      if (eh != null)
      {
        eh(this, e);
        return e.Handled;
      }
      else
      {
        return false;
      }
    }

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

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

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

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

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

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

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

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

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

    #endregion

  }

  public class DataGridFooterRow : object, IGridLineHost, ICellBackFillerOwner
  {

    #region privates
    private DataGridEh grid;
    private Font font;
    private bool foreColorStored;
    private Color foreColor = Color.Empty;
    private readonly GridLine horzLine;
    private readonly CellBackFiller backFiller;
    #endregion

    public DataGridFooterRow()
    {
      horzLine = new GridLine(this);
      this.backFiller = new CellBackFiller(this);
    }

    #region properties
    [Browsable(false)]
    public DataGridEh Grid
    {
      get { return grid; }
      protected internal set { grid = value; }
    }

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

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

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

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

    public int Height
      {
        get;
        internal set;
      }
    #endregion properties

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

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

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

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

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

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

    bool IGridLineHost.GridLineDefaultVisible(GridLine gl)
    {
      return Grid.Footer.HorzLine.Visible;
    }

    Color IGridLineHost.GridLineDefaultColor(GridLine gl)
    {
      return Grid.Footer.HorzLine.Color;
    }

    DashStyle IGridLineHost.GridLineDefaultStyle(GridLine gl)
    {
      return Grid.Footer.HorzLine.Style;
    }

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

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

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

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

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

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

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

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

    //Other
    internal virtual int GetFooterHeight()
    {
      if (Grid.VisibleColumns.Count == 0)
      {
        Size sz = EhLibUtils.MeasureText(EhLibUtils.DisplayGraphicsCash, "0", Font);
        int th = sz.Height;
        th = th + Grid.Footer.Padding.Top + Grid.Footer.Padding.Bottom;
        return th;
      }
      else
      {
        int rowIndex = Grid.Footer.Rows.IndexOf(this);
        int maxh = GetOptimalCellHeight();

        foreach (DataGridColumn col in Grid.VisibleColumns)
        {
          int colh = 0;
          if (rowIndex < col.Footer.Items.Count)
            colh = col.Footer.Items[rowIndex].GetOptimalCellHeight();
          if (colh > maxh)
            maxh = colh;
        }
        return maxh;
      }
    }

    internal int GetOptimalCellHeight()
    {
      int fontHeight = EhLibUtils.GetFontHeight(Font);
      int th = fontHeight + Grid.Footer.Padding.Top + Grid.Footer.Padding.Bottom;
      return th;
    }
    #endregion

  }

  [Editor("EhLib.Design.DataGridFooterRowsEditor" + EhLibUtils.EhLibDesignDesignerVersionInfo, "System.Drawing.Design.UITypeEditor, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a")]
  public class DataGridFooterRows : object, IList<DataGridFooterRow>, IList
  {

    #region DataGridFooterCollection privates
    private CollectionChangeEventHandler onCollectionChanged;
    private readonly List<DataGridFooterRow> items = new List<DataGridFooterRow>();
    private readonly DataGridFooter gridFooter;
    private int updateCount;
    private readonly List<DataGridFooterRow> oldItems = new List<DataGridFooterRow>();
    #endregion

    public DataGridFooterRows(DataGridFooter gridFooter)
    {
      this.gridFooter = gridFooter;
    }

    #region DataGridFooterCollection Explicit interfaces 
    int IList<DataGridFooterRow>.IndexOf(DataGridFooterRow value)
    {
      return this.items.IndexOf(value);
    }

    void IList<DataGridFooterRow>.RemoveAt(int index)
    {
      this.RemoveAt(index);
    }

    void IList<DataGridFooterRow>.Insert(int index, DataGridFooterRow value)
    {
      this.Insert(index, value);
    }

    public bool IsReadOnly
    {
      get { return false; }
    }

    void ICollection<DataGridFooterRow>.Clear()
    {
      this.Clear();
    }

    bool ICollection<DataGridFooterRow>.Contains(DataGridFooterRow value)
    {
      return this.items.Contains(value);
    }

    bool ICollection<DataGridFooterRow>.Remove(DataGridFooterRow value)
    {
      this.Remove(value);
      return true;
    }

    void ICollection<DataGridFooterRow>.Add(DataGridFooterRow value)
    {
      this.Add(value);
    }

    int ICollection<DataGridFooterRow>.Count
    {
      get { return this.items.Count; }
    }

    IEnumerator<DataGridFooterRow> IEnumerable<DataGridFooterRow>.GetEnumerator()
    {
      return this.items.GetEnumerator();
    }

    public IEnumerator GetEnumerator()
    {
      return this.items.GetEnumerator();
    }

    #endregion DataGridFooterCollection Explicit interfaces 

    //  Properties
    [Browsable(false)]
    public virtual int Count
    {
      get { return this.items.Count; }
    }

    protected DataGridEh Grid
    {
      get { return this.gridFooter.Grid; }
    }

    [Browsable(false)]
    public DataGridFooterRow this[int index]
    {
      get { return this.items[index]; }
      set { throw new NotSupportedException(); }
    }

    [Browsable(false)]
    public bool Updating
    {
      get { return (updateCount > 0); }
    }

    public bool IsFixedSize
    {
      get { return false; }
    }

    int ICollection.Count
    {
      get { return this.items.Count; }
    }

    public object SyncRoot
    {
      get { return this; }
    }

    public bool IsSynchronized
    {
      get { return false; }
    }

    object IList.this[int index]
    {
      get { return this[index]; }
      set { throw new NotSupportedException(); }
    }

    // Events
    public event CollectionChangeEventHandler CollectionChanged
    {
      add { this.onCollectionChanged += value; }
      remove { this.onCollectionChanged -= value; }
    }

    // Methods
    public virtual int Add(DataGridFooterRow footer)
    {
      Debug.Assert(this.Grid != null);
      //this.Grid.OnAddingFooter(dataGridViewFooter);

      this.items.Add(footer);
      int index = this.items.Count - 1;
      footer.Grid = Grid;
      if (!Updating)
      {
        Grid.FooterAdded(footer, index);
        Grid.FooterCollectionListChanged();
      }
      //  Grid.FootersUpdateCommited();
      return index;
    }

    public virtual void AddRange(params DataGridFooterRow[] footers)
    {
      BeginUpdate();
      try
      {
        foreach (DataGridFooterRow footer in footers)
        {
          Add(footer);
        }
      }
      finally
      {
        EndUpdate();
      }
    }

    public virtual void Insert(int index, DataGridFooterRow footer)
    {
      this.items.Insert(index, footer);
      footer.Grid = Grid;
      if (!Updating)
      {
        Grid.FooterAdded(footer, index);
        Grid.FooterCollectionListChanged();
      }
    }

    public virtual void Clear()
    {
      BeginUpdate();
      try
      {
        while (Count > 0)
        {
          RemoveAt(Count - 1);
        }
      }
      finally
      {
        EndUpdate();
      }
    }

    public virtual bool Contains(DataGridFooterRow footer)
    {
      return this.items.IndexOf(footer) != -1;
    }

    public void CopyTo(DataGridFooterRow[] array, int arrayIndex)
    {
      this.items.CopyTo(array, arrayIndex);
    }

    public int IndexOf(DataGridFooterRow footer)
    {
      return this.items.IndexOf(footer);
    }

    protected virtual void OnCollectionChanged(CollectionChangeEventArgs e)
    {
      if (this.onCollectionChanged != null)
      {
        this.onCollectionChanged(this, e);
      }
    }

    public virtual void Remove(DataGridFooterRow footer)
    {
      if (footer.Grid != this.Grid)
      {
        throw new ArgumentException(@"Footer Does Not Belong To Data Grid", "footer");
      }

      for (int i = 0; i < this.items.Count; i++)
      {
        if (this.items[i] == footer)
        {
          RemoveAt(i);
          return;
        }
      }

      Debug.Fail("Footer should have been found in DataGridFooterCollection.Remove");
    }

    public virtual void RemoveAt(int index)
    {
      if (index < 0 || index >= this.Count)
      {
        throw new ArgumentOutOfRangeException("index", (index).ToString(CultureInfo.CurrentCulture));
      }

      RemoveAtInternal(index, false /*force*/);

      if (!Updating)
        Grid.FooterCollectionListChanged();
    }

    internal void RemoveAtInternal(int index, bool force)
    {
      DataGridFooterRow footer = this.items[index];
      this.items.RemoveAt(index);
      footer.Grid = null;
      if (!Updating)
        Grid.FooterRemoved(footer, index);
      OnCollectionChanged(new CollectionChangeEventArgs(CollectionChangeAction.Remove, footer));
    }

    public virtual void BeginUpdate()
    {
      if (!Updating)
      {
        oldItems.Clear();
        oldItems.AddRange(this);
      }

      updateCount = updateCount + 1;
    }

    public virtual void EndUpdate()
    {
      Debug.Assert(updateCount > 0);
      updateCount = updateCount - 1;
      if (!Updating)
      {
        DispatchListChanges();
        Grid.FooterCollectionListChanged();
      }
      //if (updateCount == 0)
      //  Grid.FootersUpdateCommited();
    }


    protected void DispatchListChanges()
    {
      for (int i = oldItems.Count - 1; i >= 0; i--)
      {
        DataGridFooterRow footer = oldItems[i];
        if (!Contains(footer))
        {
          Grid.FooterRemoved(footer, i);
          oldItems.RemoveAt(i);
        }
      }

      for (int i = 0; i < Count; i++)
      {
        int oldIdx;
        DataGridFooterRow footer = this[i];
        if (i >= oldItems.Count || footer != oldItems[i])
        {
          oldIdx = oldItems.IndexOf(footer);
          if (oldIdx == -1)
          {
            Grid.FooterAdded(footer, i);
            oldItems.Insert(i, footer);
          }
          else
          {
            Grid.FooterRowMoved(oldIdx, i);
            oldItems.RemoveAt(oldIdx);
            oldItems.Insert(i, footer);
          }
        }
      }
    }

    int IList.Add(object value)
    {
      return this.Add((DataGridFooterRow)value);
    }

    bool IList.Contains(object value)
    {
      return this.items.Contains((DataGridFooterRow)value);
    }

    void IList.Clear()
    {
      this.Clear();
    }

    int IList.IndexOf(object value)
    {
      return this.items.IndexOf((DataGridFooterRow)value);
    }

    void IList.Insert(int index, object value)
    {
      this.Insert(index, (DataGridFooterRow)value);
    }

    void IList.Remove(object value)
    {
      this.Remove((DataGridFooterRow)value);
    }

    void IList.RemoveAt(int index)
    {
      this.RemoveAt(index);
    }

    void ICollection.CopyTo(Array array, int index)
    {
      ArrayList arLst = new ArrayList(this.items);
      arLst.CopyTo(array);
    }

    //public void SetItems(DataGridFooterRow[] footerRows)
    //{
    //  int srcIndex;

    //  for (int i = 0; i < footerRows.Length; i++)
    //  {
    //    DataGridFooterRow row = footerRows[i];
    //    srcIndex = this.IndexOf(row);
    //    if (srcIndex == -1)
    //    {
    //      Insert(i, row);
    //    }
    //    else if (srcIndex != i)
    //    {
    //      MoveItem(srcIndex, i);
    //    }
    //  }

    //  for (int i = this.Count-1; i >= footerRows.Length; i--)
    //  {
    //    //DataGridFooterRow row = this[i];
    //    RemoveAt(i);
    //  }
    //}

    public void MoveItem(int oldIndex, int newIndex)
    {
      DataGridFooterRow row = this.items[oldIndex];
      items.RemoveAt(oldIndex);
      items.Insert(newIndex, row);
      if (!Updating)
      {
        Grid.FooterRowMoved(oldIndex, newIndex);
        Grid.FooterCollectionListChanged();
      }
    }
  }

  [ToolboxItem(false)]
  public class DataGridColumnFooter : Component
  {
    #region private consts
    private static readonly object EventKeyFooterCellPaint = new object();
    private static readonly object EventKeyInitCalculation = new object();
    private static readonly object EventKeyRowStepCalculation = new object();
    private static readonly object EventKeyFinalizeCalculation = new object();
    private static readonly object EventKeyFormatValue = new object();
    private static readonly object EventKeyCellMouseDown = new object();
    private static readonly object EventKeyCellMouseMove = new object();
    private static readonly object EventKeyCellMouseUp = new object();
    private static readonly object EventKeyCellMouseClick = new object();
    private static readonly object EventKeyCellMouseDoubleClick = new object();
    private static readonly object EventKeyCellMouseEnter = new object();
    private static readonly object EventKeyCellMouseLeave = new object();
    private static readonly object EventKeyCellMouseHover = new object();
    #endregion

    #region privates
    private readonly DataGridColumn column;
    private readonly DataGridColumnFooterItems items;
    private readonly DataGridColumnFooterItemsOrNull itemsOrNull;
    #endregion

    public DataGridColumnFooter(DataGridColumn column)
    {
      this.column = column;
      this.items = new DataGridColumnFooterItems(this);
      this.itemsOrNull = new DataGridColumnFooterItemsOrNull(this);
    }

    #region properties
    [Browsable(false)]
    public DataGridColumn Column
    {
      get { return column; }
    }

    [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
    public DataGridColumnFooterItems Items
    {
      get { return items; }
    }

    [Browsable(false)]
    public DataGridColumnFooterItemsOrNull ItemsOrNull
    {
      get { return itemsOrNull; }
    }

    //ISite IComponent.Site { get { return null; } set { } }
    #endregion

    #region events
    public event EventHandler<DataGridFooterCellPaintEventArgs> CellPaint
    {
      add
      {
        this.Events.AddHandler(EventKeyFooterCellPaint, value);
      }
      remove
      {
        this.Events.RemoveHandler(EventKeyFooterCellPaint, value);
      }
    }

    public event EventHandler<DataGridFooterCalculationEventArgs> InitCalculation
    {
      add
      {
        this.Events.AddHandler(EventKeyInitCalculation, value);
      }
      remove
      {
        this.Events.RemoveHandler(EventKeyInitCalculation, value);
      }
    }

    public event EventHandler<DataGridFooterCalculationEventArgs> RowStepCalculation
    {
      add
      {
        this.Events.AddHandler(EventKeyRowStepCalculation, value);
      }
      remove
      {
        this.Events.RemoveHandler(EventKeyRowStepCalculation, value);
      }
    }

    public event EventHandler<DataGridFooterCalculationEventArgs> FinalizeCalculation
    {
      add
      {
        this.Events.AddHandler(EventKeyFinalizeCalculation, value);
      }
      remove
      {
        this.Events.RemoveHandler(EventKeyFinalizeCalculation, value);
      }
    }

    public event EventHandler<DataGridFooterCellFormatValueEventArgs> CellFormatValue
    {
      add
      {
        this.Events.AddHandler(EventKeyFormatValue, value);
      }
      remove
      {
        this.Events.RemoveHandler(EventKeyFormatValue, value);
      }
    }

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

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

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

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

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

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

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

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

    //event EventHandler IComponent.Disposed
    //{
    //  add
    //  {
    //  }

    //  remove
    //  {
    //  }
    //}

    #endregion

    #region methods
    internal void HandlePaintEvent(DataGridFooterCellPaintEventArgs e)
    {
      var eh = this.Events[EventKeyFooterCellPaint] as EventHandler<DataGridFooterCellPaintEventArgs>;
      if (eh != null)
        eh(this, e);
    }

    internal bool HandleInitCalculationEvent(DataGridFooterCalculationEventArgs e)
    {
      var eh = this.Events[EventKeyInitCalculation] as EventHandler<DataGridFooterCalculationEventArgs>;
      if (eh != null)
      {
        eh(this, e);
        return e.Handled;
      }
      else
      {
        return false;
      }
    }

    internal bool HandleRowStepCalculationEvent(DataGridFooterCalculationEventArgs e)
    {
      var eh = this.Events[EventKeyRowStepCalculation] as EventHandler<DataGridFooterCalculationEventArgs>;
      if (eh != null)
      {
        eh(this, e);
        return e.Handled;
      }
      else
      {
        return false;
      }
    }

    internal bool HandleFinalizeCalculationEvent(DataGridFooterCalculationEventArgs e)
    {
      var eh = this.Events[EventKeyFinalizeCalculation] as EventHandler<DataGridFooterCalculationEventArgs>;
      if (eh != null)
      {
        eh(this, e);
        return e.Handled;
      }
      else
      {
        return false;
      }
    }

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

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

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

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

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

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

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

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

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

    //void IDisposable.Dispose()
    //{
    //}
    #endregion

  }

  //[Serializable]
  [DesignTimeVisible(false)]
  [ToolboxItem(false)]
  public class DataGridColumnFooterItem : Component, IGridLineHost, ICellBackFillerOwner
  {
    #region private consts
    private static readonly object EventKeyFooterCellPaint = new object();
    private static readonly object EventKeyInitCalculation = new object();
    private static readonly object EventKeyRowStepCalculation = new object();
    private static readonly object EventKeyFinalizeCalculation = new object();
    private static readonly object EventKeyFormatValue = new object();
    private static readonly object EventKeyCellMouseDown = new object();
    private static readonly object EventKeyCellMouseMove = new object();
    private static readonly object EventKeyCellMouseUp = new object();
    private static readonly object EventKeyCellMouseClick = new object();
    private static readonly object EventKeyCellMouseDoubleClick = new object();
    private static readonly object EventKeyCellMouseEnter = new object();
    private static readonly object EventKeyCellMouseLeave = new object();
    private static readonly object EventKeyCellMouseHover = new object();
    #endregion

    #region privates
    private DataGridColumn column;

    private Font font;
    private bool foreColorStored;
    private Color foreColor = Color.Empty;
    private object value;
    private AggregationCalculator calculator;
    //private Type valueFunctionType;
    private AggregationCalculator calcValueFunction;
    private bool horzAlignStored;
    private HorizontalAlignment horzAlign;
    private readonly GridLine vertLine;
    private readonly CellBackFiller backFiller;
    private Padding padding = new Padding(0);
    private bool paddingStored;
    private int index;
    private bool formatStringStored;
    private string formatString;
    private readonly Padding defaultPadding = new Padding(3, 2, 3, 4);
    #endregion

    public DataGridColumnFooterItem()
    {
      vertLine = new GridLine(this);
      backFiller = new CellBackFiller(this);

      StaticText = "";
      //FormatString = "";
      index = -1;
    }

    #region designtime properties
    //[DefaultValue(DataGridFooterValueFunction.Non)]
    //public DataGridFooterValueFunction ValueFunction
    //{
    //  get
    //  {
    //    return valueFunction;
    //  }

    //  set
    //  {
    //    if (valueFunction != value)
    //    {
    //      valueFunction = value;
    //      UpdateCalculator();
    //      if (Column != null && Column.Grid != null)
    //        Column.Grid.FooterValueFunctionChanged(this);
    //    }
    //  }
    //}

    //[TypeConverter("EhLib.Design.DataGridFooterValueFunctionTypeConverter")]
    ////[Editor("EhLib.Design.DataGridFooterValueFunctionTypeConverter"+EhLibUtils.EhLibDesignDesignerVersionInfo, "System.Drawing.Design.UITypeEditor, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a")]
    //[DefaultValue(null)]
    //public Type ValueFunctionType
    //{
    //  get
    //  {
    //    return valueFunctionType;
    //  }
    //  set
    //  {
    //    if (valueFunctionType != value)
    //    {
    //      valueFunctionType = value;
    //      UpdateCalculator();
    //      if (Column != null && Column.Grid != null)
    //        Column.Grid.FooterValueFunctionChanged(this);
    //    }
    //  }
    //}

    [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
    [Editor("EhLib.Design.ObjectSelectorEditorByType" + EhLibUtils.EhLibDesignDesignerVersionInfo, "System.Drawing.Design.UITypeEditor, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a")]
    [DefaultValue(null)]
    public AggregationCalculator CalcValueFunction
    {
      get
      {
        return calcValueFunction;
      }
      set
      {
        if (calcValueFunction != value)
        {
          calcValueFunction = value;
          UpdateCalculator();
          if (Column != null && Column.Grid != null)
            Column.Grid.FooterValueFunctionChanged(this);
        }
      }
    }

    [DefaultValue("")]
    public string StaticText
    { get; set; }

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

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

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

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

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

    //[DefaultValue(null)]
    public string FormatString
    {
      get
      {
        if (formatStringStored)
          return formatString;
        else
          return DefaultFormatString();
      }
      set
      {
        if ((formatStringStored == false) || (formatString != value))
        {
          formatStringStored = true;
          formatString = value;
          FormatStringChanged();
        }
      }
    }

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

    #region events
    public event EventHandler<DataGridFooterCellPaintEventArgs> CellPaint
    {
      add
      {
        this.Events.AddHandler(EventKeyFooterCellPaint, value);
      }
      remove
      {
        this.Events.RemoveHandler(EventKeyFooterCellPaint, value);
      }
    }

    public event EventHandler<DataGridFooterCalculationEventArgs> InitCalculation
    {
      add
      {
        this.Events.AddHandler(EventKeyInitCalculation, value);
      }
      remove
      {
        this.Events.RemoveHandler(EventKeyInitCalculation, value);
      }
    }

    public event EventHandler<DataGridFooterCalculationEventArgs> RowStepCalculation
    {
      add
      {
        this.Events.AddHandler(EventKeyRowStepCalculation, value);
      }
      remove
      {
        this.Events.RemoveHandler(EventKeyRowStepCalculation, value);
      }
    }

    public event EventHandler<DataGridFooterCalculationEventArgs> FinalizeCalculation
    {
      add
      {
        this.Events.AddHandler(EventKeyFinalizeCalculation, value);
      }
      remove
      {
        this.Events.RemoveHandler(EventKeyFinalizeCalculation, value);
      }
    }

    public event EventHandler<DataGridFooterCellFormatValueEventArgs> CellFormatValue
    {
      add
      {
        this.Events.AddHandler(EventKeyFormatValue, value);
      }
      remove
      {
        this.Events.RemoveHandler(EventKeyFormatValue, value);
      }
    }

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

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

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

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

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

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

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

    public event EventHandler<DataGridFooterCellMouseEventArgs> CellMouseHover
    {
      add
      {
        this.Events.AddHandler(EventKeyCellMouseHover, value);
      }
      remove
      {
        this.Events.RemoveHandler(EventKeyCellMouseHover, value);
      }
    }
    #endregion

    #region runtime properties
    [Browsable(false)]
    public virtual DataGridEh Grid
    {
      get
      {
        if (column == null)
          return null;
        else
          return column.Grid;

      }
    }

    [Browsable(false)]
    public DataGridColumn Column
    {
      get
      {
        return column;
      }
      internal set
      {
        column = value;
        index = -1;
      }
    }

    [Browsable(false)]
    public DataGridFooterRow FooterRow
    {
      get
      {
        if (Column != null && Index < Column.Grid.Footer.Rows.Count)
          return Column.Grid.Footer.Rows[Index];
        else
          return null;
      }
      //internal set { footerRow = value; }
    }

    //[Browsable(false)]
    //public string DisplayText
    //{
    //  get
    //  {
    //    StaticTextCalculator textCalc = calculator as StaticTextCalculator;
    //    if (textCalc != null)
    //      return StaticText;
    //    else
    //    {
    //      if (Value == null)
    //        return "";
    //      else
    //        return Value.ToString();
    //    }
    //  } 
    //}

    [Browsable(false)]
    public object Value
    {
      get
      {
        StaticTextCalculator textCalc = calculator as StaticTextCalculator;
        if (textCalc != null)
          return StaticText;
        else
          return value;
      }
    }

    [Browsable(false)]
    public int Index
    {
      get
      {
        if (Column != null && Column.Footer.Items.indexesIncorrect)
          Column.Footer.Items.UpdateIndexes();
        return index;
      }
      internal set { index = value; }
    }
    #endregion

    #region methods

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

    Color ICellBackFillerOwner.BackFillerDefaultColor(CellBackFiller backFiller)
    {
      if (FooterRow != null)
        return FooterRow.BackFiller.Color;
      else if (Grid != null)
        return Grid.Footer.BackFiller.Color;
      else
        return Color.Empty;
    }

    Color ICellBackFillerOwner.BackFillerDefaultSecondColor(CellBackFiller backFiller)
    {
      if (FooterRow != null)
        return FooterRow.BackFiller.SecondColor;
      else if (Grid != null)
        return Grid.Footer.BackFiller.SecondColor;
      else
        return Color.Empty;
    }

    CellFillStyle ICellBackFillerOwner.BackFillerDefaultFillStyle(CellBackFiller backFiller)
    {
      if (FooterRow != null)
        return FooterRow.BackFiller.FillStyle;
      else if (Grid != null)
        return Grid.Footer.BackFiller.FillStyle;
      else
        return CellFillStyle.Solid;
    }

    CellInnerBorderStyle ICellBackFillerOwner.BackFillerDefaultInnerBorder(CellBackFiller backFiller)
    {
      if (FooterRow != null)
        return FooterRow.BackFiller.InnerBorder;
      else if (Grid != null)
        return Grid.Footer.BackFiller.InnerBorder;
      else
        return CellInnerBorderStyle.None;
    }

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

    bool IGridLineHost.GridLineDefaultVisible(GridLine gl)
    {
      if (Grid != null)
        return Grid.Footer.VertLine.Visible;
      else
        return false;
    }

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

    DashStyle IGridLineHost.GridLineDefaultStyle(GridLine gl)
    {
      if (Grid != null)
        return Grid.Footer.VertLine.Style;
      else
        return DashStyle.Solid;
    }

    //Font
    protected virtual Font DefaultFont()
    {
      if (FooterRow != null)
        return FooterRow.Font;
      else
        return null;
    }

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

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

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

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

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

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

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

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

    protected virtual Padding DefaultPadding()
    {
      if (Grid != null)
        return Grid.Footer.Padding;
      else
        return Padding.Empty;
    }

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

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

    //FormatString
    protected virtual void FormatStringChanged()
    {
      if (Column != null && Column.Grid != null)
        Column.Grid.InvalidateGrid();
    }

    public string DefaultFormatString()
    {
      if (calculator != null)
        return calculator.DefaultFormatString;
      else
        return null;
    }

    protected virtual bool ShouldSerializeFormatString()
    {
      return (formatStringStored == true);
    }

    public virtual void ResetFormatString()
    {
      formatStringStored = false;
      FormatStringChanged();
    }

    protected virtual void HorzAlignChanged()
    {
      if (Column != null && Column.Grid != null)
        Column.Grid.InvalidateGrid();
    }

    //Other
    public HorizontalAlignment DefaultHorzAlign()
    {
      DataGridMonoCellColumn monoCellColumn = Column as DataGridMonoCellColumn;
      if (monoCellColumn != null)
        return monoCellColumn.HorzAlign;
      else
        return HorizontalAlignment.Left;
    }

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

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

    public virtual void Recalculate()
    {
      int footerItemIndex = Column.Footer.Items.IndexOf(this);

      var e = new DataGridFooterCalculationEventArgs(Column, null, this, footerItemIndex, -1);

      bool handled = HandleInitCalculationEvent(e);
      if (!handled && calculator != null)
        calculator.InitCalcData(Column.DataType);

      int step = 0;
      foreach (DataGridRow row in this.Column.Grid.Rows)
      {
        e.Reset(Column, row, this, footerItemIndex, step);
        handled = HandleRowStepCalculationEvent(e);

        if (!handled && calculator != null)
        {
          if (calculator.IncludeHidenRows == false && row.Visible == false)
            EhLibUtils.DoNothing();
          else
            calculator.StepCalcData(Column.GetRowValue(row));
        }

        step++;
      }

      e.Reset(Column, null, this, footerItemIndex, step);
      handled = HandleFinalizeCalculationEvent(e);

      if (!handled && calculator != null)
        value = calculator.FinalizeCalcData();
      else
        value = e.Value;
    }

    protected virtual void UpdateCalculator()
    {
      //if (valueFunctionType != null)
      //{
      //  calculator = (AggregationCalculator)Activator.CreateInstance(valueFunctionType);
      //}
      //else
      //{
      //  calculator = null;
      //}
      calculator = CalcValueFunction;
    }

    internal bool HandleInitCalculationEvent(DataGridFooterCalculationEventArgs e)
    {
      bool handled = false;

      var eh = this.Events[EventKeyInitCalculation] as EventHandler<DataGridFooterCalculationEventArgs>;
      if (eh != null)
      {
        eh(this, e);
        handled = e.Handled;
      }

      if (!handled)
        handled = Column.Footer.HandleInitCalculationEvent(e);
      if (!handled)
        handled = Grid.Footer.HandleInitCalculationEvent(e);
      return handled;
    }

    internal bool HandleRowStepCalculationEvent(DataGridFooterCalculationEventArgs e)
    {
      bool handled = false;

      var eh = this.Events[EventKeyRowStepCalculation] as EventHandler<DataGridFooterCalculationEventArgs>;
      if (eh != null)
      {
        eh(this, e);
        handled = e.Handled;
      }

      if (!handled)
        handled = Column.Footer.HandleRowStepCalculationEvent(e);
      if (!handled)
        handled = Grid.Footer.HandleRowStepCalculationEvent(e);
      return handled;
    }

    internal bool HandleFinalizeCalculationEvent(DataGridFooterCalculationEventArgs e)
    {
      bool handled = false;

      var eh = this.Events[EventKeyFinalizeCalculation] as EventHandler<DataGridFooterCalculationEventArgs>;
      if (eh != null)
      {
        eh(this, e);
        handled = e.Handled;
      }

      if (!handled)
        handled = Column.Footer.HandleFinalizeCalculationEvent(e);
      if (!handled)
        handled = Grid.Footer.HandleFinalizeCalculationEvent(e);
      return handled;
    }

    internal int GetOptimalCellHeight()
    {
      int fontHeight = EhLibUtils.GetFontHeight(Font);
      int th = fontHeight + Padding.Top + Padding.Bottom;
      return th;
    }

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

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

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

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

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

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

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

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

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

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

  [TypeConverter("EhLib.Design.ExpandableCollectionTypeConverter")]
  //[TypeConverter(typeof(ExpandableObjectConverter))]
  public class DataGridColumnFooterItems : Collection<DataGridColumnFooterItem>, ICollection, ICollection<DataGridColumnFooterItem>//, IComponent
  {
    private readonly DataGridColumnFooter columnFooter;
    private CollectionChangeEventHandler onCollectionChanged;
    private DataGridColumnFooterItem appartItem = new DataGridColumnFooterItem();

    internal bool indexesIncorrect;

    public DataGridColumnFooterItems(DataGridColumnFooter columnFooter)
    {
      this.columnFooter = columnFooter;
    }

    // Properties
    public DataGridColumnFooterItem AppartItem { get { return appartItem; } }

    // Events
    public event CollectionChangeEventHandler CollectionChanged
    {
      add { this.onCollectionChanged += value; }
      remove { this.onCollectionChanged -= value; }
    }

    //Methods
    protected override void ClearItems()
    {
      foreach (var item in Items)
        item.Column = null;
      base.ClearItems();
    }

    protected override void InsertItem(int index, DataGridColumnFooterItem item)
    {
      base.InsertItem(index, item);
      item.Column = columnFooter.Column;
      indexesIncorrect = true;
    }

    protected override void RemoveItem(int index)
    {
      var removingItem = Items[index];
      base.RemoveItem(index);
      removingItem.Column = null;
      indexesIncorrect = true;
    }

    protected override void SetItem(int index, DataGridColumnFooterItem item)
    {
      if (Items[index] != item)
      {
        var oldItem = Items[index];
        base.SetItem(index, item);
        oldItem.Column = null;
        item.Column = columnFooter.Column;
        indexesIncorrect = true;
      }
    }

    public void AddRange(IEnumerable<DataGridColumnFooterItem> collection)
    {
      foreach (DataGridColumnFooterItem item in collection)
      {
        Add(item);
      }
    }

    internal void UpdateIndexes()
    {
      for (int i = 0; i < Count; i++)
        Items[i].Index = i;
      indexesIncorrect = false;
    }

    bool ICollection<DataGridColumnFooterItem>.IsReadOnly
    {
      get
      {
        return IsReadOnly;
      }
    }

    public bool IsReadOnly
    {
      get
      {
        if ((columnFooter.Column.Grid == null) ||
            (columnFooter.Column.Grid != null && columnFooter.Column.Grid.InInitialization))
          return false;
        else
          return true;
      }
    }

    //event EventHandler IComponent.Disposed
    //{
    //  add
    //  {
    //  }

    //  remove
    //  {
    //  }
    //}

    //void IDisposable.Dispose()
    //{
    //}

    //ISite IComponent.Site { get { return null; } set { } }
  }

  public class DataGridColumnFooterItemsOrNull
  {
    private DataGridColumnFooter columnFooter;

    public DataGridColumnFooterItemsOrNull(DataGridColumnFooter columnFooter)
    {
      this.columnFooter = columnFooter;
    }

    public DataGridColumnFooterItem this[int index]
    {
      get
      {
        if (index < columnFooter.Items.Count)
          return columnFooter.Items[index];
        else
          return null;
      }
    }
  }

  public class DataGridFooterCellMan : DataGridColumnCellMan
  {

    public override BaseGridCellPaintEventArgs GetCellPaintParams(
        Graphics graphics,
        int colIndex, int rowIndex,
        Rectangle paintRect,
        BasePaintCellStates state,
        int areaColIndex, int areaRowIndex,
        Point inCellMousePos
      )
    {
      DataGridColumn column;
      if (areaColIndex >= 0 && areaColIndex < Grid.VisibleColumns.Count)
        column = Grid.VisibleColumns[areaColIndex];
      else
        column = null;

      var result = new DataGridFooterCellPaintEventArgs(
        this, graphics, colIndex, rowIndex, paintRect, state, areaColIndex, areaRowIndex, inCellMousePos, column);

      FillPaintParams(result);

      return result;
    }

    protected internal virtual void FillPaintParams(DataGridFooterCellPaintEventArgs e)
    {

      if (e.Column != null)
      {
        DataGridColumnFooterItem footer = null;

        e.ContentRect = e.CellRect;
        e.VertAlign = Grid.Footer.VertAlign;

        if (e.AreaRowIndex < e.Column.Footer.Items.Count)
        {
          footer = e.Column.Footer.Items[e.AreaRowIndex];

          //e.FormattedValue = footer.DisplayText;
          e.FillStyle = footer.BackFiller.FillStyle;
          e.BackColor = footer.BackFiller.Color;
          e.SecondFillColor = footer.BackFiller.SecondColor;
          e.InnerBorder = footer.BackFiller.InnerBorder;
          e.Padding = Grid.Footer.Padding;

          e.Font = footer.Font;
          e.ForeColor = footer.ForeColor;
          e.HorzAlign = footer.HorzAlign;
        }
        else
        {
          e.FillStyle = Grid.Footer.BackFiller.FillStyle;
          e.BackColor = Grid.Footer.BackFiller.Color;
          e.SecondFillColor = Grid.Footer.BackFiller.SecondColor;
          e.InnerBorder = Grid.Footer.BackFiller.InnerBorder;
          e.Padding = Grid.Footer.Padding;

          e.Font = Grid.Footer.Font;
          e.ForeColor = Grid.Footer.ForeColor;
          e.HorzAlign = HorizontalAlignment.Left;
        }
      }
      else
      {
        e.ContentRect = e.CellRect;
        //e.FormattedValue = "";

        e.FillStyle = Grid.Footer.BackFiller.FillStyle;
        e.BackColor = Grid.Footer.BackFiller.Color;
        e.SecondFillColor = Grid.Footer.BackFiller.SecondColor;
        e.InnerBorder = Grid.Footer.BackFiller.InnerBorder;
        e.Padding = Grid.Footer.Padding;

        e.Font = Grid.Footer.Font;
        e.ForeColor = Grid.Footer.ForeColor;
        //drPrms.HorzAlign = grid.FooterOptions.HorzAlign;
        e.VertAlign = Grid.Footer.VertAlign;
      }

      e.ContentRect = e.CellClientRect;
    }

    protected internal override void HandlePaintEvent(BaseGridCellPaintEventArgs e)
    {
      var te = (DataGridFooterCellPaintEventArgs)e;
      DataGridColumnFooterItem footer = null;

      Grid.Footer.HandlePaintEvent(te);
      if (te.Column != null)
      {
        footer = te.Column.Footer.ItemsOrNull[e.AreaRowIndex];
        if (footer != null)
          footer.HandlePaintEvent(te);
        te.Column.Footer.HandlePaintEvent(te);
      }

    }

    protected internal override void OnPaint(BaseGridCellPaintEventArgs e)
    {
      var tp = (DataGridFooterCellPaintEventArgs)e;

      OnPaintBackground(tp);
      OnPaintForeground(tp);
    }

    //protected internal virtual void GetCellPaintParams(DataGridColumnPaintCellParams p)
    //{
    //  if (p.Column != null)
    //  {
    //    DataGridColumnFooterItem footer = p.Column.Footers[p.DataRow];

    //    p.ContentRect = p.CellRect;
    //    p.FormattedValue = footer.DisplayText;

    //    p.FillStyle =  footer.BackFiller.FillStyle;
    //    p.BackColor = footer.BackFiller.Color;
    //    p.SecondFillColor = footer.BackFiller.SecondColor;
    //    p.InnerBorder = footer.BackFiller.InnerBorder;
    //    p.Padding = Grid.Footer.Padding;

    //    p.Font = footer.Font;
    //    p.ForeColor = footer.ForeColor;
    //    p.HorzAlign = footer.HorzAlign;
    //    p.VertAlign = Grid.Footer.VertAlign;
    //  }
    //  else
    //  {
    //    p.ContentRect = p.CellRect;
    //    p.FormattedValue = "";

    //    p.FillStyle = Grid.Footer.BackFiller.FillStyle;
    //    p.BackColor = Grid.Footer.BackFiller.Color;
    //    p.SecondFillColor = Grid.Footer.BackFiller.SecondColor;
    //    p.InnerBorder = Grid.Footer.BackFiller.InnerBorder;
    //    p.Padding = Grid.Footer.Padding;

    //    p.Font = Grid.Footer.Font;
    //    p.ForeColor = Grid.Footer.ForeColor;
    //    //drPrms.HorzAlign = grid.FooterOptions.HorzAlign;
    //    p.VertAlign = Grid.Footer.VertAlign;
    //  }
    //}

    protected internal virtual void OnPaintBackground(DataGridFooterCellPaintEventArgs e)
    {
      BaseGridFillFixedCellEventArgs styledPaintArgs = new BaseGridFillFixedCellEventArgs();

      styledPaintArgs.CellRect = e.CellClientRect;
      styledPaintArgs.Graphics = e.Graphics;
      styledPaintArgs.IsHot = false;
      styledPaintArgs.IsPressed = false;
      styledPaintArgs.IsSelected = false;
      styledPaintArgs.BackColor = e.BackColor;
      styledPaintArgs.FillStyle = e.FillStyle;
      styledPaintArgs.InnerBorder = e.InnerBorder;
      styledPaintArgs.FillColor = e.BackColor;
      styledPaintArgs.SecondFillColor = e.SecondFillColor;

      Grid.GetDrawStyle().FillFixedCell(Grid, styledPaintArgs);
    }

    protected internal virtual void OnPaintForeground(DataGridFooterCellPaintEventArgs e)
    {
      string text;
      //TextFormatFlagsEh flags = TextFormatFlagsEh.Default;

      if (e.Column != null)
      {
        text = GetDisplayText(e.Column, e.AreaRowIndex);
      }
      else
      {
        text = "";
      }

      e.ContentRect = EhLibUtils.TrimPadding(e.CellClientRect, e.Padding);

      Grid.PaintingDrawText(e.Graphics, text, e.Font, e.ContentRect,
        e.ForeColor, e.HorzAlign, e.VertAlign, e.WordWrap);
    }

    protected internal override void PrintCell(PrintServiceEventArgs e,
      Rectangle paintRect, int areaColIndex,
      int areaRowIndex,
      PrintServiceEventArgs printContext
        )
    {
      DataGridFooterCellPaintEventArgs pea = (DataGridFooterCellPaintEventArgs)GetCellPaintParams(
        e.Graphics, -1, -1, paintRect, 0, areaColIndex, areaRowIndex, new Point(-1, -1));

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

        if (pea.WordWrap)
          flags = flags | TextFormatFlagsEh.WordBreak;

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

    protected internal override BaseGridCellPaintEventArgs GetCellPaintEmptyAreaEventArgs(
        Graphics graphics,
        int colIndex, int rowIndex,
        Rectangle paintRect,
        BasePaintCellStates state,
        int areaColIndex, int areaRowIndex,
        Point inCellMousePos
      )
    {
      return GetCellPaintParams(graphics, colIndex, rowIndex, paintRect, state, areaColIndex, areaRowIndex, inCellMousePos);
    }

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

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

    public override string GetDisplayText(DataGridColumn column, int dataRowIndex)
    {
      DataGridColumnFooterItem columnFooter;
      if (dataRowIndex < column.Footer.Items.Count)
      {
        columnFooter = column.Footer.Items[dataRowIndex];
        return ProcessFormatValue(column, columnFooter, dataRowIndex);
      }
      else
      {
        return String.Empty;
      }
    }

    protected internal override void OnGetCellBorderParams(BaseGridCellBorderEventArgs e)
    {
      GridLine gl;

      base.OnGetCellBorderParams(e);

      if (e.BorderType == GridCellBorderType.Right || e.BorderType == GridCellBorderType.Left)
      {
        if (e.AreaColIndex >= 0 && e.AreaColIndex < Grid.VisibleColumns.Count)
        {
          
          DataGridColumn column = Grid.VisibleColumns[e.AreaColIndex];
          if (e.AreaRowIndex < column.Footer.Items.Count)
            gl = column.Footer.Items[e.AreaRowIndex].VertLine;
          else
            gl = Grid.Footer.VertLine;
        }
        else
        {
          gl = Grid.Footer.VertLine;
        }
      }
      else if (e.BorderType == GridCellBorderType.Bottom || e.BorderType == GridCellBorderType.Top)
      {
        if (e.BorderType == GridCellBorderType.Top && e.AreaRowIndex == 0)
          gl = Grid.Footer.HorzLine;
        else
          gl = Grid.Footer.Rows[e.AreaRowIndex].HorzLine;
      }
      else
      {
        throw new ArgumentException(@"Can't assign gl");
      }

      e.Visible = gl.Visible;
      e.Color = gl.Color;
      e.Style = gl.Style;
      e.IsExtent = true;
    }

    protected internal string ProcessFormatValue(DataGridColumn column, DataGridColumnFooterItem footerItem, int footerItemIndex)
    {
      var e = new DataGridFooterCellFormatValueEventArgs(column, footerItem, footerItemIndex, footerItem.Value);

      HandleFormatValueEvent(e);
      if (!e.Handled)
        OnFormatValue(e);

      if (e.FormatedValue == null)
        return null;
      else
        return e.FormatedValue.ToString();
    }

    private void HandleFormatValueEvent(DataGridFooterCellFormatValueEventArgs e)
    {
      if (e.Column != null)
      {
        if (e.FooterItem != null)
          e.FooterItem.HandleFormatValueEvent(e);
        if (!e.Handled)
          e.Column.Footer.HandleFormatValueEvent(e);
        if (!e.Handled)
          Grid.Footer.HandleFormatValueEvent(e);
      }
    }

    protected internal virtual void OnFormatValue(DataGridFooterCellFormatValueEventArgs e)
    {
      //e.FormatedValue = 
      //  EhLibManager.DefaultEhLibManager.ValueConverter.FormatValue(e.SourceValue, typeof(string));
      e.FormatedValue =
        EhLibManager.DefaultEhLibManager.ValueConverter.FormatValue(e.SourceValue, typeof(string), null, null, e.FooterItem.FormatString, null, null, null);
    }

    protected internal override BaseGridCellMouseEventArgs CreateMouseEventArgs(
      int colIndex, int rowIndex, int areaColIndex, int areaRowIndex, int inCellX, int inCellY,
      Rectangle cellRect, MouseEventArgs gridMouseArgs)
    {
      DataGridColumn column = Grid.VisibleColumns[areaColIndex];
      DataGridColumnFooterItem columnFooter = null;

      if (areaRowIndex < column.Footer.Items.Count)
        columnFooter = column.Footer.Items[areaRowIndex];

      return new DataGridFooterCellMouseEventArgs(this, colIndex, rowIndex, areaColIndex, areaRowIndex, 
        inCellX, inCellY, cellRect, gridMouseArgs, column, columnFooter, areaRowIndex);
    }

    protected internal override void HandleMouseDownEvent(BaseGridCellMouseEventArgs e)
    {
      DataGridFooterCellMouseEventArgs fe = (DataGridFooterCellMouseEventArgs)e;
      if (fe.Column != null)
      {
        if (fe.FooterItem != null)
          fe.FooterItem.HandleMouseDownEvent(fe);
        if (!e.Handled)
          fe.Column.Footer.HandleMouseDownEvent(fe);
        if (!e.Handled)
          Grid.Footer.HandleMouseDownEvent(fe);
      }
    }

    protected internal override void HandleMouseMoveEvent(BaseGridCellMouseEventArgs e)
    {
      DataGridFooterCellMouseEventArgs fe = (DataGridFooterCellMouseEventArgs)e;
      if (fe.Column != null)
      {
        if (fe.FooterItem != null)
          fe.FooterItem.HandleMouseMoveEvent(fe);
        if (!e.Handled)
          fe.Column.Footer.HandleMouseMoveEvent(fe);
        if (!e.Handled)
          Grid.Footer.HandleMouseMoveEvent(fe);
      }
    }

    protected internal override void HandleMouseUpEvent(BaseGridCellMouseEventArgs e)
    {
      DataGridFooterCellMouseEventArgs fe = (DataGridFooterCellMouseEventArgs)e;
      if (fe.Column != null)
      {
        if (fe.FooterItem != null)
          fe.FooterItem.HandleMouseUpEvent(fe);
        if (!e.Handled)
          fe.Column.Footer.HandleMouseUpEvent(fe);
        if (!e.Handled)
          Grid.Footer.HandleMouseUpEvent(fe);
      }
    }

    protected internal override void HandleMouseClickEvent(BaseGridCellMouseEventArgs e)
    {
      DataGridFooterCellMouseEventArgs fe = (DataGridFooterCellMouseEventArgs)e;
      if (fe.Column != null)
      {
        if (fe.FooterItem != null)
          fe.FooterItem.HandleMouseClickEvent(fe);
        if (!e.Handled)
          fe.Column.Footer.HandleMouseClickEvent(fe);
        if (!e.Handled)
          Grid.Footer.HandleMouseClickEvent(fe);
      }
    }

    protected internal override void HandleMouseDoubleClickEvent(BaseGridCellMouseEventArgs e)
    {
      DataGridFooterCellMouseEventArgs fe = (DataGridFooterCellMouseEventArgs)e;
      if (fe.Column != null)
      {
        if (fe.FooterItem != null)
          fe.FooterItem.HandleMouseDoubleClickEvent(fe);
        if (!e.Handled)
          fe.Column.Footer.HandleMouseDoubleClickEvent(fe);
        if (!e.Handled)
          Grid.Footer.HandleMouseDoubleClickEvent(fe);
      }
    }

    protected internal override BaseGridCellEnterEventArgs CreateCellEnterEventArgs(
      int colIndex, int rowIndex, int areaColIndex, int areaRowIndex, Rectangle cellRect, int leaveColIndex, int leaveRowIndex)
    {
      DataGridColumn column = Grid.VisibleColumns[areaColIndex];
      DataGridColumnFooterItem columnFooter = null;

      if (areaRowIndex < column.Footer.Items.Count)
        columnFooter = column.Footer.Items[areaRowIndex];

      return new DataGridFooterCellEnterEventArgs(colIndex, rowIndex, areaColIndex, areaRowIndex, cellRect, leaveColIndex, leaveRowIndex, 
        column, columnFooter, areaRowIndex);
    }

    protected override void HandleMouseEnterEvent(BaseGridCellEnterEventArgs e)
    {
      DataGridFooterCellEnterEventArgs fe = (DataGridFooterCellEnterEventArgs)e;
      if (fe.Column != null)
      {
        if (fe.FooterItem != null)
          fe.FooterItem.HandleMouseEnterEvent(fe);
        fe.Column.Footer.HandleMouseEnterEvent(fe);
        Grid.Footer.HandleMouseEnterEvent(fe);
      }
    }

    protected internal override BaseGridCellLeaveEventArgs CreateCellLeaveEventArgs(
      int colIndex, int rowIndex, int areaColIndex, int areaRowIndex, Rectangle cellRect, int enterColIndex, int enterRowIndex)
    {
      DataGridColumn column = Grid.VisibleColumns[areaColIndex];
      DataGridColumnFooterItem columnFooter = null;

      if (areaRowIndex < column.Footer.Items.Count)
        columnFooter = column.Footer.Items[areaRowIndex];

      return new DataGridFooterCellLeaveEventArgs(colIndex, rowIndex, areaColIndex, areaRowIndex, cellRect, enterColIndex, enterRowIndex, 
        column, columnFooter, areaRowIndex);
    }

    protected override void HandleMouseLeaveEvent(BaseGridCellLeaveEventArgs e)
    {
      DataGridFooterCellLeaveEventArgs fe = (DataGridFooterCellLeaveEventArgs)e;
      if (fe.Column != null)
      {
        if (fe.FooterItem != null)
          fe.FooterItem.HandleMouseLeaveEvent(fe);
        fe.Column.Footer.HandleMouseLeaveEvent(fe);
        Grid.Footer.HandleMouseLeaveEvent(fe);
      }
    }

    protected override void HandleMouseHoverEvent(BaseGridCellMouseEventArgs e)
    {
      DataGridFooterCellMouseEventArgs fe = (DataGridFooterCellMouseEventArgs)e;
      if (fe.Column != null)
      {
        if (fe.FooterItem != null)
          fe.FooterItem.HandleMouseHoverEvent(fe);
        if (!e.Handled)
          fe.Column.Footer.HandleMouseHoverEvent(fe);
        if (!e.Handled)
          Grid.Footer.HandleMouseHoverEvent(fe);
      }
    }

  }
}