// 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 "stdafx.h"
#include "AssociationSchemaTest.h"
#include <ctime>
#include <cppunit/extensions/HelperMacros.h>
#include "SDF/SdfCommandType.h"
#include "SDF/ICreateSDFFile.h"
#ifdef _WIN32
const wchar_t* TEST_FILE = L"..\\..\\TestData\\AssocSchemaTest.SDX";
#else
#include <unistd.h>
const wchar_t* TEST_FILE = L"../../TestData/AssocSchemaTest.SDX";
#endif


CPPUNIT_TEST_SUITE_REGISTRATION( AssociationSchemaTest );
CPPUNIT_TEST_SUITE_NAMED_REGISTRATION( AssociationSchemaTest, "AssociationSchemaTest");

const wchar_t* multiplicity = L"m";
const wchar_t* rev_multiplicity = L"1";
static FdoDeleteRule deleteRule = FdoDeleteRule_Break;

AssociationSchemaTest::AssociationSchemaTest(void)
{
    
}

AssociationSchemaTest::~AssociationSchemaTest(void)
{
    
}

void AssociationSchemaTest::SetDeleteRule( FdoDeleteRule rule )
{
    deleteRule = rule;
}

FdoIConnection* AssociationSchemaTest::openConnection( bool re_create )
{
#ifdef _WIN32
    wchar_t fullpath[1024];
    _wfullpath(fullpath, TEST_FILE, 1024);
#else
    char cpath[PATH_MAX];
    char cfullpath[PATH_MAX];
    wcstombs(cpath, TEST_FILE, PATH_MAX);
    realpath(cpath, cfullpath);
    wchar_t fullpath[PATH_MAX];
    mbstowcs(fullpath, cfullpath, PATH_MAX);
#endif

    FdoPtr<IConnectionManager> manager = FdoFeatureAccessManager::GetConnectionManager ();
    FdoIConnection *conn = manager->CreateConnection (L"OSGeo.SDF");
    if( re_create )
    {
        size_t len = wcstombs(NULL, TEST_FILE, 0);
        char* mbsPath = new char[len+1];
        wcstombs(mbsPath, TEST_FILE, len+1);

#ifdef _WIN32    
        SetFileAttributes(mbsPath, FILE_ATTRIBUTE_NORMAL);
        DeleteFile(mbsPath);
#else
        unlink(mbsPath);
#endif

        delete[] mbsPath;


        FdoPtr<FdoICreateSDFFile> crsdf = (FdoICreateSDFFile*)(conn->CreateCommand(SdfCommandType_CreateSDFFile));

        crsdf->SetCoordinateSystemWKT(L"[LL84]");
        crsdf->SetFileName(fullpath);
        crsdf->SetSpatialContextDescription(L"World Coordinate System, Degrees, what else do you need to know?");
        crsdf->SetSpatialContextName(L"World Geodetic Coordinate System, 1984");
        crsdf->SetXYTolerance(17.0);
        crsdf->SetZTolerance(3.14159);

        crsdf->Execute();

    }
    std::wstring connStr = std::wstring(L"File=") + std::wstring(fullpath);
    conn->SetConnectionString(connStr.c_str());
    FdoPtr<FdoIConnectionInfo>info = conn->GetConnectionInfo();
    FdoPtr<FdoIConnectionPropertyDictionary> prop = info->GetConnectionProperties();
    conn->Open();

    return conn;
}

void AssociationSchemaTest::setUp ()
{

}

void AssociationSchemaTest::tearDown ()
{
}

