## Copyright 2007-2008 Cisco Systems Inc.
##
## Licensed under the Apache License, Version 2.0 (the "License"); you may not
## use this file except in compliance with the License. You may obtain a copy
## of the License at
##
##      http://www.apache.org/licenses/LICENSE-2.0
##
## Unless required by applicable law or agreed to in writing, software
## distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
## WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
## License for the specific language governing permissions and limitations
## under the License.
// This file automatically generated by:
//   $version
//   $now
// This file is automatically created and should not be edited!
#set($i = $intf.name())

using Org.Apache.Etch.Bindings.Csharp.Msg;
using Org.Apache.Etch.Bindings.Csharp.Support;
using Org.Apache.Etch.Bindings.Csharp.Transport;
using Org.Apache.Etch.Bindings.Csharp.Util;

/// <summary>
/// Transport helper for ${i}.
/// </summary>
namespace $intf.parent().name()
{
    public class ${i}Helper : TransportHelper
    {
#if ( $helper.isServer($mc) || $helper.isBoth($mc) )

		/// <summary>Constructs a new server session listener per specifications
		/// in uri and resources.</summary>
		/// <param name="uri"> contains specifications for the server session
		/// listener and for the server session transport stack.</param>
		/// <param name="resources"> additional resources to aid in constructing
		/// new server sessions.</param>
		/// <param name="implFactory"> called upon accepting a new server session to
		/// construct a new server implementation to handle messages
		/// from the client during the session.</param>
		/// <returns> an out-of-band source that may be used to control
		/// the listener.</returns>

		public static ServerFactory NewListener( string uri,		
			Resources resources, ${i}ServerFactory implFactory )
		{
			Resources res = InitResources(resources);
			Transport<ServerFactory> listener = TransportFactory.GetListener(uri, res);
			return new MyServerFactory(listener, implFactory);
		}
		
		public class MyServerFactory : DefaultServerFactory
		{
			public MyServerFactory(Transport<ServerFactory> listener, ${i}ServerFactory implFactory )
				: base(listener, implFactory)
			{
				_listener = listener;
				_implFactory = implFactory;
			}

		    private readonly Transport<ServerFactory> _listener;

            private readonly ${i}ServerFactory _implFactory;

            public override void NewServer(TransportMessage m, string uri, Resources resources)
			{
                ValueFactory vf = (ValueFactory)resources.Get(TransportConsts.VALUE_FACTORY);
                MailboxManager r = new PlainMailboxManager(m, uri, resources);
                DeliveryService d = new DefaultDeliveryService(r, uri, resources);
				Remote${i}Client client = new Remote${i}Client(d, vf);
				${i}Server server = _implFactory.New${i}Server(client);
                Pool qp = (Pool)resources[QUEUED_POOL];
                Pool fp = (Pool)resources[FREE_POOL];
				new Stub${i}Server(d, server, qp, fp);
				client._Start();
			}

            public override ValueFactory NewValueFactory(string uri)
            {
                return new ValueFactory${i}(uri);
            }

            public override string ToString()
            {
                return "${i}Helper.ServerFactory/" + _listener;
            }
		}
		
		/// <summary>
		/// Factory for a Listener to use to create new instances of ${i}Server.
		/// </summary>
		
		public interface ${i}ServerFactory
		{
			/// <param name="client"> an Remote${i}Client instance for server implementation
			/// to use to call back to the client.</param>
			/// <returns> an instance of ${i}Server (e.g., Impl${i}Server) to
			/// handle messages which arrive from the client.</returns>
			
			${i}Server New${i}Server( Remote${i}Client client );
		}		
#end
#if ( $helper.isClient($mc) || $helper.isBoth($mc) )

		/// <summary>Constructs a new client session per specifications in uri
		/// and resources.</summary>
		/// <param name="uri"> contains specifications for the client session
		/// transport stack.</param>
		/// <param name="resources"> additional resources to aid in constructing
		/// new sessions.</param>
		/// <param name="implFactory">factory used to construct a new instance implementing
		/// ${i}Client. The new instance will receive and process messages from the
		///	server session.</param>
		/// <returns> new remote server instance initialized by uri
		/// and resources which may be used to send messages to the
		/// server session.</returns>
		
		public static Remote${i}Server NewServer( string uri,
			Resources resources, ${i}ClientFactory implFactory )
		{
			resources = InitResources(resources);
			
			ValueFactory${i} vf= new ValueFactory${i}(uri);
			resources.Add( TransportConsts.VALUE_FACTORY, vf );
			
			URL u = new URL(uri);

            TransportMessage m = TransportFactory.GetTransport(uri, resources);
            MailboxManager r = new PlainMailboxManager(m, u, resources);
            DeliveryService d = new DefaultDeliveryService(r, u, resources);
			Remote${i}Server server = new Remote${i}Server(d, vf);
			${i}Client client = implFactory.New${i}Client(server);			
			new Stub${i}Client(d,
					client,
					(Pool) resources[QUEUED_POOL],
					(Pool) resources[FREE_POOL]);
	
			return server;
		}
		
		///<summary>
		///Factory used by
		///{@link ${i}Helper#new${i}Server(String, Resources, ${i}ClientFactory)}
		///to construct a new instance implementing {@link ${i}Client}. The new
		///instance will receive and process messages from the server session.
		///</summary>
		
		public interface ${i}ClientFactory
		{
			///<summary>
			///Constructs a new instance implementing ${i}Client. The new
			///instance will receive and process messages from the server session.</summary>
		 	///<param name=server> an instance of Remote${i}Server which may be used to
			/// send messages to the server session. </param>
			///<returns> new instance implementing ${i}Client (typically
			///Impl${i}Client). </returns>
			
			${i}Client New${i}Client( Remote${i}Server server );			
		}
#end
	}
}
