// PhoneNoDlg.cpp : implementation file
//

#include "stdafx.h"
#include "PhoneNoDlg.h"
#include "MyTapi.h"     // My TAPI wrappers

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

/////////////////////////////////////////////////////////////////////////////
// CPhoneNoDlg dialog

#define INVALID_LINE ((DWORD)-1)

CPhoneNoDlg::CPhoneNoDlg(CWnd* pParent /*=NULL*/)
	: CDialog(CPhoneNoDlg::IDD, pParent),
    m_rgbShouldShowLines(0),
    m_nLineID(INVALID_LINE),
    m_nAddressID(0),
    m_nLines(0),
    m_hLineApp(0),
    m_aApiVersions(0)
{
	//{{AFX_DATA_INIT(CPhoneNoDlg)
	m_sAreaCode = _T("");
	m_sDialString = _T("");
	m_sPhoneNo = _T("");
	m_bBuildCanonical = FALSE;
	//}}AFX_DATA_INIT
}

BOOL CPhoneNoDlg::ShouldShowLine(DWORD nLineID)
{
    if( m_rgbShouldShowLines )
    {
        return m_rgbShouldShowLines[nLineID];
    }
    else
    {
        return TRUE;
    }
}

void CPhoneNoDlg::DoDataExchange(CDataExchange* pDX)
{
	CDialog::DoDataExchange(pDX);
	//{{AFX_DATA_MAP(CPhoneNoDlg)
	DDX_Control(pDX, IDC_ADDRESSES, m_listAddresses);
	DDX_Control(pDX, IDC_CONFIG_DIALOG, m_btnConfigDialog);
	DDX_Control(pDX, IDC_TRANSLATE_DIALOG, m_btnTranslateDialog);
	DDX_Control(pDX, IDC_LINE_ICON, m_iconLine);
	DDX_Control(pDX, IDC_AREA_CODE, m_editAreaCode);
	DDX_Control(pDX, IDOK, m_btnOK);
	DDX_Control(pDX, IDC_LINES, m_listLines);
	DDX_Control(pDX, IDC_LOCATIONS, m_listLocations);
	DDX_Control(pDX, IDC_COUNTRY_CODE, m_listCountryCodes);
	DDX_Text(pDX, IDC_AREA_CODE, m_sAreaCode);
	DDX_Check(pDX, IDC_BUILD_CANONICAL, m_bBuildCanonical);
	DDX_Text(pDX, IDC_DIAL_STRING, m_sDialString);
	DDX_Text(pDX, IDC_PHONE_NO, m_sPhoneNo);
	//}}AFX_DATA_MAP
}

BEGIN_MESSAGE_MAP(CPhoneNoDlg, CDialog)
	//{{AFX_MSG_MAP(CPhoneNoDlg)
	ON_CBN_SELCHANGE(IDC_LOCATIONS, OnSelchangeLocations)
	ON_EN_CHANGE(IDC_AREA_CODE, OnChangeAreaCode)
	ON_BN_CLICKED(IDC_BUILD_CANONICAL, OnChangeBuildCanonical)
	ON_EN_CHANGE(IDC_PHONE_NO, OnChangePhoneNo)
	ON_CBN_SELCHANGE(IDC_COUNTRY_CODE, OnSelchangeCountryCode)
	ON_CBN_SELCHANGE(IDC_LINES, OnSelchangeLines)
	ON_BN_CLICKED(IDC_CONFIG_DIALOG, OnConfigDialog)
	ON_BN_CLICKED(IDC_TRANSLATE_DIALOG, OnTranslateDialog)
	//}}AFX_MSG_MAP
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CPhoneNoDlg message handlers

BOOL CPhoneNoDlg::OnInitDialog() 
{
    // Set initial dialog values based on input phone no.
    // (before the values are shown in the dialog)
    m_sAreaCode = m_pno.GetAreaCode();
    m_sPhoneNo = m_pno.GetPhoneNo();

    // Check for canonical setting
    LPCSTR  pszCountryCode = m_pno.GetCountryCode();

    // Assume we're going to have enough info to fill out
    // the canonical format if we have a country code or
    // we don't yet have anything (as we'll set defaults)
    if( pszCountryCode ||
        /*!pszCountryCode && */ m_sAreaCode.IsEmpty() && m_sPhoneNo.IsEmpty() )
    {
        m_bBuildCanonical = TRUE;
    }
    else
    {
        m_bBuildCanonical = FALSE;
    }

    // Set location defaults if necessary
    CtPhoneNo   pnoLocation;

    // Set the default area code if we don't have one and
    // both the country code and the phone no. aren't set
    // (because the area code is optional for canonical format)
    if( m_sAreaCode.IsEmpty() &&
        !(pszCountryCode && !m_sPhoneNo.IsEmpty()) )
    {
        m_sAreaCode = pnoLocation.GetAreaCode();
    }

    // Set the country code if we don't have one
    if( !pszCountryCode )
    {
        pszCountryCode = pnoLocation.GetCountryCode();
    }

    CDialog::OnInitDialog();

    // Populate the country code list
    PopulateCountryCodes(DWORD(::atol(pszCountryCode)));

    // Populate locations (also happens after the translate dialog)
    PopulateLocations();

    // Set default line to first shown line
    if( m_nLineID == INVALID_LINE )
    {
        for( DWORD nLineID = 0; nLineID < m_nLines; nLineID++ )
        {
            if( ShouldShowLine(nLineID) )
            {
                m_nLineID = nLineID;
                break;
            }
        }
    }

    // Populate lines list box
    PopulateLines();

    // Populate addresses list box
    PopulateAddresses();

    // Show initial line icon
    ShowLineIcon();

    // Update controls based on current data
    UpdateControls();    

    return TRUE;  // return TRUE unless you set the focus to a control
	              // EXCEPTION: OCX Property Pages should return FALSE
}