void AssociationSchemaTest::TestCreate ( bool useIdent, bool useObjProp, bool useNestedObj, bool useTransaction, bool commitTransaction, bool associatedIsFeat, bool ownerIsFeat, bool addToSubclass )
{
    FdoPtr<FdoIConnection> connection = openConnection();
    try
    {
        FdoFeatureSchema* pTestSchema = FdoFeatureSchema::Create( L"AssociationSchema", L"Test Association schema" );
       // pSchemas->Add( pTestSchema );


        FdoClassDefinition*    pfeatureclass;
        FdoPtr<FdoDataPropertyDefinition> pProp;
        // Create a feature class
        if( ownerIsFeat )
        {
            pfeatureclass = FdoFeatureClass::Create(L"TestFeatureClass", L"FeatureClass Desc");
            // Add identity property
            pProp = FdoDataPropertyDefinition::Create( L"FeatId", L"FeatId Prop" );
            pProp->SetDataType( FdoDataType_Int32 );
            pProp->SetNullable(false);
            pProp->SetIsAutoGenerated(true);
            FdoPtr<FdoPropertyDefinitionCollection>(pfeatureclass->GetProperties())->Add( pProp );
            FdoPtr<FdoDataPropertyDefinitionCollection>(pfeatureclass->GetIdentityProperties())->Add( pProp );
        }
        else
        {
            pfeatureclass = FdoClass::Create(L"TestFeatureClass", L"FeatureClass Desc");
            pProp = FdoDataPropertyDefinition::Create( L"Id", L"Id Prop" );
            pProp->SetDataType( FdoDataType_Int32 );
            pProp->SetNullable(false);
            FdoPtr<FdoPropertyDefinitionCollection>(pfeatureclass->GetProperties())->Add( pProp );
            FdoPtr<FdoDataPropertyDefinitionCollection>(pfeatureclass->GetIdentityProperties())->Add( pProp );
        }
        // Add first name and last name properties
        pProp = FdoDataPropertyDefinition::Create( L"First Name", L"First Name" );
        pProp->SetDataType( FdoDataType_String );
        pProp->SetLength(32);
        pProp->SetNullable(false);
        FdoPtr<FdoPropertyDefinitionCollection>(pfeatureclass->GetProperties())->Add( pProp );
        pProp = FdoDataPropertyDefinition::Create( L"Last Name", L"Last Name" );
        pProp->SetDataType( FdoDataType_String );
        pProp->SetLength(32);
        pProp->SetNullable(false);
        FdoPtr<FdoPropertyDefinitionCollection>(pfeatureclass->GetProperties())->Add( pProp );


        pProp = FdoDataPropertyDefinition::Create( L"PlaceHolder", L"a dummy property" );
        pProp->SetDataType( FdoDataType_String );
        pProp->SetLength(32);
        pProp->SetNullable(true);
        FdoPtr<FdoPropertyDefinitionCollection>(pfeatureclass->GetProperties())->Add( pProp );


        // Create a class
        FdoClassDefinition*           pclass;
        if( associatedIsFeat )
        {
            pclass = FdoFeatureClass::Create(L"TestClass", L"Class Desc");
            pProp = FdoDataPropertyDefinition::Create( L"FeatId", L"FeatId Prop" );
            pProp->SetDataType( FdoDataType_Int32 );
            pProp->SetNullable(false);
            pProp->SetIsAutoGenerated(true);
            FdoPtr<FdoPropertyDefinitionCollection>(pclass->GetProperties())->Add( pProp );
            FdoPtr<FdoDataPropertyDefinitionCollection>(pclass->GetIdentityProperties())->Add( pProp );
        }
        else
        {
            pclass = FdoClass::Create(L"TestClass", L"Class Desc");
            // Add identity property
            pProp = FdoDataPropertyDefinition::Create( L"Id", L"Id Prop" );
            pProp->SetDataType( FdoDataType_Int32 );
            pProp->SetNullable(false);
            FdoPtr<FdoPropertyDefinitionCollection>(pclass->GetProperties())->Add( pProp );
            FdoPtr<FdoDataPropertyDefinitionCollection>(pclass->GetIdentityProperties())->Add( pProp );
        }
        // Add name one and name two properties
        pProp = FdoDataPropertyDefinition::Create( L"Name One", L"Name One" );
        pProp->SetDataType( FdoDataType_String );
        pProp->SetNullable(false);
        pProp->SetLength(32);
        FdoPtr<FdoPropertyDefinitionCollection>(pclass->GetProperties())->Add( pProp );
        
        pProp = FdoDataPropertyDefinition::Create( L"Name Two", L"Name Two" );
        pProp->SetDataType( FdoDataType_String );
        pProp->SetNullable(false);
        pProp->SetLength(32);
        FdoPtr<FdoPropertyDefinitionCollection>(pclass->GetProperties())->Add( pProp );

        pProp = FdoDataPropertyDefinition::Create( L"PlaceHolder", L"a dummy property" );
        pProp->SetDataType( FdoDataType_String );
        pProp->SetNullable(true);
        pProp->SetLength(32);
        FdoPtr<FdoPropertyDefinitionCollection>(pclass->GetProperties())->Add( pProp );

        // Create a class
        FdoClass*           pclassLeafObj = FdoClass::Create(L"TestSuperObjClass", L"Obj Class Desc");
        // Add identity property
        pProp = FdoDataPropertyDefinition::Create( L"Id", L"ObjId Prop" );
        pProp->SetDataType( FdoDataType_Int32 );
        pProp->SetNullable(false);
        FdoPtr<FdoPropertyDefinitionCollection>(pclassLeafObj->GetProperties())->Add( pProp );
        FdoPtr<FdoDataPropertyDefinitionCollection>(pclassLeafObj->GetIdentityProperties())->Add( pProp );
        // Add name one and name two properties
        pProp = FdoDataPropertyDefinition::Create( L"First Name", L"Name One" );
        pProp->SetDataType( FdoDataType_String );
        pProp->SetNullable(false);
        pProp->SetLength(32);
        FdoPtr<FdoPropertyDefinitionCollection>(pclassLeafObj->GetProperties())->Add( pProp );
        pProp = FdoDataPropertyDefinition::Create( L"Last Name", L"Name Two" );
        pProp->SetDataType( FdoDataType_String );
        pProp->SetNullable(false);
        pProp->SetLength(32);
        FdoPtr<FdoPropertyDefinitionCollection>(pclassLeafObj->GetProperties())->Add( pProp );

        // Create a class
        FdoClass*           pclassObj = FdoClass::Create(L"TestOC", L"Obj Class Desc");
        // Add identity property
        pProp = FdoDataPropertyDefinition::Create( L"Id", L"ObjId Prop" );
        pProp->SetDataType( FdoDataType_Int32 );
        pProp->SetNullable(false);
        FdoPtr<FdoPropertyDefinitionCollection>(pclassObj->GetProperties())->Add( pProp );
        FdoPtr<FdoDataPropertyDefinitionCollection>(pclassObj->GetIdentityProperties())->Add( pProp );
        // Add name one and name two properties
        pProp = FdoDataPropertyDefinition::Create( L"First Name", L"Name One" );
        pProp->SetDataType( FdoDataType_String );
        pProp->SetNullable(false);
        pProp->SetLength(32);
        FdoPtr<FdoPropertyDefinitionCollection>(pclassObj->GetProperties())->Add( pProp );
        pProp = FdoDataPropertyDefinition::Create( L"Last Name", L"Name Two" );
        pProp->SetDataType( FdoDataType_String );
        pProp->SetNullable(false);
        pProp->SetLength(32);
        FdoPtr<FdoPropertyDefinitionCollection>(pclassObj->GetProperties())->Add( pProp );
        
        // Create a feature Sub class class
        FdoClassDefinition*    pSubFeatureclass;
        if( ownerIsFeat )
        {
            pSubFeatureclass = FdoFeatureClass::Create(L"TestSubFeatureClass", L"A subclass from a featureClass");

            pSubFeatureclass->SetBaseClass( pfeatureclass );
            // Add a regular property
            pProp = FdoDataPropertyDefinition::Create( L"Id", L"An Id Prop" );
            pProp->SetDataType( FdoDataType_Int32 );
            pProp->SetNullable(true);
            FdoPtr<FdoPropertyDefinitionCollection>(pSubFeatureclass->GetProperties())->Add( pProp );
        }
        else
        {
            pSubFeatureclass = FdoClass::Create(L"TestSubFeatureClass", L"A subclass from a featureClass");
            pSubFeatureclass->SetBaseClass( pfeatureclass );
        }
        // Add the classes to the schema class collection
        FdoClassesP(pTestSchema->GetClasses())->Add( pfeatureclass );
        FdoClassesP(pTestSchema->GetClasses())->Add( pclass );
        FdoClassesP(pTestSchema->GetClasses())->Add( pclassLeafObj );
        FdoClassesP(pTestSchema->GetClasses())->Add( pclassObj );
        FdoClassesP(pTestSchema->GetClasses())->Add( pSubFeatureclass );

        
        // Create a valid association property
        FdoPtr<FdoAssociationPropertyDefinition> passprop = FdoAssociationPropertyDefinition::Create(L"Association Prop1", L"Association Prop Desc");
        
        passprop->SetLockCascade( true );
        passprop->SetDeleteRule( deleteRule );
        passprop->SetReverseName( L"Reverse Name" );
        passprop->SetMultiplicity(multiplicity);
        passprop->SetReverseMultiplicity(rev_multiplicity);
        if( useIdent )
        {
            FdoPtr<FdoDataPropertyDefinition> pprop = (FdoDataPropertyDefinition*)FdoPtr<FdoPropertyDefinitionCollection>(pclass->GetProperties())->GetItem( L"Name One" );
            FdoPtr<FdoDataPropertyDefinitionCollection>(passprop->GetIdentityProperties())->Add( pprop );
           
            FdoPtr<FdoDataPropertyDefinitionCollection>(passprop->GetIdentityProperties())->Add( 
                FdoPtr<FdoDataPropertyDefinition>( (FdoDataPropertyDefinition*)
                    FdoPtr<FdoPropertyDefinitionCollection>(pclass->GetProperties())->GetItem( L"Name Two" )
                )
            );
            FdoPtr<FdoDataPropertyDefinitionCollection>(passprop->GetReverseIdentityProperties())->Add( 
                FdoPtr<FdoDataPropertyDefinition>( (FdoDataPropertyDefinition*)
                    FdoPtr<FdoPropertyDefinitionCollection>(pfeatureclass->GetProperties())->GetItem( L"First Name" )
                )
            );
            FdoPtr<FdoDataPropertyDefinitionCollection>(passprop->GetReverseIdentityProperties())->Add( 
                FdoPtr<FdoDataPropertyDefinition>( (FdoDataPropertyDefinition*)
                    FdoPtr<FdoPropertyDefinitionCollection>(pfeatureclass->GetProperties())->GetItem( L"Last Name" )
                )
            );
        }
        passprop->SetAssociatedClass(pclass);
        
        if( ! useObjProp )
        {

            // Add a second association property
            FdoPtr<FdoAssociationPropertyDefinition> passprop2 = FdoAssociationPropertyDefinition::Create(L"Association Prop2", L"Second Association Prop Desc");    
            passprop2->SetLockCascade( true );
            passprop2->SetDeleteRule( deleteRule );
            //passprop2->SetReverseName( L"Reverse Name" );
            passprop2->SetMultiplicity(L"m");
            passprop2->SetReverseMultiplicity(L"0_1");
            passprop2->SetAssociatedClass(pclass);

            // Add the association property to the feature class property collection
            if( addToSubclass )
            {
                FdoPtr<FdoPropertyDefinitionCollection>(pSubFeatureclass->GetProperties())->Add( passprop );
                FdoPtr<FdoPropertyDefinitionCollection>(pSubFeatureclass->GetProperties())->Add( passprop2 );
            }
            else
            {
                FdoPtr<FdoPropertyDefinitionCollection>(pfeatureclass->GetProperties())->Add( passprop );
                FdoPtr<FdoPropertyDefinitionCollection>(pfeatureclass->GetProperties())->Add( passprop2 );
            }
        }
        else
        {
            if( useNestedObj )
            {
                // Add the association property to the leaf class of the obj class
                FdoPtr<FdoPropertyDefinitionCollection>(pclassLeafObj->GetProperties())->Add( passprop );
                FdoPtr<FdoObjectPropertyDefinition>pLeafObjPropData = FdoObjectPropertyDefinition::Create( L"LeafObject", L"object property" );
                pLeafObjPropData->SetClass( pclassLeafObj );
                pLeafObjPropData->SetObjectType( FdoObjectType_Value );
                FdoPtr<FdoPropertyDefinitionCollection>(pclassObj->GetProperties())->Add( pLeafObjPropData );
            }
            else
            {
                // Add the association property to the Obj class property collection
                FdoPtr<FdoPropertyDefinitionCollection>(pclassObj->GetProperties())->Add( passprop );
            }
            // Add an object property that contain an association
            FdoPtr<FdoObjectPropertyDefinition>pObjPropData = FdoObjectPropertyDefinition::Create( L"Object", L"object property" );
            pObjPropData->SetClass( pclassObj );
            pObjPropData->SetObjectType( FdoObjectType_Value );
            FdoPtr<FdoPropertyDefinitionCollection>(pfeatureclass->GetProperties())->Add( pObjPropData );
        }

        pclassObj->Release();
        pSubFeatureclass->Release();
        pclassLeafObj->Release();
        pclass->Release();
        pfeatureclass->Release();
        
        FdoPtr<FdoIApplySchema>pCmd = (FdoIApplySchema*) connection->CreateCommand(FdoCommandType_ApplySchema);

        pCmd->SetFeatureSchema( pTestSchema );

        pCmd->Execute();

        pTestSchema->Release();

        CheckResult( connection, useIdent, addToSubclass );

    }
    catch ( FdoException* e )
    {
        printf("TestSchema Error: %ls\n", e->GetExceptionMessage() );
        e->Release();
        throw "Association schema TestCreate exception";
    }
}

