/*
         * 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;
        }
		///////////////////////////////////////////////////////////////////////////
		
		// A duplication of the IAgentInterface API which this class wraps
		public Int32 OpenConnection(Process AgentProcess, bool AgentProcessOwner, Int32 LocalProcessID, ELogFlags LoggingFlags, out AgentConfiguration NewConfiguration)
		{
			OpenConnectionDelegate DOpenConnection = Connection.OpenConnection;
			
			// Set up the versioned hashtable input parameters
			Hashtable InParameters = new Hashtable();
			InParameters["Version"] = ESwarmVersionValue.VER_1_0;
			InParameters["ProcessID"] = LocalProcessID;
			InParameters["ProcessIsOwner"] = (AgentProcessOwner == true ? true : false);
			InParameters["LoggingFlags"] = LoggingFlags;
			
			Hashtable OutParameters = null;
			IAsyncResult Result = DOpenConnection.BeginInvoke(InParameters, ref OutParameters, null, null);
			
			// This will wait with an occasional wake up to check to see if the
			// agent process is still alive and kicking (avoids infinite wait,
			// allows for very long start up times while debugging)
			Int32 StartupSleep = 1000;
			while ((Result.AsyncWaitHandle.WaitOne(StartupSleep) == false) &&
			      (AgentProcess.HasExited == false) &&
			      (AgentProcess.Responding == true))
			{
				// While the application is alive and responding, wait
				DebugLog.Write("[OpenConnection] Waiting for agent to respond ...");
			}

			if (Result.IsCompleted)
			{
				// If the invocation didn't fail, end to get the result
				Int32 ReturnValue = DOpenConnection.EndInvoke(ref OutParameters, Result);
				if (OutParameters != null)
				{
					if ((ESwarmVersionValue)OutParameters["Version"] == ESwarmVersionValue.VER_1_0)
					{
						NewConfiguration = new AgentConfiguration();
						NewConfiguration.AgentProcessID = (Int32 )OutParameters["AgentProcessID"];
						NewConfiguration.AgentCachePath = (String )OutParameters["AgentCachePath"];
						NewConfiguration.AgentJobGuid = (AgentGuid )OutParameters["AgentJobGuid"];
						
						if (OutParameters.ContainsKey("IsPureLocalConnection"))
						{
							NewConfiguration.IsPureLocalConnection = (bool)OutParameters["IsPureLocalConnection"];
						}
						
						// Complete and successful
						return ReturnValue;
					}
				}
			}
			// Otherwise, error
			NewConfiguration = null;
			return Constants.ERROR_CONNECTION_DISCONNECTED;
		}
        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
        }