// RadioBrowseSearchDlg.cpp : implementation file
//

#include "stdafx.h"
#include "dslavsplit.h"
#include "RadioBrowseSearchDlg.h"

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

// Context
#define ID_ADD_TAG 1
#define ID_EDIT_TAG 2
#define ID_DELETE_TAG 3
#define ID_CLEAR_LIST 4
// Default conbo strings
#define DEF_COUNTRY_STR _T("No Country")
#define DEF_STATE_STR _T("No State")
#define DEF_LANGUAGE_STR _T("No Language")



/////////////////////////////////////////////////////////////////////////////
// CRbSearchDlg dialog


CRbSearchDlg::CRbSearchDlg(CWnd* pParent /*=NULL*/)
	: CDialog(CRbSearchDlg::IDD, pParent)
{
	//{{AFX_DATA_INIT(CRbSearchDlg)
	m_countryCodeStr = _T("");
	m_languageCodeStr = _T("");
	m_stateStr = _T("");
	m_nameStr = _T("");
	m_topicStr = _T("Imported Media");
	m_iMinimumClicks = 0;
	m_iMinimumVotes = 0;
	m_iMaxResults = 0;
	//}}AFX_DATA_INIT
	m_pDoc = NULL;

	// Results List.
	bSortAscend = TRUE;

	// Resizing Dlg
	m_nOrigHeight = 0;
	m_nCurHeight = 0;
	m_nScrollPos = 0;
	m_rect.SetRectEmpty(); 
}


void CRbSearchDlg::DoDataExchange(CDataExchange* pDX)
{
	CDialog::DoDataExchange(pDX);
	//{{AFX_DATA_MAP(CRbSearchDlg)
	DDX_Control(pDX, IDC_RB_VOTES_EDIT, m_ctrlMinVotesEdit);
	DDX_Control(pDX, IDC_RB_CLICKS_EDIT, m_ctrlMinClicksEdit);
	DDX_Control(pDX, IDC_RB_LANGUAGE_COMBO, m_ctrlLanguageCodeCombo);
	DDX_Control(pDX, IDC_RB_COUNTRY_COMBO, m_ctrlCountryCodeCombo);
	DDX_Control(pDX, IDC_RB_STATE_COMBO, m_ctrlStatesCombo);
	DDX_Control(pDX, IDC_RB_TAG_COMBO, m_ctrlTagCombo);
	DDX_Control(pDX, IDC_RB_RESULTS_LIST, m_ctrlResultsList);
	DDX_Control(pDX, IDC_RB_TAG_LIST, m_ctrlTagList);
	DDX_Control(pDX, IDC_RB_TOPIC_EDIT, m_ctrlTopicEdit);
	DDX_Control(pDX, IDC_RB_MAX_RSLTS_EDIT, m_ctrlMaxRestultsEdit);
	DDX_Control(pDX, IDC_RB_RESULTS_STATIC, m_ctrlResultsStatic);
	DDX_CBString(pDX, IDC_RB_COUNTRY_COMBO, m_countryCodeStr);
	DDX_CBString(pDX, IDC_RB_LANGUAGE_COMBO, m_languageCodeStr);
	DDX_CBString(pDX, IDC_RB_STATE_COMBO, m_stateStr);
	DDX_Text(pDX, IDC_RB_NAME_EDIT, m_nameStr);
	DDX_Text(pDX, IDC_RB_TOPIC_EDIT, m_topicStr);
	DDX_Text(pDX, IDC_RB_CLICKS_EDIT, m_iMinimumClicks);
	DDV_MinMaxInt(pDX, m_iMinimumClicks, 0, 2000000000);
	DDX_Text(pDX, IDC_RB_VOTES_EDIT, m_iMinimumVotes);
	DDV_MinMaxInt(pDX, m_iMinimumVotes, 0, 2000000000);
	DDX_Text(pDX, IDC_RB_MAX_RSLTS_EDIT, m_iMaxResults);
	DDV_MinMaxInt(pDX, m_iMaxResults, 0, 2000000000);
	//}}AFX_DATA_MAP
}


