using System;
using System.Data;
using DotNetMock;

namespace DotNetMock.Framework.Data
{
	/// <summary>
	/// This Mock Object implements the IDbConnection interface
	/// </summary>
	public class MockDbConnection : MockObject, IDbConnection
	{
		private IDbCommand _command = null;
		private ExpectationCounter _closeCalls = new ExpectationCounter("MockDbConnection.CloseCalls");
		private ExpectationCounter _createCalls = new ExpectationCounter("MockDbConnection.CreateCalls");
		private ExpectationCounter _openCalls = new ExpectationCounter("MockDbConnection.OpenCalls");
		private ExpectationString _connectionString = new ExpectationString("MockDbConnection.ConnectionString");

		private Exception _createCommandException = null;

		private ConnectionState _connectionState = ConnectionState.Closed;
		private int _connectionTimeout = 0;
		/// <summary>
		/// Default Constructor
		/// </summary>
		public MockDbConnection() {}
		/// <summary>
		/// Constructor that sets the name of the Mock Object
		/// </summary>
		/// <param name="name">Name of the Mock Object</param>
		public MockDbConnection( string name ) : base( name ) {}

		#region Mock Methods

		/// <summary>
		/// Sets expected connection state for the State property
		/// </summary>
		/// <param name="state">ConnectionState to expect</param>
		public void SetExpectedConnectionState( ConnectionState state )
		{	
			_connectionState = state;
		}

		/// <summary>
		/// Sets expected number of Open() calls to expect
		/// </summary>
		/// <param name="openCalls">Number of calls to expect</param>
		public void SetExpectedOpenCalls( int openCalls )
		{
			_openCalls.Expected = openCalls;
		}
		/// <summary>
		/// Sets expected connection timeout value for the ConnectionTimeout property
		/// </summary>
		/// <param name="timeout">Connection timeout to expect</param>
		public void SetExpectedConnectionTimeout( int timeout )
		{
			_connectionTimeout = timeout;
		}

		/// <summary>
		/// Set expected connection string for connection string property 
		/// </summary>
		/// <param name="connectionString">String to use</param>
		public void SetExpectedConnectionString(string connectionString)
		{
			_connectionString.Expected = connectionString;
		}
		/// <summary>
		/// Set expected command to return on CreateCommand()
		/// </summary>
		/// <param name="command">Command to return</param>
		public void SetExpectedCommand(IDbCommand command)
		{
			_command = command;
		}
		/// <summary>
		/// Set expected number of Close() calls to expect
		/// </summary>
		/// <param name="calls">Count to expect</param>
		public void SetExpectedCloseCalls(int calls)
		{
			_closeCalls.Expected = calls;
		}
		/// <summary>
		/// Set exception to throw when CreateCommand() is called
		/// </summary>
		/// <param name="exception">Exception to throw</param>
		public void SetCreateCommandException(Exception exception)
		{
			_createCommandException = exception;
		}
		/// <summary>
		/// Set expected number of CreateCommand() calls
		/// </summary>
		/// <param name="calls">Count to expect</param>
		public void SetExpectedCreateCalls(int calls)
		{
			_createCalls.Expected = calls;
		}
		#endregion

		#region Implementation of IDbConnection
		/// <summary>
		/// Changes the current database for an open connection object.  Currently does nothing
		/// </summary>
		/// <param name="databaseName">Database to change to</param>
		public void ChangeDatabase(string databaseName)
		{
			
		}
		/// <summary>
		/// Begins a database transaction.  Currently returns a new MockTransaction object that is
		/// associated with the current connection.  Also, associated the given isolation level 
		/// with the new transaction.
		/// </summary>
		/// <param name="il">One of the IsolationLevel values.</param>
		/// <returns>An object representing the new transaction.</returns>
		public System.Data.IDbTransaction BeginTransaction(System.Data.IsolationLevel il)
		{
			IDbTransaction transaction = BeginTransaction();
			((MockTransaction)transaction).SetTransactionIsolationLevel( il );
			return transaction;
		}
		/// <summary>
		/// Begins a database transaction.  Currently returns a new MockTransaction object that is
		/// associated with the current connection.
		/// </summary>
		/// <returns>An object representing the new transaction.</returns>
		public System.Data.IDbTransaction BeginTransaction()
		{
			IDbTransaction transaction = new MockTransaction();
			((MockTransaction )transaction).SetParentConnection( this );
			return transaction;
		}
		/// <summary>
		/// Increments Create calls counter then returns the command object designated by the
		/// SetupCommand method or throws exception
		/// </summary>
		/// <returns>Command Object</returns>
		public System.Data.IDbCommand CreateCommand()
		{
			_createCalls.Inc();
			if (_createCommandException != null)
			{
				throw _createCommandException;
			}
			
			if (_command == null) 
			{
				IDbCommand command = new MockCommand();
				command.Connection = this;
				return command;
			}
			else
			{
				_command.Connection = this;
				return _command;
			}
		}
		/// <summary>
		/// Opens a database connection with the settings  specified by the ConnectionString property of the provider-specific Connection object.
		/// </summary>
		public void Open()
		{
			_openCalls.Inc();
			_connectionState = ConnectionState.Open;
		}
		/// <summary>
		/// Increments CloseCalls counter
		/// </summary>
		public void Close()
		{
			_closeCalls.Inc();
			_connectionState = ConnectionState.Closed;
		}
		/// <summary>
		/// Gets the current state of the Connection
		/// </summary>
		public System.Data.ConnectionState State
		{
			get
			{
				return _connectionState;
			}
		}
		/// <summary>
		/// Gets/Sets the string used to open a database
		/// </summary>
		public string ConnectionString
		{
			get
			{
				return _connectionString.Actual;
			}
			set
			{
				_connectionString.Actual = value;
			}
		}
		/// <summary>
		/// Gets the name of the current database or the database to be used once a connection is open
		/// </summary>
		public string Database
		{
			get
			{
				return null;
			}
		}
		/// <summary>
		/// Gets the time to wait while trying to establish a connection before terminating the attempt and generating an error
		/// </summary>
		public int ConnectionTimeout
		{
			get
			{
				return _connectionTimeout;
			}
		}
		#endregion

		#region Implementation of IDisposable
		/// <summary>
		/// Releases resources used by MockDbConnection
		/// </summary>
		public void Dispose() 
		{
	    if (_connectionState != ConnectionState.Closed)
      {
	      Close();
      }
		}
		#endregion
	}
}
