//------------------------------------------------------------------------------
// <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.Globalization;
using System.Windows.Forms;

namespace EhLib
{
  [ListBindable(false)]
  //[TypeConverter(typeof(DataAxisGridPropertyBarsConverter))]
  //[TypeConverter("EhLib.Design.DataAxisGridPropertyBarsConverter, EhLib.WinForms.Design, Version=1.0.0.0, Culture=neutral, PublicKeyToken=d379614f4f89b099")]

  [TypeConverter("EhLib.Design.DataAxisGridPropertyBarsConverter")]
  public class DataAxisGridStaticPropBarCollection : object, IList<PropertyAxisBar>, IList, IEnumerable<PropertyAxisBar>, IEnumerable
  {

    #region privates
    private CollectionChangeEventHandler onCollectionChanged;
    private readonly List<PropertyAxisBar> items = new List<PropertyAxisBar>();
    private readonly DataAxisGrid grid;
    //private int updateCount;
    #endregion privates

    public DataAxisGridStaticPropBarCollection(DataAxisGrid grid)
    {
      this.grid = grid;
    }

    #region Properties

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

    //protected virtual ArrayList List
    //{
    //  get { return this.items; }
    //}

    protected DataAxisGrid Grid
    {
      get { return this.grid; }
    }

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

    [Browsable(false)]
    public PropertyAxisBar this[string propBarName]
    {
      get
      {
        int itemCount = this.items.Count;
        for (int i = 0; i < itemCount; ++i)
        {
          PropertyAxisBar propBar = this.items[i];

          if (string.Equals(propBar.Name, propBarName, StringComparison.OrdinalIgnoreCase))
          {
            return propBar;
          }
        }
        return null;
      }
    }

    [Browsable(false)]
    public bool Updating
    {
      get { return Grid.PropBars.Updating; }
    }

    public bool IsReadOnly
    {
      get { return false; }
    }

