/*
         * Clean up all of the remainders from a closed connection, including the network channels, etc.
         */
        Int32 CleanupClosedConnection()
        {
            Monitor.Enter(CleanupClosedConnectionLock);

            // NOTE: Do not make any calls to the real Connection in here!
            // If, for any reason, the connection has died, calling into it from here will
            // end up causing this thread to hang, waiting for the dead connection to respond.
            DebugLog.Write("[Interface:CleanupClosedConnection] Closing all connections to the Agent");

            // Reset all necessary assigned variables
            AgentProcess = null;
            AgentProcessOwner = false;

            if (Connection != null)
            {
                // Notify the connection wrapper that the connection is gone
                Connection.SignalConnectionDropped();
                Connection = null;
            }
            ConnectionHandle = Constants.INVALID;
            ConnectionConfiguration = null;

            // Clean up and close up the connection callback
            if (ConnectionCallback != null)
            {
                IntPtr QuitMessage = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(FMessage)));
                Marshal.StructureToPtr(new FMessage(ESwarmVersionValue.VER_1_0, EMessageType.QUIT), QuitMessage, false);
                ConnectionCallback(QuitMessage, ConnectionCallbackData);
            }
            ConnectionCallback = null;
            ConnectionCallbackData = IntPtr.Zero;

            // Close all associated channels
            if (OpenChannels.Count > 0)
            {
                foreach (ChannelInfo NextChannel in OpenChannels.Values)
                {
                    // Just close the handle and we'll clear the entire list later
                    if (NextChannel.ChannelFileStream != null)
                    {
                        NextChannel.ChannelFileStream.Close();
                        NextChannel.ChannelFileStream = null;
                    }
                }
                OpenChannels.Clear();
            }

            // Unregister the primary network communication channel
            if (NetworkChannel != null)
            {
                ChannelServices.UnregisterChannel(NetworkChannel);
                NetworkChannel = null;
            }

            Monitor.Exit(CleanupClosedConnectionLock);

            return Constants.SUCCESS;
        }
		Int32 TryOpenConnection(FConnectionCallback CallbackFunc, IntPtr CallbackData, ELogFlags LoggingFlags)
		{
			try
			{
				// Allocate our new connection wrapper object
				Connection = new IAgentInterfaceWrapper();

				// Make sure the agent is alive and responsive before continuing
				EditorLog(EVerbosityLevel.Informative, "[TryOpenConnection] Testing the Agent");
				Hashtable InParameters = null;
				Hashtable OutParameters = null;
				bool AgentIsReady = false;
				while (!AgentIsReady)
				{
					try
					{
						// Simply try to call the method and if it doesn't throw
						// an exception, consider it a success
						Connection.Method(0, InParameters, ref OutParameters);
						AgentIsReady = true;
					}
					catch (Exception ex)
					{
						// Wait a little longer
						EditorLog(EVerbosityLevel.Critical, "[TryOpenConnection] Waiting for the agent to start up ...");
						EditorLog(EVerbosityLevel.Critical, ex.ToString());
						Thread.Sleep(5000);
					}
				}

				// Request an official connection to the Agent
				EditorLog(EVerbosityLevel.Informative, "[TryOpenConnection] Opening Connection to Agent");
				EditorLog(EVerbosityLevel.Informative, "[TryOpenConnection] Local Process ID is " + Process.GetCurrentProcess().Id.ToString());

				StartTiming("OpenConnection-Remote", false);
				ConnectionHandle = Connection.OpenConnection(AgentProcess, AgentProcessOwner, Process.GetCurrentProcess().Id, LoggingFlags, out ConnectionConfiguration);
				StopTiming();

				if (ConnectionHandle >= 0)
				{
					Log(EVerbosityLevel.Informative, ELogColour.Green, "[Interface:TryOpenConnection] Local connection established");

					// Spawn a thread to monitor the message queue
					MessageThreadData ThreadData = new MessageThreadData();
					ThreadData.Owner = this;
					ThreadData.Connection = Connection;
					ThreadData.ConnectionHandle = ConnectionHandle;
					ThreadData.ConnectionCallback = CallbackFunc;
					ThreadData.ConnectionCallbackData = CallbackData;
					ThreadData.ConnectionConfiguration = ConnectionConfiguration;

					// Launch the message queue thread
					ConnectionMessageThread = new Thread(new ParameterizedThreadStart(MessageThreadProc));
					ConnectionMessageThread.Name = "ConnectionMessageThread";
					ConnectionMessageThread.Start( ThreadData );

					// Launch the agent monitor thread
					ConnectionMonitorThread = new Thread(new ParameterizedThreadStart(MonitorThreadProc));
					ConnectionMonitorThread.Name = "ConnectionMonitorThread";
					ConnectionMonitorThread.Start(ThreadData);

					// Save the user's callback routine
					ConnectionCallback = CallbackFunc;
					ConnectionCallbackData = CallbackData;
					ConnectionLoggingFlags = LoggingFlags;
				}
			}
			catch (Exception Ex)
			{
				EditorLog(EVerbosityLevel.Critical, "[TryOpenConnection] Error: " + Ex.Message);
				EditorLog(EVerbosityLevel.Critical, Ex.ToString());
				ConnectionHandle = Constants.INVALID;
				Connection = null;
			}

			return ConnectionHandle;
		}
        FSwarmInterface()
        {
            AgentProcess = null;
            AgentProcessOwner = false;
            Connection = null;
            ConnectionHandle = Constants.INVALID;
            ConnectionMessageThread = null;
            ConnectionMonitorThread = null;
            ConnectionConfiguration = null;
            ConnectionCallback = null;
            BaseChannelHandle = 0;
            PendingTasks = null;
            NetworkChannel = null;
            PerfTimerInstance = null;

            OpenChannels = new ReaderWriterDictionary<Int32, ChannelInfo>();
            FreeChannelWriteBuffers = new Stack<byte[]>();
            CleanupClosedConnectionLock = new Object();

            // TODO: Delete old files
        }