//*********************************************************************
//*                  Microsoft Windows                               **
//*            Copyright(c) Microsoft Corp., 1999                    **
//*********************************************************************
//
//  LANGUAGE.CPP - Header for the implementation of CLanguage
//
//  HISTORY:
//
//  1/27/99 a-jaswed Created.
//

#include "precomp.h"
#include "msobmain.h"
#include "language.h"
#include "appdefs.h"
#include "dispids.h"

#define DEFAULT_BUFFER_SIZE BYTES_REQUIRED_BY_CCH(2048)

DISPATCHLIST LanguageExternalInterface[] =
{
    {L"get_NumOfRegions",         DISPID_GETNUMOFREGIONS         },
    {L"get_RegionName",           DISPID_GETREGIONNAME           },
    {L"get_RegionIndex",          DISPID_GETREGIONINDEX          },
    {L"set_RegionIndex",          DISPID_SETREGIONINDEX          },
    {L"get_NumOfLangs",           DISPID_GETNUMOFLANGS           },
    {L"get_LangName",             DISPID_GETLANGNAME             },
    {L"get_LangIndex",            DISPID_GETLANGINDEX            },
    {L"set_LangIndex",            DISPID_SETLANGINDEX            },
    {L"get_NumOfKeyboardLayouts", DISPID_GETNUMOFKEYLAYOUTS      },
    {L"get_KeyboardLayoutName",   DISPID_GETKEYNAME              },
    {L"get_KeyboardLayoutIndex",  DISPID_GETKEYLAYOUTINDEX       },
    {L"set_KeyboardLayoutIndex",  DISPID_SETKEYLAYOUTINDEX       },
    {L"get_RebootState",          DISPID_LANGUAGE_GETREBOOTSTATE },
    {L"SaveSettings",             DISPID_LANGUAGE_SAVESETTINGS   },
    {L"get_PhoneCountries",       DISPID_GETPHONECOUNTRIES       }
};


//+---------------------------------------------------------------------------
//
//  Function:   CompareNameLookUpElements()
//
//  Synopsis:   Function to compare names used by sort
//
//+---------------------------------------------------------------------------
int __cdecl CompareNameLookUpElements(const void *e1, const void *e2)
{

    LPNAMELOOKUPELEMENT pCUE1 = (LPNAMELOOKUPELEMENT)e1;
    LPNAMELOOKUPELEMENT pCUE2 = (LPNAMELOOKUPELEMENT)e2;

    return CompareString(LOCALE_USER_DEFAULT, 0,
        pCUE1->pszName,
        -1,
        pCUE2->pszName,
        -1) - 2;
}

/////////////////////////////////////////////////////////////
// CLanguage::CLanguage
CLanguage::CLanguage()
{
    WCHAR szINIPath[MAX_PATH] = L"";
    WCHAR Answer[MAX_PATH];


    // Init member vars
    m_cRef                   = 0;
    m_lRebootState           = LANGUAGE_REBOOT_NEVER;

    m_poliRegions            = NULL;
    m_lRegionTotal           = 0;
    m_lRegionDefault         = -1;

    m_poliLangs              = NULL;
    m_lLangTotal             = 0;
    m_lLangDefault           = -1;

    m_poliKeyboards          = NULL;
    m_lKeyboardLayoutTotal   = 0;
    m_lKeyboardLayoutDefault = -1;

    GetCanonicalizedPath(szINIPath, INI_SETTINGS_FILENAME);

    m_DefaultRegion = GetPrivateProfileInt(
        OPTIONS_SECTION,
        DEFAULT_REGION,
        0,
        szINIPath
        );

    GetPrivateProfileString(
        OPTIONS_SECTION,
        DEFAULT_LANGUAGE,
        L"",
        Answer,
        MAX_PATH,
        szINIPath
        );
    m_DefaultLanguage = wcstoul(Answer, NULL, 16);

    GetPrivateProfileString(
        OPTIONS_SECTION,
        DEFAULT_KEYBOARD,
        L"",
        Answer,
        MAX_PATH,
        szINIPath
        );
    m_DefaultKeyboard = wcstoul(Answer, NULL, 16);

    SetupGetGeoOptions(
        m_DefaultRegion,
        &m_poliRegions,
        (LPDWORD) &m_lRegionTotal,
        (LPDWORD) &m_lRegionDefault
        );
    MYASSERT( m_poliRegions );

    SetupGetLocaleOptions(
        m_DefaultLanguage,
        &m_poliLangs,
        (LPDWORD) &m_lLangTotal,
        (LPDWORD) &m_lLangDefault
        );
    MYASSERT( m_poliLangs );

    SetupGetKeyboardOptions(
        m_DefaultKeyboard,
        &m_poliKeyboards,
        (LPDWORD) &m_lKeyboardLayoutTotal,
        (LPDWORD) &m_lKeyboardLayoutDefault);
    MYASSERT( m_poliKeyboards );

    // The current index should be the defaults.
    //
    m_lRegionIndex           = m_lRegionDefault;
    m_lLangIndex             = m_lLangDefault;
    m_lKeyboardLayoutIndex   = m_lKeyboardLayoutDefault;
}

