using System;
using System.Data;
using System.Collections;
using System.Globalization;
using DotNetMock;

namespace DotNetMock.Framework.Data
{
	/// <summary>
	/// This is a Mock Object that implements the IDataParameterCollection interface.  It holds a collection of IDataParamter objects.
	/// </summary>
	public class MockDataParameterCollection : MockObject, IDataParameterCollection
	{
		/// <summary>
		/// Internal collection of parameters.
		/// </summary>
		private ArrayList _actualCollection = new ArrayList();
		private ArrayList _expectedCollection = new ArrayList();
		/// <summary>
		/// Flag indicating read-only status.
		/// </summary>
		private bool _isReadOnly = false;
		/// <summary>
		/// Flag indicating fixed-size status.
		/// </summary>
		private bool _isFixedSize = false;

		/// <summary>
		/// Default constructor
		/// </summary>
		public MockDataParameterCollection() {}

		/// <summary>
		/// Adds expected paramter to the expected collection
		/// </summary>
		/// <param name="parameter">Parameter to add</param>
		public void AddExpected(IDataParameter parameter)
		{
			_expectedCollection.Add(parameter);
		}
		#region Implementation of IDataParameterCollection

		/// <summary>
		/// Removes a parameter from the Actual collection
		/// </summary>
		/// <param name="parameterName">Name of parameter to remove</param>
		public void RemoveAt(string parameterName)
		{
			if (!this.Contains(parameterName) )
			{
				throw new ApplicationException("Parameter by that name cannot be found.");
			}
			for (int i = 0; i < _actualCollection.Count; i++)
			{						
				MockDataParameter mockDP = (MockDataParameter) _actualCollection[i];
				if (mockDP.ParameterName.Equals(parameterName))
				{
					_actualCollection.RemoveAt(i);
				}
			}
		}
		/// <summary>
		/// Verifies if the collection contains a parameter with the given name
		/// </summary>
		/// <param name="parameterName">Name of parameter to check</param>
		/// <returns>True/False</returns>
		public bool Contains(string parameterName)
		{
			bool result = false;
			
			for (int i = 0; i < _actualCollection.Count; i++)
			{
				IDataParameter mockDP = (IDataParameter) _actualCollection[i];
				if (mockDP.ParameterName.Equals(parameterName))
				{
					result = true;
				}
			}
			return result;
		}
		/// <summary>
		/// Returns the index of the parameter with the given name
		/// </summary>
		/// <param name="parameterName">Name of the parameter</param>
		/// <returns>Zero based index of the parameter</returns>
		public int IndexOf(string parameterName)
		{
			if (!this.Contains(parameterName) )
			{
				throw new ApplicationException("Parameter by that name cannot be found.");
			}
			int index = 0;

			for (int i = 0; i < _actualCollection.Count; i++)
			{
				IDataParameter mockDP = (IDataParameter) _actualCollection[i];
				if (mockDP.ParameterName.Equals(parameterName))
				{
					index = i;
				}
			}
			return index;
		}
		/// <summary>
		/// Property: Provides index-based access to the parameter collection
		/// </summary>
		public object this[string parameterName]
		{
			get
			{
				return _actualCollection[IndexOf(parameterName)];
			}
			set
			{
				_actualCollection[IndexOf(parameterName)] = value;
			}
		}
		#endregion