BEGIN_MESSAGE_MAP(CRbSearchDlg, CDialog)
	//{{AFX_MSG_MAP(CRbSearchDlg)
	ON_WM_CONTEXTMENU()
	ON_LBN_KILLFOCUS(IDC_RB_TAG_LIST, OnKillfocusRbTagList)
	ON_CBN_SELCHANGE(IDC_RB_TAG_COMBO, OnSelchangeTagCombo)
	ON_CBN_SELCHANGE(IDC_RB_COUNTRY_COMBO, OnSelchangeCountryCodeCombo)
	ON_BN_CLICKED(IDC_RB_CLEAR_CRIT_BUTTON, OnClearCriterea)
	ON_BN_CLICKED(IDC_RB_SEARCH_BUTTON, OnSearch)
	ON_NOTIFY(LVN_COLUMNCLICK, IDC_RB_RESULTS_LIST, OnColumnclickResultsList)
	ON_BN_CLICKED(IDC_RB_CLEAR_RSLTS_BUTTON, OnClearRsltsButton)
	ON_NOTIFY(NM_CLICK, IDC_RB_RESULTS_LIST, OnClickResultsList)
	ON_BN_CLICKED(IDC_RB_IMPORT_BUTTON, OnImportButton)
	ON_WM_SIZE()
	ON_WM_VSCROLL()
	ON_WM_HELPINFO()
	ON_EN_KILLFOCUS(IDC_RB_MAX_RSLTS_EDIT, OnKillfocusMaxRsltsEdit)
	ON_EN_KILLFOCUS(IDC_RB_CLICKS_EDIT, OnKillfocusClicksEdit)
	ON_EN_KILLFOCUS(IDC_RB_VOTES_EDIT, OnKillfocusVotesEdit)
	//}}AFX_MSG_MAP
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CRbSearchDlg message handlers

BOOL CRbSearchDlg::OnInitDialog() 
{
	CDialog::OnInitDialog();

	// Set Tag Combo.
	SetTagCombo();

	// Set CountryCode combo.
	SetCountryCodeCombo();

	// Set States combo.
	SetStatesCombo();

	// Set Language combo.
	SetLanguageCodeCombo();

	// Set static Results string.
	m_ctrlResultsStatic.SetWindowText(_T("Search Results"));

	// Set Results List columns.
	CRect rect;
	m_ctrlResultsList.GetClientRect(rect);
	int width = rect.Width() / 6;
	m_ctrlResultsList.InsertColumn(0, _T("Name"),	LVCFMT_LEFT, width * 2);
	m_ctrlResultsList.InsertColumn(1, _T("Votes"),	LVCFMT_LEFT, width);
	m_ctrlResultsList.InsertColumn(2, _T("Clicks"), LVCFMT_LEFT, width);
	m_ctrlResultsList.InsertColumn(3, _T("URL"),	LVCFMT_LEFT, width * 2);

	// Resizing Dlg.
	GetWindowRect(m_rect);
	m_nScrollPos = 0;
	
	return TRUE;  // return TRUE unless you set the focus to a control
	              // EXCEPTION: OCX Property Pages should return FALSE
}

// Context menu for lists - framework auto routes here ok.
void CRbSearchDlg::OnContextMenu(CWnd* pWnd, CPoint point) 
{
	HWND hwndParam = pWnd->GetSafeHwnd();
	HWND hwndTagList = m_ctrlTagList.GetSafeHwnd();
	HWND hwndResults = m_ctrlResultsList.GetSafeHwnd();
	// Route to handler.
	if(hwndParam == hwndTagList)
		OnContextMenuTagList(pWnd, point);
	else if(hwndParam == hwndResults)
		OnContextMenuResultsList(pWnd, point);
}

