context: using System;
  using System.IO;
  using System.Threading;
  using System.Collections;
  using Asterisk.NET.Manager.Action;
  using Asterisk.NET.Manager.Event;
  using Asterisk.NET.Manager.Response;
  using System.Text.RegularExpressions;
  using System.Text;
  using System.Net.Sockets;
  using System.Collections.Generic;
  using System.Reflection;
  using Asterisk.NET.IO;
  using Asterisk.NET.Util;
  
  namespace Asterisk.NET.Manager
  {
  	#region Event delegate
  
  	public delegate void ManagerEventHandler(object sender, ManagerEvent e);
  	public delegate void AgentCallbackLoginEventHandler(object sender, Event.AgentCallbackLoginEvent e);
  	public delegate void AgentCallbackLogoffEventHandler(object sender, Event.AgentCallbackLogoffEvent e);
  	public delegate void AgentCalledEventHandler(object sender, Event.AgentCalledEvent e);
  	public delegate void AgentCompleteEventHandler(object sender, Event.AgentCompleteEvent e);
  	public delegate void AgentConnectEventHandler(object sender, Event.AgentConnectEvent e);
  	public delegate void AgentDumpEventHandler(object sender, Event.AgentDumpEvent e);
  	public delegate void AgentLoginEventHandler(object sender, Event.AgentLoginEvent e);
  	public delegate void AgentLogoffEventHandler(object sender, Event.AgentLogoffEvent e);
  	public delegate void AgentsCompleteEventHandler(object sender, Event.AgentsCompleteEvent e);
  	public delegate void AgentsEventHandler(object sender, Event.AgentsEvent e);
  	public delegate void AlarmClearEventHandler(object sender, Event.AlarmClearEvent e);
  	public delegate void AlarmEventHandler(object sender, Event.AlarmEvent e);
  	public delegate void CdrEventHandler(object sender, Event.CdrEvent e);
  	public delegate void DBGetResponseEventHandler(object sender, Event.DBGetResponseEvent e);
  	public delegate void DialEventHandler(object sender, Event.DialEvent e);
  	public delegate void DNDStateEventHandler(object sender, Event.DNDStateEvent e);
  	public delegate void ExtensionStatusEventHandler(object sender, Event.ExtensionStatusEvent e);
  	public delegate void HangupEventHandler(object sender, Event.HangupEvent e);
  	public delegate void HoldedCallEventHandler(object sender, Event.HoldedCallEvent e);
  	public delegate void HoldEventHandler(object sender, Event.HoldEvent e);
  	public delegate void JoinEventHandler(object sender, Event.JoinEvent e);
  	public delegate void LeaveEventHandler(object sender, Event.LeaveEvent e);
  	public delegate void LinkEventHandler(object sender, Event.LinkEvent e);
  	public delegate void LogChannelEventHandler(object sender, Event.LogChannelEvent e);
  	public delegate void MeetMeJoinEventHandler(object sender, Event.MeetmeJoinEvent e);
  	public delegate void MeetMeLeaveEventHandler(object sender, Event.MeetmeLeaveEvent e);
  	public delegate void MeetMeTalkingEventHandler(object sender, Event.MeetmeTalkingEvent e);
  	public delegate void MessageWaitingEventHandler(object sender, Event.MessageWaitingEvent e);
  	public delegate void NewCallerIdEventHandler(object sender, Event.NewCallerIdEvent e);
  	public delegate void NewChannelEventHandler(object sender, Event.NewChannelEvent e);
  	public delegate void NewExtenEventHandler(object sender, Event.NewExtenEvent e);
  	public delegate void NewStateEventHandler(object sender, Event.NewStateEvent e);
  	public delegate void OriginateResponseEventHandler(object sender, Event.OriginateResponseEvent e);
  	public delegate void ParkedCallEventHandler(object sender, Event.ParkedCallEvent e);
  	public delegate void ParkedCallGiveUpEventHandler(object sender, Event.ParkedCallGiveUpEvent e);
  	public delegate void ParkedCallsCompleteEventHandler(object sender, Event.ParkedCallsCompleteEvent e);
  	public delegate void ParkedCallTimeOutEventHandler(object sender, Event.ParkedCallTimeOutEvent e);
  	public delegate void PeerEntryEventHandler(object sender, Event.PeerEntryEvent e);
  	public delegate void PeerlistCompleteEventHandler(object sender, Event.PeerlistCompleteEvent e);
  	public delegate void PeerStatusEventHandler(object sender, Event.PeerStatusEvent e);
  	public delegate void QueueEntryEventHandler(object sender, Event.QueueEntryEvent e);
  	public delegate void QueueMemberAddedEventHandler(object sender, Event.QueueMemberAddedEvent e);
  	public delegate void QueueMemberEventHandler(object sender, Event.QueueMemberEvent e);
  	public delegate void QueueMemberPausedEventHandler(object sender, Event.QueueMemberPausedEvent e);
  	public delegate void QueueMemberRemovedEventHandler(object sender, Event.QueueMemberRemovedEvent e);
  	public delegate void QueueMemberStatusEventHandler(object sender, Event.QueueMemberStatusEvent e);
  	public delegate void QueueParamsEventHandler(object sender, Event.QueueParamsEvent e);
  	public delegate void QueueStatusCompleteEventHandler(object sender, Event.QueueStatusCompleteEvent e);
  	public delegate void RegistryEventHandler(object sender, Event.RegistryEvent e);
  	public delegate void RenameEventHandler(object sender, Event.RenameEvent e);
  	public delegate void StatusCompleteEventHandler(object sender, Event.StatusCompleteEvent e);
  	public delegate void StatusEventHandler(object sender, Event.StatusEvent e);
  	public delegate void UnholdEventHandler(object sender, Event.UnholdEvent e);
  	public delegate void UnlinkEventHandler(object sender, Event.UnlinkEvent e);
  	public delegate void UnparkedCallEventHandler(object sender, Event.UnparkedCallEvent e);
  	public delegate void UserEventHandler(object sender, Event.UserEvent e);
  	public delegate void ZapShowChannelsCompleteEventHandler(object sender, Event.ZapShowChannelsCompleteEvent e);
  	public delegate void ZapShowChannelsEventHandler(object sender, Event.ZapShowChannelsEvent e);
  	public delegate void ConnectionStateEventHandler(object sender, Event.ConnectionStateEvent e);
  
  	#endregion
  
  	/// <summary>
  	/// Default implemention of the ManagerConnection interface.
  	/// </summary>
  	public class ManagerConnection
  	{
  		#region Variables
  
  #if LOGGER
  		private Logger logger = Logger.Instance();
  #endif
  		private long actionIdCount = 0;
  		private string hostname;
  		private int port;
  		private string username;
  		private string password;
  
  		private SocketConnection mrSocket;
  		private ThreadClass mrReaderThread;
  		private ManagerReader mrReader;
  
  		private int defaultResponseTimeout = 2000;
  		private int defaultEventTimeout = 5000;
  		private int sleepTime = 50;
  		private bool keepAlive = true;
  		private bool keepAliveAfterAuthenticationFailure = false;
  		private string protocolIdentifier;
  		private AsteriskVersion asteriskVersion;
  		private Dictionary<int, IResponseHandler> responseHandlers;
  		private Dictionary<int, IResponseHandler> pingHandlers;
  		private Dictionary<int, IResponseHandler> responseEventHandlers;
  		private int pingInterval = 10000;
  
  		private object lockSocket = new object();
  		private object lockHandlers = new object();
  
  		private bool enableEvents = true;
  		private string version = string.Empty;
  		private Encoding socketEncoding = Encoding.ASCII;
  		private bool reconnected = false;
  		private bool reconnectEnable = false;
  		private int reconnectCount;
  
  		private Dictionary<int, ConstructorInfo> registeredEventClasses;
  		private Dictionary<int, int> registeredEventHandlers;
  		private event ManagerEventHandler internalEvent;
  		private bool fireAllEvents = false;
  		private Thread callerThread;
  		private bool traceCallerThread = true;
  
  		/// <summary> Default Fast Reconnect retry counter.</summary>
  		private int reconnectRetryFast = 5;
  		/// <summary> Default Maximum Reconnect retry counter.</summary>
  		private int reconnectRetryMax = 10;
  		/// <summary> Default Fast Reconnect interval in milliseconds.</summary>
  		private int reconnectIntervalFast = 5000;
  		/// <summary> Default Slow Reconnect interval in milliseconds.</summary>
  		private int reconnectIntervalMax = 10000;
  
  		#endregion
  
  		#region Events
  
  		/// <summary>
  		/// An UnhandledEvent is triggered on unknown event.
  		/// </summary>
  		public event ManagerEventHandler UnhandledEvent;
  		/// <summary>
  		/// An AgentCallbackLogin is triggered when an agent is successfully logged in.
  		/// </summary>
  		public event AgentCallbackLoginEventHandler AgentCallbackLogin;
  		/// <summary>
  		/// An AgentCallbackLogoff is triggered when an agent that previously logged in is logged of.<br/>
  		/// </summary>
  		public event AgentCallbackLogoffEventHandler AgentCallbackLogoff;
  		/// <summary>
  		/// An AgentCalled is triggered when an agent is ring.<br/>
  		/// To enable AgentCalled you have to set <code>eventwhencalled = yes</code> in <code>queues.conf</code>.<br/>
  		/// </summary>
  		public event AgentCalledEventHandler AgentCalled;
  		/// <summary>
  		/// An AgentCompleteEvent is triggered when at the end of a call if the caller was connected to an agent.
  		/// </summary>
  		public event AgentCompleteEventHandler AgentComplete;
  		/// <summary>
  		/// An AgentConnectEvent is triggered when a caller is connected to an agent.
  		/// </summary>
  		public event AgentConnectEventHandler AgentConnect;
  		/// <summary>
  		/// An AgentDumpEvent is triggered when an agent dumps the caller while listening to the queue announcement.
  		/// </summary>
  		public event AgentDumpEventHandler AgentDump;
  		/// <summary>
  		/// An AgentLoginEvent is triggered when an agent is successfully logged in using AgentLogin.
  		/// </summary>
  		public event AgentLoginEventHandler AgentLogin;
  		/// <summary>
  		/// An AgentCallbackLogoffEvent is triggered when an agent that previously logged in using AgentLogin is logged of.
  		/// </summary>
  		public event AgentLogoffEventHandler AgentLogoff;
  		/// <summary>
  		/// An AgentsCompleteEvent is triggered after the state of all agents has been reported in response to an AgentsAction.
  		/// </summary>
  		public event AgentsCompleteEventHandler AgentsComplete;
  		/// <summary>
  		/// An AgentsEvent is triggered for each agent in response to an AgentsAction.
  		/// </summary>
  		public event AgentsEventHandler Agents;
  		/// <summary>
  		/// An AlarmEvent is triggered when a Zap channel leaves alarm state.
  		/// </summary>
  		public event AlarmClearEventHandler AlarmClear;
  		/// <summary>
  		/// An AlarmEvent is triggered when a Zap channel enters or changes alarm state.
  		/// </summary>
  		public event AlarmEventHandler Alarm;
  		/// <summary>
  		/// A CdrEvent is triggered when a call detail record is generated, usually at the end of a call.
  		/// </summary>
  		public event CdrEventHandler Cdr;
  		public event DBGetResponseEventHandler DBGetResponse;
  		/// <summary>
  		/// A Dial is triggered whenever a phone attempts to dial someone.<br/>
  		/// </summary>
  		public event DialEventHandler Dial;
  		/// <summary>
  		/// A DNDStateEvent is triggered by the Zap channel driver when a channel enters or leaves DND (do not disturb) state.
  		/// </summary>
  		public event DNDStateEventHandler DNDState;
  		/// <summary>
  		/// An ExtensionStatus is triggered when the state of an extension changes.<br/>
  		/// </summary>
  		public event ExtensionStatusEventHandler ExtensionStatus;
  		/// <summary>
  		/// A Hangup is triggered when a channel is hung up.<br/>
  		/// </summary>
  		public event HangupEventHandler Hangup;
  		/// <summary>
  		/// A HoldedCall is triggered when a channel is put on hold.<br/>
  		/// </summary>
  		public event HoldedCallEventHandler HoldedCall;
  		/// <summary>
  		/// A Hold is triggered by the SIP channel driver when a channel is put on hold.<br/>
  		/// </summary>
  		public event HoldEventHandler Hold;
  		/// <summary>
  		/// A Join is triggered when a channel joines a queue.<br/>
  		/// </summary>
  		public event JoinEventHandler Join;
  		/// <summary>
  		/// A Leave is triggered when a channel leaves a queue.<br/>
  		/// </summary>
  		public event LeaveEventHandler Leave;
  		/// <summary>
  		/// A Link is triggered when two voice channels are linked together and voice data exchange commences.<br/>
  		/// Several Link events may be seen for a single call. This can occur when Asterisk fails to setup a
  		/// native bridge for the call.This is when Asterisk must sit between two telephones and perform
  		/// CODEC conversion on their behalf.
  		/// </summary>
  		public event LinkEventHandler Link;
  		/// <summary>
  		/// A LogChannel is triggered when logging is turned on or off.<br/>
  		/// </summary>
  		public event LogChannelEventHandler LogChannel;
  		/// <summary>
  		/// A MeetMeJoin is triggered if a channel joins a meet me conference.<br/>
  		/// </summary>
  		public event MeetMeJoinEventHandler MeetMeJoin;
  		/// <summary>
  		/// A MeetMeLeave is triggered if a channel leaves a meet me conference.<br/>
  		/// </summary>
  		public event MeetMeLeaveEventHandler MeetMeLeave;
  		// public event MeetMeStopTalkingEventHandler MeetMeStopTalking;
  		/// <summary>
  		/// A MeetMeTalkingEvent is triggered when a user starts talking in a meet me conference.<br/>
  		/// To enable talker detection you must pass the option 'T' to the MeetMe application.
  		/// </summary>
  		public event MeetMeTalkingEventHandler MeetMeTalking;
  		/// <summary>
  		/// A MessageWaiting is triggered when someone leaves voicemail.<br/>
  		/// </summary>
  		public event MessageWaitingEventHandler MessageWaiting;
  		/// <summary>
  		/// A NewCallerId is triggered when the caller id of a channel changes.<br/>
  		/// </summary>
  		public event NewCallerIdEventHandler NewCallerId;
  		/// <summary>
  		/// A NewChannel is triggered when a new channel is created.<br/>
  		/// </summary>
  		public event NewChannelEventHandler NewChannel;
  		/// <summary>
  		/// A NewExten is triggered when a channel is connected to a new extension.<br/>
  		/// </summary>
  		public event NewExtenEventHandler NewExten;
  		/// <summary>
  		/// A NewState is triggered when the state of a channel has changed.<br/>
  		/// </summary>
  		public event NewStateEventHandler NewState;
  		// public event OriginateEventHandler Originate;
  		/// <summary>
  		/// An OriginateFailure is triggered when the execution of an OriginateAction failed.
  		/// </summary>
  		// public event OriginateFailureEventHandler OriginateFailure;
  		/// <summary>
  		/// An OriginateSuccess is triggered when the execution of an OriginateAction succeeded.
  		/// </summary>
  		// public event OriginateSuccessEventHandler OriginateSuccess;
  		/// <summary>
  		/// An OriginateResponse is triggered when the execution of an Originate.
  		/// </summary>
  		public event OriginateResponseEventHandler OriginateResponse;
  		/// <summary>
  		/// A ParkedCall is triggered when a channel is parked (in this case no
  		/// action id is set) and in response to a ParkedCallsAction.<br/>
  		/// </summary>
  		public event ParkedCallEventHandler ParkedCall;
  		/// <summary>
  		/// A ParkedCallGiveUp is triggered when a channel that has been parked is hung up.<br/>
  		/// </summary>
  		public event ParkedCallGiveUpEventHandler ParkedCallGiveUp;
  		/// <summary>
  		/// A ParkedCallsComplete is triggered after all parked calls have been reported in response to a ParkedCallsAction.
  		/// </summary>
  		public event ParkedCallsCompleteEventHandler ParkedCallsComplete;
  		/// <summary>
  		/// A ParkedCallTimeOut is triggered when call parking times out for a given channel.<br/>
  		/// </summary>
  		public event ParkedCallTimeOutEventHandler ParkedCallTimeOut;
  		/// <summary>
  		/// A PeerEntry is triggered in response to a SIPPeersAction or SIPShowPeerAction and contains information about a peer.<br/>
  		/// </summary>
  		public event PeerEntryEventHandler PeerEntry;
  		/// <summary>
  		/// A PeerlistComplete is triggered after the details of all peers has been reported in response to an SIPPeersAction or SIPShowPeerAction.<br/>
  		/// </summary>
  		public event PeerlistCompleteEventHandler PeerlistComplete;
  		/// <summary>
  		/// A PeerStatus is triggered when a SIP or IAX client attempts to registrer at this asterisk server.<br/>
  		/// </summary>
  		public event PeerStatusEventHandler PeerStatus;
  		/// <summary>
  		/// A QueueEntryEvent is triggered in response to a QueueStatusAction and contains information about an entry in a queue.
  		/// </summary>
  		public event QueueEntryEventHandler QueueEntry;
  		/// <summary>
  		/// A QueueMemberAddedEvent is triggered when a queue member is added to a queue.
  		/// </summary>
  		public event QueueMemberAddedEventHandler QueueMemberAdded;
  		/// <summary>
  		/// A QueueMemberEvent is triggered in response to a QueueStatusAction and contains information about a member of a queue.
  		/// </summary>
  		public event QueueMemberEventHandler QueueMember;
  		/// <summary>
  		/// A QueueMemberPausedEvent is triggered when a queue member is paused or unpaused.
  		/// </summary>
  		public event QueueMemberPausedEventHandler QueueMemberPaused;
  		/// <summary>
  		/// A QueueMemberRemovedEvent is triggered when a queue member is removed from a queue.
  		/// </summary>
  		public event QueueMemberRemovedEventHandler QueueMemberRemoved;
  		/// <summary>
  		/// A QueueMemberStatusEvent shows the status of a QueueMemberEvent.
  		/// </summary>
  		public event QueueMemberStatusEventHandler QueueMemberStatus;
  		/// <summary>
  		/// A QueueParamsEvent is triggered in response to a QueueStatusAction and contains the parameters of a queue.
  		/// </summary>
  		public event QueueParamsEventHandler QueueParams;
  		/// <summary>
  		/// A QueueStatusCompleteEvent is triggered after the state of all queues has been reported in response to a QueueStatusAction.
  		/// </summary>
  		public event QueueStatusCompleteEventHandler QueueStatusComplete;
  		/// <summary>
  		/// A Registry is triggered when this asterisk server attempts to register
  		/// as a client at another SIP or IAX server.<br/>
  		/// </summary>
  		public event RegistryEventHandler Registry;
  		/// <summary>
  		/// A RenameEvent is triggered when the name of a channel is changed.
  		/// </summary>
  		public event RenameEventHandler Rename;
  		/// <summary>
  		/// A StatusCompleteEvent is triggered after the state of all channels has been reported in response to a StatusAction.
  		/// </summary>
  		public event StatusCompleteEventHandler StatusComplete;
  		/// <summary>
  		/// A StatusEvent is triggered for each active channel in response to a StatusAction.
  		/// </summary>
  		public event StatusEventHandler Status;
  		/// <summary>
  		/// An UnholdEvent is triggered by the SIP channel driver when a channel is no longer put on hold.
  		/// </summary>
  		public event UnholdEventHandler Unhold;
  		/// <summary>
  		/// An UnlinkEvent is triggered when a link between two voice channels is discontinued, for example, just before call completion.
  		/// </summary>
  		public event UnlinkEventHandler Unlink;
  		/// <summary>
  		/// A UnparkedCallEvent is triggered when a channel that has been parked is resumed.
  		/// </summary>
  		public event UnparkedCallEventHandler UnparkedCall;
  		/// <summary>
  		/// A ZapShowChannelsEvent is triggered on UserEvent in dialplan.
  		/// </summary>
  		public event UserEventHandler UserEvents;
  		/// <summary>
  		/// A ZapShowChannelsCompleteEvent is triggered after the state of all zap channels has been reported in response to a ZapShowChannelsAction.
  		/// </summary>
  		public event ZapShowChannelsCompleteEventHandler ZapShowChannelsComplete;
  		/// <summary>
  		/// A ZapShowChannelsEvent is triggered in response to a ZapShowChannelsAction and shows the state of a zap channel.
  		/// </summary>
  		public event ZapShowChannelsEventHandler ZapShowChannels;
  		/// <summary>
  		/// A ConnectionState is triggered after Connect/Disconnect/Reload/Shutdown events.
  		/// </summary>
  		public event ConnectionStateEventHandler ConnectionState;
  
  		#endregion
  
  		#region Constructor - ManagerConnection()
  		/// <summary> Creates a new instance.</summary>
  		public ManagerConnection()
  		{
  			callerThread = Thread.CurrentThread;
  
  			socketEncoding = Encoding.ASCII;
  
  			responseHandlers = new Dictionary<int, IResponseHandler>();
  			pingHandlers = new Dictionary<int, IResponseHandler>();
  			responseEventHandlers = new Dictionary<int, IResponseHandler>();
  			registeredEventClasses = new Dictionary<int, ConstructorInfo>();
  
  			Helper.RegisterBuiltinEventClasses(registeredEventClasses);
  
  			registeredEventHandlers = new Dictionary<int, int>();
  
  			#region Event mapping table
  			Helper.RegisterEventHandler(registeredEventHandlers, 0, typeof(AgentCallbackLoginEvent));
  			Helper.RegisterEventHandler(registeredEventHandlers, 1, typeof(AgentCallbackLogoffEvent));
  			Helper.RegisterEventHandler(registeredEventHandlers, 2, typeof(AgentCalledEvent));
  			Helper.RegisterEventHandler(registeredEventHandlers, 3, typeof(AgentCompleteEvent));
  			Helper.RegisterEventHandler(registeredEventHandlers, 4, typeof(AgentConnectEvent));
  			Helper.RegisterEventHandler(registeredEventHandlers, 5, typeof(AgentDumpEvent));
  			Helper.RegisterEventHandler(registeredEventHandlers, 6, typeof(AgentLoginEvent));
  			Helper.RegisterEventHandler(registeredEventHandlers, 7, typeof(AgentLogoffEvent));
  			Helper.RegisterEventHandler(registeredEventHandlers, 8, typeof(AgentsCompleteEvent));
  			Helper.RegisterEventHandler(registeredEventHandlers, 9, typeof(AgentsEvent));
  			Helper.RegisterEventHandler(registeredEventHandlers, 10, typeof(AlarmClearEvent));
  			Helper.RegisterEventHandler(registeredEventHandlers, 11, typeof(AlarmEvent));
  			Helper.RegisterEventHandler(registeredEventHandlers, 12, typeof(CdrEvent));
  
  			Helper.RegisterEventHandler(registeredEventHandlers, 14, typeof(DBGetResponseEvent));
  			Helper.RegisterEventHandler(registeredEventHandlers, 15, typeof(DialEvent));
  
  			Helper.RegisterEventHandler(registeredEventHandlers, 17, typeof(DNDStateEvent));
  			Helper.RegisterEventHandler(registeredEventHandlers, 18, typeof(ExtensionStatusEvent));
  			Helper.RegisterEventHandler(registeredEventHandlers, 19, typeof(HangupEvent));
  			Helper.RegisterEventHandler(registeredEventHandlers, 20, typeof(HoldedCallEvent));
  			Helper.RegisterEventHandler(registeredEventHandlers, 21, typeof(HoldEvent));
  			Helper.RegisterEventHandler(registeredEventHandlers, 22, typeof(JoinEvent));
  			Helper.RegisterEventHandler(registeredEventHandlers, 23, typeof(LeaveEvent));
  			Helper.RegisterEventHandler(registeredEventHandlers, 24, typeof(LinkEvent));
  			Helper.RegisterEventHandler(registeredEventHandlers, 25, typeof(LogChannelEvent));
  			Helper.RegisterEventHandler(registeredEventHandlers, 26, typeof(MeetmeJoinEvent));
  			Helper.RegisterEventHandler(registeredEventHandlers, 27, typeof(MeetmeLeaveEvent));
  			Helper.RegisterEventHandler(registeredEventHandlers, 28, typeof(MeetmeTalkingEvent));
  			Helper.RegisterEventHandler(registeredEventHandlers, 29, typeof(MessageWaitingEvent));
  			Helper.RegisterEventHandler(registeredEventHandlers, 30, typeof(NewCallerIdEvent));
  			Helper.RegisterEventHandler(registeredEventHandlers, 31, typeof(NewChannelEvent));
  			Helper.RegisterEventHandler(registeredEventHandlers, 32, typeof(NewExtenEvent));
  			Helper.RegisterEventHandler(registeredEventHandlers, 33, typeof(NewStateEvent));
  			Helper.RegisterEventHandler(registeredEventHandlers, 34, typeof(OriginateResponseEvent));
  			Helper.RegisterEventHandler(registeredEventHandlers, 35, typeof(ParkedCallEvent));
  			Helper.RegisterEventHandler(registeredEventHandlers, 36, typeof(ParkedCallGiveUpEvent));
  			Helper.RegisterEventHandler(registeredEventHandlers, 37, typeof(ParkedCallsCompleteEvent));
  			Helper.RegisterEventHandler(registeredEventHandlers, 38, typeof(ParkedCallTimeOutEvent));
  			Helper.RegisterEventHandler(registeredEventHandlers, 39, typeof(PeerEntryEvent));
  			Helper.RegisterEventHandler(registeredEventHandlers, 40, typeof(PeerlistCompleteEvent));
  			Helper.RegisterEventHandler(registeredEventHandlers, 41, typeof(PeerStatusEvent));
  			Helper.RegisterEventHandler(registeredEventHandlers, 42, typeof(QueueEntryEvent));
  			Helper.RegisterEventHandler(registeredEventHandlers, 43, typeof(QueueMemberAddedEvent));
  			Helper.RegisterEventHandler(registeredEventHandlers, 44, typeof(QueueMemberEvent));
  			Helper.RegisterEventHandler(registeredEventHandlers, 45, typeof(QueueMemberPausedEvent));
  			Helper.RegisterEventHandler(registeredEventHandlers, 46, typeof(QueueMemberRemovedEvent));
  			Helper.RegisterEventHandler(registeredEventHandlers, 47, typeof(QueueMemberStatusEvent));
  			Helper.RegisterEventHandler(registeredEventHandlers, 48, typeof(QueueParamsEvent));
  			Helper.RegisterEventHandler(registeredEventHandlers, 49, typeof(QueueStatusCompleteEvent));
  			Helper.RegisterEventHandler(registeredEventHandlers, 50, typeof(RegistryEvent));
  
  			Helper.RegisterEventHandler(registeredEventHandlers, 52, typeof(RenameEvent));
  
  			Helper.RegisterEventHandler(registeredEventHandlers, 54, typeof(StatusCompleteEvent));
  			Helper.RegisterEventHandler(registeredEventHandlers, 55, typeof(StatusEvent));
  			Helper.RegisterEventHandler(registeredEventHandlers, 56, typeof(UnholdEvent));
  			Helper.RegisterEventHandler(registeredEventHandlers, 57, typeof(UnlinkEvent));
  			Helper.RegisterEventHandler(registeredEventHandlers, 58, typeof(UnparkedCallEvent));
  			Helper.RegisterEventHandler(registeredEventHandlers, 59, typeof(UserEvent));
  			Helper.RegisterEventHandler(registeredEventHandlers, 60, typeof(ZapShowChannelsCompleteEvent));
  			Helper.RegisterEventHandler(registeredEventHandlers, 61, typeof(ZapShowChannelsEvent));
  
  			Helper.RegisterEventHandler(registeredEventHandlers, 62, typeof(ConnectEvent));
  			Helper.RegisterEventHandler(registeredEventHandlers, 62, typeof(DisconnectEvent));
  			Helper.RegisterEventHandler(registeredEventHandlers, 62, typeof(ReloadEvent));
  			Helper.RegisterEventHandler(registeredEventHandlers, 62, typeof(ShutdownEvent));
  
  
  			#endregion
  
  			this.internalEvent += new ManagerEventHandler(internalEventHandler);
  		}
  		#endregion
  
  		#region Constructor - ManagerConnection(hostname, port, username, password)
  		/// <summary>
  		/// Creates a new instance with the given connection parameters.
  		/// </summary>
  		/// <param name="hostname">the hosname of the Asterisk server to connect to.</param>
  		/// <param name="port">the port where Asterisk listens for incoming Manager API connections, usually 5038.</param>
  		/// <param name="username">the username to use for login</param>
  		/// <param name="password">the password to use for login</param>
  		public ManagerConnection(string hostname, int port, string username, string password)
  			: this()
  		{
  			this.hostname = hostname;
  			this.port = port;
  			this.username = username;
  			this.password = password;
  		}
  		#endregion
  
  		#region Constructor - ManagerConnection(hostname, port, username, password, Encoding socketEncoding)
  		/// <summary>
  		/// Creates a new instance with the given connection parameters.
  		/// </summary>
  		/// <param name="hostname">the hosname of the Asterisk server to connect to.</param>
  		/// <param name="port">the port where Asterisk listens for incoming Manager API connections, usually 5038.</param>
  		/// <param name="username">the username to use for login</param>
  		/// <param name="password">the password to use for login</param>
  		/// <param name="socketEncoding">text encoding to asterisk input/output stream</param>
  		public ManagerConnection(string hostname, int port, string username, string password, Encoding encoding)
  			: this()
  		{
  			this.hostname = hostname;
  			this.port = port;
  			this.username = username;
  			this.password = password;
  			this.socketEncoding = encoding;
  		}
  		#endregion
  
  		/// <summary>
  		/// Default Fast Reconnect retry counter.
  		/// </summary>
  		public int ReconnectRetryFast
  		{
  			get { return reconnectRetryFast; }
  			set { reconnectRetryFast = value; }
  		}
  		/// <summary> Default Maximum Reconnect retry counter.</summary>
  		public int ReconnectRetryMax
  		{
  			get { return reconnectRetryMax; }
  			set { reconnectRetryMax = value; }
  		}
  		/// <summary> Default Fast Reconnect interval in milliseconds.</summary>
  		public int ReconnectIntervalFast
  		{
  			get { return reconnectIntervalFast; }
  			set { reconnectIntervalFast = value; }
  		}
  		/// <summary> Default Slow Reconnect interval in milliseconds.</summary>
  		public int ReconnectIntervalMax
  		{
  			get { return reconnectIntervalMax; }
  			set { reconnectIntervalMax = value; }
  		}
  
  		#region TraceCallerThread
  		/// <summary>
  		/// Enable 
  		/// </summary>
  		internal bool TraceCallerThread
  		{
  			get { return traceCallerThread; }
  			set { traceCallerThread = value; }
  		}
  		#endregion
  
  		#region CallerThread
  		internal Thread CallerThread
  		{
  			get { return callerThread; }
  		}
  		#endregion
  
  		#region internalEventHandler(object sender, ManagerEvent e)
  		private void internalEventHandler(object sender, ManagerEvent e)
  		{
  			int eventHash = e.GetType().Name.GetHashCode();
  			if (registeredEventHandlers.ContainsKey(eventHash))
  			{
  				switch (registeredEventHandlers[eventHash])
  				{
  					#region A-C
  					case 0:
  						if (AgentCallbackLogin != null)
  						{
  							AgentCallbackLogin(this, (AgentCallbackLoginEvent)e);
  							return;
  						}
  						break;
  					case 1:
  						if (AgentCallbackLogoff != null)
  						{
  							AgentCallbackLogoff(this, (AgentCallbackLogoffEvent)e);
  							return;
  						}
  						break;
  					case 2:
  						if (AgentCalled != null)
  						{
  							AgentCalled(this, (Event.AgentCalledEvent)e);
  							return;
  						}
  						break;
  					case 3:
  						if (AgentComplete != null)
  						{
  							AgentComplete(this, (Event.AgentCompleteEvent)e);
  							return;
  						}
  						break;
  					case 4:
  						if (AgentConnect != null)
  						{
  							AgentConnect(this, (Event.AgentConnectEvent)e);
  							return;
  						}
  						break;
  					case 5:
  						if (AgentDump != null)
  						{
  							AgentDump(this, (Event.AgentDumpEvent)e);
  							return;
  						}
  						break;
  					case 6:
  						if (AgentLogin != null)
  						{
  							AgentLogin(this, (Event.AgentLoginEvent)e);
  							return;
  						}
  						break;
  					case 7:
  						if (AgentLogoff != null)
  						{
  							AgentLogoff(this, (Event.AgentLogoffEvent)e);
  							return;
  						}
  						break;
  					case 8:
  						if (AgentsComplete != null)
  						{
  							AgentsComplete(this, (AgentsCompleteEvent)e);
  							return;
  						}
  						break;
  					case 9:
  						if (Agents != null)
  						{
  							Agents(this, (AgentsEvent)e);
  							return;
  						}
  						break;
  					case 10:
  						if (AlarmClear != null)
  						{
  							AlarmClear(this, (AlarmClearEvent)e);
  							return;
  						}
  						break;
  					case 11:
  						if (Alarm != null)
  						{
  							Alarm(this, (AlarmEvent)e);
  							return;
  						}
  						break;
  					case 12:
  						if (Cdr != null)
  						{
  							Cdr(this, (CdrEvent)e);
  							return;
  						}
  						break;
  					#endregion
  					#region D-L
  					case 14:
  						if (DBGetResponse != null)
  						{
  							DBGetResponse(this, (DBGetResponseEvent)e);
  							return;
  						}
  						break;
  					case 15:
  						if (Dial != null)
  						{
  							Dial(this, (DialEvent)e);
  							return;
  						}
  						break;
  					case 17:
  						if (DNDState != null)
  						{
  							DNDState(this, (DNDStateEvent)e);
  							return;
  						}
  						break;
  					case 18:
  						if (ExtensionStatus != null)
  						{
  							ExtensionStatus(this, (ExtensionStatusEvent)e);
  							return;
  						}
  						break;
  					case 19:
  						if (Hangup != null)
  						{
  							Hangup(this, (HangupEvent)e);
  							return;
  						}
  						break;
  					case 20:
  						if (HoldedCall != null)
  						{
  							HoldedCall(this, (HoldedCallEvent)e);
  							return;
  						}
  						break;
  					case 21:
  						if (Hold != null)
  						{
  							Hold(this, (HoldEvent)e);
  							return;
  						}
  						break;
  					case 22:
  						if (Join != null)
  						{
  							Join(this, (JoinEvent)e);
  							return;
  						}
  						break;
  					case 23:
  						if (Leave != null)
  						{
  							Leave(this, (LeaveEvent)e);
  							return;
  						}
  						break;
  					case 24:
  						if (Link != null)
  						{
  							Link(this, (LinkEvent)e);
  							return;
  						}
  						break;
  					case 25:
  						if (LogChannel != null)
  						{
  							LogChannel(this, (LogChannelEvent)e);
  							return;
  						}
  						break;
  					#endregion
  					#region M-P
  					case 26:
  						if (MeetMeJoin != null)
  						{
  							MeetMeJoin(this, (MeetmeJoinEvent)e);
  							return;
  						}
  						break;
  					case 27:
  						if (MeetMeLeave != null)
  						{
  							MeetMeLeave(this, (MeetmeLeaveEvent)e);
  							return;
  						}
  						break;
  					case 28:
  						if (MeetMeTalking != null)
  						{
  							MeetMeTalking(this, (MeetmeTalkingEvent)e);
  							return;
  						}
  						break;
  					case 29:
  						if (MessageWaiting != null)
  						{
  							MessageWaiting(this, (MessageWaitingEvent)e);
  							return;
  						}
  						break;
  					case 30:
  						if (NewCallerId != null)
  						{
  							NewCallerId(this, (NewCallerIdEvent)e);
  							return;
  						}
  						break;
  					case 31:
  						if (NewChannel != null)
  						{
  							NewChannel(this, (NewChannelEvent)e);
  							return;
  						}
  						break;
  					case 32:
  						if (NewExten != null)
  						{
  							NewExten(this, (NewExtenEvent)e);
  							return;
  						}
  						break;
  					case 33:
  						if (NewState != null)
  						{
  							NewState(this, (NewStateEvent)e);
  							return;
  						}
  						break;
  					case 34:
  						if (OriginateResponse != null)
  						{
  							OriginateResponse(this, (OriginateResponseEvent)e);
  							return;
  						}
  						break;
  					case 35:
  						if (ParkedCall != null)
  						{
  							ParkedCall(this, (ParkedCallEvent)e);
  							return;
  						}
  						break;
  					case 36:
  						if (ParkedCallGiveUp != null)
  						{
  							ParkedCallGiveUp(this, (ParkedCallGiveUpEvent)e);
  							return;
  						}
  						break;
  					case 37:
  						if (ParkedCallsComplete != null)
  						{
  							ParkedCallsComplete(this, (ParkedCallsCompleteEvent)e);
  							return;
  						}
  						break;
  					case 38:
  						if (ParkedCallTimeOut != null)
  						{
  							ParkedCallTimeOut(this, (ParkedCallTimeOutEvent)e);
  							return;
  						}
  						break;
  					case 39:
  						if (PeerEntry != null)
  						{
  							PeerEntry(this, (PeerEntryEvent)e);
  							return;
  						}
  						break;
  					case 40:
  						if (PeerlistComplete != null)
  						{
  							PeerlistComplete(this, (PeerlistCompleteEvent)e);
  							return;
  						}
  						break;
  					case 41:
  						if (PeerStatus != null)
  						{
  							PeerStatus(this, (PeerStatusEvent)e);
  							return;
  						}
  						break;
  					#endregion
  					#region Q-Z
  					case 42:
  						if (QueueEntry != null)
  						{
  							QueueEntry(this, (QueueEntryEvent)e);
  							return;
  						}
  						break;
  					case 43:
  						if (QueueMemberAdded != null)
  						{
  							QueueMemberAdded(this, (QueueMemberAddedEvent)e);
  							return;
  						}
  						break;
  					case 44:
  						if (QueueMember != null)
  						{
  							QueueMember(this, (QueueMemberEvent)e);
  							return;
  						}
  						break;
  					case 45:
  						if (QueueMemberPaused != null)
  						{
  							QueueMemberPaused(this, (QueueMemberPausedEvent)e);
  							return;
  						}
  						break;
  					case 46:
  						if (QueueMemberRemoved != null)
  						{
  							QueueMemberRemoved(this, (QueueMemberRemovedEvent)e);
  							return;
  						}
  						break;
  					case 47:
  						if (QueueMemberStatus != null)
  						{
  							QueueMemberStatus(this, (QueueMemberStatusEvent)e);
  							return;
  						}
  						break;
  					case 48:
  						if (QueueParams != null)
  						{
  							QueueParams(this, (QueueParamsEvent)e);
  							return;
  						}
  						break;
  					case 49:
  						if (QueueStatusComplete != null)
  						{
  							QueueStatusComplete(this, (QueueStatusCompleteEvent)e);
  							return;
  						}
  						break;
  					case 50:
  						if (Registry != null)
  						{
  							Registry(this, (RegistryEvent)e);
  							return;
  						}
  						break;
  					case 52:
  						if (Rename != null)
  						{
  							Rename(this, (RenameEvent)e);
  							return;
  						}
  						break;
  					case 54:
  						if (StatusComplete != null)
  						{
  							StatusComplete(this, (StatusCompleteEvent)e);
  							return;
  						}
  						break;
  					case 55:
  						if (Status != null)
  						{
  							Status(this, (StatusEvent)e);
  							return;
  						}
  						break;
  					case 56:
  						if (Unhold != null)
  						{
  							Unhold(this, (UnholdEvent)e);
  							return;
  						}
  						break;
  					case 57:
  						if (Unlink != null)
  						{
  							Unlink(this, (UnlinkEvent)e);
  							return;
  						}
  						break;
  					case 58:
  						if (UnparkedCall != null)
  						{
  							UnparkedCall(this, (UnparkedCallEvent)e);
  							return;
  						}
  						break;
  					case 59:
  						if (UserEvents != null)
  						{
  							UserEvents(this, (UserEvent)e);
  							return;
  						}
  						break;
  					case 60:
  						if (ZapShowChannelsComplete != null)
  						{
  							ZapShowChannelsComplete(this, (ZapShowChannelsCompleteEvent)e);
  							return;
  						}
  						break;
  					case 61:
  						if (ZapShowChannels != null)
  						{
  							ZapShowChannels(this, (ZapShowChannelsEvent)e);
  							return;
  						}
  						break;
  					#endregion
  
  					case 62:
  						if (ConnectionState != null)
  						{
  							ConnectionState(this, (ConnectionStateEvent)e);
  							return;
  						}
  						break;
  
  					default:
  						if (UnhandledEvent != null)
  							UnhandledEvent(this, e);
  						return;
  				}
  			}
  			if (fireAllEvents && UnhandledEvent != null)
  				UnhandledEvent(this, e);
  		}
  		#endregion
  
  		#region FireAllEvents
  		/// <summary>
  		/// If this property set to <b>true</b> then ManagerConnection send all unassigned events to UnhandledEvent handler,<br/>
  		/// if set to <b>false</b> then all unassgned events lost and send only UnhandledEvent.<br/>
  		/// Default: <b>false</b>
  		/// </summary>
  		public bool FireAllEvents
  		{
  			get { return this.fireAllEvents; }
  			set { this.fireAllEvents = value; }
  		}
  		#endregion
  
  		#region PingInterval
  		/// <summary>
  		/// Timeout from Ping to Pong. If no Pong received send Disconnect event. Set to zero to disable.
  		/// </summary>
  		public int PingInterval
  		{
  			get { return pingInterval; }
  			set { pingInterval = value; }
  		}
  		#endregion
  
  		#region Hostname
  		/// <summary> Sets the hostname of the asterisk server to connect to.<br/>
  		/// Default is <code>localhost</code>.
  		/// </summary>
  		public string Hostname
  		{
  			get { return hostname; }
  			set { hostname = value; }
  		}
  		#endregion
  
  		#region Port
  		/// <summary>
  		/// Sets the port to use to connect to the asterisk server. This is the port
  		/// specified in asterisk's <code>manager.conf</code> file.<br/>
  		/// Default is 5038.
  		/// </summary>
  		public int Port
  		{
  			get { return port; }
  			set { port = value; }
  		}
  		#endregion
  
  		#region UserName
  		/// <summary>
  		/// Sets the username to use to connect to the asterisk server. This is the
  		/// username specified in asterisk's <code>manager.conf</code> file.
  		/// </summary>
  		public string Username
  		{
  			get { return username; }
  
gt: 			set { username = value; }