void CPhoneNoDlg::PopulateCountryCodes(DWORD nCountryCode)
{
    LPLINECOUNTRYLIST   plcl = 0;
    if( ::MyGetCountryList(TAPI_CURRENT_VERSION, 0, &plcl) == 0 )
    {
        for( DWORD i = 0; i < plcl->dwNumCountries; i++ )
        {
            CString sCountry;
            sCountry.Format("%s (%d)", ::MyGetCountryName(plcl, i), ::MyGetCountryCode(plcl, i));
            
            int nIndex = m_listCountryCodes.AddString(sCountry);
            m_listCountryCodes.SetItemData(nIndex, ::MyGetCountryCode(plcl, i));

            // Set the correct initial country
            if( ::MyGetCountryCode(plcl, i) == nCountryCode )
            {
                m_listCountryCodes.SetCurSel(nIndex);
                nCountryCode = 0;   // Don't pick another one
            }
        }
    }

    ::free(plcl);
}

void CPhoneNoDlg::PopulateLocations()
{
    m_listLocations.ResetContent();

    // Populate the locations list box
    LPLINETRANSLATECAPS ptc = 0;
    if( ::MyGetTranslateCaps(m_hLineApp, TAPI_CURRENT_VERSION, &ptc) == 0 )
    {
        for( DWORD i = 0; i < ptc->dwNumLocations; i++ )
        {
            int nIndex = m_listLocations.AddString(::MyGetLocationName(ptc, i));
            if( nIndex >= 0 )
            {
                m_listLocations.SetItemData(nIndex, ::MyGetPermanentLocationID(ptc, i));
                
                // Set the current location
                if( ::MyGetPermanentLocationID(ptc, i) == ptc->dwCurrentLocationID )
                {
                    m_listLocations.SetCurSel(nIndex);
                }
            }
        }
    }

    ::free(ptc);
}

void CPhoneNoDlg::PopulateLines()
{
    LPLINEDEVCAPS   pldc = 0;
    for( DWORD nLineID = 0; nLineID < m_nLines; nLineID++ )
    {
        if( ShouldShowLine(nLineID) &&
            ::MyGetLineDevCaps(m_hLineApp, m_aApiVersions[nLineID], nLineID, &pldc) == 0 )
        {
            CString sLine;
            sLine.Format("Line %d: %s", nLineID + 1, ::MyGetLineName(pldc));
            int nIndex = m_listLines.AddString(sLine);
            if( nIndex >= 0 )
            {
                m_listLines.SetItemData(nIndex, nLineID);

                if( nLineID == m_nLineID )
                {
                    m_listLines.SetCurSel(nIndex);
                }
            }
        }
    }

    ::free(pldc);
}

void CPhoneNoDlg::PopulateAddresses()
{
    m_listAddresses.ResetContent();

    if( m_nLineID != INVALID_LINE )
    {
        LPLINEDEVCAPS   pldc = 0;
        if( ::MyGetLineDevCaps(m_hLineApp, m_aApiVersions[m_nLineID], m_nLineID, &pldc) == 0 )
        {
            DWORD   nAddrs = pldc->dwNumAddresses;
            for( DWORD nAddressID = 0; nAddressID < nAddrs; nAddressID++ )
            {
                LPLINEADDRESSCAPS   pac = 0;
                if( ::MyGetAddressCaps(m_hLineApp, m_nLineID, nAddressID,
                                       m_aApiVersions[m_nLineID], &pac) == 0 )
                {
                    CString sAddress;
                    LPCSTR  pszAddressName = ::MyGetAddress(pac);
                    if( pszAddressName && *pszAddressName )
                    {
                        sAddress.Format("Address %d: %s", nAddressID + 1, pszAddressName);
                    }
                    else
                    {
                        sAddress.Format("Address %d", nAddressID + 1);
                    }

                    int nIndex = m_listAddresses.AddString(sAddress);
                    if( nIndex >= 0 )
                    {
                        m_listAddresses.SetItemData(nIndex, nAddressID);

                        if( nAddressID == m_nAddressID )
                        {
                            m_listAddresses.SetCurSel(nIndex);
                        }
                    }
                }

                ::free(pac);
            }
        }

        ::free(pldc);
    }
}

