using System;
using System.Reflection;
namespace Csla
{
  /// 
  /// Contains utility methods used by the
  /// CSLA .NET framework.
  /// 
  public static class Utilities
  {
    #region Replacements for VB runtime functionality
    /// 
    /// Determines whether the specified
    /// value can be converted to a valid number.
    /// 
    public static bool IsNumeric(object value)
    {
      double dbl;
      return double.TryParse(value.ToString(), System.Globalization.NumberStyles.Any,
        System.Globalization.NumberFormatInfo.InvariantInfo, out dbl);
    }
    /// 
    /// Allows late bound invocation of
    /// properties and methods.
    /// 
    /// Object implementing the property or method.
    /// Name of the property or method.
    /// Specifies how to invoke the property or method.
    /// List of arguments to pass to the method.
    /// The result of the property or method invocation.
    public static object CallByName(
      object target, string methodName, CallType callType, 
      params object[] args)
    {
      switch (callType)
      {
        case CallType.Get:
          {
            PropertyInfo p = target.GetType().GetProperty(methodName);
            return p.GetValue(target, args);
          }
        case CallType.Let:
        case CallType.Set:
          {
            PropertyInfo p = target.GetType().GetProperty(methodName);
            object[] index = null;
            args.CopyTo(index, 1);
            p.SetValue(target, args[0], index);
            return null;
          }
        case CallType.Method:
          {
            MethodInfo m = target.GetType().GetMethod(methodName);
            return m.Invoke(target, args);
          }
      }
      return null;
    }
    #endregion
    /// 
    /// Returns a property's type, dealing with
    /// Nullable(Of T) if necessary.
    /// 
    /// Type of the
    /// property as returned by reflection.
    public static Type GetPropertyType(Type propertyType)
    {
      Type type = propertyType;
      if (type.IsGenericType &&
        (type.GetGenericTypeDefinition() == typeof(Nullable<>)))
        return Nullable.GetUnderlyingType(type);
      return type;
    }
    /// 
    /// Returns the type of child object
    /// contained in a collection or list.
    /// 
    /// Type of the list.
    public static Type GetChildItemType(Type listType)
    {
      Type result = null;
      if (listType.IsArray)
        result = listType.GetElementType();
      else
      {
        DefaultMemberAttribute indexer =
          (DefaultMemberAttribute)Attribute.GetCustomAttribute(
          listType, typeof(DefaultMemberAttribute));
        if (indexer != null)
          foreach (PropertyInfo prop in listType.GetProperties(
            BindingFlags.Public | 
            BindingFlags.Instance | 
            BindingFlags.FlattenHierarchy))
          {
            if (prop.Name == indexer.MemberName)
              result = Utilities.GetPropertyType(prop.PropertyType);
          }
      }
      return result;
    }
  }
  /// 
  /// Valid options for calling a property or method
  /// via the  method.
  /// 
  public enum CallType
  {
    /// 
    /// Gets a value from a property.
    /// 
    Get,
    /// 
    /// Sets a value into a property.
    /// 
    Let,
    /// 
    /// Invokes a method.
    /// 
    Method,
    /// 
    /// Sets a value into a property.
    /// 
    Set
  }
}