void SCH_REFERENCE_LIST::Annotate( bool aUseSheetNum, int aSheetIntervalId, int aStartNumber,
      SCH_MULTI_UNIT_REFERENCE_MAP aLockedUnitMap )
{
    if ( componentFlatList.size() == 0 )
        return;

    int LastReferenceNumber = 0;
    int NumberOfUnits, Unit;

    /* calculate index of the first component with the same reference prefix
     * than the current component.  All components having the same reference
     * prefix will receive a reference number with consecutive values:
     * IC .. will be set to IC4, IC4, IC5 ...
     */
    unsigned first = 0;

    // calculate the last used number for this reference prefix:
#ifdef USE_OLD_ALGO
    int minRefId = 0;

    // when using sheet number, ensure ref number >= sheet number* aSheetIntervalId
    if( aUseSheetNum )
        minRefId = componentFlatList[first].m_SheetNum * aSheetIntervalId;

    LastReferenceNumber = GetLastReference( first, minRefId );
#else
    int minRefId;

    // when using sheet number, ensure ref number >= sheet number* aSheetIntervalId
    if( aUseSheetNum )
        minRefId = componentFlatList[first].m_SheetNum * aSheetIntervalId + 1;
    else
        minRefId = aStartNumber + 1;

    // For multi units components, when "keep order of multi unit" option is selected,
    // store the list of already used full references.
    // The algorithm try to allocate the new reference to components having the same
    // old reference.
    // This algo works fine as long as the previous annotation has no duplicates.
    // But when a hierarchy is reannotated with this option, the previous anotation can
    // have duplicate references, and obviously we must fix these duplicate.
    // therefore do not try to allocate a full reference more than once when trying
    // to keep this order of multi units.
    // inUseRefs keep trace of previously allocated references
    std::unordered_set<wxString> inUseRefs;

    // This is the list of all Id already in use for a given reference prefix.
    // Will be refilled for each new reference prefix.
    std::vector<int>idList;
    GetRefsInUse( first, idList, minRefId );
#endif
    for( unsigned ii = 0; ii < componentFlatList.size(); ii++ )
    {
        if( componentFlatList[ii].m_Flag )
            continue;

        // Check whether this component is in aLockedUnitMap.
        SCH_REFERENCE_LIST* lockedList = NULL;
        for( SCH_MULTI_UNIT_REFERENCE_MAP::value_type& pair : aLockedUnitMap )
        {
            unsigned n_refs = pair.second.GetCount();
            for( unsigned thisRefI = 0; thisRefI < n_refs; ++thisRefI )
            {
                SCH_REFERENCE &thisRef = pair.second[thisRefI];

                if( thisRef.IsSameInstance( componentFlatList[ii] ) )
                {
                    lockedList = &pair.second;
                    break;
                }
            }
            if( lockedList != NULL ) break;
        }

        if(  ( componentFlatList[first].CompareRef( componentFlatList[ii] ) != 0 )
          || ( aUseSheetNum && ( componentFlatList[first].m_SheetNum != componentFlatList[ii].m_SheetNum ) )  )
        {
            // New reference found: we need a new ref number for this reference
            first = ii;
#ifdef USE_OLD_ALGO
            minRefId = 0;

            // when using sheet number, ensure ref number >= sheet number* aSheetIntervalId
            if( aUseSheetNum )
                minRefId = componentFlatList[ii].m_SheetNum * aSheetIntervalId;

            LastReferenceNumber = GetLastReference( ii, minRefId );

#else
            // when using sheet number, ensure ref number >= sheet number* aSheetIntervalId
            if( aUseSheetNum )
                minRefId = componentFlatList[ii].m_SheetNum * aSheetIntervalId + 1;
            else
                minRefId = aStartNumber + 1;

            GetRefsInUse( first, idList, minRefId );
#endif
        }

        // Annotation of one part per package components (trivial case).
        if( componentFlatList[ii].GetLibPart()->GetUnitCount() <= 1 )
        {
            if( componentFlatList[ii].m_IsNew )
            {
#ifdef USE_OLD_ALGO
                LastReferenceNumber++;
#else
                LastReferenceNumber = CreateFirstFreeRefId( idList, minRefId );
#endif
                componentFlatList[ii].m_NumRef = LastReferenceNumber;
            }

            componentFlatList[ii].m_Unit  = 1;
            componentFlatList[ii].m_Flag  = 1;
            componentFlatList[ii].m_IsNew = false;
            continue;
        }

        // Annotation of multi-unit parts ( n units per part ) (complex case)
        NumberOfUnits = componentFlatList[ii].GetLibPart()->GetUnitCount();

        if( componentFlatList[ii].m_IsNew )
        {
#ifdef USE_OLD_ALGO
            LastReferenceNumber++;
#else
            LastReferenceNumber = CreateFirstFreeRefId( idList, minRefId );
#endif
            componentFlatList[ii].m_NumRef = LastReferenceNumber;

            if( !componentFlatList[ii].IsUnitsLocked() )
                componentFlatList[ii].m_Unit = 1;

            componentFlatList[ii].m_Flag = 1;
        }

        // If this component is in aLockedUnitMap, copy the annotation to all
        // components that are not it
        if( lockedList != NULL )
        {
            unsigned n_refs = lockedList->GetCount();

            for( unsigned thisRefI = 0; thisRefI < n_refs; ++thisRefI )
            {
                SCH_REFERENCE &thisRef = (*lockedList)[thisRefI];

                if( thisRef.IsSameInstance( componentFlatList[ii] ) )
                {
                    // This is the component we're currently annotating. Hold the unit!
                    componentFlatList[ii].m_Unit = thisRef.m_Unit;
                }

                if( thisRef.CompareValue( componentFlatList[ii] ) != 0 )
                    continue;

                if( thisRef.CompareLibName( componentFlatList[ii] ) != 0 )
                    continue;

                // Find the matching component
                for( unsigned jj = ii + 1; jj < componentFlatList.size(); jj++ )
                {
                    if( ! thisRef.IsSameInstance( componentFlatList[jj] ) )
                        continue;

                    wxString ref_candidate = buildFullReference( componentFlatList[ii] );

                    // propagate the new reference and unit selection to the "old" component,
                    // if this new full reference is not already used (can happens when initial
                    // multiunits components have duplicate references)
                    if( inUseRefs.find( ref_candidate ) == inUseRefs.end() )
                    {
                        componentFlatList[jj].m_NumRef = componentFlatList[ii].m_NumRef;
                        componentFlatList[jj].m_Unit = thisRef.m_Unit;
                        componentFlatList[jj].m_IsNew = false;
                        componentFlatList[jj].m_Flag = 1;
                        // lock this new full reference
                        inUseRefs.insert( ref_candidate );
                        break;
                    }
                }
            }
        }

        else
        {
            /* search for others units of this component.
            * we search for others parts that have the same value and the same
            * reference prefix (ref without ref number)
            */
            for( Unit = 1; Unit <= NumberOfUnits; Unit++ )
            {
                if( componentFlatList[ii].m_Unit == Unit )
                    continue;

                int found = FindUnit( ii, Unit );

                if( found >= 0 )
                    continue; // this unit exists for this reference (unit already annotated)

                // Search a component to annotate ( same prefix, same value, not annotated)
                for( unsigned jj = ii + 1; jj < componentFlatList.size(); jj++ )
                {
                    if( componentFlatList[jj].m_Flag )    // already tested
                        continue;

                    if( componentFlatList[ii].CompareRef( componentFlatList[jj] ) != 0 )
                        continue;

                    if( componentFlatList[jj].CompareValue( componentFlatList[ii] ) != 0 )
                        continue;

                    if( componentFlatList[jj].CompareLibName( componentFlatList[ii] ) != 0 )
                        continue;

                    if( !componentFlatList[jj].m_IsNew )
                        continue;

                    // Component without reference number found, annotate it if possible
                    if( !componentFlatList[jj].IsUnitsLocked()
                        || ( componentFlatList[jj].m_Unit == Unit ) )
                    {
                        componentFlatList[jj].m_NumRef = componentFlatList[ii].m_NumRef;
                        componentFlatList[jj].m_Unit   = Unit;
                        componentFlatList[jj].m_Flag   = 1;
                        componentFlatList[jj].m_IsNew  = false;
                        break;
                    }
                }
            }
        }
    }
}
void SCH_REFERENCE_LIST::Annotate( bool aUseSheetNum, int aSheetIntervalId,
      SCH_MULTI_UNIT_REFERENCE_MAP aLockedUnitMap )
{
    if ( componentFlatList.size() == 0 )
        return;

    int LastReferenceNumber = 0;
    int NumberOfUnits, Unit;

    // Components with an invisible reference (power...) always are re-annotated.
    ResetHiddenReferences();

    /* calculate index of the first component with the same reference prefix
     * than the current component.  All components having the same reference
     * prefix will receive a reference number with consecutive values:
     * IC .. will be set to IC4, IC4, IC5 ...
     */
    unsigned first = 0;

    // calculate the last used number for this reference prefix:
#ifdef USE_OLD_ALGO
    int minRefId = 0;

    // when using sheet number, ensure ref number >= sheet number* aSheetIntervalId
    if( aUseSheetNum )
        minRefId = componentFlatList[first].m_SheetNum * aSheetIntervalId;

    LastReferenceNumber = GetLastReference( first, minRefId );
#else
    int minRefId = 1;

    // when using sheet number, ensure ref number >= sheet number* aSheetIntervalId
    if( aUseSheetNum )
        minRefId = componentFlatList[first].m_SheetNum * aSheetIntervalId + 1;

    // This is the list of all Id already in use for a given reference prefix.
    // Will be refilled for each new reference prefix.
    std::vector<int>idList;
    GetRefsInUse( first, idList, minRefId );
#endif
    for( unsigned ii = 0; ii < componentFlatList.size(); ii++ )
    {
        if( componentFlatList[ii].m_Flag )
            continue;

        // Check whether this component is in aLockedUnitMap.
        SCH_REFERENCE_LIST* lockedList = NULL;
        BOOST_FOREACH( SCH_MULTI_UNIT_REFERENCE_MAP::value_type& pair, aLockedUnitMap )
        {
            unsigned n_refs = pair.second.GetCount();
            for( unsigned thisRefI = 0; thisRefI < n_refs; ++thisRefI )
            {
                SCH_REFERENCE &thisRef = pair.second[thisRefI];

                if( thisRef.IsSameInstance( componentFlatList[ii] ) )
                {
                    lockedList = &pair.second;
                    break;
                }
            }
            if( lockedList != NULL ) break;
        }

        if(  ( componentFlatList[first].CompareRef( componentFlatList[ii] ) != 0 )
          || ( aUseSheetNum && ( componentFlatList[first].m_SheetNum != componentFlatList[ii].m_SheetNum ) )  )
        {
            // New reference found: we need a new ref number for this reference
            first = ii;
#ifdef USE_OLD_ALGO
            minRefId = 0;

            // when using sheet number, ensure ref number >= sheet number* aSheetIntervalId
            if( aUseSheetNum )
                minRefId = componentFlatList[ii].m_SheetNum * aSheetIntervalId;

            LastReferenceNumber = componentFlatList.GetLastReference( ii, minRefId );
#else
            minRefId = 1;

            // when using sheet number, ensure ref number >= sheet number* aSheetIntervalId
            if( aUseSheetNum )
                minRefId = componentFlatList[ii].m_SheetNum * aSheetIntervalId + 1;

            GetRefsInUse( first, idList, minRefId );
#endif
        }

        // Annotation of one part per package components (trivial case).
        if( componentFlatList[ii].GetLibComponent()->GetUnitCount() <= 1 )
        {
            if( componentFlatList[ii].m_IsNew )
            {
#ifdef USE_OLD_ALGO
                LastReferenceNumber++;
#else
                LastReferenceNumber = CreateFirstFreeRefId( idList, minRefId );
#endif
                componentFlatList[ii].m_NumRef = LastReferenceNumber;
            }

            componentFlatList[ii].m_Unit  = 1;
            componentFlatList[ii].m_Flag  = 1;
            componentFlatList[ii].m_IsNew = false;
            continue;
        }

        // Annotation of multi-unit parts ( n units per part ) (complex case)
        NumberOfUnits = componentFlatList[ii].GetLibComponent()->GetUnitCount();

        if( componentFlatList[ii].m_IsNew )
        {
#ifdef USE_OLD_ALGO
            LastReferenceNumber++;
#else
            LastReferenceNumber = CreateFirstFreeRefId( idList, minRefId );
#endif
            componentFlatList[ii].m_NumRef = LastReferenceNumber;

            if( !componentFlatList[ii].IsUnitsLocked() )
                componentFlatList[ii].m_Unit = 1;

            componentFlatList[ii].m_Flag = 1;
        }

        // If this component is in aLockedUnitMap, copy the annotation to all
        // components that are not it
        if( lockedList != NULL )
        {
            unsigned n_refs = lockedList->GetCount();
            for( unsigned thisRefI = 0; thisRefI < n_refs; ++thisRefI )
            {
                SCH_REFERENCE &thisRef = (*lockedList)[thisRefI];
                if( thisRef.IsSameInstance( componentFlatList[ii] ) )
                {
                    // This is the component we're currently annotating. Hold the unit!
                    componentFlatList[ii].m_Unit = thisRef.m_Unit;
                }

                if( thisRef.CompareValue( componentFlatList[ii] ) != 0 ) continue;
                if( thisRef.CompareLibName( componentFlatList[ii] ) != 0 ) continue;

                // Find the matching component
                for( unsigned jj = ii + 1; jj < componentFlatList.size(); jj++ )
                {
                    if( ! thisRef.IsSameInstance( componentFlatList[jj] ) ) continue;
                    componentFlatList[jj].m_NumRef = componentFlatList[ii].m_NumRef;
                    componentFlatList[jj].m_Unit = thisRef.m_Unit;
                    componentFlatList[jj].m_IsNew = false;
                    componentFlatList[jj].m_Flag = 1;
                    break;
                }
            }
        }

        else
        {
            /* search for others units of this component.
            * we search for others parts that have the same value and the same
            * reference prefix (ref without ref number)
            */
            for( Unit = 1; Unit <= NumberOfUnits; Unit++ )
            {
                if( componentFlatList[ii].m_Unit == Unit )
                    continue;

                int found = FindUnit( ii, Unit );

                if( found >= 0 )
                    continue; // this unit exists for this reference (unit already annotated)

                // Search a component to annotate ( same prefix, same value, not annotated)
                for( unsigned jj = ii + 1; jj < componentFlatList.size(); jj++ )
                {
                    if( componentFlatList[jj].m_Flag )    // already tested
                        continue;

                    if( componentFlatList[ii].CompareRef( componentFlatList[jj] ) != 0 )
                        continue;

                    if( componentFlatList[jj].CompareValue( componentFlatList[ii] ) != 0 )
                        continue;

                    if( componentFlatList[jj].CompareLibName( componentFlatList[ii] ) != 0 )
                        continue;

                    if( !componentFlatList[jj].m_IsNew )
                        continue;

                    // Component without reference number found, annotate it if possible
                    if( !componentFlatList[jj].IsUnitsLocked()
                        || ( componentFlatList[jj].m_Unit == Unit ) )
                    {
                        componentFlatList[jj].m_NumRef = componentFlatList[ii].m_NumRef;
                        componentFlatList[jj].m_Unit   = Unit;
                        componentFlatList[jj].m_Flag   = 1;
                        componentFlatList[jj].m_IsNew  = false;
                        break;
                    }
                }
            }
        }
    }
void SCH_REFERENCE_LIST::Annotate( bool aUseSheetNum, int aSheetIntervalId  )
{
    if ( componentFlatList.size() == 0 )
        return;

    int LastReferenceNumber = 0;
    int NumberOfUnits, Unit;

    /* Components with an invisible reference (power...) always are re-annotated. */
    ResetHiddenReferences();

    /* calculate index of the first component with the same reference prefix
     * than the current component.  All components having the same reference
     * prefix will receive a reference number with consecutive values:
     * IC .. will be set to IC4, IC4, IC5 ...
     */
    unsigned first = 0;

    /* calculate the last used number for this reference prefix: */
#ifdef USE_OLD_ALGO
    int minRefId = 0;

    // when using sheet number, ensure ref number >= sheet number* aSheetIntervalId
    if( aUseSheetNum )
        minRefId = componentFlatList[first].m_SheetNum * aSheetIntervalId;

    LastReferenceNumber = GetLastReference( first, minRefId );
#else
    int minRefId = 1;

    // when using sheet number, ensure ref number >= sheet number* aSheetIntervalId
    if( aUseSheetNum )
        minRefId = componentFlatList[first].m_SheetNum * aSheetIntervalId + 1;

    // This is the list of all Id already in use for a given reference prefix.
    // Will be refilled for each new reference prefix.
    std::vector<int>idList;
    GetRefsInUse( first, idList, minRefId );
#endif
    for( unsigned ii = 0; ii < componentFlatList.size(); ii++ )
    {
        if( componentFlatList[ii].m_Flag )
            continue;

        if(  ( componentFlatList[first].CompareRef( componentFlatList[ii] ) != 0 )
          || ( aUseSheetNum && ( componentFlatList[first].m_SheetNum != componentFlatList[ii].m_SheetNum ) )  )
        {
            /* New reference found: we need a new ref number for this reference */
            first = ii;
#ifdef USE_OLD_ALGO
            minRefId = 0;

            // when using sheet number, ensure ref number >= sheet number* aSheetIntervalId
            if( aUseSheetNum )
                minRefId = componentFlatList[ii].m_SheetNum * aSheetIntervalId;

            LastReferenceNumber = componentFlatList.GetLastReference( ii, minRefId );
#else
            minRefId = 1;

            // when using sheet number, ensure ref number >= sheet number* aSheetIntervalId
            if( aUseSheetNum )
                minRefId = componentFlatList[ii].m_SheetNum * aSheetIntervalId + 1;

            GetRefsInUse( first, idList, minRefId );
#endif
        }

        // Annotation of one part per package components (trivial case).
        if( componentFlatList[ii].GetLibComponent()->GetPartCount() <= 1 )
        {
            if( componentFlatList[ii].m_IsNew )
            {
#ifdef USE_OLD_ALGO
                LastReferenceNumber++;
#else
                LastReferenceNumber = CreateFirstFreeRefId( idList, minRefId );
#endif
                componentFlatList[ii].m_NumRef = LastReferenceNumber;
            }

            componentFlatList[ii].m_Unit  = 1;
            componentFlatList[ii].m_Flag  = 1;
            componentFlatList[ii].m_IsNew = false;
            continue;
        }

        /* Annotation of multi-part components ( n parts per package ) (complex case) */
        NumberOfUnits = componentFlatList[ii].GetLibComponent()->GetPartCount();

        if( componentFlatList[ii].m_IsNew )
        {
#ifdef USE_OLD_ALGO
            LastReferenceNumber++;
#else
            LastReferenceNumber = CreateFirstFreeRefId( idList, minRefId );
#endif
            componentFlatList[ii].m_NumRef = LastReferenceNumber;

            if( !componentFlatList[ii].IsPartsLocked() )
                componentFlatList[ii].m_Unit = 1;

            componentFlatList[ii].m_Flag = 1;
        }

        /* search for others units of this component.
         * we search for others parts that have the same value and the same
         * reference prefix (ref without ref number)
         */
        for( Unit = 1; Unit <= NumberOfUnits; Unit++ )
        {
            if( componentFlatList[ii].m_Unit == Unit )
                continue;

            int found = FindUnit( ii, Unit );

            if( found >= 0 )
                continue; /* this unit exists for this reference (unit already annotated) */

            /* Search a component to annotate ( same prefix, same value, not annotated) */
            for( unsigned jj = ii + 1; jj < componentFlatList.size(); jj++ )
            {
                if( componentFlatList[jj].m_Flag )    // already tested
                    continue;

                if( componentFlatList[ii].CompareRef( componentFlatList[jj] ) != 0 )
                    continue;

                if( componentFlatList[jj].CompareValue( componentFlatList[ii] ) != 0 )
                    continue;

                if( componentFlatList[jj].CompareLibName( componentFlatList[ii] ) != 0 )
                    continue;

                if( !componentFlatList[jj].m_IsNew )
                    continue;

                /* Component without reference number found, annotate it if possible */
                if( !componentFlatList[jj].IsPartsLocked()
                    || ( componentFlatList[jj].m_Unit == Unit ) )
                {
                    componentFlatList[jj].m_NumRef = componentFlatList[ii].m_NumRef;
                    componentFlatList[jj].m_Unit   = Unit;
                    componentFlatList[jj].m_Flag   = 1;
                    componentFlatList[jj].m_IsNew  = false;
                    break;
                }
            }
        }
    }
}