/*
 * Copyright (C) 2004-2006  Autodesk, Inc.
 * 
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of version 2.1 of the GNU Lesser
 * General Public License as published by the Free Software Foundation.
 * 
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 * 
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 *
 */
#include "Pch.h"
#include "FdoTransactionTest.h"
#include "UnitTestUtil.h"

FdoTransactionTest::FdoTransactionTest(void)
{
    
}

FdoTransactionTest::~FdoTransactionTest(void)
{
    
}

void FdoTransactionTest::setUp ()
{
    set_provider();
    CreateTestDataStore();
    connect();
    CreateTestSchema();
}

void FdoTransactionTest::tearDown ()
{
    DropTestSchema();
    DestroyTestDataStore();
    if( mConnection != NULL )
        mConnection->Close();
    mConnection = NULL;
}

void FdoTransactionTest::connect ()
{
    try
    {
        mConnection = (FdoIConnection *) UnitTestUtil::GetConnection(L"TranTest");
    }
    catch (FdoException *ex)
    {
        printf("FDO error: %ls\n", ex->GetExceptionMessage());
        if( mConnection != NULL && mConnection->GetConnectionState() == FdoConnectionState_Open)
            mConnection->Close();
        mConnection= NULL;
        ex->Release();
        throw;
    }
}

void FdoTransactionTest::CreateTestDataStore()
{
    try
    {
        DestroyTestDataStore();
        UnitTestUtil::CreateDB(false, false, L"TranTest");
    }
    catch(FdoException* ex)
    {
        printf("FDO error: %ls\n", ex->GetExceptionMessage());
        if( mConnection != NULL && mConnection->GetConnectionState() == FdoConnectionState_Open)
            mConnection->Close();
        mConnection= NULL;
        ex->Release();
        throw;
    }
}

void FdoTransactionTest::DestroyTestDataStore()
{
    try
    {
        if(mConnection != NULL && mConnection->GetConnectionState() == FdoConnectionState_Open)
        {
            mConnection->Close();
        }
        UnitTestUtil::DropDb(L"TranTest");
    }
    catch(FdoException* ex)
    {
        printf("FDO error: %ls\n", ex->GetExceptionMessage());
        if( mConnection != NULL && mConnection->GetConnectionState() == FdoConnectionState_Open)
            mConnection->Close();
        mConnection= NULL;
        ex->Release();
        throw;
    }
}

void FdoTransactionTest::CreateTestSchema()
{
    FdoPtr<FdoISQLCommand> sqlCmd;
    if( mConnection != NULL )
    {
        try
        {
            UnitTestUtil::CreateSpatialContext(mConnection, L"TestContext", L"", -100000, -100000, 100000, 100000);

            FdoPtr<FdoFeatureSchema> transSchema = FdoFeatureSchema::Create(L"TestTransaction", L"Schema of the transaction test");
            FdoPtr<FdoFeatureClass> testFc = FdoFeatureClass::Create(L"TestTransactionClass", L"Feature class for transaction test");    
            FdoPtr<FdoClassCollection>(transSchema->GetClasses())->Add(testFc);
            FdoPtr<FdoPropertyDefinitionCollection> properties = testFc->GetProperties();
            
            FdoPtr<FdoGeometricPropertyDefinition> geometry = FdoGeometricPropertyDefinition::Create(L"geom", L"");
            geometry->SetGeometryTypes(FdoGeometricType_Point);
            geometry->SetSpatialContextAssociation(L"TestContext");
            properties->Add(geometry);
            testFc->SetGeometryProperty(geometry);

            FdoPtr<FdoDataPropertyDefinition> dpd = FdoDataPropertyDefinition::Create(L"name", L"");
            dpd->SetDataType(FdoDataType_String);
            dpd->SetLength(64);
            properties->Add(dpd);

            dpd = FdoDataPropertyDefinition::Create(L"is_true", L"");
            dpd->SetDataType(FdoDataType_Boolean);
            properties->Add(dpd);

            dpd = FdoDataPropertyDefinition::Create(L"id", L"");
            dpd->SetDataType(FdoDataType_Int64);
            dpd->SetNullable(false);
            dpd->SetIsAutoGenerated(true);
            properties->Add(dpd);
            FdoPtr<FdoDataPropertyDefinitionCollection>(testFc->GetIdentityProperties())->Add(dpd);
            
            FdoPtr<FdoIApplySchema> applyschema = static_cast<FdoIApplySchema*>(mConnection->CreateCommand(FdoCommandType_ApplySchema));
            applyschema->SetFeatureSchema(transSchema);
            applyschema->Execute();
        }
        catch( FdoException *ex )
        {
            wprintf(L"%ls", ex->GetExceptionMessage());
        }
    }
}