void CPhoneNoDlg::ShowLineIcon()
{
    HICON   hicon = 0;
    if( m_nLineID != INVALID_LINE )
    {
        ::lineGetIcon(m_nLineID, m_sDeviceClass, &hicon);
    }

    m_iconLine.SetIcon(hicon);
}

void CPhoneNoDlg::UpdateControls()
{
    if( UpdateData(TRUE) )
    {
        int     nCountryIndex = m_listCountryCodes.GetCurSel();
        DWORD   nCountryCode = (nCountryIndex >= 0 ? m_listCountryCodes.GetItemData(nCountryIndex) : 0);

        // Calculate phone number
        if( m_bBuildCanonical )
        {
            char    szCountryBuf[8];    // country codes size = 8
            m_pno.SetCountryCode(nCountryCode
                                 ? ::itoa(nCountryCode, szCountryBuf, 10)
                                 : 0);
            m_pno.SetAreaCode(m_sAreaCode);
            m_pno.SetPhoneNo(m_sPhoneNo);
        }
        else
        {
            m_pno.SetWholePhoneNo(m_sPhoneNo);
        }

        // Use phone no and line ID to translate phone number to show
        CString sDisplayable;
        LPCSTR  pszTranslatable;

        // Only map letters to digits in the US (where I know how)
        if( nCountryCode == 1 )
        {
            pszTranslatable = m_pno.GetTranslatable();
        }
        else
        {
            pszTranslatable = m_pno.GetTranslatable(0);
        }

        LPLINETRANSLATEOUTPUT   plto = 0;
        if( m_nLineID != INVALID_LINE &&
            pszTranslatable &&
            ::MyTranslateAddress(m_hLineApp, m_nLineID, m_aApiVersions[m_nLineID],
                                 pszTranslatable, &plto) == 0 )
        {
            sDisplayable = ::MyGetDisplayableString(plto);
        }
        else
        {
            sDisplayable = m_pno.GetDisplayable();
        }

        ::free(plto);

        // Cache translated phone no.
        m_sDialable = sDisplayable;

        // Show phone calculated phone no.
        SetDlgItemText(IDC_DIAL_STRING, sDisplayable);

        // Enable county code and area code fields based on check box
        m_listCountryCodes.EnableWindow(m_bBuildCanonical);
        m_editAreaCode.EnableWindow(m_bBuildCanonical);

        // Enable sub-dialogs if we've got a line
        m_btnTranslateDialog.EnableWindow(m_nLineID != INVALID_LINE);
        m_btnConfigDialog.EnableWindow(m_nLineID != INVALID_LINE);

        // Only allow OK if proper options are set
        // i.e. make sure a line is selected, that either
        // we're building a canonical phone no. and we can or
        // we're not building a canonical phone no. and we have a phone no.
        BOOL    bDataIsOK = FALSE;
        if( m_nLineID != INVALID_LINE &&
            (m_bBuildCanonical && m_pno.GetCanonical() ||
             !m_bBuildCanonical && m_pno.GetPhoneNo()) )
        {
            bDataIsOK = TRUE;
        }

        m_btnOK.EnableWindow(bDataIsOK);
    }
}

void CPhoneNoDlg::OnChangeAreaCode() 
{
	UpdateControls();
}

void CPhoneNoDlg::OnChangeBuildCanonical() 
{
	UpdateControls();
}

void CPhoneNoDlg::OnChangePhoneNo() 
{
	UpdateControls();
}

void CPhoneNoDlg::OnSelchangeCountryCode() 
{
	UpdateControls();
}

void CPhoneNoDlg::OnSelchangeLocations() 
{
    DWORD   nLocationID = m_listLocations.GetItemData(m_listLocations.GetCurSel());
    ::lineSetCurrentLocation(m_hLineApp, nLocationID);
	UpdateControls();
}

void CPhoneNoDlg::OnSelchangeLines() 
{
    // Cache line ID
    int     nLineIndex = m_listLines.GetCurSel();
    m_nLineID = (nLineIndex < 0 ? INVALID_LINE : m_listLines.GetItemData(nLineIndex));

    // Update addresses
    PopulateAddresses();

    // Show line icon and update the rest of the controls based on the new line
    ShowLineIcon();
	UpdateControls();
}

void CPhoneNoDlg::OnConfigDialog() 
{
    if( ::lineConfigDialog(m_nLineID, GetSafeHwnd(), m_sDeviceClass) == 0 )
    {
        UpdateControls();
    }
}

void CPhoneNoDlg::OnTranslateDialog() 
{
    if( ::lineTranslateDialog(m_hLineApp, m_nLineID, m_aApiVersions[m_nLineID],
                              GetSafeHwnd(), m_pno.GetTranslatable()) == 0 )
    {
        // Locations may have changed...
        PopulateLocations();

        UpdateControls();
    }
}
