static bool getNumberingOffset( const std::string& str,
        DIALOG_CREATE_ARRAY::ARRAY_NUMBERING_TYPE_T type,
        int& offsetToFill )
{
    const std::string alphabet = alphabetFromNumberingScheme( type );

    wxASSERT_MSG( !alphabet.empty(), wxString(
                    "Unable to determine alphabet for numbering scheme: " ) << type );

    int offset = 0;
    const int radix = alphabet.length();

    for( unsigned i = 0; i < str.length(); i++ )
    {
        int chIndex = alphabet.find( str[i], 0 );

        if( chIndex == wxNOT_FOUND )
            return false;

        const bool start0 = schemeNonUnitColsStartAt0( type );

        // eg "AA" is actually index 27, not 26
        if( start0 && i < str.length() - 1 )
            chIndex++;

        offset  *= radix;
        offset  += chIndex;
    }

    offsetToFill = offset;
    return true;
}
std::string DIALOG_CREATE_ARRAY::ARRAY_OPTIONS::getCoordinateNumber( int n,
        ARRAY_NUMBERING_TYPE_T type )
{
    std::string itemNum;
    const std::string& alphabet = alphabetFromNumberingScheme( type );

    if( !alphabet.empty() )
    {
        const bool nonUnitColsStartAt0 = schemeNonUnitColsStartAt0( type );

        bool    firstRound = true;
        int     radix = alphabet.length();

        do {
            int modN = n % radix;

            if( nonUnitColsStartAt0 && !firstRound )
                modN--;    // Start the "tens/hundreds/etc column" at "Ax", not "Bx"

            itemNum.insert( 0, 1, alphabet[modN] );

            n /= radix;
            firstRound = false;
        } while( n );
    }

    return itemNum;
}
/**
 * Validates and saves (if valid) the type and offset of an array axis numbering
 *
 * @param offsetEntry the entry of the offset (text)
 * @param typeEntry the entry of the axis nmbering scheme (choice)
 * @param type the destination of the type if valid
 * @param offset the destination of the offset if valid
 * @param errors error string accumulator
 * @return if all valid
 */
static bool validateNumberingTypeAndOffset( const wxTextCtrl& offsetEntry,
                                            const wxChoice& typeEntry,
                                            DIALOG_CREATE_ARRAY::ARRAY_NUMBERING_TYPE_T& type,
                                            int& offset,
                                            wxArrayString& errors )
{
    const int typeVal = typeEntry.GetSelection();
    // mind undefined casts to enums (should not be able to happen)
    bool ok = typeVal <= DIALOG_CREATE_ARRAY::NUMBERING_TYPE_MAX;

    if( ok )
    {
        type = (DIALOG_CREATE_ARRAY::ARRAY_NUMBERING_TYPE_T) typeVal;
    }
    else
    {
        wxString err;
        err.Printf( _("Unrecognised numbering scheme: %d"), typeVal );
        errors.Add( err );
        // we can't proceed - we don't know the numbering type
        return false;
    }

    const wxString text = offsetEntry.GetValue();
    ok = getNumberingOffset( text, type, offset );

    if( !ok )
    {
        const wxString& alphabet = alphabetFromNumberingScheme( type );

        wxString err;
        err.Printf( _( "Could not determine numbering start from \"%s\": "
                       "expected value consistent with alphabet \"%s\"" ),
                    text, alphabet );
        errors.Add(err);
    }

    return ok;
}