// Resizing Dlg - see MSDN Q262954.
void CRbSearchDlg::OnSize(UINT nType, int cx, int cy) 
{
	CDialog::OnSize(nType, cx, cy);

	// Save the original height of dialog.
	if(!m_nOrigHeight)
		m_nOrigHeight = cy;

	// If user is resizing larger than original,
	// ensure the window is scrolled to the top. 
	if(m_nOrigHeight < cy)
	{
		// Scroll window to top.
		int nPos = GetScrollPos(SB_VERT);
		ScrollWindow(0, nPos);
		m_nScrollPos = 0;
		UpdateWindow();		// must
	}

	// Set scroll info for current size.
	m_nCurHeight = cy;
	int nScrollMax;
	int height = m_rect.Height();
	if(cy < height)
		nScrollMax = m_rect.Height() - cy;
	else
		nScrollMax = 0;

	SCROLLINFO si;
	si.cbSize = sizeof(SCROLLINFO);
	si.fMask = SIF_ALL; // SIF_ALL = SIF_PAGE | SIF_RANGE | SIF_POS;
	si.nMin = 0;
	si.nMax = nScrollMax;
	si.nPage = si.nMax/10;
	si.nPos = 0;
	SetScrollInfo(SB_VERT, &si, TRUE); 

}
void CRbSearchDlg::OnVScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar) 
{
	int nDelta;
	int nMaxPos = m_rect.Height() - m_nCurHeight;

	switch(nSBCode)
	{
	case SB_LINEDOWN:
		if(m_nScrollPos >= nMaxPos)
			return;
		nDelta = min(nMaxPos / 10, nMaxPos - m_nScrollPos);
		break;

	case SB_LINEUP:
		if(m_nScrollPos <= 0)
			return;
		nDelta = -min(nMaxPos / 10, m_nScrollPos);
		break;

	case SB_PAGEDOWN:
		if(m_nScrollPos >= nMaxPos)
			return;
		nDelta = min(nMaxPos / 10, nMaxPos - m_nScrollPos);
		break;

	case SB_THUMBPOSITION:
		nDelta = (int)nPos - m_nScrollPos;
		break;

	case SB_PAGEUP:
		if(m_nScrollPos <= 0)
			return;
		nDelta = -min(nMaxPos / 10, m_nScrollPos);
		break;
	
	default:
		return;
	}
	m_nScrollPos += nDelta;
	SetScrollPos(SB_VERT, m_nScrollPos, TRUE);
	ScrollWindow(0, -nDelta);
	CDialog::OnVScroll(nSBCode, nPos, pScrollBar);
}

///////////////////////////////////////////////////////
// Misc handlers

// Clear all search criterea
void CRbSearchDlg::OnClearCriterea() 
{
	// Set vars.
	m_iMinimumClicks = 0;
	m_iMinimumVotes = 0;
	m_iMaxResults = 0;
	m_nameStr = _T("");
	m_languageCodeStr = _T("");
	// Update vars.
	UpdateData(FALSE);
	
	// States combo storage - resets when a country is selected..
	m_ctrlStatesCombo.ResetContent();
	m_ctrlStatesCombo.AddString(DEF_STATE_STR);
	m_ctrlStatesCombo.SetCurSel(0);

	// Tag List Box & CStringArray storage.
	m_ctrlTagList.ResetContent();
	m_tagListAr.RemoveAll();

	// Tag Combo sel.
	m_ctrlTagCombo.SetCurSel(-1);

	// Country Codes sel.
	m_ctrlCountryCodeCombo.SetCurSel(0);
	
	// Language Codes sel.
	m_ctrlLanguageCodeCombo.SetCurSel(0);

	// Update ctrls.
	UpdateData(TRUE);	
}

// Set to 0 - needed for ddx - else user must enter.
void CRbSearchDlg::OnKillfocusMaxRsltsEdit() 
{
	CString str;
	m_ctrlMaxRestultsEdit.GetWindowText(str);
	if(str == _T(""))
		m_ctrlMaxRestultsEdit.SetWindowText(_T("0"));	
}
void CRbSearchDlg::OnKillfocusClicksEdit() 
{
	CString str;
	m_ctrlMinClicksEdit.GetWindowText(str);
	if(str == _T(""))
		m_ctrlMinClicksEdit.SetWindowText(_T("0"));	
}
void CRbSearchDlg::OnKillfocusVotesEdit() 
{
	CString str;
	m_ctrlMinVotesEdit.GetWindowText(str);
	if(str == _T(""))
		m_ctrlMinVotesEdit.SetWindowText(_T("0"));	
}


///////////////////////////////////////////////////////
// States Combo - m_ctrlStatesCombo