void AssociationSchemaTest::CheckResult( FdoIConnection* connection, bool useIdent, bool addToSubclass )
{
    FdoPtr<FdoIDescribeSchema>pDescSchemaCmd = (FdoIDescribeSchema*) connection->CreateCommand(FdoCommandType_DescribeSchema);
    pDescSchemaCmd->SetSchemaName( L"AssociationSchema" );
    FdoPtr<FdoFeatureSchemaCollection>pfsc = pDescSchemaCmd->Execute();
    
    FdoPtr<FdoFeatureSchema> schema = pfsc->GetItem(L"AssociationSchema");
    FdoPtr<FdoClassCollection> classes = schema->GetClasses();
    FdoPtr<FdoClassDefinition> cls;

    cls = classes->GetItem(L"TestSubFeatureClass");

    CPPUNIT_ASSERT(cls.p != NULL);

    FdoPtr<FdoAssociationPropertyDefinition> prop;
    if( addToSubclass )
    {
        FdoPtr<FdoPropertyDefinitionCollection> propCol = cls->GetProperties();
        prop = (FdoAssociationPropertyDefinition*)propCol->GetItem(L"Association Prop1");
    }
    else
    {
        FdoPtr<FdoReadOnlyPropertyDefinitionCollection> propCol = cls->GetBaseProperties();
        prop = (FdoAssociationPropertyDefinition*)propCol->GetItem(L"Association Prop1");
    }
    
    CPPUNIT_ASSERT( wcscmp((FdoPtr<FdoClassDefinition>(prop->GetAssociatedClass()))->GetName(),L"TestClass" ) == 0 );
    CPPUNIT_ASSERT( wcscmp(prop->GetMultiplicity(), multiplicity ) == 0 );
    
    if( useIdent )
    {
        FdoPtr<FdoDataPropertyDefinitionCollection> identProps = prop->GetIdentityProperties();
        CPPUNIT_ASSERT(identProps->GetCount()==2);
        for(int i=0; i<identProps->GetCount(); i++ )
        {
            FdoPtr<FdoDataPropertyDefinition> idProp = identProps->GetItem(i);
            //printf("\tIdent(%d): name(%ls) \n", i, idProp->GetName());
        }
        identProps = prop->GetReverseIdentityProperties();
        CPPUNIT_ASSERT(identProps->GetCount()==2);
        for(int i=0; i<identProps->GetCount(); i++ )
        {
            FdoPtr<FdoDataPropertyDefinition> idProp = identProps->GetItem(i);
            //printf("\tRevIdent(%d): name(%ls) \n", i, idProp->GetName());
        }
    }
}