/////////////////////////////////////////////////////////////
// CLanguage::~CLanguage
CLanguage::~CLanguage()
{
    if ( m_poliRegions )
        SetupDestroyLanguageList( m_poliRegions, m_lRegionTotal );
    if ( m_poliLangs )
        SetupDestroyLanguageList( m_poliLangs, m_lLangTotal );
    if ( m_poliKeyboards )
        SetupDestroyLanguageList( m_poliKeyboards, m_lKeyboardLayoutTotal );

    MYASSERT(m_cRef == 0);
}

HRESULT CLanguage::get_NumOfRegions(long* plVal)
{
    *plVal = m_lRegionTotal;

    return S_OK;
}

HRESULT CLanguage::get_NumOfKeyboardLayouts(long* plVal)
{
    *plVal = m_lKeyboardLayoutTotal;

    return S_OK;
}

HRESULT CLanguage::get_RegionName(long lIndex, BSTR* pbstrVal)
{

    if ( lIndex >= m_lRegionTotal )
        return E_FAIL;

    // *pbstrVal = SysAllocString(m_pRegionNameLookUp[lIndex].pszName);
    *pbstrVal = SysAllocString( m_poliRegions[lIndex].Name );

    return S_OK;
}

HRESULT CLanguage::get_KeyboardLayoutName(long lIndex, BSTR* pbstrVal)
{

    if ( lIndex >= m_lKeyboardLayoutTotal )
        return E_FAIL;

    // *pbstrVal = SysAllocString(m_pKeyboardNameLookUp[lIndex].pszName);
    *pbstrVal = SysAllocString( m_poliKeyboards[lIndex].Name );

    return S_OK;
}

HRESULT CLanguage::get_RebootState(long* plVal)
{
    *plVal = m_lRebootState;

    return S_OK;
}

HRESULT CLanguage::SaveSettings()
{
    // Only save the settings if they changed.
    //
    if ( ( m_lRegionIndex >= 0 ) &&
         ( m_lLangIndex >= 0 ) &&
         ( m_lKeyboardLayoutIndex >= 0 ) &&
         m_poliRegions &&
         m_poliLangs &&
         m_poliKeyboards
         )
         //( m_lRegionDefault != m_lRegionIndex ) ||
         //( m_lKeyboardLayoutDefault != m_lKeyboardLayoutIndex ) )
    {
        if (SetupSetIntlOptions(
            m_poliRegions[m_lRegionIndex].Id,
            m_poliLangs[m_lLangIndex].Id,
            m_poliKeyboards[m_lKeyboardLayoutIndex].Id
            ))
        {
            // BUGBUG: The return value from SetIntlOptions on Win9x is
            // interpreted as a reboot state.  How do we determine reboot state
            // on Whistler?
            // Now the defaults are what is currently saved.
            //
            m_lRegionDefault = m_lRegionIndex;
            m_lLangDefault = m_lLangIndex;
            m_lKeyboardLayoutDefault = m_lKeyboardLayoutIndex;
        }

    }

    return S_OK;
}



////////////////////////////////////////////////
////////////////////////////////////////////////
//// GET / SET :: RegionIndex
////
HRESULT CLanguage::get_RegionIndex(long* plVal)
{
    *plVal = m_lRegionIndex;

    return S_OK;
}

HRESULT CLanguage::set_RegionIndex(long lVal)
{
    m_lRegionIndex = lVal;
    // m_lRegionIndex = m_pRegionNameLookUp[lVal].nIndex;

    return S_OK;
}

////////////////////////////////////////////////
////////////////////////////////////////////////
//// GET / SET :: KeyboardLayoutIndex
////
HRESULT CLanguage::get_KeyboardLayoutIndex(long* plVal)
{
    *plVal = m_lKeyboardLayoutIndex;

    return S_OK;
}

HRESULT CLanguage::set_KeyboardLayoutIndex(long lVal)
{
    m_lKeyboardLayoutIndex = lVal;
    // m_lKeyboardLayoutIndex = m_pKeyboardNameLookUp[lVal].nIndex;;

    return S_OK;
}