// Init combo with CDsLavDoc m_radioBrowse states array strings.
void CRbSearchDlg::SetStatesCombo() 
{
	if(!m_pDoc)
		return;
	m_ctrlStatesCombo.ResetContent();

	// We init the combo with states from the selected country.
	if(m_countryCodeStr == DEF_COUNTRY_STR ||
	   m_countryCodeStr.IsEmpty() )
	{
		// Add default.
		m_ctrlStatesCombo.AddString(DEF_STATE_STR);
		// Select.
		m_ctrlStatesCombo.SetCurSel(0);
		// Set m_stateStr member.
		UpdateData(TRUE);
		return;
	}

	// Get the 2 letter code for m_countryCodeStr;
	CString ccCode;
	if(!GetCountryCodeCode(m_countryCodeStr, ccCode))
		return;

	// Add default first.
	m_ctrlStatesCombo.AddString(DEF_STATE_STR);

	// Add array.
	int sz = m_pDoc->m_radioBrowse.GetStateArSize();
	for(int i = 0; i < sz; i++)
	{
		CState & state = m_pDoc->m_radioBrowse.GetStateAt(i);
		// If state's code matches, add.
		if(state.m_country == ccCode && state.m_name != _T("") )
		{
			// A repair to do when building RB.
			if(ccCode == _T("US") && state.m_name == _T(" "))
				continue;

			m_ctrlStatesCombo.AddString(state.m_name);
		}
	}
	// Check results.
	sz = m_ctrlStatesCombo.GetCount();

	// Select No State.
	m_ctrlStatesCombo.SetCurSel(0);

	// Set m_stateStr member.
	UpdateData(TRUE);
}

///////////////////////////////////////////////////////
// Language Combo - m_ctrlLanguageCombo

// Init combo with CDsLavDoc m_radioBrowse states array strings.
void CRbSearchDlg::SetLanguageCodeCombo() 
{
	if(!m_pDoc)
		return;
	m_ctrlLanguageCodeCombo.ResetContent();

	// Add default first.
	m_ctrlLanguageCodeCombo.AddString(DEF_LANGUAGE_STR);

	// Add array.
	int sz = m_pDoc->m_radioBrowse.GetLanguageCodesArSize();
	for(int i = 0; i < sz; i++)
	{
		CLanguageCode & lc = m_pDoc->m_radioBrowse.GetLanguageCodeAt(i);

		// If used, add.
		if(lc.m_isUsed)
		{
			m_ctrlLanguageCodeCombo.AddString(lc.m_name);
		}
	}
	// Check results.
	sz = m_ctrlLanguageCodeCombo.GetCount();	// 96 used

	// Select No Language.
	m_ctrlLanguageCodeCombo.SetCurSel(0);

	// Set m_languageStr member.
	UpdateData(TRUE);
}

///////////////////////////////////////////////////////
// Countries Combo - m_ctrlCountryCodeCombo

// Init combo with CDsLavDoc m_radioBrowse country code array strings.
void CRbSearchDlg::SetCountryCodeCombo() 
{
	if(!m_pDoc)
		return;
	m_ctrlCountryCodeCombo.ResetContent();

	// Add default first.
	m_ctrlCountryCodeCombo.AddString(DEF_COUNTRY_STR);

	// Add array.
	int sz = m_pDoc->m_radioBrowse.GetCountryCodeArSize();
	for(int i = 0; i < sz; i++)
	{
		CCountryCode & cc = m_pDoc->m_radioBrowse.GetCountryCodeAt(i);
		m_ctrlCountryCodeCombo.AddString(cc.m_name);
	}
	// No Country cur sel.
	m_ctrlCountryCodeCombo.SetCurSel(0);
	// Set m_countryCodeStr member.
	UpdateData(TRUE);

}

void CRbSearchDlg::OnSelchangeCountryCodeCombo() 
{
	int nIndex = m_ctrlCountryCodeCombo.GetCurSel();
	CString ccStr;
	m_ctrlCountryCodeCombo.GetLBText(nIndex, ccStr);

	// Set m_countryCodeStr member.
	m_ctrlCountryCodeCombo.SetCurSel(nIndex);// must call for UpdateData
	UpdateData(TRUE);

	// Update States Combo with country's states.
	SetStatesCombo();	
}

///////////////////////////////////////////////////////
// Tag Combo - m_ctrlTagCombo handlers - Drop List style

// Init combo with CDsLavDoc m_radioBrowse tag array strings.
void CRbSearchDlg::SetTagCombo() 
{
	if(!m_pDoc)
		return;
	m_ctrlTagCombo.ResetContent();
	int sz = m_pDoc->m_radioBrowse.GetTagArSize();
	for(int i = 0; i < sz; i++)
	{
		CTag & tag = m_pDoc->m_radioBrowse.GetTagAt(i);
		m_ctrlTagCombo.AddString(tag.m_name);
	}
	// No cur sel.
	m_ctrlTagCombo.SetCurSel(-1);
}