void AssociationSchemaTest::TestLoad ( bool withObj )
{
    FdoPtr<FdoIConnection> connection = openConnection(false);

    try
    {
        FdoPtr<FdoIDescribeSchema>pDescSchemaCmd = (FdoIDescribeSchema*) connection->CreateCommand(FdoCommandType_DescribeSchema);
        pDescSchemaCmd->SetSchemaName( L"AssociationSchema" );
        FdoPtr<FdoFeatureSchemaCollection>pfsc = pDescSchemaCmd->Execute();
       
        FdoPtr<FdoFeatureSchema> schema = pfsc->GetItem(L"AssociationSchema");
        FdoPtr<FdoClassCollection> classes = schema->GetClasses();
        FdoPtr<FdoClassDefinition> cls;

        cls = classes->GetItem(L"TestFeatureClass");
        if( cls )
        {
            FdoPtr<FdoAssociationPropertyDefinition> prop;
            FdoPtr<FdoPropertyDefinitionCollection> propCol = cls->GetProperties();
            
            prop = (FdoAssociationPropertyDefinition*)propCol->GetItem(L"Association Prop1");
            CPPUNIT_ASSERT( wcscmp((FdoPtr<FdoClassDefinition>(prop->GetAssociatedClass()))->GetName(),L"TestClass" ) == 0 );
            CPPUNIT_ASSERT( wcscmp(prop->GetMultiplicity(), L"m" ) == 0 );
            
            FdoPtr<FdoDataPropertyDefinitionCollection> identProps = prop->GetIdentityProperties();
            CPPUNIT_ASSERT(identProps->GetCount()==2);
            for(int i=0; i<identProps->GetCount(); i++ )
            {
                FdoPtr<FdoDataPropertyDefinition> idProp = identProps->GetItem(i);
               // printf("\tIdent(%d): name(%ls) \n", i, idProp->GetName());
            }
            identProps = prop->GetReverseIdentityProperties();
            CPPUNIT_ASSERT(identProps->GetCount()==2);
            for(int i=0; i<identProps->GetCount(); i++ )
            {
                FdoPtr<FdoDataPropertyDefinition> idProp = identProps->GetItem(i);
               // printf("\tRevIdent(%d): name(%ls) \n", i, idProp->GetName());
            }
        } 
        
        cls = classes->GetItem(L"TestSubFeatureClass");
        if( cls )
        {
            FdoPtr<FdoAssociationPropertyDefinition> prop;
            FdoPtr<FdoReadOnlyPropertyDefinitionCollection> propCol = cls->GetBaseProperties();
            
            prop = (FdoAssociationPropertyDefinition*)propCol->GetItem(L"Association Prop1");

            
            CPPUNIT_ASSERT( wcscmp((FdoPtr<FdoClassDefinition>(prop->GetAssociatedClass()))->GetName(),L"TestClass" ) == 0 );
            CPPUNIT_ASSERT( wcscmp(prop->GetMultiplicity(), L"m" ) == 0 );

            FdoPtr<FdoDataPropertyDefinitionCollection> identProps = prop->GetIdentityProperties();
            CPPUNIT_ASSERT(identProps->GetCount()==2);
            for(int i=0; i<identProps->GetCount(); i++ )
            {
                FdoPtr<FdoDataPropertyDefinition> idProp = identProps->GetItem(i);
                //printf("\tIdent(%d): name(%ls) \n", i, idProp->GetName());
            }
            identProps = prop->GetReverseIdentityProperties();
            CPPUNIT_ASSERT(identProps->GetCount()==2);
            for(int i=0; i<identProps->GetCount(); i++ )
            {
                FdoPtr<FdoDataPropertyDefinition> idProp = identProps->GetItem(i);
                //printf("\tRevIdent(%d): name(%ls) \n", i, idProp->GetName());
            }
        } 
    }
    catch ( FdoException* e )
    {
        printf("TestLoad Error: %ls\n", e->GetExceptionMessage() );
        e->Release();
        throw "Association schema TestLoad exception";
    }
}

