//-----------------------------------------------------------------------
// 
//     Copyright (c) Microsoft Corporation.
// 
//-----------------------------------------------------------------------
namespace Microsoft.Isam.Esent.Interop
{
    using System;
    using System.Diagnostics;
    using System.Globalization;
    using Microsoft.Isam.Esent.Interop.Windows8;
    /// 
    /// A class that encapsulates a transaction on a JET_SESID.
    /// 
    public class Transaction : EsentResource
    {
        /// 
        /// The underlying JET_SESID.
        /// 
        private readonly JET_SESID sesid;
        /// 
        /// Initializes a new instance of the Transaction class. This automatically
        /// begins a transaction. The transaction will be rolled back if
        /// not explicitly committed.
        /// 
        /// The session to start the transaction for.
        public Transaction(JET_SESID sesid)
        {
            this.sesid = sesid;
            this.Begin();
        }
        /// 
        /// Gets the current transaction level of the
        /// .
        /// Requires Win10.
        /// 
        public int TransactionLevel
        {
            get
            {
                int transactionLevel = -1;
                if (EsentVersion.SupportsWindows10Features)
                {
                    Windows8Api.JetGetSessionParameter(
                        this.sesid,
                        Windows10.Windows10Sesparam.TransactionLevel,
                        out transactionLevel);
                }
                return transactionLevel;
            }
        }
        /// 
        /// Gets a value indicating whether this object is currently in a
        /// transaction.
        /// 
        public bool IsInTransaction
        {
            get
            {
                this.CheckObjectIsNotDisposed();
                return this.HasResource;
            }
        }
        /// 
        /// Returns a  that represents the current .
        /// 
        /// 
        /// A  that represents the current .
        /// 
        public override string ToString()
        {
            return string.Format(CultureInfo.InvariantCulture, "Transaction (0x{0:x})", this.sesid.Value);
        }
        /// 
        /// Begin a transaction. This object should not currently be
        /// in a transaction.
        /// 
        public void Begin()
        {
            this.CheckObjectIsNotDisposed();
            if (this.IsInTransaction)
            {
                throw new InvalidOperationException("Already in a transaction");
            }
            Api.JetBeginTransaction(this.sesid);
            this.ResourceWasAllocated();
            Debug.Assert(this.IsInTransaction, "Begin finished, but object isn't in a transaction");
        }
        /// 
        /// Commit a transaction. This object should be in a transaction.
        /// 
        /// JetCommitTransaction options.
        public void Commit(CommitTransactionGrbit grbit)
        {
            this.CheckObjectIsNotDisposed();
            if (!this.IsInTransaction)
            {
                throw new InvalidOperationException("Not in a transaction");
            }
            Api.JetCommitTransaction(this.sesid, grbit);
            this.ResourceWasReleased();
            Debug.Assert(!this.IsInTransaction, "Commit finished, but object is still in a transaction");
        }
        /// 
        /// Commit a transaction. This object should be in a transaction.
        /// 
        /// JetCommitTransaction options.
        /// Duration for committing lazy transactions.
        /// Commit-id for this commit record.
        public void Commit(CommitTransactionGrbit grbit, TimeSpan durableCommit, out JET_COMMIT_ID commitId)
        {
            this.CheckObjectIsNotDisposed();
            if (!this.IsInTransaction)
            {
                throw new InvalidOperationException("Not in a transaction");
            }
            Windows8.Windows8Api.JetCommitTransaction2(this.sesid, grbit, durableCommit, out commitId);
            this.ResourceWasReleased();
            Debug.Assert(!this.IsInTransaction, "Commit finished, but object is still in a transaction");
        }
        /// 
        /// Rollback a transaction. This object should be in a transaction.
        /// 
        public void Rollback()
        {
            this.CheckObjectIsNotDisposed();
            if (!this.IsInTransaction)
            {
                throw new InvalidOperationException("Not in a transaction");
            }
            Api.JetRollback(this.sesid, RollbackTransactionGrbit.None);
            this.ResourceWasReleased();
            Debug.Assert(!this.IsInTransaction, "Commit finished, but object is still in a transaction");
        }
        /// 
        /// Called when the transaction is being disposed while active.
        /// This should rollback the transaction.
        /// 
        protected override void ReleaseResource()
        {
            this.Rollback();
        }
    }
}