// User selected combo tag.
void CRbSearchDlg::OnSelchangeTagCombo() 
{
	int nIndex = m_ctrlTagCombo.GetCurSel();
	CString tag;
	m_ctrlTagCombo.GetLBText(nIndex, tag);

	// Add tag to list string array.
	int iNewTag = m_tagListAr.Add(tag);
	// Reset List Ctrl.
	SetTagsList();

	// Set cur sel in list box.
	m_ctrlTagList.SetFocus();
	m_ctrlTagList.SetCurSel(iNewTag);
}

///////////////////////////////////////////////////////
// Tag List - m_ctrlTagList handlers

// Init list with m_tagListAr strings.
void CRbSearchDlg::SetTagsList() 
{
	// Clean existing.
	m_ctrlTagList.ResetContent();

	// Add all.
	int sz = m_tagListAr.GetSize();
	for(int i = 0; i < sz; i++)
	{
		m_ctrlTagList.AddString(m_tagListAr[i]);
	}
}

// Tag List context menu.
//  Called from OnContextMenu().
void CRbSearchDlg::OnContextMenuTagList(CWnd* pWnd, CPoint point) 
{
	BOOL bTagList = FALSE;
	HWND hwndParam = pWnd->GetSafeHwnd();
	HWND hwndTagList = m_ctrlTagList.GetSafeHwnd();
	HWND hwndResults = m_ctrlResultsList.GetSafeHwnd();

	BOOL selBlankSpace = FALSE;
	BOOL selTag = FALSE;

	int nTags = m_ctrlTagList.GetCount();
	int iSel = m_ctrlTagList.GetCurSel();
	if(iSel == LB_ERR)
	{
		selBlankSpace = TRUE;
	}
	else
	{
		// Check if right clicked outside a selected item
		CPoint clientPt = point;
		m_ctrlTagList.ScreenToClient(&clientPt);
		BOOL bOutside;
		int iSel2 = m_ctrlTagList.ItemFromPoint(clientPt, bOutside);
		if(bOutside)
			selBlankSpace = TRUE;
		else
			selTag = TRUE;
	}

	if(!selBlankSpace && !selTag)
		return;

	// Create the context.
	CMenu menu;
	menu.CreatePopupMenu();
	CString str;

	// Add item.
	if(selBlankSpace)
	{
		str = _T("Add New Tag");
		menu.AppendMenu(MF_STRING, ID_ADD_TAG, str);
		str = _T("Clear List");
		menu.AppendMenu(MF_STRING, ID_CLEAR_LIST, str);
	}
	// Add item & edit item
	else if(selTag)
	{
		str = _T("Edit Tag");
		menu.AppendMenu(MF_STRING, ID_EDIT_TAG, str);
		str = _T("Add New Tag");
		menu.AppendMenu(MF_STRING, ID_ADD_TAG, str);
		str = _T("Delete Tag");
		menu.AppendMenu(MF_STRING, ID_DELETE_TAG, str);
		str = _T("Clear List");
		menu.AppendMenu(MF_STRING, ID_CLEAR_LIST, str);

		// todo-delete tag, remove all tags.
	}

	//////////////////////
	// Show Context Menu.
	int nCmd = menu.TrackPopupMenu(	TPM_LEFTALIGN  | 
									TPM_LEFTBUTTON |
									TPM_RETURNCMD,		// see sdk TrackPopupMenu
									point.x, point.y,	// screen
									this);
	// Handle user sel.
	//
	// Edit tag.
	if(nCmd == ID_EDIT_TAG)
	{
		// Ensure bounds.
		if(iSel < 0 || iSel >= nTags)
			return;
		// Launch Edit Tag dlg.
		CRbTagDlg dlg;
		dlg.m_dlgTitle = _T("Edit Tag");
		dlg.m_strTag = m_tagListAr[iSel];
		int ret = dlg.DoModal();
		if(ret == IDOK)
		{
			// Update Array.
			CString tagStr = dlg.m_strTag;
			m_tagListAr[iSel] = tagStr;
			// Reset List Ctrl.
			SetTagsList();
			// Select.
			m_ctrlTagList.SetCurSel(iSel);
		}
	}
	// Add tag.
	if(nCmd == ID_ADD_TAG)
	{
		// Launch Add Tag dlg.
		CRbTagDlg dlg;
		dlg.m_dlgTitle = _T("Add Tag");
		int ret = dlg.DoModal();
		if(ret == IDOK)
		{
			// Add tag to array.
			CString tagStr = dlg.m_strTag;
			int iNewTag = m_tagListAr.Add(tagStr);
			// Reset List Ctrl.
			SetTagsList();
			m_ctrlTagList.SetCurSel(iNewTag);
		}
	}
	// Delete tag.
	if(nCmd == ID_DELETE_TAG)
	{
		// Remove tag from array.
		m_tagListAr.RemoveAt(iSel);
		// Reset List Ctrl.
		SetTagsList();
		// Set sel to tag above.
		if(iSel == 0)
			m_ctrlTagList.SetCurSel(0);
		else if(nTags > 1)
			m_ctrlTagList.SetCurSel(iSel - 1);
		else
			m_ctrlTagList.SetCurSel(-1);
	}
	// Clear list.
	if(nCmd == ID_CLEAR_LIST)
	{
		// Remove all tags from array.
		m_tagListAr.RemoveAll();
		// Reset List Ctrl.
		SetTagsList();
		// Set no sel.
		m_ctrlTagList.SetCurSel(-1);
		// Tag Combo sel.
		m_ctrlTagCombo.SetCurSel(-1);
	}

}
// Deselect tag if list looses focus.
void CRbSearchDlg::OnKillfocusRbTagList() 
{
	// Remove any selection when leaving list box.
	m_ctrlTagList.SetCurSel(-1);
}

