/*****************************************************************
 * Module: EnumDescConverter.cs
 * Type: C# Source Code
 * Version: 1.0
 * Description: Enum Converter using Description Attributes
 * 
 * Revisions
 * ------------------------------------------------
 * [F] 24/02/2004, Jcl - Shaping up
 * [B] 25/02/2004, Jcl - Made it much easier :-)
 * 
 *****************************************************************/
using System;
using System.ComponentModel;
using System.Drawing;
using System.Drawing.Design;
using System.Reflection;
using System.Collections;
using System.Data;
namespace DescriptiveEnum
{
  /// 
  /// EnumConverter supporting System.ComponentModel.DescriptionAttribute
  /// 
  public class EnumDescConverter : System.ComponentModel.EnumConverter
  {
    protected System.Type myVal;
    /// 
    /// Gets Enum Value's Description Attribute
    /// 
    /// The value you want the description attribute for
    /// The description, if any, else it's .ToString()
    public static string GetEnumDescription(Enum value)
    {
			//Console.WriteLine("{0}", value);
			FieldInfo fi = value.GetType().GetField(value.ToString());
			if (fi == null) return value.ToString();
      DescriptionAttribute[] attributes = 
        (DescriptionAttribute[])fi.GetCustomAttributes(
        typeof(DescriptionAttribute), false);
			//Console.WriteLine("{0},{1},{2}", value.ToString(), attributes.Length, (attributes.Length > 0) ? attributes[0].Description : value.ToString());
      return (attributes.Length>0)?attributes[0].Description:value.ToString();
    }
    
    /// 
    /// Gets the description for certaing named value in an Enumeration
    /// 
    /// The type of the Enumeration
    /// The name of the Enumeration value
    /// The description, if any, else the passed name
    public static string GetEnumDescription(System.Type value, string name)
    {
      FieldInfo fi= value.GetField(name); 
      DescriptionAttribute[] attributes = 
        (DescriptionAttribute[])fi.GetCustomAttributes(
        typeof(DescriptionAttribute), false);
      return (attributes.Length>0)?attributes[0].Description:name;
    }
    
    /// 
    /// Gets the value of an Enum, based on it's Description Attribute or named value
    /// 
    /// The Enum type
    /// The description or name of the element
    /// The value, or the passed in description, if it was not found
    public static object GetEnumValue(System.Type value, string description)
    {
      FieldInfo [] fis = value.GetFields();
      foreach(FieldInfo fi in fis) 
      {
        DescriptionAttribute[] attributes = 
          (DescriptionAttribute[])fi.GetCustomAttributes(
          typeof(DescriptionAttribute), false);
        if(attributes.Length>0) 
        {
          if(attributes[0].Description == description)
          {
            return fi.GetValue(fi.Name);
          }
        }
        if(fi.Name == description)
        {
          return fi.GetValue(fi.Name);
        }
      }
      return description;
    }
    public EnumDescConverter(System.Type type) : base(type.GetType())
    {
      myVal = type;
    }
    public override object ConvertTo(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value, Type destinationType)
    {
      if(value is Enum && destinationType == typeof(string)) 
      {
				return EnumDescConverter.GetEnumDescription((Enum)value);
      }
      if(value is string && destinationType == typeof(string)) 
      {
				return EnumDescConverter.GetEnumDescription(myVal, (string)value);
      }
      return base.ConvertTo (context, culture, value, destinationType);
    }
    public override object ConvertFrom(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value)
    {
      if(value is string) 
      {
				return EnumDescConverter.GetEnumValue(myVal, (string)value);        
      }
      if(value is Enum) 
      {
				return EnumDescConverter.GetEnumDescription((Enum)value);        
      }
      return base.ConvertFrom (context, culture, value);
    }
      public override bool GetPropertiesSupported(ITypeDescriptorContext context)
    {
        return true;
    }
    public override TypeConverter.StandardValuesCollection GetStandardValues(ITypeDescriptorContext context)
    {
        ArrayList values = new ArrayList();
        FieldInfo[] fis = myVal.GetFields();
        foreach (FieldInfo fi in fis)
        {
            DescriptionAttribute[] attributes =(DescriptionAttribute[])fi.GetCustomAttributes(
               typeof(DescriptionAttribute), false);
            //if (attributes.Length > 0) 
						if (fi.Name != "value__")
              values.Add(fi.GetValue(fi.Name));
        }
        return new TypeConverter.StandardValuesCollection(values);                    
    }
		public static string GetEnumKeyDescription(Enum value)
		{
			FieldInfo fi = value.GetType().GetField(value.ToString());
			DescriptionAttribute[] attributes =
				(DescriptionAttribute[])fi.GetCustomAttributes(
				typeof(DescriptionAttribute), false);
			return (attributes.Length > 0) ? attributes[0].Description : value.ToString();
		}
		public static DataTable GetEnumAsDataTable(System.Type EnumType)
		{
			DataTable DTEnum = new DataTable();
			DTEnum.Columns.Add(new DataColumn("EnumID", typeof(Int32)));
			DTEnum.Columns.Add(new DataColumn("Enum", typeof(string)));
			DTEnum.Columns.Add(new DataColumn("Description", typeof(string)));
			foreach (int i in Enum.GetValues(EnumType))
			{
				System.Enum fooItem = (System.Enum)Enum.ToObject(EnumType, i);
				DTEnum.Rows.Add(new object[] { i, fooItem.ToString(), GetEnumKeyDescription(fooItem) });
			}
			return DTEnum;
		}
  }
}