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

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

namespace EhLib.Design
{
  public class DataAxisGridPropertyBarsEditor : CollectionEditor
  {
    private Type[] returnedTypes;
    IServiceProvider srvProvider;

    public DataAxisGridPropertyBarsEditor(Type type) : base(type)
    {
    }

    public virtual Type GetRootPropertyBarType()
    {
      return typeof(PropertyAxisBar);
    }

    public virtual Type GetDataGridColumnDesignTimeVisibleAttribute()
    {
      return typeof(DataAxisGridPropBarDesignTimeVisibleAttribute);
    }

    protected override Type[] CreateNewItemTypes()
    {
      return returnedTypes;
    }

    public override object EditValue(ITypeDescriptorContext context, IServiceProvider provider, object value)
    {
      if (returnedTypes == null)
      {
        returnedTypes = GetReturnedTypes(provider);
      }
      srvProvider = provider;
      return base.EditValue(context, provider, value);
    }

    private Type[] GetReturnedTypes(IServiceProvider provider)
    {
      List<Type> result = new List<Type>();

      ITypeDiscoveryService tds = (ITypeDiscoveryService)
          provider.GetService(typeof(ITypeDiscoveryService));


      Type rootType = GetRootPropertyBarType();
      Type dataGridColumnDesignTimeVisibleAttributeType = GetDataGridColumnDesignTimeVisibleAttribute();

      if (tds != null)
      {
        foreach (Type propBarType in tds.GetTypes(rootType, false))
        {
          var attr = TypeDescriptor.GetAttributes(propBarType)[dataGridColumnDesignTimeVisibleAttributeType] as DataAxisGridPropBarDesignTimeVisibleAttribute;
          if ((attr == null) || 
              (attr != null && !attr.Visible))
          {
            continue;
          }

          if (!result.Contains(propBarType) &&
              (propBarType != rootType))
          {
            result.Add(propBarType);
          }
        }
      }

      return result.ToArray();
    }

    protected override object CreateInstance(Type itemType)
    {
      DataAxisGridStaticPropBarCollection stBars = ((DataAxisGrid)Context.Instance).StaticPropBars;

      IDesignerHost host = (IDesignerHost)srvProvider.GetService(typeof(IDesignerHost));
      PropertyAxisBar band = (PropertyAxisBar)host.CreateComponent(itemType);

      //stBars.Add(band);
      return band;
    }

    protected override object SetItems(object editValue, object[] value)
    {
      DataAxisGridStaticPropBarCollection stBars = (DataAxisGridStaticPropBarCollection)editValue;
      stBars.BeginUpdate();
      try
      {
        return base.SetItems(editValue, value);
      }
      finally
      {
        stBars.EndUpdate();
        ((IDataAxisGridInternal)Context.Instance).ResetViewOrderedPropBars();
      }
    }

    protected override CollectionForm CreateCollectionForm()
    {
      CollectionForm form = base.CreateCollectionForm();
      return form;
    }

  }

  public class DataAxisGridPropertyBarsConverter : TypeConverter
  {

    public DataAxisGridPropertyBarsConverter()
    {
    }

    public override PropertyDescriptorCollection GetProperties(ITypeDescriptorContext context, object value, Attribute[] attributes)
    {
      PropertyDescriptorCollection pds = new NoneSortingPropertyDescriptorCollection(null);

      DataAxisGridStaticPropBarCollection bands = (DataAxisGridStaticPropBarCollection)value;

      foreach (PropertyAxisBar col in bands)
      {
        var pd = new DataAxisGridPropBarCollectionPropertyDescriptor(bands, col);
        pds.Add(pd);
      }
      return pds;
    }

    public override bool GetPropertiesSupported(ITypeDescriptorContext context)
    {
      return true;
    }

    internal class DataAxisGridPropBarCollectionPropertyDescriptor : PropertyDescriptor
    {
      private readonly DataAxisGridStaticPropBarCollection collection;
      private readonly object item;

      public DataAxisGridPropBarCollectionPropertyDescriptor(DataAxisGridStaticPropBarCollection collection, object item) :
        base("#" + item.ToString(), null)
      {
        this.collection = collection;
        this.item = item;
      }

      public override AttributeCollection Attributes
      {
        get
        {
          return new AttributeCollection(null);
        }
      }

      public override bool CanResetValue(object component)
      {
        return true;
      }

      public override Type ComponentType
      {
        get
        {
          return this.collection.GetType();
        }
      }

      public override string DisplayName
      {
        get
        {
          return item.ToString();
        }
      }

      public override string Description
      {
        get
        {
          return item.ToString();
        }
      }