void FdoTransactionTest::DropTestSchema()
{
    FdoPtr<FdoISQLCommand> sqlCmd;
    if( mConnection != NULL )
    {
        try
        {
            FdoPtr<FdoIDelete> deleteCommand = (FdoIDelete *) mConnection->CreateCommand(FdoCommandType_Delete);
            deleteCommand->SetFeatureClassName(L"TestTransaction:TestTransactionClass");
	        deleteCommand->Execute();
            
            FdoPtr<FdoIDestroySchema>  pDestCmd = (FdoIDestroySchema*) mConnection->CreateCommand(FdoCommandType_DestroySchema);
    	    pDestCmd->SetSchemaName( L"TestTransaction" );
    	    pDestCmd->Execute();
        }
        catch( FdoException *ex )
        {
			TestCommonFail (ex);
        }
    }
}

void FdoTransactionTest::TestBeginTransaction()
{
    bool expectedExc = false; 
    try
    {
        FdoPtr<FdoITransaction> trans = mConnection->BeginTransaction();
        FdoPtr<FdoIInsert> insCmd = static_cast<FdoIInsert*>(mConnection->CreateCommand(FdoCommandType_Insert));
        insCmd->SetFeatureClassName(L"TestTransaction:TestTransactionClass");
        FdoPtr<FdoPropertyValueCollection> vals = insCmd->GetPropertyValues();
        FdoPtr<FdoPropertyValue> propIns;
        
        FdoPtr<FdoStringValue> valPropName = FdoStringValue::Create(L"MyName1");
        propIns = FdoPropertyValue::Create(L"name", valPropName);
        vals->Add(propIns);
        FdoPtr<FdoIFeatureReader> rdr = insCmd->Execute();
        rdr->Close();

        expectedExc = true;
        FdoPtr<FdoITransaction> trans2 = mConnection->BeginTransaction();
    }
    catch( FdoException *ex )
    {
		if(!expectedExc)
            TestCommonFail (ex);
        else
            ex->Release();
    }
}

void FdoTransactionTest::TestCommit()
{
    try
    {
        FdoPtr<FdoITransaction> trans = mConnection->BeginTransaction();
        FdoPtr<FdoIInsert> insCmd = (FdoIInsert*)(mConnection->CreateCommand(FdoCommandType_Insert));
        insCmd->SetFeatureClassName(L"TestTransaction:TestTransactionClass");
        FdoPtr<FdoPropertyValueCollection> vals = insCmd->GetPropertyValues();
        FdoPtr<FdoPropertyValue> propIns;
        
        FdoPtr<FdoStringValue> valPropName = FdoStringValue::Create(L"MyName1");
        propIns = FdoPropertyValue::Create(L"name", valPropName);
        vals->Add(propIns);
        FdoPtr<FdoBooleanValue> valPropIsTrue = FdoBooleanValue::Create(true);
        propIns = FdoPropertyValue::Create(L"is_true", valPropIsTrue);
        vals->Add(propIns);
        FdoPtr<FdoIFeatureReader> rdr = insCmd->Execute();
        rdr->Close();

        trans->Commit();

        int count = 0;     
        FdoPtr<FdoISelect> selCmd = (FdoISelect*)mConnection->CreateCommand( FdoCommandType_Select );
        selCmd->SetFeatureClassName(L"TestTransaction:TestTransactionClass");
        FdoPtr<FdoIFeatureReader> reader = selCmd->Execute();
        while(reader ->ReadNext())
        {
            count++;
        }
        CPPUNIT_ASSERT(count == 1);
    }
    catch( FdoException *ex )
    {
        TestCommonFail (ex);
    }
}

