using System;
using System.Data;

namespace DotNetMock.Framework.Data
{
	/// <summary>
	/// This Mock Object implements the IDbTransaction interface
	/// </summary>
	public class MockTransaction : MockObject, IDbTransaction
	{
		private IDbConnection _parentConnection = null;
		private IsolationLevel _isolationLevel = IsolationLevel.Unspecified;

		private ExpectationBool _commitCalled = new ExpectationBool( "MockDbTransaction.CommitCalled" );
		private ExpectationBool _rollbackCalled = new ExpectationBool( "MockDbTransaction.RollbackCalled" );

		private Exception _commitException = null;
		private Exception _rollbackException = null;

		private bool _hasCommitFailed = false; // to allow for rollback later

		/// <summary>
		/// Default Constructor
		/// </summary>
		public MockTransaction() {}


		#region Mock Methods
		/// <summary>
		/// Set expected <see cref="Exception"/> on commit.
		/// </summary>
		/// <param name="exception">expected <see cref="Exception"/></param>
		public void SetExpectedCommitException( Exception exception )
		{
			_commitException = exception;
		}
		/// <summary>
		/// Set expected <see cref="Exception"/> on rollback.
		/// </summary>
		/// <param name="exception">expected <see cref="Exception"/></param>
		public void SetExpectedRollbackException( Exception exception )
		{
			_rollbackException = exception;
		}
		/// <summary>
		/// Set whether a commit call is expected.
		/// </summary>
		/// <param name="commit">true if we expect a commit call</param>
		public void ExpectCommitCall( bool commit )
		{
			_commitCalled.Expected = commit;
		}
		/// <summary>
		/// Set whether a rollback call is expected.
		/// </summary>
		/// <param name="rollback">true if we expect a rollback call</param>
		public void ExpectRollbackCall( bool rollback )
		{
			_rollbackCalled.Expected = rollback;
		}
		#endregion

		#region Implementation of IDbTransaction
		/// <summary>
		/// Rolls back a transaction from a pending state.  Currently Not Implemented
		/// </summary>
		public void Rollback()
		{
			if ( _rollbackCalled.Actual ) 
			{
				throw new InvalidOperationException( "Cannot call rollback more than once." );
			}
			_rollbackCalled.Actual = true;
			if ( _commitCalled.Actual  && _hasCommitFailed == false) 
			{
				throw new InvalidOperationException( "Cannot call rollback after Commit() has been called." );
			}
			if ( _rollbackException != null ) 
			{
				throw _rollbackException;
			}
		}
		/// <summary>
		/// Commits the database transaction
		/// </summary>
		public void Commit()
		{
			if ( _commitCalled.Actual ) 
			{
				throw new InvalidOperationException( "Cannot call commit more than once." );
			}
			_commitCalled.Actual = true;
			if ( _commitException != null ) 
			{
				_hasCommitFailed = true;
				throw _commitException;
			}
		}
		/// <summary>
		/// Gets the Connection object associated with the transaction.  Currently Not Implemented
		/// </summary>
		public System.Data.IDbConnection Connection
		{
			get
			{
				return _parentConnection;
			}
		}
		/// <summary>
		/// Gets the IsolationLevel for this transaction.  Currently Not Implemented
		/// </summary>
		public System.Data.IsolationLevel IsolationLevel
		{
			get
			{
				return _isolationLevel;
			}
		}
		#endregion

		#region Implementation of IDisposable
		/// <summary>
		/// Releases the resources used by MockTransaciton
		/// </summary>
		public void Dispose() 
		{
		}
		#endregion

		#region Internal Methods
		internal void SetParentConnection( IDbConnection connection ) 
		{
			_parentConnection = connection;
		}
		internal void SetTransactionIsolationLevel( IsolationLevel isolationLevel )
		{
			_isolationLevel = isolationLevel;
		}
		#endregion
	}
}