      public override object GetValue(object component)
      {
        return item;
      }

      public override bool IsReadOnly
      {
        get { return false; }
      }

      public override string Name
      {
        get { return "#" + item.ToString(); }
      }

      public override Type PropertyType
      {
        get { return this.item.GetType(); }
      }

      public override void ResetValue(object component)
      {
      }

      public override bool ShouldSerializeValue(object component)
      {
        return true;
      }

      public override void SetValue(object component, object value)
      {
        // this.collection[index] = value;
      }
    }
  }

  internal class NoneSortingPropertyDescriptorCollection : PropertyDescriptorCollection
  {
    public NoneSortingPropertyDescriptorCollection(PropertyDescriptor[] propertyDescriptors)
        : base(propertyDescriptors)
    {
    }

    public override PropertyDescriptorCollection Sort()
    {
      return this;
    }
    public override PropertyDescriptorCollection Sort(string[] names)
    {
      return this;
    }

    public override PropertyDescriptorCollection Sort(string[] names, System.Collections.IComparer comparer)
    {
      return this;
    }
    public override PropertyDescriptorCollection Sort(System.Collections.IComparer comparer)
    {
      return this;
    }
  }

  public class DataAxisGridPropBarDataPropertyNameConverter : TypeConverter
  {

    public override bool GetStandardValuesSupported(ITypeDescriptorContext context)
    {
      return true;
    }

    public override bool GetStandardValuesExclusive(ITypeDescriptorContext context)
    {
      return false;
    }

    public override TypeConverter.StandardValuesCollection GetStandardValues(ITypeDescriptorContext context)
    {
      PropertyAxisBar band = (context.Instance as PropertyAxisBar);
      Debug.Assert(band != null, @"column != null");
      CurrencyManager curMan = band.Grid.CurrencyManager;
      string propName;
      if (curMan == null)
        return null;

      List<string> sList = new List<string>();

      foreach (PropertyDescriptor prop in curMan.GetItemProperties())
      {
        propName = prop.Name;
        sList.Add(propName);
      }
      //      MessageBox.Show(context.Instance.GetType().ToString());
      TypeConverter.StandardValuesCollection svc = new TypeConverter.StandardValuesCollection(sList);
      return svc;
    }

    public override bool CanConvertFrom(ITypeDescriptorContext context,
       Type sourceType)
    {
      if (sourceType == typeof(string))
        return true;
      else
        return base.CanConvertFrom(context, sourceType);
    }

    public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
    {
      var s = value as string;
      if (s != null)
        return s;
      else
        return base.ConvertFrom(context, culture, value);
    }

  }

  public class ExpandableCollectionTypeConverter : TypeConverter
  {

    public ExpandableCollectionTypeConverter()
    {
    }

    public override PropertyDescriptorCollection GetProperties(ITypeDescriptorContext context, object value, Attribute[] attributes)
    {
      PropertyDescriptorCollection pds = new NoneSortingPropertyDescriptorCollection(null);

      ICollection collection = value as ICollection;

      foreach (object item in collection)
      {
        var pd = new ExpandableCollectionItemPropertyDescriptor(collection, item);
        pds.Add(pd);
      }
      return pds;
    }

    public override bool GetPropertiesSupported(ITypeDescriptorContext context)
    {
      return true;
    }

    internal class ExpandableCollectionItemPropertyDescriptor : PropertyDescriptor
    {
      private readonly ICollection collection;
      private readonly object item;

      public ExpandableCollectionItemPropertyDescriptor(ICollection collection, object item) :
        base("#" + item.ToString(), null)
      {
        this.collection = collection;
        this.item = item;
      }

      public override AttributeCollection Attributes
      {
        get
        {
          return new AttributeCollection(null);
        }
      }

      public override bool CanResetValue(object component)
      {
        return true;
      }

      public override Type ComponentType
      {
        get
        {
          return this.collection.GetType();
        }
      }

      public override string DisplayName
      {
        get
        {
          return item.ToString();
        }
      }

      public override string Description
      {
        get
        {
          return item.ToString();
        }
      }

      public override object GetValue(object component)
      {
        return item;
      }

      public override bool IsReadOnly
      {
        get { return true; }
      }

      public override string Name
      {
        get { return "#" + item.ToString(); }
      }

      public override Type PropertyType
      {
        get { return this.item.GetType(); }
      }

      public override void ResetValue(object component)
      {
      }

      public override bool ShouldSerializeValue(object component)
      {
        return true;
      }

      public override void SetValue(object component, object value)
      {
        // this.collection[index] = value;
      }
    }
  }
}