/////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////
/////// IUnknown implementation
///////
///////

/////////////////////////////////////////////////////////////
// CLanguage::QueryInterface
STDMETHODIMP CLanguage::QueryInterface(REFIID riid, LPVOID* ppvObj)
{
    // must set out pointer parameters to NULL
    *ppvObj = NULL;

    if ( riid == IID_IUnknown)
    {
        AddRef();
        *ppvObj = (IUnknown*)this;
        return ResultFromScode(S_OK);
    }

    if (riid == IID_IDispatch)
    {
        AddRef();
        *ppvObj = (IDispatch*)this;
        return ResultFromScode(S_OK);
    }

    // Not a supported interface
    return ResultFromScode(E_NOINTERFACE);
}

/////////////////////////////////////////////////////////////
// CLanguage::AddRef
STDMETHODIMP_(ULONG) CLanguage::AddRef()
{
    return ++m_cRef;
}

/////////////////////////////////////////////////////////////
// CLanguage::Release
STDMETHODIMP_(ULONG) CLanguage::Release()
{
    return --m_cRef;
}

/////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////
/////// IDispatch implementation
///////
///////

/////////////////////////////////////////////////////////////
// CLanguage::GetTypeInfo
STDMETHODIMP CLanguage::GetTypeInfo(UINT, LCID, ITypeInfo**)
{
    return E_NOTIMPL;
}

/////////////////////////////////////////////////////////////
// CLanguage::GetTypeInfoCount
STDMETHODIMP CLanguage::GetTypeInfoCount(UINT* pcInfo)
{
    return E_NOTIMPL;
}


/////////////////////////////////////////////////////////////
// CLanguage::GetIDsOfNames
STDMETHODIMP CLanguage::GetIDsOfNames(REFIID    riid,
                                       OLECHAR** rgszNames,
                                       UINT      cNames,
                                       LCID      lcid,
                                       DISPID*   rgDispId)
{

    HRESULT hr  = DISP_E_UNKNOWNNAME;
    rgDispId[0] = DISPID_UNKNOWN;

    for (int iX = 0; iX < sizeof(LanguageExternalInterface)/sizeof(DISPATCHLIST); iX ++)
    {
        if(lstrcmp(LanguageExternalInterface[iX].szName, rgszNames[0]) == 0)
        {
            rgDispId[0] = LanguageExternalInterface[iX].dwDispID;
            hr = NOERROR;
            break;
        }
    }

    // Set the disid's for the parameters
    if (cNames > 1)
    {
        // Set a DISPID for function parameters
        for (UINT i = 1; i < cNames ; i++)
            rgDispId[i] = DISPID_UNKNOWN;
    }

    return hr;
}