void AssociationSchemaTest::TestCreateMultiple()
{
    FdoPtr<FdoIConnection> connection = openConnection();

    try
    {
        FdoPtr<FdoFeatureSchema>pTestSchema = FdoFeatureSchema::Create( L"AssociationSchema", L"Test Association schema" );


        // Create a feature class
        FdoPtr<FdoFeatureClass>pfeatureclass1 = FdoFeatureClass::Create(L"TestClassOne", L"FeatureClass Desc");
        FdoPtr<FdoFeatureClass>pfeatureclass2 = FdoFeatureClass::Create(L"TestClassTwo", L"FeatureClass Desc");
        FdoPtr<FdoFeatureClass>pfeatureclass3 = FdoFeatureClass::Create(L"TestClassThree", L"FeatureClass Desc");
        FdoPtr<FdoFeatureClass>pfeatureclass4 = FdoFeatureClass::Create(L"TestClassFour", L"FeatureClass Desc");
        
        // Add identity property
        FdoPtr<FdoDataPropertyDefinition> pProp = FdoDataPropertyDefinition::Create( L"FeatId", L"FeatId Prop" );
        pProp->SetDataType( FdoDataType_Int32 );
        pProp->SetNullable(false);
        pProp->SetIsAutoGenerated(true);
        FdoPtr<FdoPropertyDefinitionCollection>(pfeatureclass1->GetProperties())->Add( pProp );
        FdoPtr<FdoDataPropertyDefinitionCollection>(pfeatureclass1->GetIdentityProperties())->Add( pProp );

        pProp = FdoDataPropertyDefinition::Create( L"FeatId", L"FeatId Prop" );
        pProp->SetDataType( FdoDataType_Int32 );
        pProp->SetNullable(false);
        pProp->SetIsAutoGenerated(true);
        FdoPtr<FdoPropertyDefinitionCollection>(pfeatureclass2->GetProperties())->Add( pProp );
        FdoPtr<FdoDataPropertyDefinitionCollection>(pfeatureclass2->GetIdentityProperties())->Add( pProp );

        pProp = FdoDataPropertyDefinition::Create( L"FeatId", L"FeatId Prop" );
        pProp->SetDataType( FdoDataType_Int32 );
        pProp->SetNullable(false);
        pProp->SetIsAutoGenerated(true);
        FdoPtr<FdoPropertyDefinitionCollection>(pfeatureclass3->GetProperties())->Add( pProp );
        FdoPtr<FdoDataPropertyDefinitionCollection>(pfeatureclass3->GetIdentityProperties())->Add( pProp );

        pProp = FdoDataPropertyDefinition::Create( L"FeatId", L"FeatId Prop" );
        pProp->SetDataType( FdoDataType_Int32 );
        pProp->SetNullable(false);
        pProp->SetIsAutoGenerated(true);
        FdoPtr<FdoPropertyDefinitionCollection>(pfeatureclass4->GetProperties())->Add( pProp );
        FdoPtr<FdoDataPropertyDefinitionCollection>(pfeatureclass4->GetIdentityProperties())->Add( pProp );

        FdoClassesP classes = pTestSchema->GetClasses();
        classes->Add( pfeatureclass1 );
        classes->Add( pfeatureclass2 );
        classes->Add( pfeatureclass3 );
        classes->Add( pfeatureclass4 );

        FdoPtr<FdoFeatureClass>pclass = FdoFeatureClass::Create(L"AssoClass", L"Associated FeatureClass Desc");
        pProp = FdoDataPropertyDefinition::Create( L"FeatId", L"FeatId Prop" );
        pProp->SetDataType( FdoDataType_Int32 );
        pProp->SetNullable(false);
        pProp->SetIsAutoGenerated(true);
        FdoPtr<FdoPropertyDefinitionCollection>(pclass->GetProperties())->Add( pProp );
        FdoPtr<FdoDataPropertyDefinitionCollection>(pclass->GetIdentityProperties())->Add( pProp );
        classes->Add( pclass );

        FdoPtr<FdoAssociationPropertyDefinition> passprop = FdoAssociationPropertyDefinition::Create(L"AssocProp1", L"Association Prop Desc");
        passprop->SetAssociatedClass(pclass);
        FdoPtr<FdoPropertyDefinitionCollection>(pfeatureclass1->GetProperties())->Add( passprop );

        passprop = FdoAssociationPropertyDefinition::Create(L"AssocProp1", L"Association Prop Desc");
        passprop->SetAssociatedClass(pclass);
        FdoPtr<FdoPropertyDefinitionCollection>(pfeatureclass2->GetProperties())->Add( passprop );

        passprop = FdoAssociationPropertyDefinition::Create(L"AssocProp1", L"Association Prop Desc");
        passprop->SetAssociatedClass(pclass);
        FdoPtr<FdoPropertyDefinitionCollection>(pfeatureclass3->GetProperties())->Add( passprop );

        passprop = FdoAssociationPropertyDefinition::Create(L"AssocProp1", L"Association Prop Desc");
        passprop->SetAssociatedClass(pclass);
        FdoPtr<FdoPropertyDefinitionCollection>(pfeatureclass4->GetProperties())->Add( passprop );

        FdoPtr<FdoIApplySchema>pCmd = (FdoIApplySchema*) connection->CreateCommand(FdoCommandType_ApplySchema);

        pCmd->SetFeatureSchema( pTestSchema );

        pCmd->Execute();
    }
    catch ( FdoException* e )
    {
        printf("TestCreateMultiple Error: %ls\n", e->GetExceptionMessage() );
        e->Release();
        throw "Association schema TestCreateMultiple exception";
    }
}

