bool ComponentCollection::ValidateComponent( const ComponentPtr &component, tstring& error ) const
{
    HELIUM_ASSERT( component->GetSlot() != Reflect::ReservedTypes::Invalid );

    // Check for duplicates.
    if ( ContainsComponent( component->GetSlot() ) )
    {
        error = tstring( TXT( "The component '" ) )+ component->GetClass()->m_UIName + TXT( "' is a duplicate (a component already occupies that slot in the collection)." );
        return false;
    }

    // Check to make sure this type of collection accepts this type of component.
    if ( !ValidateCompatible( component, error ) )
    {
        return false;
    }

    // Check to make sure that each component already within the collection is valid with the new one.
    M_Component::const_iterator itr = m_Components.begin();
    M_Component::const_iterator end = m_Components.end();
    for ( ; itr != end; ++itr )
    {
        // Check both directions so that the validation rule only has to be implemented in one place.
        if ( !itr->second->ValidateSibling( component, error ) || !component->ValidateSibling( itr->second.Ptr(), error ) )
        {
            return false;
        }
    }

    return true;
}
ComponentCollection::ComponentCollection( const ComponentPtr& component )
{
    HELIUM_ASSERT( component->GetSlot() != Reflect::ReservedTypes::Invalid );

    m_Components.insert( M_Component::value_type( component->GetSlot(), component ) );
    component->AddChangedListener( ElementChangeSignature::Delegate::Create<ComponentCollection, void (ComponentCollection::*)( const Reflect::ElementChangeArgs& )> ( this, &ComponentCollection::ComponentChanged ) );
    m_Modified = true;
}
ComponentCollection::ComponentCollection( const ComponentPtr& component )
{
    HELIUM_ASSERT( component->GetSlot() != NULL );

    m_Components.insert( M_Component::value_type( component->GetSlot(), component ) );
    component->e_Changed.Add( ObjectChangeSignature::Delegate::Create<ComponentCollection, void (ComponentCollection::*)( const Reflect::ObjectChangeArgs& )> ( this, &ComponentCollection::ComponentChanged ) );
    m_Modified = true;
}
bool ComponentCollection::ValidatePersistent( const ComponentPtr& component ) const
{
    HELIUM_ASSERT( component->GetSlot() != Reflect::ReservedTypes::Invalid );

    // by default, all attributes are persistent
    return true;
}
bool ComponentCollection::ValidatePersistent( const ComponentPtr& component ) const
{
    HELIUM_ASSERT( component->GetSlot() != NULL );

    // by default, all attributes are persistent
    return true;
}
bool ComponentCollection::SetComponent(const ComponentPtr& component, bool validate, std::string* error )
{
    HELIUM_ASSERT( component->GetSlot() != NULL );

    M_Component::const_iterator found = m_Components.find( component->GetSlot() );
    if (found != m_Components.end() && found->second == component)
    {
        return true; // nothing to do, this is already in the collection
    }

    std::string errorMessage;
    if ( validate && !ValidateComponent( component, errorMessage ) )
    {
        if ( error )
        {
            std::string componentName;
            Helium::ConvertString( component->GetMetaClass()->m_Name, componentName );

            std::string collectionName;
            Helium::ConvertString( GetMetaClass()->m_Name, collectionName );

            *error = std::string( TXT( "Component '" ) ) + componentName + TXT( "' is not valid for collection '" ) + collectionName + TXT( "': " ) + errorMessage;
        }

        return false;
    }

    // Event args
    ComponentCollectionChanged args ( this, component );

    // Set the component and connect the collection
    m_Components[ component->GetSlot() ] = component;
    component->SetCollection( this );

    // Start caring about change to the component
    component->e_Changed.Add( ObjectChangeSignature::Delegate::Create<ComponentCollection, void (ComponentCollection::*)( const Reflect::ObjectChangeArgs& )> ( this, &ComponentCollection::ComponentChanged ) );

    // Raise event
    m_Modified = true;
    m_ComponentAdded.Raise( args );
    return true;
}
bool ComponentCollection::ValidateCompatible( const ComponentPtr& component, tstring& error ) const
{
    HELIUM_ASSERT( component->GetSlot() != Reflect::ReservedTypes::Invalid );

    if ( component->GetComponentBehavior() == ComponentBehaviors::Exclusive )
    {
        error = component->GetClass()->m_UIName + TXT( " cannot be added to a(n) " ) + GetClass()->m_UIName + TXT( " because it is an exclusive component." );
        return false;
    }

    return true;
}
bool ComponentCollection::CopyComponentTo( ComponentCollection& destCollection, const ComponentPtr& destAttrib, const ComponentPtr& srcAttrib )
{
    bool inserted = false;
    Reflect::Registry* registry = Reflect::Registry::GetInstance();

    tstring unused;
    // If there is already an component in the destination slot, or the
    // component is not in the destination, but is allowed to be...
    if ( destCollection.ValidateComponent( destAttrib, unused ) )
    {
        // Component can be added to the destination collection, so do it!
        srcAttrib->CopyTo( destAttrib );
        destCollection.SetComponent( destAttrib, false );
        inserted = true;
    }
    else
    {
        ComponentPtr existing = destCollection.GetComponent( destAttrib->GetSlot() );
        if ( existing.ReferencesObject() )
        {
            destCollection.RemoveComponent( existing->GetSlot() );
            if ( destCollection.ValidateComponent( destAttrib, unused ) )
            {
                srcAttrib->CopyTo( destAttrib );
                destCollection.SetComponent( destAttrib, false );
                inserted = true;
            }
            else
            {
                destCollection.SetComponent( existing, false );
            }
        }
    }

    return inserted;
}
bool ComponentCollection::SetComponent(const ComponentPtr& component, bool validate, tstring* error )
{
    HELIUM_ASSERT( component->GetSlot() != Reflect::ReservedTypes::Invalid );

    M_Component::const_iterator found = m_Components.find( component->GetSlot() );
    if (found != m_Components.end() && found->second == component)
    {
        return true; // nothing to do, this is already in the collection
    }

    tstring errorMessage;
    if ( validate && !ValidateComponent( component, errorMessage ) )
    {
        if ( error )
        {
            *error = tstring( TXT( "Component '" ) ) + component->GetClass()->m_ShortName + TXT( "' is not valid for collection '" ) + GetClass()->m_ShortName + TXT( "': " ) + errorMessage;
        }
        
        return false;
    }

    // Event args
    ComponentCollectionChanged args ( this, component );

    // Set the component and connect the collection
    m_Components[ component->GetSlot() ] = component;
    component->SetCollection( this );

    // Start caring about change to the component
    component->AddChangedListener( ElementChangeSignature::Delegate::Create<ComponentCollection, void (ComponentCollection::*)( const Reflect::ElementChangeArgs& )> ( this, &ComponentCollection::ComponentChanged ) );

    // Raise event
    m_Modified = true;
    m_ComponentAdded.Raise( args );
    return true;
}
bool ComponentCollection::ValidateCompatible( const ComponentPtr& component, std::string& error ) const
{
    HELIUM_ASSERT( component->GetSlot() != NULL );

    if ( component->GetComponentBehavior() == ComponentBehaviors::Exclusive )
    {
        error = *component->GetMetaClass()->m_Name;
        error += TXT( " cannot be added to a(n) " );
        error += *GetMetaClass()->m_Name;
        error += TXT( " because it is an exclusive component." );
        return false;
    }

    return true;
}