// Created with MonoDevelop
//
//    Copyright (C) 2016 Hiperscan GmbH Dresden, Germany
//
//    This program is free software: you can redistribute it and/or modify
//    it under the terms of the GNU General Public License as published by
//    the Free Software Foundation, either version 3 of the License, or
//    (at your option) any later version.
//
//    This program is distributed in the hope that it will be useful,
//    but WITHOUT ANY WARRANTY; without even the implied warranty of
//    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//    GNU General Public License for more details.
//
//    You should have received a copy of the GNU General Public License
//    along with this program.  If not, see <http://www.gnu.org/licenses/>.



using System;
using System.Collections;
using System.Reflection;


namespace Hiperscan.Common
{
	
	public class StringEnum
	{
		private Type enum_type;
		private static Hashtable string_value = new Hashtable();

		public StringEnum(Type enum_type)
		{
			if (!enum_type.IsEnum)
				throw new ArgumentException(string.Format("Type must be an Enum. Type was {0}", enum_type.ToString()));

			this.enum_type = enum_type;
		}

		public string GetStringValue(string value_name)
		{
			Enum enum_type;
			string string_value = null;
			try
			{
				enum_type = (Enum)Enum.Parse(this.enum_type, value_name);
				string_value = GetStringValue(enum_type);
			}
			catch {}

			return string_value;
		}

		public Array GetStringValues()
		{
			ArrayList values = new ArrayList();

			foreach (FieldInfo fi in this.enum_type.GetFields())
			{
				StringValueAttribute[] attrs = fi.GetCustomAttributes(typeof (StringValueAttribute), false) as StringValueAttribute[];
				if (attrs.Length > 0)
					values.Add(attrs[0].Value);
			}

			return values.ToArray();
		}

		public IList GetListValues()
		{
			Type underlyingType = Enum.GetUnderlyingType(this.enum_type);
			ArrayList values = new ArrayList();

			foreach (FieldInfo fi in this.enum_type.GetFields())
			{
				StringValueAttribute[] attrs = fi.GetCustomAttributes(typeof (StringValueAttribute), false) as StringValueAttribute[];
				if (attrs.Length > 0)
					values.Add(new DictionaryEntry(Convert.ChangeType(Enum.Parse(this.enum_type, fi.Name), underlyingType), attrs[0].Value));
				
			}

			return values;
		}

		public bool IsStringDefined(string string_value)
		{
			return Parse(this.enum_type, string_value) != null;
		}

		public bool IsStringDefined(string string_value, bool ignore_case)
		{
			return Parse(this.enum_type, string_value, ignore_case) != null;
		}

		public Type EnumType
		{
			get { return this.enum_type; }
		}

		public static string GetStringValue(Enum value)
		{
			string output = null;
			Type type = value.GetType();

			if (StringEnum.string_value.ContainsKey(value))
				output = (StringEnum.string_value[value] as StringValueAttribute).Value;
			else 
			{
				FieldInfo fi = type.GetField(value.ToString());
				StringValueAttribute[] attrs = fi.GetCustomAttributes(typeof (StringValueAttribute), false) as StringValueAttribute[];
				if (attrs.Length > 0)
				{
					StringEnum.string_value.Add(value, attrs[0]);
					output = attrs[0].Value;
				}

			}
			return output;

		}
 
		public static object Parse(Type type, string string_value)
		{
			return Parse(type, string_value, false);
		}

		public static object Parse(Type type, string string_value, bool ignore_case)
		{
			object output = null;
			string enum_string_value = null;

			if (!type.IsEnum)
				throw new ArgumentException(string.Format("Supplied type must be an Enum. Type was {0}", type.ToString()));
			
			foreach (FieldInfo fi in type.GetFields())
			{
				StringValueAttribute[] attrs = fi.GetCustomAttributes(typeof (StringValueAttribute), false) as StringValueAttribute[];
				if (attrs.Length > 0)
					enum_string_value = attrs[0].Value;
				
				if (string.Compare(enum_string_value, string_value, ignore_case) == 0)
				{
					output = Enum.Parse(type, fi.Name);
					break;
				}
			}

			return output;
		}

		public static bool IsStringDefined(Type enum_type, string string_value)
		{
			return Parse(enum_type, string_value) != null;
		}

		public static bool IsStringDefined(Type enum_type, string string_value, bool ignore_case)
		{
			return Parse(enum_type, string_value, ignore_case) != null;
		}
	}

	public class StringValueAttribute : System.Attribute
	{
		private string value;

		public StringValueAttribute(string value)
		{
			this.value = value;
		}
		  
		public string Value
		{
			get { return this.value; }
		}
	}
}

