// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject to
// the following conditions:
// 
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
// 
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
// Copyright (c) 2007 Novell, Inc.
//

// Modified by: Alexander Tzyganenko

using System;
using System.ComponentModel;
using System.Collections;

namespace System.Windows.Forms
{
  public class BindingSource : Component
  {
    IList list;
    object datasource;

    public object DataSource
    {
      get { return datasource; }
      set
      {
        if (datasource != value)
        {
          datasource = value;
          ResetList();
        }
      }
    }

    IList GetListFromEnumerable(IEnumerable enumerable)
    {
      IList l;

      IEnumerator e = enumerable.GetEnumerator();

      if (enumerable is string)
      {
        /* special case this.. seems to be the only one .net special cases? */
        l = new BindingList<char>();
      }
      else
      {
        /* try to figure out the type based on
         * the first element, if there is
         * one */
        object first = null;
        if (e.MoveNext())
        {
          first = e.Current;
        }

        if (first == null)
        {
          return null;
        }
        else
        {
          Type t = typeof(BindingList<>).MakeGenericType(new Type[] { first.GetType() });
          l = (IList)Activator.CreateInstance(t);
        }
      }

      e.Reset();
      while (e.MoveNext())
      {
        l.Add(e.Current);
      }

      return l;
    }

    void ResetList()
    {
      IList l;
      object source = ListBindingHelper.GetList(datasource, null);

      // 
      // If original source is null, then create a new object list
      // Otherwise, try to infer the list item type
      //

      if (datasource == null)
      {
        l = new BindingList<object>();
      }
      else if (source == null)
      {
        //Infer type based on datasource and datamember,
        // where datasource is an empty IEnumerable
        // and need to find out the datamember type

        Type property_type = ListBindingHelper.GetListItemProperties(datasource)[""].PropertyType;
        Type t = typeof(BindingList<>).MakeGenericType(new Type[] { property_type });
        l = (IList)Activator.CreateInstance(t);
      }
      else if (source is IList)
      {
        l = (IList)source;
      }
      else if (source is IEnumerable)
      {
        IList new_list = GetListFromEnumerable((IEnumerable)source);
        l = new_list == null ? list : new_list;
      }
      else if (source is Type)
      {
        Type t = typeof(BindingList<>).MakeGenericType(new Type[] { (Type)source });
        l = (IList)Activator.CreateInstance(t);
      }
      else
      {
        Type t = typeof(BindingList<>).MakeGenericType(new Type[] { source.GetType() });
        l = (IList)Activator.CreateInstance(t);
        l.Add(source);
      }

      list = l;
    }

    public virtual PropertyDescriptorCollection GetItemProperties(PropertyDescriptor[] listAccessors)
    {
      return ListBindingHelper.GetListItemProperties(list, listAccessors);
    }
  }
}