void FdoTransactionTest::TestRollback()
{
     try
    {
        FdoPtr<FdoIInsert> insCmd = (FdoIInsert*)(mConnection->CreateCommand(FdoCommandType_Insert));
        insCmd->SetFeatureClassName(L"TestTransaction:TestTransactionClass");
        FdoPtr<FdoPropertyValueCollection> vals = insCmd->GetPropertyValues();
        FdoPtr<FdoPropertyValue> propIns1;
        FdoPtr<FdoPropertyValue> propIns2;
        
        FdoPtr<FdoStringValue> valPropName = FdoStringValue::Create(L"MyName1");
        propIns1 = FdoPropertyValue::Create(L"name", valPropName);
        vals->Add(propIns1);
        FdoPtr<FdoBooleanValue> valPropIsTrue = FdoBooleanValue::Create(true);
        propIns2 = FdoPropertyValue::Create(L"is_true", valPropIsTrue);
        vals->Add(propIns2);
        FdoPtr<FdoIFeatureReader> rdr = insCmd->Execute();
        rdr->Close();

        int count = 0;     
        FdoPtr<FdoISelect> selCmd = (FdoISelect*)mConnection->CreateCommand( FdoCommandType_Select );
        selCmd->SetFeatureClassName(L"TestTransaction:TestTransactionClass");
        FdoPtr<FdoIFeatureReader> reader = selCmd->Execute();
        while(reader ->ReadNext())
        {
            count++;
        }
        CPPUNIT_ASSERT(count == 1);

        count = 0;
        FdoPtr<FdoITransaction> trans = mConnection->BeginTransaction();
        valPropName = FdoStringValue::Create(L"MyName2");
        propIns1->SetValue(valPropName);
        valPropIsTrue = FdoBooleanValue::Create(false);
        propIns2->SetValue(valPropIsTrue);
        rdr = insCmd->Execute();
        rdr->Close();
        
        reader = selCmd->Execute();
        while(reader ->ReadNext())
        {
            count++;
        }
        CPPUNIT_ASSERT(count == 2);
        trans->Rollback();

        count = 0;
        reader = selCmd->Execute();
        while(reader->ReadNext())
        {
            count++;
        }
        CPPUNIT_ASSERT(count == 1);
    }
    catch( FdoException *ex )
    {
        TestCommonFail (ex);
    }
}

void FdoTransactionTest::TestAddSavePoint()
{
    try
    {
        FdoStringP savePointName1;
        FdoStringP savePointName2;

        //Test to make sure that all save points added have unique names
        FdoPtr<FdoITransaction> transaction = mConnection->BeginTransaction();
        savePointName1 = transaction->AddSavePoint(L"Test");
        savePointName2 = transaction->AddSavePoint(L"Test");

        CPPUNIT_ASSERT(savePointName1 != savePointName2);
        transaction->Commit();
    }
    catch( FdoException *ex )
    {
        TestCommonFail (ex);
    }
}