		#region Implementation of IList
		/// <summary>
		/// Removes the parameter at the given index
		/// </summary>
		/// <param name="index">Index to remove</param>
		public void RemoveAt(int index)
		{
			_actualCollection.RemoveAt(index);
		}
		/// <summary>
		/// Inserts a parameter at the given index.  Currently *Not Implemented*
		/// </summary>
		/// <param name="index">Index to use</param>
		/// <param name="value">Parameter to use</param>
		public void Insert(int index, object value)
		{
			throw new NotImplementedException("Not implemented.  Please use one of the Add() methods instead");
		}
		/// <summary>
		/// Removes parameter.  Currently *Not Implemented*.  Please use RemoveAt() instead.
		/// </summary>
		/// <param name="value">Parameter to remove</param>
		public void Remove(object value)
		{
			throw new NotImplementedException("Not implemented.  Please use RemoveAt() instead");
		}
		/// <summary>
		/// Verifies object is contained in the collection.  Currently *Not Implemented*.  Please use Contains(string parameterName) instead.
		/// </summary>
		/// <param name="value">Parameter to check</param>
		/// <returns>True/False</returns>
		public bool Contains(object value)
		{
			throw new NotImplementedException("Not implemented.  Please use IDataParameterCollection.Contains(string parameterName) instead");
		}
		/// <summary>
		/// Clears Actual Collection
		/// </summary>
		public void Clear()
		{
			_actualCollection.Clear();
		}
		/// <summary>
		/// Returns index of value.  Currently *Not Implemented*.  Please use IndexOf(string parameterName) instead.
		/// </summary>
		/// <param name="value">Value to check</param>
		/// <returns>Index of value</returns>
		public int IndexOf(object value)
		{
			throw new NotImplementedException("Not implemented.  Please use IDataParameterCollection.IndexOf(string parameterName) instead");
		}
		/// <summary>
		/// Adds a new MockDataParameter to the collection, with the given name and value.
		/// </summary>
		/// <param name="parameterName">Parameter name to use.</param>
		/// <param name="parameterValue">Parameter value to use.</param>
		/// <returns>Parameter added</returns>
		public IDataParameter Add(string parameterName, string parameterValue)
		{
			MockDataParameter mockDP = new MockDataParameter( parameterName, parameterValue);
			_actualCollection.Add( mockDP );		
			return null;
		}
		/// <summary>
		/// Adds IDataParameter to the collection.
		/// </summary>
		/// <param name="value">Parameter to add.</param>
		/// <returns>Parameter added</returns>
		public IDataParameter Add(IDataParameter value)
		{
			_actualCollection.Add( value );
			return null;
		}
		/// <summary>
		/// Adds a new MockDataParameter to the collection, with the given name and type.
		/// </summary>
		/// <param name="parameterName">Parameter name to use.</param>
		/// <param name="type">Type of new parameter</param>
		/// <returns>Parameter added</returns>
		public IDataParameter Add(string parameterName, DbType type)
		{
			MockDataParameter mockDP = new MockDataParameter( parameterName, type );
			_actualCollection.Add( mockDP );
			return null;
		}
		/// <summary>
		/// Adds value to the collection, as a IDataParameter.
		/// </summary>
		/// <param name="value">Value to add</param>
		/// <returns>0</returns>
		public int Add(object value)
		{
			_actualCollection.Add( value );
			return 0;
		}
		/// <summary>
		/// Gets value indicating if the collection is read-only.  
		/// </summary>
		public bool IsReadOnly
		{
			get
			{
				return _isReadOnly;
			}
			set 
			{ 
				_isReadOnly = value; 
			}
		}
		/// <summary>
		/// Provides zero-based index access to the collection.
		/// </summary>
		public object this[int index]
		{
			get
			{
				return (object)_actualCollection[index];
			}
			set
			{
				_actualCollection[index] = (IDataParameter)value;
			}
		}
		/// <summary>
		/// Gets value indicating if the collection is fixed-size or not.
		/// </summary>
		public bool IsFixedSize
		{
			get
			{
				return _isFixedSize;
			}
			set
			{
				_isFixedSize = value;
			}
		}
		#endregion

		#region Implementation of ICollection
		/// <summary>
		/// Copies section of collection to given array.  Currently *Not Implemented*
		/// </summary>
		/// <param name="array">Array to use</param>
		/// <param name="index">Collection index to start at</param>
		public void CopyTo(System.Array array, int index)
		{
			throw new NotImplementedException("Not Implemented.");
		}
		/// <summary>
		/// Gets count of collection
		/// </summary>
		public int Count
		{
			get
			{
				return _actualCollection.Count;
			}
		}
		// TODO: Implement thread-safe collection
		/// <summary>
		/// Gets value indicating if the collection is synchronized for thread-safe use.
		/// </summary>
		public bool IsSynchronized
		{
			get
			{
				throw new NotImplementedException("Not implemented.");
			}
		}
		// TODO: Implement thread-safe collection
		/// <summary>
		/// Returns synchronized root of the collection.
		/// </summary>
		public object SyncRoot
		{
			get
			{
				throw new NotImplementedException("Not implemented.");
			}
		}
		#endregion

		#region Implementation of IEnumerable
		/// <summary>
		/// Gets IEnumerator that can enumerate over the collection
		/// </summary>
		/// <returns></returns>
		public System.Collections.IEnumerator GetEnumerator()
		{
			return _actualCollection.GetEnumerator();
		}
		#endregion
		#region MockObject overrides
		/// <summary>
		/// <see cref="MockObject.Verify"/>
		/// </summary>
		public override void Verify()
		{
			if (_expectedCollection.Count > _actualCollection.Count) 
			{
				Assertion.Fail("Expected Parameters count" + _expectedCollection.Count + " does not equal Actual Parameters count " + _actualCollection.Count);
			}
			
			for (int i = 0; i < _expectedCollection.Count; i++)
			{
				MockDataParameter verify = new MockDataParameter();
				IDataParameter actual = (IDataParameter)_actualCollection[i];
				IDataParameter expected = (IDataParameter)_expectedCollection[i];
				
				verify.SetExpectedName( expected.ParameterName );
				verify.SetExpectedNullable( expected.IsNullable );
				verify.SetExpectedSourceColumn( expected.SourceColumn );
				verify.SetExpectedType( expected.DbType );
				verify.SetExpectedValue( expected.Value );

				verify.ParameterName = actual.ParameterName;
				verify.IsNullable = actual.IsNullable;
				verify.SourceColumn = actual.SourceColumn;
				verify.DbType = actual.DbType;
				verify.Value = actual.Value;

				verify.Verify();
			}
		}
		#endregion

	}
}
