#region License

/*
 * Copyright © 2002-2007 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#endregion

#if NET_2_0

#region Imports

using System;
using System.Data;
using System.Data.SqlClient;
using System.Transactions;
using NUnit.Framework;
using Spring.Data.Common;
using Spring.Data.Core;
using Spring.Transaction;
using Spring.Transaction.Support;

#endregion

namespace Spring.Data
{
    /// <summary>
    /// This class contains tests for nesting transaction scopes.
    /// </summary>
    /// <author>Mark Pollack</author>
    [TestFixture]
    public class NestedTxScopeTests
    {
        


        [Test]
        public void TxTemplate()
        {
            IDbProvider dbProvider = DbProviderFactory.GetDbProvider("System.Data.SqlClient");
            dbProvider.ConnectionString = @"Data Source=MARKT60\SQL2005;Initial Catalog=CreditsAndDebits;User ID=springqa; Password=springqa";
            //IPlatformTransactionManager tm = new ServiceDomainPlatformTransactionManager();
            //IPlatformTransactionManager tm = new TxScopeTransactionManager();
            IPlatformTransactionManager tm = new AdoPlatformTransactionManager(dbProvider);
            AdoTemplate adoTemplate = new AdoTemplate(dbProvider);

            TransactionTemplate tt = new TransactionTemplate(tm);
            tt.PropagationBehavior = TransactionPropagation.Required;
            tt.Execute(delegate(ITransactionStatus status)
                           {
                               if (System.Transactions.Transaction.Current != null) Console.WriteLine("tx 1 id = " + System.Transactions.Transaction.Current.TransactionInformation.LocalIdentifier);
                               Console.WriteLine("tx 1 'IsNewTransaction' = " + status.IsNewTransaction);
                               adoTemplate.ExecuteNonQuery(CommandType.Text, "insert into Credits (CreditAmount) VALUES (@amount)", "amount", DbType.Decimal, 0,444);
                               TransactionTemplate tt2 = new TransactionTemplate(tm);
                               tt2.PropagationBehavior = TransactionPropagation.RequiresNew;
                               
                               tt2.Execute(delegate(ITransactionStatus status2)
                                               {
                                                   if (System.Transactions.Transaction.Current != null) Console.WriteLine("tx 2 = " + System.Transactions.Transaction.Current.TransactionInformation.LocalIdentifier);
                                                   Console.WriteLine("tx 2 'IsNewTransaction' = " + status2.IsNewTransaction);
                                                   adoTemplate.ExecuteNonQuery(CommandType.Text, "insert into dbo.Debits (DebitAmount) VALUES (@amount)", "amount", DbType.Decimal, 0,555);
                                                   //throw new ArithmeticException("can't do the math.");
                                                   status2.SetRollbackOnly();
                                                   return null;
                                               });
                               
                               if (System.Transactions.Transaction.Current != null) Console.WriteLine("tx id1 = " + System.Transactions.Transaction.Current.TransactionInformation.LocalIdentifier);                               
                               return null;
                           });
        }

        [Test]
        public void TxScope()
        {
            Method1();
        }
        private void Method1()
        {
            string updateSql1 = "insert into Credits (CreditAmount) VALUES (333)";
            using (TransactionScope ts =
                new TransactionScope(TransactionScopeOption.Required))
            {
                Console.WriteLine("tx id1 = " +
                  System.Transactions.Transaction.Current.TransactionInformation.LocalIdentifier);
                using (SqlConnection cn2005 = new SqlConnection())
                {
                    cn2005.ConnectionString =
                        @"Data Source=MARKT60\SQL2005;Initial Catalog=CreditsAndDebits;User ID=springqa; Password=springqa";
                    SqlCommand cmd = new SqlCommand(updateSql1, cn2005);
                    cn2005.Open();
                    cmd.ExecuteNonQuery();
                }
                Method2();
                Console.WriteLine("tx id1 = " +
                  System.Transactions.Transaction.Current.TransactionInformation.LocalIdentifier);
                ts.Complete();
            }
        }

        private void Method2()
        {
            bool rollback = true;
            string updateSql2 = "insert into Debits (DebitAmount) VALUES (222)";
            using (TransactionScope ts =
                new TransactionScope(TransactionScopeOption.RequiresNew))
            {
                Console.WriteLine("tx id2 = " +
  System.Transactions.Transaction.Current.TransactionInformation.LocalIdentifier);
                using (SqlConnection cn2005 = new SqlConnection())
                {
                    cn2005.ConnectionString = @"Data Source=MARKT60\SQL2005;Initial Catalog=CreditsAndDebits;User ID=springqa; Password=springqa";
                    SqlCommand cmd = new SqlCommand(updateSql2, cn2005);
                    cn2005.Open();
                    cmd.ExecuteNonQuery();
                }
                if (rollback)
                {
                    System.Transactions.Transaction.Current.Rollback();
                }
                else
                {
                    ts.Complete(); 
                }
                Console.WriteLine("end of 2nd data access operation");
                
            }
        }

        [Test]
        public void UnwantedPromotion()
        {
            using (TransactionScope ts = new TransactionScope())
            {
                InnerMethod();
                InnerMethod();
                ts.Complete();
            }
        }

        private void InnerMethod()
        {
            string updateSql2 = "insert into Debits (DebitAmount) VALUES (222)";

            using (SqlConnection cn2005 = new SqlConnection())
            {
                cn2005.ConnectionString = @"Data Source=MARKT60\SQL2005;Initial Catalog=CreditsAndDebits;User ID=springqa; Password=springqa";
                SqlCommand cmd = new SqlCommand(updateSql2, cn2005);
                cn2005.Open();
                cmd.ExecuteNonQuery();

                #region logging
                Console.WriteLine("TransactionSynchronizationManager.CurrentTransactionIsolationLevel = " +
                  TransactionSynchronizationManager.CurrentTransactionIsolationLevel);
                Console.WriteLine("System.Transactions.Transaction.Current.IsolationLevel = " + System.Transactions.Transaction.Current.IsolationLevel);
                string name = TransactionSynchronizationManager.CurrentTransactionName;
                bool read = TransactionSynchronizationManager.CurrentTransactionReadOnly;
                #endregion
            }
        }
    }
}
#endif