void AssociationSchemaTest::TestLoadMultiple()
{
    FdoPtr<FdoIConnection> connection  = openConnection(false);

    try
    {
        FdoPtr<FdoIDescribeSchema>pDescSchemaCmd = (FdoIDescribeSchema*) connection->CreateCommand(FdoCommandType_DescribeSchema);
        pDescSchemaCmd->SetSchemaName( L"AssociationSchema" );
        FdoPtr<FdoFeatureSchemaCollection>pfsc = pDescSchemaCmd->Execute();
       
        FdoPtr<FdoFeatureSchema> schema = pfsc->GetItem(L"AssociationSchema");
        FdoPtr<FdoClassCollection> classes = schema->GetClasses();
        FdoPtr<FdoClassDefinition> cls;
        int assocCount = 0;
        for(int i=0; i<classes->GetCount(); i++ )
        {
            cls = classes->GetItem(i);
            if( cls )
            {
                //printf("Class: %ls\n", (FdoString *) cls->GetQualifiedName() );
                FdoPtr<FdoPropertyDefinition> prop;
                FdoPtr<FdoPropertyDefinitionCollection> propCol = cls->GetProperties();
                if( propCol )
                {
                    for(int j=0; j<propCol->GetCount(); j++ )
                    {
                        prop = propCol->GetItem( j );
                        if( prop->GetPropertyType() == FdoPropertyType_AssociationProperty )
                            assocCount++;
                        //printf("\tProp: %ls\n", prop->GetName() );
                    }
                }
            }
        }
        CPPUNIT_ASSERT( assocCount == 4 );
    }
    catch ( FdoException* e )
    {
        printf("TestLoadMultiple Error: %ls\n", e->GetExceptionMessage() );
        e->Release();
        throw "Association schema TestLoadMultiple exception";
    }
}

void AssociationSchemaTest::TestCreate_Cardinality_1_1 ()
{ 
    multiplicity = L"1";
    rev_multiplicity = L"1";
    TestCreate( true, false ); 
    multiplicity = L"m";
    rev_multiplicity = L"1";
}

void AssociationSchemaTest::SetMultiplicity( wchar_t *val )
{
    multiplicity = val;
}

void AssociationSchemaTest::SetRevMultiplicity( wchar_t *val )
{
    rev_multiplicity = val;
}