///////////////////////////////////////////////////////
// Results List - m_ctrlResultsList handlers

// Column header clicked - sort per column.
void CRbSearchDlg::OnColumnclickResultsList(NMHDR* pNMHDR, LRESULT* pResult) 
{
	NM_LISTVIEW* pNMListView = (NM_LISTVIEW*)pNMHDR;
	*pResult = 0;

	// Note: ListCtrl must be no-sort else it overrides results.

	// Must have pDoc.
	if(!m_pDoc)
		return;

	// Must have results.
	int sz = m_pDoc->m_radioBrowse.GetResultsArSize();
	if(!sz)
		return;

	// Get col index.
	int colIndex = pNMListView->iSubItem;

	// Sort name.
	if(colIndex == 0)
	{
		m_pDoc->m_radioBrowse.SortResultsArray(bSortAscend, TRUE, FALSE, FALSE);
	}
	// Sort votes.
	else if(colIndex == 1)
	{
		m_pDoc->m_radioBrowse.SortResultsArray(bSortAscend, FALSE, TRUE, FALSE);
	}
	// Sort clicks.
	else if(colIndex == 2)
	{
		m_pDoc->m_radioBrowse.SortResultsArray(bSortAscend, FALSE, FALSE, TRUE);
	}
	// Nada
	else
		return;

	// Reverse the sort order for next time.
	bSortAscend = !bSortAscend;

	// Redraw the Results list.
	FillResultsList();
}

// Init m_ctrlResultsList with search results.
void CRbSearchDlg::FillResultsList()
{
	// Must have pDoc and results.
	if(!m_pDoc)
	{
		// Clear m_ctrlResultsList ListCtrl.
		m_ctrlResultsList.DeleteAllItems();
		return;
	}

	// Must have results to draw.
	int sz = m_pDoc->m_radioBrowse.GetResultsArSize();
	if(!sz)
	{
		m_ctrlResultsList.DeleteAllItems();
		return;
	}

	// Pause redraw.
	m_ctrlResultsList.SetRedraw(FALSE);

	// Clear m_ctrlResultsList ListCtrl.
	m_ctrlResultsList.DeleteAllItems();

	// Redraw m_ctrlResultsList
	CString votes, clicks;
	int nPlaylists = 0;
	for(int i = 0; i < sz; i++)
	{
		// Limit displayed results.
		if(m_iMaxResults && i >= m_iMaxResults) // ones based
			break;

		// Get a ref.
		CStation & station = m_pDoc->m_radioBrowse.GetSearchResultsAt(i);

		// Convert vote-click ints.
		votes.Format(_T("%d"), station.m_nVotes);  //_itow
		clicks.Format(_T("%d"), station.m_nClicks);

		// Name col.
		m_ctrlResultsList.InsertItem(i, (LPCTSTR)station.m_name);
		// Votes, clicks, url.
		m_ctrlResultsList.SetItemText(i, 1, (LPCTSTR)votes);
		m_ctrlResultsList.SetItemText(i, 2, (LPCTSTR)clicks);
		m_ctrlResultsList.SetItemText(i, 3, (LPCTSTR)station.m_url);
	}
	// Do redraw.
	m_ctrlResultsList.SetRedraw(TRUE);
	m_ctrlResultsList.Invalidate();
}