/////////////////////////////////////////////////////////////
// CLanguage::Invoke
HRESULT CLanguage::Invoke
(
    DISPID      dispidMember,
    REFIID      riid,
    LCID        lcid,
    WORD        wFlags,
    DISPPARAMS* pdispparams,
    VARIANT*    pvarResult,
    EXCEPINFO*  pexcepinfo,
    UINT*       puArgErr
)
{
    HRESULT hr = S_OK;

    switch(dispidMember)
    {
        case DISPID_GETNUMOFREGIONS:
        {

            TRACE(L"DISPID_GETNUMOFREGIONS\n");

            if(pvarResult)
            {
                VariantInit(pvarResult);
                V_VT(pvarResult) = VT_I4;

                get_NumOfRegions(&(pvarResult->lVal));
            }
            break;
        }

        case DISPID_GETREGIONINDEX:
        {

            TRACE(L"DISPID_GETREGIONINDEX\n");

            if(pvarResult)
            {
                VariantInit(pvarResult);
                V_VT(pvarResult) = VT_I4;

                get_RegionIndex(&(pvarResult->lVal));
            }
            break;
        }

        case DISPID_SETREGIONINDEX:
        {

            TRACE(L"DISPID_SETREGIONINDEX\n");

            if(pdispparams && &pdispparams[0].rgvarg[0])
                set_RegionIndex(pdispparams[0].rgvarg[0].lVal);
            break;
        }

        case DISPID_GETREGIONNAME:
        {

            TRACE(L"DISPID_GETREGIONNAME\n");

            if(pvarResult)
            {
                VariantInit(pvarResult);
                V_VT(pvarResult) = VT_BSTR;

                if(pdispparams && &pdispparams[0].rgvarg[0])
                    get_RegionName(pdispparams[0].rgvarg[0].lVal, &(pvarResult->bstrVal));
            }
            break;
        }

    // BUGBUG: Need to Lang processing to syssetup.dll
        case DISPID_GETNUMOFLANGS:
        {

            TRACE(L"DISPID_GETNUMOFFLANGS\n");

            if(pvarResult)
            {
                VariantInit(pvarResult);
                V_VT(pvarResult) = VT_I4;

                pvarResult->lVal = m_lLangTotal;
            }
            break;
        }

        case DISPID_GETLANGINDEX:
        {

            TRACE(L"DISPID_GETLANGINDEX\n");

            if(pvarResult)
            {
                VariantInit(pvarResult);
                V_VT(pvarResult) = VT_I4;

                pvarResult->lVal =  m_lLangIndex;
            }
            break;
        }

        case DISPID_SETLANGINDEX:
        {

            TRACE(L"DISPID_SETLANGINDEX\n");

            if(pdispparams && &pdispparams[0].rgvarg[0]) {
               m_lLangIndex = pdispparams[0].rgvarg[0].lVal;
            }
            break;
        }

        case DISPID_GETLANGNAME:
        {

            TRACE(L"DISPID_GETLANGNAME\n");

            if(pvarResult)
            {
                VariantInit(pvarResult);
                V_VT(pvarResult) = VT_BSTR;

                if(pdispparams && &pdispparams[0].rgvarg[0]) {

                    long lIndex = pdispparams[0].rgvarg[0].lVal;

                    // BUGBUG: What if lIndex < 0??
                    if ( lIndex >= m_lLangTotal )
                        return E_FAIL;

                    pvarResult->bstrVal = SysAllocString( m_poliLangs[lIndex].Name );
                }
            }
            break;
        }


         case DISPID_GETNUMOFKEYLAYOUTS:
        {

            TRACE(L"DISPID_GETNUMOFKEYLAYOUTS\n");

            if(pvarResult)
            {
                VariantInit(pvarResult);
                V_VT(pvarResult) = VT_I4;

                get_NumOfKeyboardLayouts(&(pvarResult->lVal));
            }
            break;
        }

        case DISPID_GETKEYLAYOUTINDEX:
        {

            TRACE(L"DISPID_GETKEYLAYOUTINDEX\n");

            if(pvarResult)
            {
                VariantInit(pvarResult);
                V_VT(pvarResult) = VT_I4;

                get_KeyboardLayoutIndex(&(pvarResult->lVal));
            }
            break;
        }

        case DISPID_SETKEYLAYOUTINDEX:
        {

            TRACE(L"DISPID_SETKEYLAYOUTINDEX\n");

            if(pdispparams && &pdispparams[0].rgvarg[0])
                set_KeyboardLayoutIndex(pdispparams[0].rgvarg[0].lVal);
            break;
        }

        case DISPID_GETKEYNAME:
        {

            TRACE(L"DISPID_GETKEYNAME\n");

            if(pvarResult)
            {
                VariantInit(pvarResult);
                V_VT(pvarResult) = VT_BSTR;

                if(pdispparams && &pdispparams[0].rgvarg[0])
                    get_KeyboardLayoutName(pdispparams[0].rgvarg[0].lVal, &(pvarResult->bstrVal));
            }
            break;
        }

        case DISPID_LANGUAGE_GETREBOOTSTATE:
        {

            TRACE(L"DISPID_LANGUAGE_GETREBOOTSTATE\n");

            if(pvarResult)
            {
                VariantInit(pvarResult);
                V_VT(pvarResult) = VT_I4;

                get_RebootState(&(pvarResult->lVal));
            }
            break;
        }

        case DISPID_LANGUAGE_SAVESETTINGS:
        {

            TRACE(L"DISPID_LANGUAGE_SAVESETTINGS\n");

            SaveSettings();
            break;
        }

        case DISPID_GETPHONECOUNTRIES:
        {

            TRACE(L"DISPID_GETPHONECOUNTRIES");

            if(pvarResult)
            {
                WCHAR   PhoneInfName[MAX_PATH];

                GetOOBEMUIPath( PhoneInfName );
                lstrcat( PhoneInfName, L"\\phone.inf" );

                VariantInit(pvarResult);
                V_VT(pvarResult) = VT_BSTR;

                pvarResult->bstrVal = SysAllocString(
                    SetupReadPhoneList( PhoneInfName ) );
            }
            break;
        }

        default:
        {
            hr = DISP_E_MEMBERNOTFOUND;
            break;
        }
    }
    return hr;
}