//-----------------------------------------------------------------------------
// File: XbRandName.cpp
//
// Desc: Generates a random and somewhat readable name. Useful for fake
//       player names, session names, etc.
//
// Hist: 10.10.01 - New for Nov release
//       11.07.02 - Changed to simpler, non-class interface
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//-----------------------------------------------------------------------------
#include "XbRandName.h"




//-----------------------------------------------------------------------------
// Name: GetRand()
// Desc: Generates a pseudo random number. This implementation is based on
//       the portable implementation defined in the C Standard. We use
//       this instead of CRT rand() to avoid interfering with the random
//       number sequence generated by rand().
//
//       Based on "Random Number Generators; Good ones are hard to find", 
//       Stephen K. Park and Keith W. Miller, Communications of the ACM,
//       October 1988, Volume 31, Number 10, page 1192-1201.
//-----------------------------------------------------------------------------
static DWORD GetRand()
{
    // These values based on original RNG article (see above)
    const LONG MODULUS    = 2147483647L;
    const LONG MULTIPLIER = 48271L;
    const LONG Q          = MODULUS / MULTIPLIER;
    const LONG R          = MODULUS % MULTIPLIER;

    static LONG nValue = 0;
    if( 0 == nValue )
        nValue = (LONG)(GetTickCount() % MODULUS);

    nValue = ( MULTIPLIER * ( nValue % Q ) ) - ( R * ( nValue / Q ) );
    if( nValue <= 0 )
        nValue += MODULUS;

    return (DWORD)nValue;
}




//-----------------------------------------------------------------------------
// Name: GetVowel()
// Desc: Return a random vowel or vowel group string
//-----------------------------------------------------------------------------
static WCHAR* GetVowel()
{
    WCHAR* strVowelGroup[] =
    {
        L"a",  L"e",  L"i",  L"o",  L"u",  L"a",  L"e",  L"i",  L"o",  L"u",
        L"ai", L"au", L"ay", L"ea", L"ee", L"ie", L"oa", L"oi", L"oo", L"ou"
    };
    return strVowelGroup[ GetRand() % 20 ];
}




//-----------------------------------------------------------------------------
// Name: GetLeadingConsonant()
// Desc: Return a random consonant or consonant group string
//-----------------------------------------------------------------------------
static WCHAR* GetLeadingConsonant()
{
    if( ( GetRand() % 2 == 0 ) )
    {
        WCHAR* strConsonants[] = 
        {
            L"b", L"c", L"d", L"f", L"g", L"h", L"j", L"k", L"l", L"m", L"n", 
            L"p", L"q", L"r", L"s", L"t", L"v", L"w", L"x", L"y", L"z"
        };
        return strConsonants[ GetRand() % 21 ];
    }
    else
    {
        WCHAR* strLeadConGroup[32] = 
        {
            L"bl", L"br", L"cl", L"cr", L"dr", L"fl", L"fr", L"gh", L"gl", L"gn", 
            L"gr", L"kl", L"kn", L"kr", L"ph", L"pl", L"pr", L"ps", L"qu", L"sc", 
            L"sk", L"sl", L"sn", L"sp", L"st", L"sw", L"th", L"tr", L"vh", L"vl", 
            L"wh", L"zh"
        };
        return strLeadConGroup[ GetRand() % 32 ];
    }
}




//-----------------------------------------------------------------------------
// Name: GetTrailingConsonant()
// Desc: Return a random consonant or consonant group string
//-----------------------------------------------------------------------------
static WCHAR* GetTrailingConsonant()
{
    if( ( GetRand() % 2 == 0 ) )
    {
        WCHAR* strConsonants[] = 
        {
            L"b", L"c", L"d", L"f", L"g", L"h", L"j", L"k", L"l", L"m", L"n", 
            L"p", L"q", L"r", L"s", L"t", L"v", L"w", L"x", L"y", L"z"
        };
        return strConsonants[ GetRand() % 21 ];
    }
    else
    {
        WCHAR* strTrailConGroup[32] = 
        {
            L"rt", L"ng", L"bs", L"cs", L"ds", L"gs", L"hs", L"sh", L"ss", L"ks",
            L"ms", L"ns", L"ps", L"rs", L"ts", L"gh", L"ph", L"sk", L"st", L"tt",
            L"nd", L"nk", L"nt", L"nx", L"pp", L"rd", L"rg", L"rk", L"rn", L"rv",
            L"th", L"ys"
        };
        return strTrailConGroup[ GetRand() % 32 ];
    }
}




//-----------------------------------------------------------------------------
// Name: XBRandName_GetRandomName()
// Desc: Generate a random name
//-----------------------------------------------------------------------------
VOID XBRandName_GetRandomName( WCHAR* strName, DWORD dwSize )
{
    // Name consists of two to five parts.
    //
    // 1) consonant or consonant group (e.g. th, qu, st) [optional]
    // 2) vowel or vowel group (e.g. ea, ee, au)
    // 3) consonant or consonant group
    // 4) vowel or vowel group [optional]
    // 5) consonant or consonant group [optional]

    *strName = L'\0';
    if( ( GetRand() % 2 == 0 ) )
        lstrcatW( strName, GetLeadingConsonant() );
    lstrcatW( strName, GetVowel() );
    lstrcatW( strName, GetTrailingConsonant() );
    if( ( GetRand() % 2 == 0 ) )
    {
        lstrcatW( strName, GetVowel() );
        if( ( GetRand() % 2 == 0 ) )
            lstrcatW( strName, GetTrailingConsonant() );
    }

    // Make the first letter upper case
    *strName = towupper( *strName );
}




