using System;
using System.Collections;
using System.ComponentModel;
using DotNetMock;

namespace DotNetMock.Framework.ComponentModel
{
	/// <summary>
	/// Base MockObject for remotable components that are marshaled by value.
	/// </summary>
	public class MockMarshalByValueComponent : MockObject, IComponent, IDisposable, IServiceProvider
	{
		private IContainer _expectedContainer = null;
		private bool _expectedDesignMode = false;
		private ISite _expectedSite = null;
		private Hashtable _serviceProviders = null;
		
		private ExpectationCounter _getServiceCalls = new ExpectationCounter( "MockMarshalByValueComponent.GetServiceCalls" );

		/// <summary>
		/// Default COnstructor
		/// </summary>
		public MockMarshalByValueComponent() : base("MockMarshalByValueComponent")
		{
			_serviceProviders = new Hashtable();
		}
		#region Mock Methods
		/// <summary>
		/// Sets the expected object that implements the IContainer interface that should be returned
		/// by the Container property.
		/// </summary>
		/// <param name="container">Expected Container</param>
		public void SetExpectedContainer( IContainer container )
		{
			_expectedContainer = container;
		}
		/// <summary>
		/// Sets the expected value for the DesignMode property to return
		/// </summary>
		/// <param name="designMode">Expected Value</param>
		public void SetExpectedDesignMode( bool designMode )
		{
			_expectedDesignMode = designMode;
		}
		/// <summary>
		/// Sets the expected object, that implements the ISite interface, to be returned via the Site property
		/// </summary>
		/// <param name="site">Expected Site</param>
		public void SetExpectedSite( ISite site )
		{
			_expectedSite = site;
		}
		/// <summary>
		/// Sets the number of expected GetService() calls that are to be made on this object.
		/// </summary>
		/// <param name="count">Expected Count</param>
		public void SetExpectedGetServiceCalls( int count )
		{
			_getServiceCalls.Expected = count;
		}
		/// <summary>
		/// Sets the expected service provider to be returned from GetService() when called for the given
		/// Type
		/// </summary>
		/// <param name="serviceProvider">Expected IServiceProvider</param>
		/// <param name="serviceType">Type to associate with the Expected IServiceProvider</param>
		public void SetExpectedServiceProvider( IServiceProvider serviceProvider , Type serviceType )
		{
			_serviceProviders.Add( serviceType, serviceProvider );
		}
		#endregion

		#region Public Properties

		/// <summary>
		/// Gets the container for the component.
		/// </summary>
		public IContainer Container
		{
			get { return _expectedContainer; }
		}
		/// <summary>
		/// Gets a value indicating whether the component is currently in design mode.
		/// </summary>
		public bool DesignMode
		{
			get 
			{
				if ( _expectedSite == null )
				{
					return false;
				}
				return _expectedDesignMode;
			}
		}
		#endregion

		#region Implementation of IComponent

		/// <summary>
		/// Adds an event handler to listen to the Disposed event on the component.
		/// </summary>
		public event System.EventHandler Disposed;

		/// <summary>
		/// Gets or sets the site of the component.
		/// </summary>
		public System.ComponentModel.ISite Site
		{
			get
			{
				return _expectedSite;
			}
			set
			{
				_expectedSite = value;
			}
		}
		#endregion

		#region Implementation of IDisposable
		/// <summary>
		/// Releases all resources used by the MarshalByValueComponent.
		/// </summary>
		public void Dispose()
		{
			Dispose( false );
		}
		/// <summary>
		/// Releases the unmanaged resources used by the MarshalByValueComponent and optionally releases the managed resources.
		/// </summary>
		/// <param name="dispose">true to release both managed and unmanaged resources; false to release only unmanaged resources.</param>
		public void Dispose( bool dispose )
		{
			Disposed( this, null );
		}
		#endregion

		#region Implementation of IServiceProvider
		/// <summary>
		/// Gets the implementer of the IServiceProvider.
		/// </summary>
		/// <param name="serviceType">Gets the implementer of the IServiceProvider.</param>
		/// <returns>An Object that represents the implementer of the IServiceProvider.</returns>
		public object GetService(Type serviceType)
		{
			_getServiceCalls.Inc();
			
			foreach ( Type expectedType in _serviceProviders.Keys ) 
			{
				if ( expectedType.Equals( serviceType ) )
				{
					return _serviceProviders[ expectedType ];
				}
			}
			return null;
		}
		#endregion
	}
}