// Clear m_ctrlResultsList ListCtrl.
void CRbSearchDlg::OnClearRsltsButton() 
{
	m_ctrlResultsList.DeleteAllItems();	
}

// Results List context menu.
//  Called from OnContextMenu(),
void CRbSearchDlg::OnContextMenuResultsList(CWnd* pWnd, CPoint point) 
{
	// future
	int g = 0;
}

void CRbSearchDlg::OnClickResultsList(NMHDR* pNMHDR, LRESULT* pResult) 
{
	*pResult = 0;

	// Must have pDoc and results.
	if(!m_pDoc)
		return;

	// Must have results.
	int sz = m_pDoc->m_radioBrowse.GetResultsArSize();
	if(!sz)
		return;

	NM_LISTVIEW* pNMListView = (NM_LISTVIEW*)pNMHDR;
	int selIndex = pNMListView->iItem;
	int selIndexSub = pNMListView->iSubItem;
	CPoint pt = pNMListView->ptAction;
	CStation station;

	// Get selected CStation.
	if(selIndex >= 0 && selIndex < sz)
	{
		station = m_pDoc->m_radioBrowse.GetSearchResultsAt(selIndex);
		int g = 0;
		
	}

}

/////////////////////////////////////////////////////////////////////////////
// Do the search

void CRbSearchDlg::OnSearch() 
{
	if(!m_pDoc)
		return;
	// Zero criteria.
	m_pDoc->m_radioBrowse.ZeroSearchCritera();

	// Get entries.
	UpdateData(TRUE);

	int nCriterea = 0;
	int nTags = m_tagListAr.GetSize();

	if(m_countryCodeStr != DEF_COUNTRY_STR)
	{
		CString ccCode;
		if(GetCountryCodeCode(m_countryCodeStr, ccCode))
		{
			m_pDoc->m_radioBrowse.SetSearchCountryCode(ccCode);
			nCriterea ++;
		}
	}
	if(m_stateStr != DEF_STATE_STR)
	{
		m_pDoc->m_radioBrowse.SetSearchState(m_stateStr);
		nCriterea ++;
	}
	if(m_languageCodeStr != DEF_LANGUAGE_STR)
	{
		CString lcCode;
		if(GetLanguageCodeCode(m_languageCodeStr, lcCode))
		{
			m_pDoc->m_radioBrowse.SetSearchLanguage(lcCode);
			nCriterea ++;
		}
	}
	if(m_nameStr != _T(""))
	{
		m_pDoc->m_radioBrowse.SetSearchName(m_nameStr);
		nCriterea ++;
	}
	if(nTags)
	{
		m_pDoc->m_radioBrowse.SetSearchTags(m_tagListAr);
		nCriterea ++;
	}
	if(m_iMinimumClicks)
	{
		m_pDoc->m_radioBrowse.SetSearchClicks(m_iMinimumClicks);
		nCriterea ++;
	}
	if(m_iMinimumVotes)
	{
		m_pDoc->m_radioBrowse.SetSearchVotes(m_iMinimumVotes);
		nCriterea ++;
	}
	if(m_iMaxResults)
	{
		// Used below when displaying results
	}
	// Need criterea.
	if(!nCriterea)
	{
		AfxMessageBox(_T("Please set one or more search criteria."));
		return;
	}

	// Search
	CString str;
	int sz = 0;
	int nResults = m_pDoc->m_radioBrowse.SearchDb();

	// Results gotten.
	if(nResults)
	{
		// Fill m_ctrlResultsList.
		FillResultsList();

		// Get count - or use nResults.
		sz = m_pDoc->m_radioBrowse.GetResultsArSize();

		// Set static Results info string.
		if(m_iMaxResults)
		{
			str.Format(_T("Showing %d of %d Stations found"), m_iMaxResults, sz);
			m_ctrlResultsStatic.SetWindowText(str);
		}
		else
		{
			str.Format(_T("Found %d Stations"), sz);
			m_ctrlResultsStatic.SetWindowText(str);
		}
	}
	// Nothing found - set static Results info string.
	else
	{
		// Fill wirh nothing.
		FillResultsList();

		// Set results string.
		sz = m_pDoc->m_radioBrowse.GetStationArSize();
		str.Format(_T("No results in %d Stations searched"), sz);
		m_ctrlResultsStatic.SetWindowText(str);
	}
}