void FdoTransactionTest::TestRollbackSavePoint()
{
    try
    {
        FdoPtr<FdoITransaction> trans = mConnection->BeginTransaction();
        FdoPtr<FdoIInsert> insCmd = (FdoIInsert*)(mConnection->CreateCommand(FdoCommandType_Insert));
        insCmd->SetFeatureClassName(L"TestTransaction:TestTransactionClass");
        FdoPtr<FdoPropertyValueCollection> vals = insCmd->GetPropertyValues();
        FdoPtr<FdoPropertyValue> propIns1;
        FdoPtr<FdoPropertyValue> propIns2;
        
        FdoPtr<FdoStringValue> valPropName = FdoStringValue::Create(L"MyName1");
        propIns1 = FdoPropertyValue::Create(L"name", valPropName);
        vals->Add(propIns1);
        FdoPtr<FdoBooleanValue> valPropIsTrue = FdoBooleanValue::Create(true);
        propIns2 = FdoPropertyValue::Create(L"is_true", valPropIsTrue);
        vals->Add(propIns2);
        FdoPtr<FdoIFeatureReader> rdr = insCmd->Execute();
        rdr->Close();
    
        int count = 0;     
        FdoPtr<FdoISelect> selCmd = (FdoISelect*)mConnection->CreateCommand( FdoCommandType_Select );
        selCmd->SetFeatureClassName(L"TestTransaction:TestTransactionClass");
        FdoPtr<FdoIFeatureReader> reader = selCmd->Execute();
        while(reader ->ReadNext())
        {
            count++;
        }
        CPPUNIT_ASSERT(count == 1);
        FdoStringP savePointName = trans->AddSavePoint(L"Test");

        valPropName = FdoStringValue::Create(L"MyName2");
        propIns1->SetValue(valPropName);
        
        valPropIsTrue = FdoBooleanValue::Create(false);
        propIns2->SetValue(valPropIsTrue);
        rdr = insCmd->Execute();
        rdr->Close();

        count = 0;
        reader = selCmd->Execute();
        while(reader ->ReadNext())
        {
            count++;
        }
        CPPUNIT_ASSERT(count == 2);
        trans->Rollback(savePointName);
        trans->Commit();

        count = 0;
        reader = selCmd->Execute();
        while(reader ->ReadNext())
        {
            count++;
        }
        CPPUNIT_ASSERT(count == 1);
    }
    catch( FdoException *ex )
    {
        TestCommonFail (ex);
    }
}

void FdoTransactionTest::TestReleaseSavePoint()
{
     bool expectedExc = false; 
    try
    {
        FdoPtr<FdoITransaction> trans = mConnection->BeginTransaction();
        FdoPtr<FdoIInsert> insCmd = (FdoIInsert*)(mConnection->CreateCommand(FdoCommandType_Insert));
        insCmd->SetFeatureClassName(L"TestTransaction:TestTransactionClass");
        FdoPtr<FdoPropertyValueCollection> vals = insCmd->GetPropertyValues();
        FdoPtr<FdoPropertyValue> propIns;
        
        FdoPtr<FdoStringValue> valPropName = FdoStringValue::Create(L"MyName1");
        propIns = FdoPropertyValue::Create(L"name", valPropName);
        vals->Add(propIns);
        FdoPtr<FdoBooleanValue> valPropIsTrue = FdoBooleanValue::Create(true);
        propIns = FdoPropertyValue::Create(L"is_true", valPropIsTrue);
        vals->Add(propIns);
        FdoPtr<FdoIFeatureReader> rdr = insCmd->Execute();
        rdr->Close();
    
        int count = 0;     
        FdoPtr<FdoISelect> selCmd = (FdoISelect*)mConnection->CreateCommand( FdoCommandType_Select );
        selCmd->SetFeatureClassName(L"TestTransaction:TestTransactionClass");
        FdoPtr<FdoIFeatureReader> reader = selCmd->Execute();
        while(reader ->ReadNext())
        {
            count++;
        }
        CPPUNIT_ASSERT(count == 1);
        FdoStringP savePointName = trans->AddSavePoint(L"Test");

        valPropName = FdoStringValue::Create(L"MyName2");
        propIns = FdoPropertyValue::Create(L"name", valPropName);
        vals->Add(propIns);
        valPropIsTrue = FdoBooleanValue::Create(false);
        propIns = FdoPropertyValue::Create(L"is_true", valPropIsTrue);
        vals->Add(propIns);
        rdr = insCmd->Execute();
        rdr->Close();

        trans->ReleaseSavePoint(savePointName);

        valPropName = FdoStringValue::Create(L"MyName3");
        propIns = FdoPropertyValue::Create(L"name", valPropName);
        vals->Add(propIns);
        valPropIsTrue = FdoBooleanValue::Create(true);
        propIns = FdoPropertyValue::Create(L"is_true", valPropIsTrue);
        vals->Add(propIns);
        rdr = insCmd->Execute();
        rdr->Close();

        trans->Rollback(savePointName);

        trans->Commit();

        count = 0;
        reader = selCmd->Execute();
        while(reader ->ReadNext())
        {
            count++;
        }
        CPPUNIT_ASSERT(count == 3);
    }
    catch( FdoException *ex )
    {
        if(!expectedExc)
            TestCommonFail(ex);
        else
            ex->Release();
    }
}