    public bool IsFixedSize
    {
      get { return false; }
    }

    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(); }
    }
    #endregion Properties

    #region Methods Explicit interfaces
    //PropertyAxisBar IList<PropertyAxisBar>.this[int index]
    //{
    //  get { return this[index]; }
    //  set { throw new NotSupportedException(); }
    //}

    int IList<PropertyAxisBar>.IndexOf(PropertyAxisBar value)
    {
      return this.items.IndexOf(value);
    }

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

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

    bool ICollection<PropertyAxisBar>.IsReadOnly
    {
      get { return false; }
    }

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

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

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

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

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

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

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

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

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

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

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

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

    void IList.Remove(object value)
    {
      this.Remove((PropertyAxisBar)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);
    }
    #endregion Methods Explicit interfaces

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

    #region Methods
    public virtual int Add(PropertyAxisBar propBar)
    {
      int index = AddInternal(propBar);
      Grid.UpdatePropBarsList();
      return index;
    }

    internal int AddInternal(PropertyAxisBar propBar)
    {
      Debug.Assert(this.Grid != null);

      this.items.Add(propBar);
      int index = this.items.Count;
      propBar.Grid = Grid;
      Grid.OnPropBarAdded(propBar);
      return index;
    }

    //public virtual void AddRange(params PropertyAxisBar[] propBars)
    //{
    //  BeginUpdate();
    //  try
    //  {
    //    foreach (PropertyAxisBar propBar in propBars)
    //    {
    //      Add(propBar);
    //    }
    //  }
    //  finally
    //  {
    //    EndUpdate();
    //  }
    //}

    public void AddRange(PropertyAxisBar[] bars)
    {
      foreach (PropertyAxisBar propAxisBar in bars)
      {
        AddInternal(propAxisBar);
      }

      if (bars.Length > 0)
        Grid.UpdatePropBarsList();
    }

    public virtual void Insert(int propBarIndex, PropertyAxisBar propBar)
    {
      this.items.Insert(propBarIndex, propBar);
      this.grid.OnPropBarAdded(propBar);
      if (!Updating)
        Grid.PropBarsUpdateCommitted();
    }

    public virtual void Move(PropertyAxisBar propBar, int newIndex)
    {
      Debug.Assert(propBar.Grid == Grid, "propBar.Grid == Grid Failed");
      int colIndex = IndexOf(propBar);
      Debug.Assert(colIndex >= 0, "IndexOf(propBar) Failed");
      if (colIndex < newIndex)
        newIndex = newIndex - 1;
      this.items.RemoveAt(colIndex);
      this.items.Insert(newIndex, propBar);
      if (!Updating)
        Grid.PropBarsUpdateCommitted();
    }

    public virtual void Clear()
    {
      if (Count > 0)
      {
        this.items.Clear();
        Grid.UpdatePropBarsList();
      }
      //if (!Updating)
      //  Grid.PropBarsUpdateCommitted();
    }

    public void SetBarsOrder(ICollection<PropertyAxisBar> orderedColumns)
    {
      bool orderChagned = false;

      if (orderedColumns.Count != Count)
        throw new InvalidOperationException("List of bars must be complete and not redundant.");

      IEnumerator<PropertyAxisBar> enmrt = orderedColumns.GetEnumerator();
      for (int i = 0; enmrt.MoveNext(); i++)
      {
        PropertyAxisBar ordCol = enmrt.Current;
        if (!Contains(ordCol))
          throw new InvalidOperationException(String.Format("PropBar {0} not in the list", ordCol));
        if (ordCol != this[i])
          orderChagned = true;
      }

      if (orderChagned == false) return;

      items.Clear();

      foreach (PropertyAxisBar col in orderedColumns)
      {
        items.Add(col);
      }

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

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

    public virtual bool Contains(string propBarName)
    {
      int Index = IndexOf(propBarName);
      if (Index >= 0)
        return true;
      else
        return false;
    }

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

    public int IndexOf(PropertyAxisBar propBar)
    {
      return this.items.IndexOf(propBar);
    }

    public int IndexOf(string propBarName)
    {
      for (int i = 0; i < this.items.Count; i++)
      {
        PropertyAxisBar propBar = this.items[i];
        // NOTE: case-insensitive
        if (0 == string.Compare(propBar.Name, propBarName, true, CultureInfo.InvariantCulture))
        {
          return i;
        }
      }
      return -1;
    }

    public PropertyAxisBar FindBarByDataProperty(string dataPropertyName)
    {
      foreach (PropertyAxisBar propBar in this.items)
      {
        // NOTE: case-insensitive
        if (string.Compare(propBar.DataPropertyName, dataPropertyName, true, CultureInfo.InvariantCulture) == 0)
        {
          return propBar;
        }
      }
      return null;
    }

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

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

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

      Debug.Fail("propBar is not found in collection");
    }

    public virtual void Remove(string propBarName)
    {
      for (int i = 0; i < this.items.Count; ++i)
      {
        PropertyAxisBar propBar = this.items[i];
        if (string.Compare(propBar.Name, propBarName, true, CultureInfo.InvariantCulture) == 0)
        {
          RemoveAt(i);
          return;
        }
      }

      throw new ArgumentException(@"propBarNotFound - " + propBarName, "propBarName");
    }

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

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

      Grid.UpdatePropBarsList();
      //if (!Updating)
      //  Grid.propBarsUpdateCommited();
    }

    internal void RemoveAtInternal(int index, bool force)
    {
      PropertyAxisBar propBar = this.items[index];
      this.items.RemoveAt(index);
      propBar.Grid = null;
      //OnCollectionChanged(new CollectionChangeEventArgs(CollectionChangeAction.Remove, propBar));
      Grid.OnPropBarRemoved(propBar);
    }

    public virtual void BeginUpdate()
    {
      Grid.PropBars.BeginUpdate();
    }

    public virtual void EndUpdate()
    {
      Grid.PropBars.EndUpdate();
    }

    //public virtual void BeginUpdate()
    //{
    //  updateCount = updateCount + 1;
    //}

    //public virtual void EndUpdate()
    //{
    //  Debug.Assert(updateCount > 0);
    //  updateCount = updateCount - 1;
    //  if (updateCount == 0)
    //    Grid.PropBarsUpdateCommitted();
    //}

    public bool AllBarsAutoGenerated()
    {
      foreach (PropertyAxisBar propBar in this.items)
      {
        if (!propBar.AutoGenerated)
          return false;
      }
      return true;
    }

    public void RemoveAutoGeneratedBars()
    {
      for (int i = this.items.Count - 1; i >= 0; i--)
      {
        PropertyAxisBar propBar = this.items[i];
        if (propBar.AutoGenerated)
          RemoveAt(i);
      }
    }

    #endregion Methods

  }

  public class DataAxisGridReadOnlyPropBarCollection : ReadOnlyCollection<PropertyAxisBar>
  {

    #region privates
    private readonly DataAxisGrid grid;
    #endregion privates

    public DataAxisGridReadOnlyPropBarCollection(DataAxisGrid grid, IList<PropertyAxisBar> list) : base(list)
    {
      this.grid = grid;
    }

    #region Properties
    protected DataAxisGrid Grid
    {
      get { return this.grid; }
    }

    [Browsable(false)]
    public PropertyAxisBar this[string propBarName]
    {
      get
      {
        int Index = IndexOf(propBarName);
        if (Index >= 0)
          return this[Index];
        else
          return null;
      }
    }
    #endregion


    #region Methods
    public int IndexOf(string propBarName)
    {
      for (int i = 0; i < this.Count; i++)
      {
        PropertyAxisBar propBar = this[i];
        // NOTE: case-insensitive
        if (0 == string.Compare(propBar.Name, propBarName, true, CultureInfo.InvariantCulture))
        {
          return i;
        }
      }
      return -1;
    }

    public bool Contains(string propBarName)
    {
      return (IndexOf(propBarName) >= 0);
    }

    public PropertyAxisBar FindBarByPropertyName(string dataPropertyName)
    {
      foreach (PropertyAxisBar propBar in this)
      {
        if (propBar.DataPropertyName == dataPropertyName)
          return propBar;
      }
      return null;
    }

    public PropertyAxisBar FindBarByName(string barName)
    {
      foreach (PropertyAxisBar propBar in this)
      {
        if (propBar.Name == barName)
          return propBar;
      }
      return null;
    }

    public void SetDisplayIndexForBarsRange(Collection<PropertyAxisBar> propBars, int newDisplayIndex)
    {

    }

    #endregion Methods

  }

  
  public class DataAxisGridViewOrderedPropBarsCollection : DataAxisGridReadOnlyPropBarCollection
  {
    public DataAxisGridViewOrderedPropBarsCollection(DataAxisGrid grid, IList<PropertyAxisBar> list) : base(grid, list)
    {
    }

    public void Reset()
    {
      Grid.ResetViewOrderedPropBars();
    }
  }

  public class DataAxisGridMainPropBarCollection : DataAxisGridReadOnlyPropBarCollection
  {
    #region privates
    private int updateCount;
    internal bool listGonnaChange;
    #endregion

    public DataAxisGridMainPropBarCollection(DataAxisGrid grid, IList<PropertyAxisBar> list) : base(grid, list)
    {
    }

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

    #region Methods
    public virtual void BeginUpdate()
    {
      updateCount = updateCount + 1;
      //if (updateCount == 1)
      //{
      //  beginUpdateList = new PropertyAxisBar[Count];
      //  CopyTo(beginUpdateList, 0);
      //}
    }

    public virtual void EndUpdate()
    {
      Debug.Assert(updateCount > 0);
      updateCount = updateCount - 1;
      if (updateCount == 0)
      {
        if (listGonnaChange)
        {
          listGonnaChange = false;
          Grid.UpdatePropBarsList();
        }
        else
          Grid.PropBarsUpdateCommitted();
      }
    }

    //private bool CheckListChanged()
    //{
    //  if (Count != beginUpdateList.Length)
    //  {
    //    return true;
    //  }
    //  else
    //  {
    //    for (int i = 0; i < beginUpdateList.Length; i++)
    //    {
    //      if (this[i] != beginUpdateList[i])
    //      {
    //        return true;
    //      }
    //    }
    //  }
    //  return false;
    //}
    #endregion
  }
}