// Import Search Results to a DsLav Topic.
void CRbSearchDlg::OnImportButton() 
{
	// Must have pDoc.
	if(!m_pDoc)
		return;

	// Must have results to import.
	int sz = m_pDoc->m_radioBrowse.GetResultsArSize();
	if(!sz)
		return;

	// Get any Topic entry.
	UpdateData(TRUE);

	// Ensure a topic entered.
	if(m_topicStr.IsEmpty())
	{
		AfxMessageBox(_T("Please enter a Topic name to import results into."));
		m_ctrlTopicEdit.SetFocus();
	}
	
	// CDsLavDoc does the work. 
	int nImported = m_pDoc->ProccessRbSearchResults(m_topicStr, m_iMaxResults);
	if(nImported)
	{
		// Set results list empty. ProccessRbSearchResults will
		// have empties the search results array.
		FillResultsList();

		// Set results string.
		CString str;
		str.Format(_T("%d Stations imported to %s Topic."), nImported, m_topicStr);
		m_ctrlResultsStatic.SetWindowText(str);
	}
}


/////////////////////////////////////////////////////////////////////////////
// Helpers

// Get 2 letter code for a country name - move to RB db?.
BOOL CRbSearchDlg::GetCountryCodeCode(const CString & name, CString & code)
{
	// Search CountryCode Ar.
	int sz = m_pDoc->m_radioBrowse.GetCountryCodeArSize();
	for(int i = 0; i < sz; i++)
	{
		CCountryCode & cc = m_pDoc->m_radioBrowse.GetCountryCodeAt(i);
		if(cc.m_name == name)
		{
			code = cc.m_code;
			return TRUE;
		}
	}
	return FALSE;
}
// Get 2 letter code for a language name.
BOOL CRbSearchDlg::GetLanguageCodeCode(const CString & name, CString & code)
{
	// Search LanguageCode Ar.
	int sz = m_pDoc->m_radioBrowse.GetLanguageCodesArSize();
	for(int i = 0; i < sz; i++)
	{
		CLanguageCode & lc = m_pDoc->m_radioBrowse.GetLanguageCodeAt(i);
		if(lc.m_name == name)
		{
			code = lc.m_code;
			return TRUE;
		}
	}
	return FALSE;
}

// Help - called from F-1 or ? button with click in a control.
BOOL CRbSearchDlg::OnHelpInfo(HELPINFO* pHelpInfo) 
{
	// Open help to RB page.
	//  VS2010 - Need ::HtmlHelp, else CWND version.
	//   but why not needed in CDsLavDoc::OnHelpDsLavHelp() ??
	//   because CDsLavDoc not a CWND ?
	::HtmlHelp(0,
			 _T("DsLavHelp.chm::/RadioStationDB.htm"),
			 HH_DISPLAY_TOPIC,
			 NULL);	
	return CDialog::OnHelpInfo(pHelpInfo);
}


/////////////////////////////////////////////////////////////////////////////
// CRbTagDlg dialog
CRbTagDlg::CRbTagDlg(CWnd* pParent /*=NULL*/)
	: CDialog(CRbTagDlg::IDD, pParent)
{
	//{{AFX_DATA_INIT(CRbTagDlg)
	m_strTag = _T("");
	//}}AFX_DATA_INIT
}

void CRbTagDlg::DoDataExchange(CDataExchange* pDX)
{
	CDialog::DoDataExchange(pDX);
	//{{AFX_DATA_MAP(CRbTagDlg)
	DDX_Control(pDX, IDC_RB_TAG_EDIT, m_ctrlTagEdit);
	DDX_Text(pDX, IDC_RB_TAG_EDIT, m_strTag);
	//}}AFX_DATA_MAP
}
BEGIN_MESSAGE_MAP(CRbTagDlg, CDialog)
	//{{AFX_MSG_MAP(CRbTagDlg)
	//}}AFX_MSG_MAP
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CRbTagDlg message handlers

BOOL CRbTagDlg::OnInitDialog() 
{
	CDialog::OnInitDialog();
	
	SetWindowText(m_dlgTitle);
	m_ctrlTagEdit.SetFocus();
	
	return TRUE;  // return TRUE unless you set the focus to a control
	              // EXCEPTION: OCX Property Pages should return FALSE
}

