context: using System;
  using System.Globalization;
  using System.Text;
  using System.Collections;
  using System.Collections.Specialized;
  using System.Threading;
  using System.Reflection;
  using System.Security.Cryptography;
  using System.Collections.Generic;
  using Asterisk.NET.Manager.Event;
  using Asterisk.NET.Manager.Response;
  using Asterisk.NET.Manager;
  
  namespace Asterisk.NET
  {
  	internal class Helper
  	{
  		private static CultureInfo defaultCulture;
  #if LOGGER
  		private static Logger logger = Logger.Instance();
  #endif
  
  		#region CultureInfo 
  		internal static CultureInfo CultureInfo
  		{
  			get
  			{
  				if (defaultCulture == null)
  					defaultCulture = System.Globalization.CultureInfo.GetCultureInfo("en");
  				return defaultCulture;
  			}
  		}
  		#endregion
  
  		#region ToHexString(sbyte[]) 
  		/// <summary> The hex digits used to build a hex string representation of a byte array.</summary>
  		internal static readonly char[] hexChar = new char[] { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
  
  		/// <summary>
  		/// Converts a byte array to a hex string representing it. The hex digits are lower case.
  		/// </summary>
  		/// <param name="b">the byte array to convert</param>
  		/// <returns> the hex representation of b</returns>
  		internal static string ToHexString(sbyte[] b)
  		{
  			StringBuilder sb = new StringBuilder(b.Length * 2);
  			for (int i = 0; i < b.Length; i++)
  			{
  				sb.Append(hexChar[Helper.URShift((b[i] & 0xf0), 4)]);
  				sb.Append(hexChar[b[i] & 0x0f]);
  			}
  			return sb.ToString();
  		}
  		#endregion
  
  		#region GetInternalActionId(actionId) 
  		internal static string GetInternalActionId(string actionId)
  		{
  			if (string.IsNullOrEmpty(actionId))
  				return string.Empty;
  			int delimiterIndex = actionId.IndexOf(Common.INTERNAL_ACTION_ID_DELIMITER);
  			if (delimiterIndex > 0)
  				return actionId.Substring(0, delimiterIndex).Trim();
  			return string.Empty;
  		}
  		#endregion
  
  		#region StripInternalActionId(actionId) 
  		internal static string StripInternalActionId(string actionId)
  		{
  			if (string.IsNullOrEmpty(actionId))
  				return string.Empty;
  			int delimiterIndex = actionId.IndexOf(Common.INTERNAL_ACTION_ID_DELIMITER);
  			if (delimiterIndex > 0)
  			{
  				if (actionId.Length > delimiterIndex + 1)
  					return actionId.Substring(delimiterIndex + 1).Trim();
  			}
  			return string.Empty;
  		}
  		#endregion
  
  		#region IsTrue(string) 
  		/// <summary>
  		/// Checks if a String represents <code>true</code> or <code>false</code> according to Asterisk's logic.<br/>
  		/// The original implementation is <code>util.c</code> is as follows:
  		/// </summary>
  		/// <param name="s">the String to check for <code>true</code>.</param>
  		/// <returns>
  		/// <code>true</code> if s represents <code>true</code>,
  		/// <code>false</code> otherwise.
  		/// </returns>
  		internal static bool IsTrue(string s)
  		{
  			if (s == null || s.Length == 0)
  				return false;
  			string sx = s.ToLower(Helper.CultureInfo);
  			if (sx == "yes" || sx == "true" || sx == "y" || sx == "t" || sx == "1" || sx == "on")
  				return true;
  			return false;
  		}
  		#endregion
  
  		#region URShift(...) 
  		/// <summary>
  		/// Performs an unsigned bitwise right shift with the specified number
  		/// </summary>
  		/// <param name="number">Number to operate on</param>
  		/// <param name="bits">Ammount of bits to shift</param>
  		/// <returns>The resulting number from the shift operation</returns>
  		internal static int URShift(int number, int bits)
  		{
  			if (number >= 0)
  				return number >> bits;
  			else
  				return (number >> bits) + (2 << ~bits);
  		}
  
  		/// <summary>
  		/// Performs an unsigned bitwise right shift with the specified number
  		/// </summary>
  		/// <param name="number">Number to operate on</param>
  		/// <param name="bits">Ammount of bits to shift</param>
  		/// <returns>The resulting number from the shift operation</returns>
  		internal static int URShift(int number, long bits)
  		{
  			return URShift(number, (int)bits);
  		}
  
  		/// <summary>
  		/// Performs an unsigned bitwise right shift with the specified number
  		/// </summary>
  		/// <param name="number">Number to operate on</param>
  		/// <param name="bits">Ammount of bits to shift</param>
  		/// <returns>The resulting number from the shift operation</returns>
  		internal static long URShift(long number, int bits)
  		{
  			if (number >= 0)
  				return number >> bits;
  			else
  				return (number >> bits) + (2L << ~bits);
  		}
  
  		/// <summary>
  		/// Performs an unsigned bitwise right shift with the specified number
  		/// </summary>
  		/// <param name="number">Number to operate on</param>
  		/// <param name="bits">Ammount of bits to shift</param>
  		/// <returns>The resulting number from the shift operation</returns>
  		internal static long URShift(long number, long bits)
  		{
  			return URShift(number, (int)bits);
  		}
  		#endregion
  
  		#region ToArray(ICollection c, object[] objects) 
  		/// <summary>
  		/// Obtains an array containing all the elements of the collection.
  		/// </summary>
  		/// <param name="objects">The array into which the elements of the collection will be stored.</param>
  		/// <returns>The array containing all the elements of the collection.</returns>
  		internal static object[] ToArray(ICollection c, object[] objects)
  		{
  			int index = 0;
  
  			Type type = objects.GetType().GetElementType();
  			object[] objs = (object[])Array.CreateInstance(type, c.Count);
  
  			IEnumerator e = c.GetEnumerator();
  
  			while (e.MoveNext())
  				objs[index++] = e.Current;
  
  			//If objects is smaller than c then do not return the new array in the parameter
  			if (objects.Length >= c.Count)
  				objs.CopyTo(objects, 0);
  
  			return objs;
  		}
  		#endregion
  
  		#region ParseVariables(Dictionary<string, string> dictionary, string variables, char[] delim)
  		/// <summary>
  		/// Parse variable(s) string to dictionary.
  		/// </summary>
  		/// <param name="dictionary"></param>
  		/// <param name="variables">variable(a) string</param>
  		/// <param name="delim">variable pairs delimiter</param>
  		/// <returns></returns>
  		internal static Dictionary<string, string> ParseVariables(Dictionary<string, string> dictionary, string variables, char[] delim)
  		{
  			if (dictionary == null)
  				dictionary = new Dictionary<string, string>();
  			else
  				dictionary.Clear();
  
  			if (string.IsNullOrEmpty(variables))
  				return dictionary;
  			string[] vars = variables.Split(delim);
  			int idx;
  			string vname, vval;
  			foreach (string var in vars)
  			{
  				idx = var.IndexOf('=');
  				if (idx > 0)
  				{
  					vname = var.Substring(0, idx);
  					vval = var.Substring(idx + 1);
  				}
  				else
  				{
  					vname = var;
  					vval = string.Empty;
  				}
  				dictionary.Add(vname, vval);
  			}
  			return dictionary;
  		}
  		#endregion
  
  		#region JoinVariables(IDictionary dictionary, string delim) 
  		/// <summary>
  		/// Join variables dictionary to string.
  		/// </summary>
  		/// <param name="dictionary"></param>
  		/// <param name="delim"></param>
  		/// <returns></returns>
  		internal static string JoinVariables(IDictionary dictionary, char[] delim, string delimKeyValue)
  		{
  			return JoinVariables(dictionary, new string(delim), delimKeyValue);
  		}
  		internal static string JoinVariables(IDictionary dictionary, string delim, string delimKeyValue)
  		{
  			if (dictionary == null)
  				return string.Empty;
  			StringBuilder sb = new StringBuilder();
  			foreach (DictionaryEntry var in dictionary)
  			{
  				if (sb.Length > 0)
  					sb.Append(delim);
  				sb.Append(string.Concat(var.Key, delimKeyValue, var.Value));
  			}
  			return sb.ToString();
  		}
  		#endregion
  
  		#region GetMillisecondsFrom(DateTime start) 
  		internal static long GetMillisecondsFrom(DateTime start)
  		{
  			TimeSpan ts = (TimeSpan)(DateTime.Now - start);
  			return (long)ts.TotalMilliseconds;
  		}
  		#endregion
  
  		#region ParseString(string val) 
  		internal static object ParseString(string val)
  		{
  			if (val == "none")
  				return string.Empty;
  			return val;
  		}
  		#endregion
  
  		#region GetGetters(class) 
  		/// <summary>
  		/// Returns a Map of getter methods of the given class.<br/>
  		/// The key of the map contains the name of the attribute that can be accessed by the getter, the
  		/// value the getter itself . A method is considered a getter if its name starts with "get",
  		/// it is declared internal and takes no arguments.
  		/// </summary>
  		/// <param name="clazz">the class to return the getters for</param>
  		/// <returns> a Map of attributes and their accessor methods (getters)</returns>
  		internal static Dictionary<string, MethodInfo> GetGetters(Type clazz)
  		{
  			string name;
  			string methodName;
  			MethodInfo method;
  
  			Dictionary<string, MethodInfo> accessors = new Dictionary<string, MethodInfo>();
  			MethodInfo[] methods = clazz.GetMethods();
  
  			for (int i = 0; i < methods.Length; i++)
  			{
  				method = methods[i];
  				methodName = method.Name;
  
  				// skip not "get..." methods and  skip methods with != 0 parameters
  				if (!methodName.StartsWith("get_") || method.GetParameters().Length != 0)
  					continue;
  
  				name = methodName.Substring(4);
  				if (name.Length == 0)
  					continue;
  				accessors[name] = method;
  			}
  			return accessors;
  		}
  		#endregion
  
  		#region GetSetters(Type clazz) 
  		/// <summary>
  		/// Returns a Map of setter methods of the given class.<br/>
  		/// The key of the map contains the name of the attribute that can be accessed by the setter, the
  		/// value the setter itself. A method is considered a setter if its name starts with "set",
  		/// it is declared internal and takes no arguments.
  		/// </summary>
  		/// <param name="clazz">the class to return the setters for</param>
  		/// <returns> a Map of attributes and their accessor methods (setters)</returns>
  		internal static IDictionary GetSetters(Type clazz)
  		{
  			IDictionary accessors = new Hashtable();
  			MethodInfo[] methods = clazz.GetMethods();
  			string name;
  			string methodName;
  			MethodInfo method;
  
  			for (int i = 0; i < methods.Length; i++)
  			{
  				method = methods[i];
  				methodName = method.Name;
  				// skip not "set..." methods and  skip methods with != 1 parameters
  				if (!methodName.StartsWith("set_") || method.GetParameters().Length != 1)
  					continue;
  				name = methodName.Substring("set_".Length).ToLower(Helper.CultureInfo);
  				if (name.Length == 0) continue;
  				accessors[name] = method;
  			}
  			return accessors;
  		}
  		#endregion
  
  		#region ToString(object obj) 
  		/// <summary>
  		/// Convert object with all properties to string
  		/// </summary>
  		/// <param name="obj"></param>
  		/// <returns></returns>
  		internal static string ToString(object obj)
  		{
  			object value;
  			StringBuilder sb = new StringBuilder(obj.GetType().Name, 1024);
  			sb.Append(" {");
  			string strValue;
  			IDictionary getters = Helper.GetGetters(obj.GetType());
  			bool notFirst = false;
  			List<MethodInfo> arrays = new List<MethodInfo>();
  			// First step - all values properties (not a list)
  			foreach (string name in getters.Keys)
  			{
  				MethodInfo getter = (MethodInfo)getters[name];
  				Type propType = getter.ReturnType;
  
gt: 				if (propType == typeof(object))