//////////////////////////////////////////////////////////////////////////////
// DSRightViewImpl.cpp
// 
//
// Created: 10/09/97 smohanty
//
//////////////////////////////////////////////////////////////////////////////

#include "stdafx.h"
#define __DS_RIGHT_VIEW_INTERFACE_IMPLEMENTATION_
#include "DSRightViewImpl.h"

#include "QCSharewareManager.h"

#ifndef BASED_CODE
#define BASED_CODE
#endif

// Include the files in the correct order to allow leak checking with malloc.
// CRTDBG_MAP_ALLOC already defined in stdafx.h
#include <stdlib.h>
#include <crtdbg.h>

#include "DebugNewHelpers.h"

extern unsigned char DSSHORTCUT[];

IMPLEMENT_DYNCREATE(DSRightView, C3DFormView)

BEGIN_MESSAGE_MAP(DSRightView, C3DFormView)
    ON_WM_SIZE()
    ON_WM_DESTROY()
    ON_NOTIFY(NM_CLICK, IDD_NDS_LC_DATABASES, OnDatabasesClk)
    ON_NOTIFY(NM_DBLCLK, IDD_NDS_LC_DATABASES, OnDatabasesDblClk)
    ON_NOTIFY(LVN_ITEMCHANGED, IDD_NDS_LC_DATABASES, OnDatabasesItemChange)
    ON_BN_CLICKED(IDD_NDS_PB_MODIFYDATABASE, OnModifyDatabase)
    ON_BN_CLICKED(IDD_NDS_PB_DELETEDATABASE, OnDeleteDatabase)
    ON_BN_CLICKED(IDD_NDS_PB_NEWDATABASE, OnNewDatabase)
    ON_NOTIFY(NM_DBLCLK, IDD_NDS_LC_PROTOCOLS, OnProtocolsDblClk)
    ON_NOTIFY(LVN_COLUMNCLICK, IDD_NDS_LC_DATABASES, OnColumnClickDatabases)
    ON_NOTIFY(LVN_COLUMNCLICK, IDD_NDS_LC_PROTOCOLS, OnColumnClickProtocols)
    ON_REGISTERED_MESSAGE(umsgActivateWazoo, OnActivateWazoo)
END_MESSAGE_MAP()

DSRightView::DSRightView()
    : C3DFormView(IDD_NDS_DIRSERV_RIGHTVIEW), pDS(NULL),
      XBaseUnit(LOWORD(::GetDialogBaseUnits())),
      YBaseUnit(HIWORD(::GetDialogBaseUnits())), shiftDown(FALSE),
      imgCache(NULL), nCurWidth(INT_MIN)
{
    // Control metrics.
    // Horizontal and vertical space.
    xSpace                 = (XBaseUnit);
    ySpace                 = (YBaseUnit)      / 2;
    tcSpace                = (YBaseUnit);
    pushButtonWidth        = (30 * XBaseUnit) / 4;
    pushButtonWidthEx      = (50 * XBaseUnit) / 4;
    pushButtonHeight       = (14 * YBaseUnit) / 8 - ySpace;

    // Horizontal metrics
    // We impose a minimum width for the protocols group box.
    minProtocolsWidth      = (2 * xSpace) + pushButtonWidthEx;
    // We also impose a minimum width for the databases group box.
    minDatabasesWidth      = (3 * xSpace) + (2 * pushButtonWidth);
    // Thus, the min Dialog width is the larger of the two.
    minDialogWidth         = ((minProtocolsWidth <= minDatabasesWidth) ?
	                     minDatabasesWidth : minProtocolsWidth) +
                             (2 * xSpace);

    // Vertical metrics
    // We impose a minimum height for the protocols list --- roughly
    // twice the pushbutton height.
    minLCProtocolsHeight   = (25 * YBaseUnit) / 8;
    // We also impose a maximum height for the protocols group box.
    maxProtocolsHeight     = 180;
    // The min height of the protocols group box is ...
    minProtocolsHeight     = tcSpace + (2 * ySpace) + minLCProtocolsHeight +
	                     pushButtonHeight;

    minLCDatabasesHeight   = (50 * YBaseUnit) / 8;
    minDatabasesHeight     = tcSpace + (2 * ySpace) + minLCDatabasesHeight +
	                     pushButtonHeight;

    minDialogHeight        = (3 * ySpace) + minProtocolsHeight +
	                     minDatabasesHeight;
}

DSRightView::~DSRightView()
{
    if (imgCache) {
	delete imgCache;
	imgCache = 0;
    }

    if (pDS != NULL) {
	if (pDS->pDirServ) {
	    pDS->pDirServ->Release();
	    pDS->pDirServ = NULL;
	}
	delete pDS;
	pDS = NULL;
    }
}

BOOL
DSRightView::SerializeSerializables()
{
    BOOL        bWritten   = FALSE;

    // Write the widht of the right pane.
    CRString    dsSect(IDS_NDS_DIRSERV_SECTION),
	        dsRightPane(IDS_NDS_DIRSERV_RIGHTPANE_X);

    char        buffer[32] = { '\0' };
    const char *section    = dsSect;
    const char *rightPane  = dsRightPane;
    const char *itoaBuf    = ::itoa(nCurWidth, buffer, 10);
    const char *iniPath    = INIPath;

    if (section && rightPane && itoaBuf && iniPath) {
	bWritten = ::WritePrivateProfileString(section, rightPane, itoaBuf,
					       iniPath);
    }
    
    return bWritten;
}

void
DSRightView::PrepareForDestruction()
{
    ASSERT(m_LC_Databases.m_hWnd);
    SerializeDatabasesState();
    ResetDatabases();
    ASSERT(m_LC_Protocols.m_hWnd);
    ResetProtocols();
}

void
DSRightView::SerializeDatabasesState()
{
    CRString dsSection(IDS_NDS_DIRSERV_SECTION);
    int   iCount = m_LC_Databases.GetItemCount();
    void *pv     = static_cast<void *>(&m_LC_Databases);

    for (int i = 0; i < iCount; i++) {
	UINT    nState  = m_LC_Databases.GetItemState(i, LVIS_STATEIMAGEMASK);
	HRESULT hErrName, hErrProtoName;
	char    szName[128] = {'\0'}, szProtoName[128] = {'\0'},
	        iniStr[258] = {'\0'};

	IDSDatabase *pDatabase = (IDSDatabase *) ::GetListItemLPARAM(pv, i);
	ASSERT(pDatabase);

	hErrName      = pDatabase->GetName(szName, sizeof(szName));
	hErrProtoName = pDatabase->GetProtocolName(szProtoName,
						   sizeof(szProtoName));
	nState >>= 12;
	nState--;

	if (SUCCEEDED(hErrName) && SUCCEEDED(hErrProtoName)) {
	    strcpy(iniStr, szProtoName);
	    strcat(iniStr, ":");
	    strcat(iniStr, szName);
	    if (nState) { // this database is checked...
		::WritePrivateProfileString(dsSection, iniStr, "1", INIPath);
	    }
	    else { // this database is not checked...
		::WritePrivateProfileString(dsSection, iniStr, "0", INIPath);
	    }
	}
    }
}

void
DSRightView::DoDataExchange(CDataExchange *pDX)
{
    C3DFormView::DoDataExchange(pDX);

    // Database
    DDX_Control(pDX, IDD_NDS_LC_PROTOCOLS, m_LC_Protocols);
    DDX_Control(pDX, IDD_NDS_PB_NEWDATABASE, m_PB_NewDatabase);
    DDX_Control(pDX, IDD_NDS_LC_DATABASES, m_LC_Databases);
    DDX_Control(pDX, IDD_NDS_PB_MODIFYDATABASE, m_PB_ModifyDatabase);
    DDX_Control(pDX, IDD_NDS_PB_DELETEDATABASE, m_PB_DeleteDatabase);
}

void
DSRightView::OnInitialUpdate()
{
    C3DFormView::OnInitialUpdate();

	// Shareware: Register that we want to know of feature changes
	QCSharewareManager *pSWM = QCSharewareManager::GetSharewareManager();
	ASSERT(pSWM);
	if (pSWM)
	{
		pSWM->QCCommandDirector::Register((QICommandClient*)this);
	}

    m_PB_NewDatabase.EnableWindow(TRUE);
    m_PB_ModifyDatabase.EnableWindow(FALSE);
    m_PB_DeleteDatabase.EnableWindow(FALSE);

    SetScaleToFitSize(CSize(1, 1));
    RECT rect;
    GetClientRect(&rect);
    OnSize(SIZE_RESTORED, rect.right - rect.left, rect.bottom - rect.top);
	InitShortcuts();
}

////////////////////////////////////////////////////////////////////////
// OnActivateWazoo [protected]
//
// Perform Just In Time display initialization.
////////////////////////////////////////////////////////////////////////
long 
DSRightView::OnActivateWazoo(WPARAM, LPARAM)
{
    ::ShouldUpdateIni(1);

    if (m_PB_NewDatabase.GetSafeHwnd() && (NULL == pDS)) {
	pDS = DEBUG_NEW_NOTHROW _directory_services;

        HRESULT hRegCOM = ::RegisterCOMObjects();

	if (SUCCEEDED(hRegCOM)) {

	    imgCache = DEBUG_NEW CImgCache;

		imgCache->Initialize(RGB(255, 0, 255));

	    if (pDS) {
		HRESULT hErr;

		hErr = CoCreateInstance(CLSID_DirServ, NULL,
					CLSCTX_INPROC_SERVER,
					IID_IDirServ,
					(void **)(&(pDS->pDirServ)));

		if (SUCCEEDED(hErr)) {
		    ASSERT(pDS->pDirServ);
		    hErr = pDS->pDirServ->Initialize();
		    if (SUCCEEDED(hErr)) {
			InitProtocols();
			PopulateProtocols();
			InitDatabases();
			PopulateDatabases();
		    }
		}
	    }
	}
	else {
		CString csTitle;
		csTitle.LoadString(IDS_DIRSERV_ERROR);
	    ::MessageBox(NULL, _ds_uds, csTitle, MB_OK | MB_ICONEXCLAMATION);
	}
    }

	DSMainSplitterWnd *pDSMSW = static_cast<DSMainSplitterWnd *>(GetParent());
	DSLeftView        *pDSLV  = static_cast<DSLeftView *>
                                (pDSMSW->GetPane(0, 0));

   pDSLV->SetQueryInputFocus();

    return 0;
}


void
DSRightView::InitProtocols()
{
    LV_COLUMN lvc;
    memset(&lvc, 0, sizeof(LV_COLUMN));
    ListView_SetImageList(GetDlgItem(IDD_NDS_LC_PROTOCOLS)->m_hWnd,
			  imgCache->GetImageList(), LVSIL_SMALL);
    lvc.mask     = LVCF_FMT|LVCF_WIDTH|LVCF_SUBITEM|LVCF_TEXT;
    lvc.fmt      = LVCFMT_LEFT;
    lvc.cx       = 300;
    lvc.iSubItem = 0;
	CString csTitle;
	csTitle.LoadString(IDS_DIRSERV_REGDRV);
    lvc.pszText  = csTitle.GetBuffer(100);
    m_LC_Protocols.InsertColumn(0, &lvc);
	csTitle.ReleaseBuffer();
}

void
DSRightView::ResetProtocols()
{
    int iCount             = m_LC_Protocols.GetItemCount();
    IDSProtocol *pProto    = NULL;
    void *pv               = static_cast<void *>(&m_LC_Protocols);

    for (int i = 0; i < iCount; i++) {
	pProto = (IDSProtocol *)  ::GetListItemLPARAM(pv, i);
	if (pProto != NULL) {
	    pProto->Release();
	}
    }
    
    m_LC_Protocols.DeleteAllItems();
}

void
DSRightView::PopulateProtocols()
{
    ASSERT(pDS);
    ASSERT(pDS->pDirServ);
    HRESULT hErr;
    IDSEnumProtocols *pEnum = NULL;

    ResetProtocols();

    hErr = pDS->pDirServ->EnumProtocols(&pEnum);

    if (SUCCEEDED(hErr)) {
	IDSProtocol *pProto;
	ULONG nProto;
	int idx = 0;

	while(pEnum->Next(1, &pProto, &nProto) != S_FALSE) {
	    char szBuf[128];
	    LV_ITEM lvi;
	    HBITMAP hBit;

	    memset(&lvi, 0, sizeof(LV_ITEM));

	    hErr = pProto->GetProtocolName(szBuf, sizeof(szBuf));
	    if (SUCCEEDED(hErr)) {
		lvi.mask |= LVIF_TEXT;
		lvi.pszText = szBuf;
	    }

	    hBit = pProto->GetProtocolImage(IMG_SMALL);
	    if (hBit != NULL) {
		lvi.iImage  = imgCache->Add(hBit);
		lvi.mask |= LVIF_IMAGE;
	    }

	    lvi.mask |= LVIF_PARAM;
	    lvi.lParam = (LPARAM) pProto;
	    lvi.iItem = idx++;
	    lvi.iSubItem = 0;
	    m_LC_Protocols.InsertItem(&lvi);
	}
	pEnum->Release();
	m_LC_Protocols.SetItemState(0, LVIS_FOCUSED|LVIS_SELECTED,
				   LVIS_FOCUSED|LVIS_SELECTED);
	m_LC_Protocols.SetColumnWidth(0, LVSCW_AUTOSIZE);
    }
}

void
DSRightView::InitDatabases()
{
    ASSERT(pDS);
    LV_COLUMN lvc;

    memset(&lvc, 0, sizeof(LV_COLUMN));

    ListView_SetImageList(GetDlgItem(IDD_NDS_LC_DATABASES)->m_hWnd,
			  imgCache->GetImageList(), LVSIL_SMALL);

    COLORREF cRF = RGB(255, 255, 255);

    pDS->ilDatabase_State.Create(MAKEINTRESOURCE(IDB_NDS_DIRSERV_STATUSUN),
				 16, 1, cRF);

    m_LC_Databases.SetImageList(&(pDS->ilDatabase_State), LVSIL_STATE);

    lvc.mask     = LVCF_FMT|LVCF_WIDTH|LVCF_SUBITEM|LVCF_TEXT;
    lvc.fmt      = LVCFMT_LEFT;
    lvc.cx       = 300;
    lvc.iSubItem = 0;
    CString csTitle1;
	csTitle1.LoadString(IDS_DIRSERV_CONFIGSERV);
    lvc.pszText = csTitle1.GetBuffer(100);
    m_LC_Databases.InsertColumn(0, &lvc);

    lvc.cx       = 100;
	CString csTitle2;
	csTitle2.LoadString(IDS_DIRSERV_PROTOCOL);
    lvc.pszText = csTitle2.GetBuffer(100);

    m_LC_Databases.InsertColumn(1, &lvc);
	csTitle1.ReleaseBuffer();
	csTitle2.ReleaseBuffer();
}

void
DSRightView::PopulateDatabases()
{
    ASSERT(pDS);
    ASSERT(pDS->pDirServ);

    IDSEnumDatabases *pEnum = NULL;
    HRESULT           hErr;

    ResetDatabases();

    hErr = pDS->pDirServ->EnumDatabases(NULL, &pEnum);

    if (SUCCEEDED(hErr)) {
	CRString dsSection(IDS_NDS_DIRSERV_SECTION);
	IDSDatabase *pDatabase;
	ULONG        nDatabase;
	int          idx = 0;

	while(pEnum->Next(1, &pDatabase, &nDatabase) != S_FALSE) {
	    char    szBuf[128]       = {'\0'},
 		    szProtoName[128] = {'\0'}, iniStr[258] = {'\0'};

	    LV_ITEM lvi;
	    HBITMAP hBit       = NULL;

	    memset(&lvi, 0, sizeof(LV_ITEM));
	    ASSERT(pDatabase);

	    hErr = pDatabase->GetName(szBuf, sizeof(szBuf));
	    if (SUCCEEDED(hErr)) {
		lvi.mask    |= LVIF_TEXT;
		lvi.pszText  = szBuf;
	    }

	    hBit = pDatabase->GetProtocolImage(IMG_SMALL);
	    if (hBit != NULL) {
		lvi.iImage  = imgCache->Add(hBit);
		lvi.mask  |= LVIF_IMAGE;
	    }

	    lvi.mask     |= LVIF_PARAM|LVIF_STATE;
	    lvi.lParam    = (LPARAM)(pDatabase);
	    lvi.iItem     = idx;
	    lvi.iSubItem  = 0;
	    lvi.stateMask = LVIS_STATEIMAGEMASK;
	    lvi.state     = INDEXTOSTATEIMAGEMASK(1);
	    m_LC_Databases.InsertItem(&lvi);

 	    HRESULT hErrProtoName;

 	    hErrProtoName = pDatabase->GetProtocolName(szProtoName,
 						       sizeof(szProtoName));
 	    if (SUCCEEDED(hErr) && SUCCEEDED(hErrProtoName)) {
 		strcpy(iniStr, szProtoName);
 		strcat(iniStr, ":");
 		strcat(iniStr, szBuf);
 		if (::GetPrivateProfileInt(dsSection, iniStr, 0, INIPath)) {
		    m_LC_Databases.SetItemState(idx, INDEXTOSTATEIMAGEMASK(2),
						LVIS_STATEIMAGEMASK);
		}
		m_LC_Databases.SetItemText(idx, 1, szProtoName);
	    }
	    idx++;
	}

	pEnum->Release();

	m_LC_Databases.SetItemState(0, LVIS_FOCUSED|LVIS_SELECTED,
				    LVIS_FOCUSED|LVIS_SELECTED);
    }

    if (m_LC_Databases.GetItemCount()) {
	UINT nSel;
	m_PB_ModifyDatabase.EnableWindow(
	    (nSel = m_LC_Databases.GetSelectedCount()) == 1);
	m_PB_DeleteDatabase.EnableWindow((nSel >= 1));
    }

    m_LC_Databases.SetColumnWidth(0, LVSCW_AUTOSIZE);
}

void
DSRightView::ResetDatabases()
{
    int iCount             = m_LC_Databases.GetItemCount();
    IDSDatabase *pDatabase = NULL;
    void *pv               = static_cast<void *>(&m_LC_Databases);

    for (int i = 0; i < iCount; i++) {
	pDatabase = (IDSDatabase *)  ::GetListItemLPARAM(pv, i);
	if (pDatabase != NULL) {
	    pDatabase->Release();
	}
    }
    
    m_LC_Databases.DeleteAllItems();
}

void
DSRightView::OnDatabasesClk(NMHDR *pNMHDR, LRESULT *pResult)
{
    UINT flags;
    int index;
    POINT pt;
    ::GetCursorPos(&pt);
    CPoint point(pt);

    // Get the location of click.
    m_LC_Databases.ScreenToClient(&point);

	UINT nState = 0;
    // If it's on the state icon do the appropriate thing...
    if ((index = m_LC_Databases.HitTest(point, &flags)) != -1) {
	if (flags & LVHT_ONITEMSTATEICON) {
	    nState = m_LC_Databases.GetItemState(index, LVIS_STATEIMAGEMASK);
	    nState >>= 12;
	    nState--;
	    nState = !nState;
	    nState++;
	    m_LC_Databases.SetItemState(index, INDEXTOSTATEIMAGEMASK(nState),
					LVIS_STATEIMAGEMASK);
	}
    }

	// Shareware: In reduced feature mode, you can only select one database
	QCSharewareManager *pSWM = QCSharewareManager::GetSharewareManager();
	ASSERT(pSWM);
	if ((pSWM) && (pSWM->UsingFullFeatureSet() == false))
	{
		// REDUCED-FEATURE MODE

		// Allow only one database to be selected at one time
		// If an item is selected, unselect all other items
		if(nState == 2)
		{
			int nItemCnt = m_LC_Databases.GetItemCount();
			for (int cnt = 0; cnt < nItemCnt; cnt++) 
			{
				if(cnt != index) 
				{
					m_LC_Databases.SetItemState(cnt, INDEXTOSTATEIMAGEMASK(1), 
						LVIS_STATEIMAGEMASK);	//unselect
				}
			}
		}
	}
    
	DSMainSplitterWnd *pDSMSW = static_cast<DSMainSplitterWnd *>(GetParent());
    DSLeftView        *pDSLV  = static_cast<DSLeftView *>
                                (pDSMSW->GetPane(0, 0));

    // If query is not in progress, enable or disable the start button.
    if (!pDSLV->IsQueryInProgress()) {

	// Post-processing --- find the first checked database if any.
	int nItemCnt = m_LC_Databases.GetItemCount();
	UINT nSt = 0;

	for (int cnt = 0; cnt < nItemCnt; cnt++) {
	    nSt = m_LC_Databases.GetItemState(cnt, LVIS_STATEIMAGEMASK);
	    nSt >>= 12;
	    nSt--;
	    if (nSt) {
		break;
	    }	
	}

	CString wndStr;
	pDSLV->GetQueryInput(wndStr);
	int nText = wndStr.GetLength();

	if (nText && nSt) {
	    pDSLV->EnableStartStop(TRUE);
	}
	else {
	    pDSLV->EnableStartStop(FALSE);
	}
    }

    *pResult = 0;
}

void
DSRightView::OnDatabasesDblClk(NMHDR* pNMHDR, LRESULT* pResult)
{
    ModifyDatabase();
    *pResult = 0;
}

void
DSRightView::ModifyDatabase()
{
    void *pv = static_cast<void *>(&m_LC_Databases);

    IDSDatabase *pDatabase = (IDSDatabase *) ::GetListFocusedItemLPARAM(pv);

    if (pDatabase != NULL) {
	if (ConfigDatabase(pDatabase) == FALSE) {
	    UpdateListFocused(pv);
	}
    }
}

BOOL
DSRightView::ConfigDatabase(IDSDatabase *pDatabase)
{
    ASSERT(pDatabase != NULL);
 
    int iCount     = 0;
    BOOL bCanceled = FALSE;

    if ((iCount = pDatabase->GetPropPageCount()) != 0) {

	HPROPSHEETPAGE *pPages;

	pPages = (HPROPSHEETPAGE *) malloc(sizeof(HPROPSHEETPAGE *) * iCount);
	if (pPages != NULL) {
	    if (SUCCEEDED(pDatabase->GetPropPages(pPages))) {
		CWnd *cWnd = GetFocus();
		int result = DisplayPropertySheet(pPages, iCount);

		if(result == 0) {
		    bCanceled = TRUE;
		}
		cWnd->SetFocus();
	    }
	    free(pPages);
	}
    }
    return(bCanceled);
}

int
DSRightView::DisplayPropertySheet(HPROPSHEETPAGE *pPages, int iCount)
{
    int result = 0;
    PROPSHEETHEADER psh;
    memset(&psh, 0, sizeof(PROPSHEETHEADER));

    // The dwSize member should be sizeof(PROPSHEETHEADER). But this
    // causes our INetSDK compiled stuff to fail on PropertySheet()
    // if you don't have IE4.0 installed. We just use the old header
    // size as a workaround.
    psh.dwSize          = PRE_IE_FOUR_OH_HEADER_SIZE;
    psh.dwFlags         = PSH_DEFAULT;//0; //PSH_PROPSHEETPAGE;
    psh.hwndParent 	= this->m_hWnd;
    psh.hInstance	= AfxGetInstanceHandle();
    psh.pszIcon 	= NULL;
	CString csTitle;
	csTitle.LoadString(IDS_DIRSERV_MODDB);
    psh.pszCaption 	= (LPSTR) csTitle.GetBuffer(100);
    psh.nPages 	        = iCount;
    psh.nStartPage 	= 0;
    psh.phpage	        = pPages;
    psh.pfnCallback     = NULL;
				
    result = PropertySheet(&psh);
    csTitle.ReleaseBuffer();
    return(result);
}

void
DSRightView::UpdateListFocused(void *pv)
{
    int idx        = -1;
    CListCtrl *pLC = static_cast<CListCtrl *>(pv);

    if ((idx = pLC->GetNextItem(-1, LVNI_FOCUSED)) != -1) {
	LV_ITEM lvi;
	memset(&lvi, 0, sizeof(LV_ITEM));
	IDSDatabase *pDatabase
	    = (IDSDatabase *) ::GetListItemLPARAM(pv, idx);
	char szBuf[256] = {'\0'};

	ASSERT(pDatabase != NULL);
	if (SUCCEEDED(pDatabase->GetName(szBuf, sizeof(szBuf)))) {
	    lvi.mask   |= LVIF_TEXT;
	    lvi.pszText = szBuf;
	    lvi.iItem    = idx;
	    pLC->SetItem(&lvi);
	}
    }
}

void
DSRightView::OnDatabasesItemChange(NMHDR *pNMHDR, LRESULT *pResult)
{
    UINT nSel;
    m_PB_ModifyDatabase.EnableWindow(
	(nSel = m_LC_Databases.GetSelectedCount()) == 1);
    m_PB_DeleteDatabase.EnableWindow((nSel >= 1));

    *pResult = 0;
}

void
DSRightView::OnModifyDatabase()
{
    ModifyDatabase();
}

void
DSRightView::OnDeleteDatabase()
{
    CString csTitle1, csTitle2;
	csTitle1.LoadString(IDS_DIRSERV_DELSELDB);
	csTitle2.LoadString(IDS_DIRSERV_DELDB);
    if (IDNO == MessageBox(csTitle1,
			               csTitle2,
			   MB_YESNO | MB_ICONQUESTION)) {
	return;
    }

    ASSERT(pDS);
    CRString dsSection(IDS_NDS_DIRSERV_SECTION);
    HRESULT hErrName, hErrProtoName;
    void *pv   = static_cast<void *>(&m_LC_Databases);

    // Serialize the states, since we are going to do a DeleteAllItems
    // and a PopulateDatabases.
    SerializeDatabasesState();

    // Delete the selected databases.
    int idx = -1;
    while((idx = m_LC_Databases.GetNextItem(idx, LVNI_SELECTED)) != -1) {
	IDSDatabase *pDatabase = (IDSDatabase *) ::GetListItemLPARAM(pv, idx);
	if (pDatabase) {
	    char            szName[128] = {'\0'}, szProtoName[128] = {'\0'},
		            iniStr[258] = {'\0'};
	    hErrName      = pDatabase->GetName(szName, sizeof(szName));
	    hErrProtoName = pDatabase->GetProtocolName(szProtoName,
						       sizeof(szProtoName));
	    if (SUCCEEDED(pDS->pDirServ->DeleteDatabase(pDatabase))) {
		// Blow away the INI entry.
		if (SUCCEEDED(hErrName) && SUCCEEDED(hErrProtoName)) {
		    strcpy(iniStr, szProtoName);
		    strcat(iniStr, ":");
		    strcat(iniStr, szName);
		    ::WritePrivateProfileString(dsSection, iniStr, NULL,
						INIPath);
		}
		pDatabase->Release();
	    }
	}
    }

    // Blow away all the items.
    m_LC_Databases.DeleteAllItems();
    // Repopulate the list.
    PopulateDatabases();
}

void
DSRightView::OnNewDatabase()
{
    void *pv            = static_cast<void *>(&m_LC_Protocols);
    IDSProtocol *pProto = (IDSProtocol *) ::GetListFocusedItemLPARAM(pv);

    if (pProto) {
	ASSERT(pDS);
	HRESULT hErr;
	IDSDatabase *pDatabase = NULL;

	hErr = pDS->pDirServ->CreateDatabase(pProto, &pDatabase);
	if (SUCCEEDED(hErr)) {
	    BOOL result = ConfigDatabase(pDatabase);
	    if (result == TRUE) {
		hErr = pDS->pDirServ->DeleteDatabase(pDatabase);
		pDatabase->Release();
	    }
	    else {
		pDatabase->Release();
		SerializeDatabasesState();
		PopulateDatabases();
	    }
	}
    }	    
}

void
DSRightView::OnProtocolsDblClk(NMHDR* pNMHDR, LRESULT* pResult)
{
    OnNewDatabase();
    *pResult = 0;
}

void
DSRightView::Error(char *s)
{
	CString csTitle;
	csTitle.LoadString(IDS_DIRSERV_ERROR);
    MessageBox(s, csTitle, MB_OK);
}

void
DSRightView::OnSize(UINT nType, int cx, int cy)
{
    C3DFormView::OnSize(nType, cx, cy);

    // Don't resize if the controls aren't created yet, or the window
    // is being minimized.

    if ((m_LC_Protocols.m_hWnd == NULL) || (nType == SIZE_MINIMIZED)) {
	return;
    }

    bool _x, _y;
    _x = (cx <= minDialogWidth);
    _y = (cy <= minDialogHeight);

    SmartSize(cx, _x, cy, _y);
	
    if (::ShouldUpdateIni() && nType != SIZE_MINIMIZED) {
	nCurWidth = cx;
	SerializeSerializables();
    }
}

////////////////////////////////////////////////////////////////////////
// OnDestroy [protected]
//
////////////////////////////////////////////////////////////////////////
void
DSRightView::OnDestroy()
{
	// Shareware: Unregister ourselves from notifications
	QCSharewareManager *pSWM = QCSharewareManager::GetSharewareManager();
	ASSERT(pSWM);
	if (pSWM)
	{
		pSWM->UnRegister(this);
	}

    PrepareForDestruction();
    C3DFormView::OnDestroy();
}

void
DSRightView::SmartSize(int cx, bool xIsMin, int cy, bool yIsMin)
{
    // Size the top group box.
    int n;
    CRect rectGBProtocols;
    // Ok, these are easy.
    rectGBProtocols.TopLeft().x     = xSpace;
    rectGBProtocols.TopLeft().y     = ySpace;
    // Slightly involved...
    rectGBProtocols.BottomRight().x = ((xIsMin) ? 
	                               minDialogWidth : cx) - xSpace;
    // Even more...
    n = static_cast<int>(0.3 * ((cy - (7 * ySpace) - (2 * tcSpace) -
	                 (2 * pushButtonHeight))));
    n = (n < 1) ? 0 : n;
    rectGBProtocols.BottomRight().y = (yIsMin) ?
	                              (ySpace + minProtocolsHeight) : 
	                              (3 * ySpace) + tcSpace +
	                              pushButtonHeight + n;
    GetDlgItem(IDD_NDS_GB_PROTOCOLS)->MoveWindow(rectGBProtocols);

    // Size the controls in the top group-box.
    // Size the NewDatabase button.
    int offSet = (rectGBProtocols.Width() - pushButtonWidthEx) / 2;
    CRect rectPBNewDatabase;
    rectPBNewDatabase.TopLeft().x     = rectGBProtocols.TopLeft().x + offSet;
    rectPBNewDatabase.TopLeft().y     = rectGBProtocols.BottomRight().y -
	                                ySpace - pushButtonHeight;
    rectPBNewDatabase.BottomRight().x = rectPBNewDatabase.TopLeft().x +
	                                pushButtonWidthEx;
    rectPBNewDatabase.BottomRight().y = rectGBProtocols.BottomRight().y -
	                                ySpace;
    m_PB_NewDatabase.MoveWindow(rectPBNewDatabase);

    // Size the List Control.
    CRect rectLCProtocols;
    rectLCProtocols.TopLeft().x     = rectGBProtocols.TopLeft().x + xSpace;
    rectLCProtocols.TopLeft().y     = rectGBProtocols.TopLeft().y + tcSpace;
    rectLCProtocols.BottomRight().x = rectGBProtocols.BottomRight().x - xSpace;
    rectLCProtocols.BottomRight().y = rectPBNewDatabase.TopLeft().y - ySpace;
    m_LC_Protocols.MoveWindow(rectLCProtocols);

    // Size the Bottom group box.
    // Size the top group box.
    CRect rectGBDatabases;
    rectGBDatabases.TopLeft().x     = xSpace;
    rectGBDatabases.TopLeft().y     = rectGBProtocols.BottomRight().y + ySpace;
    rectGBDatabases.BottomRight().x = rectGBProtocols.BottomRight().x;
    rectGBDatabases.BottomRight().y = (yIsMin) ?
                                      (rectGBDatabases.TopLeft().y +
				       minDatabasesHeight) :
                                       rectGBDatabases.TopLeft().y +
				       cy - rectGBProtocols.Height() - 
				       (3 * ySpace);
    GetDlgItem(IDD_NDS_GB_DATABASES)->MoveWindow(rectGBDatabases);
    ASSERT(rectGBDatabases.Width() >= minDatabasesWidth);

    // Size the controls in the bottom group box.
    
    int sep = rectGBDatabases.Width() - (2 * pushButtonWidth);
        sep = static_cast<int>((static_cast<double>(sep)) / 3);
        sep = (minDatabasesWidth <= rectGBDatabases.Width()) ?
	      sep : xSpace;

    CRect rectPB;
    rectPB.TopLeft().x     = rectGBDatabases.TopLeft().x + sep;
    rectPB.TopLeft().y     = rectGBDatabases.BottomRight().y -
	                     ySpace - pushButtonHeight;
    rectPB.BottomRight().x = rectPB.TopLeft().x + pushButtonWidth;
    rectPB.BottomRight().y = rectGBDatabases.BottomRight().y - ySpace;
    m_PB_ModifyDatabase.MoveWindow(rectPB);

    rectPB.TopLeft().x     = rectPB.BottomRight().x + sep;
    rectPB.BottomRight().x = rectPB.TopLeft().x + pushButtonWidth;
    m_PB_DeleteDatabase.MoveWindow(rectPB);

    CRect rectLCDatabases;
    rectLCDatabases.TopLeft().x = rectGBDatabases.TopLeft().x + xSpace;
    rectLCDatabases.TopLeft().y = rectGBDatabases.TopLeft().y + tcSpace;
    rectLCDatabases.BottomRight().x = rectGBDatabases.BottomRight().x - 
	                              xSpace;
    rectLCDatabases.BottomRight().y = rectPB.TopLeft().y - ySpace;
    m_LC_Databases.MoveWindow(rectLCDatabases);
}

BOOL
DSRightView::IsAnyDatabaseChecked()
{
    UINT nSt = 0;
    int nItemCnt = m_LC_Databases.GetItemCount();
    for (int cnt = 0; cnt < nItemCnt; cnt++) {
	nSt = m_LC_Databases.GetItemState(cnt, LVIS_STATEIMAGEMASK);
	nSt >>= 12;
	nSt--;
	if (nSt) {
	    break;
	}
	else {
	    nSt = 0;
	}
    }

    return((nSt == 0) ? FALSE : TRUE);
}

HRESULT
DSRightView::AddDatabases()
{
    ASSERT(pDS);

    int iCount = m_LC_Databases.GetItemCount();
    int nSelected = 0;
    HRESULT hErr;
    void   *pv = static_cast<void *>(&m_LC_Databases);

    for (int i = 0; i < iCount; i++) 
	{
		UINT nState = m_LC_Databases.GetItemState(i, LVIS_STATEIMAGEMASK);
		nState >>= 12;
		nState--;
		if (nState) 
		{
			ASSERT(pDS->pQuery);
			nSelected++;

			// Shareware: In reduced feature mode, you can only select one database
			QCSharewareManager *pSWM = QCSharewareManager::GetSharewareManager();
			ASSERT(pSWM);
			if ((pSWM) && (pSWM->UsingFullFeatureSet() == true))
			{
				// FULL-FEATURE MODE
				hErr = pDS->pQuery->AddDatabase((IDSDatabase *)
								(::GetListItemLPARAM(pv, i)));
				if (FAILED(hErr))
					return(hErr);
			}
			else
			{
				// REDUCED-FEATURE MODE
				// Allow only one database; Unselected any other selected databases
				if(nSelected == 1)
				{
					hErr = pDS->pQuery->AddDatabase((IDSDatabase *)
									(::GetListItemLPARAM(pv, i)));
					if (FAILED(hErr)) 
						return(hErr);
				}
				else
				{
					m_LC_Databases.SetItemState(i, INDEXTOSTATEIMAGEMASK(1), 
							LVIS_STATEIMAGEMASK);	//unselect
				}
			}
		}
    }

    if (!nSelected) {
	return(E_FAIL);
    }

    return(S_OK);
}


void
DSRightView::OnColumnClickDatabases(NMHDR *pNMHDR, LRESULT *pResult)
{
    NM_LISTVIEW *nLV = (NM_LISTVIEW *) pNMHDR;
    _DS_RV_Composite dscrv;

    shiftDown     = ShiftDown();
    dscrv.pDSRV   = this;
    dscrv.subItem   = nLV->iSubItem;
    m_LC_Databases.SortItems(CompareFuncDatabases, (DWORD)(&dscrv));
   *pResult = 0;
}

void
DSRightView::OnColumnClickProtocols(NMHDR *pNMHDR, LRESULT *pResult)
{
    NM_LISTVIEW *nLV = (NM_LISTVIEW *) pNMHDR;
    _DS_RV_Composite dscrv;

    shiftDown = ShiftDown();
    dscrv.pDSRV  = this;
    dscrv.subItem = nLV->iSubItem;
    m_LC_Protocols.SortItems(CompareFuncProtocols, (DWORD)(&dscrv));
    *pResult = 0;
}

int CALLBACK
DSRightView::CompareFuncDatabases(LPARAM one, LPARAM two, LPARAM data)
{
    int retVal = 0;
    char szBuf1[128], szBuf2[128];
    HRESULT hErr1, hErr2;

    IDSDatabase *pDB1 = (IDSDatabase *) one;
    IDSDatabase *pDB2 = (IDSDatabase *) two;
    _DS_RV_Composite *pDSCRV = (_DS_RV_Composite *) data;
    int column = pDSCRV->subItem;

    if (column == 0) { // comparison by name.
	hErr1 = pDB1->GetName(szBuf1, sizeof(szBuf1));
	hErr2 = pDB2->GetName(szBuf2, sizeof(szBuf2));

	if (SUCCEEDED(hErr1) && SUCCEEDED(hErr2)) { // could get both names.
	    if (szBuf1 && szBuf2) {
		retVal = strcmp(szBuf1, szBuf2);
		if (retVal == 0) { // do an additional comparison by protoname.
		    hErr1 = pDB1->GetProtocolName(szBuf1, sizeof(szBuf1));
		    hErr2 = pDB2->GetProtocolName(szBuf2, sizeof(szBuf2));
		    if (SUCCEEDED(hErr1) && SUCCEEDED(hErr2)) { 
			if (szBuf1 && szBuf2) {
			    retVal = strcmp(szBuf1, szBuf2);
			}
		    }
		}
	    }
	}
    }
    else { // comparison by protocol name.
	hErr1 = pDB1->GetProtocolName(szBuf1, sizeof(szBuf1));
	hErr2 = pDB2->GetProtocolName(szBuf2, sizeof(szBuf2));
	if (SUCCEEDED(hErr1) && SUCCEEDED(hErr2)) { // could get both protos.
	    if (szBuf1 && szBuf2) {
		retVal = strcmp(szBuf1, szBuf2);
		if (retVal == 0) { // do an additional comparison by name.
		    hErr1 = pDB1->GetName(szBuf1, sizeof(szBuf1));
		    hErr2 = pDB2->GetName(szBuf2, sizeof(szBuf2));
		    if (SUCCEEDED(hErr1) && SUCCEEDED(hErr2)) { 
			if (szBuf1 && szBuf2) {
			    retVal = strcmp(szBuf1, szBuf2);
			}
		    }
		}
	    }
	}
    }

    if (pDSCRV->pDSRV->shiftDown == TRUE) {
	if (retVal > 0) {
	    retVal = -1;
	}
	else if (retVal < 0) {
	    retVal = 1;
	}
    }

    return(retVal);
}

int CALLBACK
DSRightView::CompareFuncProtocols(LPARAM one, LPARAM two, LPARAM data)
{
    int retVal = 0;
    char szBuf1[128], szBuf2[128];
    HRESULT hErr1, hErr2;

    IDSProtocol *pPR1 = (IDSProtocol *) one;
    IDSProtocol *pPR2 = (IDSProtocol *) two;

    _DS_RV_Composite *pDSCRV = (_DS_RV_Composite *) data;

    hErr1 = pPR1->GetProtocolName(szBuf1, sizeof(szBuf1));
    hErr2 = pPR2->GetProtocolName(szBuf2, sizeof(szBuf2));

    if (SUCCEEDED(hErr1) && SUCCEEDED(hErr2)) { // could get both names.
	if (szBuf1 && szBuf2) {
	    retVal = strcmp(szBuf1, szBuf2);
	}
    }

    if (pDSCRV->pDSRV->shiftDown == TRUE) {
	if (retVal > 0) {
	    retVal = -1;
	}
	else if (retVal < 0) {
	    retVal = 1;
	}
    }

    return(retVal);
}

bool
DSRightView::OnlyPhSelected()
{
    ASSERT(pDS);

    bool    onlyPhSelected = true;
    bool    selected       = false;
    int     iCount = m_LC_Databases.GetItemCount();
    HRESULT hErr;
    void   *pv = static_cast<void *>(&m_LC_Databases);

    for (int i = 0; i < iCount; i++) {
	UINT nState = m_LC_Databases.GetItemState(i, LVIS_STATEIMAGEMASK);
	nState >>= 12;
	nState--;
	if (nState) {
	    char szBuf[128];
	    selected = true;
	    IDSDatabase *pDatabase = (IDSDatabase *)
		(::GetListItemLPARAM(pv, i));
	    hErr = pDatabase->GetProtocolName(szBuf, 128);
	    
	    int cmp = strcmp(szBuf, "Ph");

	    if (cmp) {
		onlyPhSelected = false;
		break;
	    }
	}
    }

    if (selected && onlyPhSelected) {
	return(true);
    }
    else {
	return(false);
    }
}

LRESULT
DSRightView::WindowProc(UINT wMessage, WPARAM wParam, LPARAM lParam)
{
    switch (wMessage) {
    case WM_GETDLGCODE:
	return(DLGC_WANTALLKEYS);
    case WM_CHAR:
	if (wParam == VK_TAB) {
	    ProcessTab();
	    return(0);
	}
	break;
    case WM_SYSCHAR:
	if (lParam & 0x20000000) {
	    if (IsThisALeftViewShortcutKey(wParam)) {
		::SendMessage(GetParent()->m_hWnd, wMessage, wParam, lParam);
		return(0);
	    }
	    else if (IsThisARightViewShortcutKey(wParam)) {
		if (ProcessShortcut(wParam) == true) {
		    return(0);
		}
	    }
	}
	break;
    default:
	break;
    }

    return(C3DFormView::WindowProc(wMessage, wParam, lParam));
} 

void
DSRightView::ProcessTab()
{
    HWND hWnd = GetFocus()->m_hWnd;
    if (hWnd == m_LC_Protocols.m_hWnd) {
	if (ShiftDown()) {
	    m_PB_DeleteDatabase.SetFocus();
	}
	else {
	    m_PB_NewDatabase.SetFocus();
	}
    }
    else if (hWnd == m_PB_NewDatabase.m_hWnd) {
	if (ShiftDown()) {
	    m_LC_Protocols.SetFocus();
	}
	else {
	    m_LC_Databases.SetFocus();
	}
    }
    else if (hWnd == m_LC_Databases.m_hWnd) {
	if (ShiftDown()) {
	    m_PB_NewDatabase.SetFocus();
	}
	else {
	    if (m_PB_ModifyDatabase.IsWindowEnabled() == TRUE) {
		m_PB_ModifyDatabase.SetFocus();
	    }
	    else {
		m_PB_DeleteDatabase.SetFocus();
	    }
	}
    }
    else if (hWnd ==  m_PB_ModifyDatabase.m_hWnd) {
	if (ShiftDown()) {
	    m_LC_Databases.SetFocus();
	}
	else {
	    m_PB_DeleteDatabase.SetFocus();
	}
    }
    else if (hWnd ==  m_PB_DeleteDatabase.m_hWnd) {
	if (ShiftDown()) {
	    if (m_PB_ModifyDatabase.IsWindowEnabled() == TRUE) {
		m_PB_ModifyDatabase.SetFocus();
	    }
	    else {
		m_LC_Databases.SetFocus();
	    }
	}
	else {
	    m_LC_Protocols.SetFocus();
	}
    }
}

bool
DSRightView::ProcessShortcut(WPARAM wParam)
{
    bool retVal = false;
    unsigned char sc = (BYTE) wParam;

    if( sc == DSSHORTCUT[SC_RV_NEWDATABASE])// New Database button.
	{
	m_PB_NewDatabase.SetFocus();
	m_PB_NewDatabase.SendMessage(WM_LBUTTONDOWN,
				     (WPARAM)MK_LBUTTON,
				     MAKELPARAM(0, 0));
	m_PB_NewDatabase.SendMessage(WM_LBUTTONUP, (WPARAM)0,
				     MAKELPARAM(0, 0));
	retVal = true;
	}
    else if( sc == DSSHORTCUT[SC_RV_MODIFYDATABASE]) // Modify Database button.
	{
	if (m_PB_ModifyDatabase.IsWindowEnabled() == TRUE) {
	    m_PB_ModifyDatabase.SetFocus();
	    m_PB_ModifyDatabase.SendMessage(WM_LBUTTONDOWN,
					    (WPARAM)MK_LBUTTON,
					    MAKELPARAM(0, 0));
	    m_PB_ModifyDatabase.SendMessage(WM_LBUTTONUP, (WPARAM)0,
					    MAKELPARAM(0, 0));
	    retVal = true;
	}
	}
    else if(sc == DSSHORTCUT[SC_RV_DELETEDATABASE]) // Delete Database button
	{
	m_PB_DeleteDatabase.SetFocus();
	m_PB_DeleteDatabase.SendMessage(WM_LBUTTONDOWN,
					(WPARAM)MK_LBUTTON,
					MAKELPARAM(0, 0));
	m_PB_DeleteDatabase.SendMessage(WM_LBUTTONUP, (WPARAM)0,
					MAKELPARAM(0, 0));
	retVal = true;
    }
    
    return(retVal);
}

bool
ShouldUpdateIni(int code)
{
    static bool bActive = false;

    switch(code) {
    case 0:
	bActive = false;
	break;
    case 1:
	bActive = true;
	break;
    default:
	break;
    }
    
    return bActive;
}

void
DSRightView::Notify(QCCommandObject*	pCommand,
						COMMAND_ACTION_TYPE	theAction,
						void*				pData)
{
	if (theAction == CA_SWM_CHANGE_FEATURE) 
	{

		// Shareware: In reduced feature mode, you can only select one database
		QCSharewareManager *pSWM = QCSharewareManager::GetSharewareManager();
		ASSERT(pSWM);
		if ((pSWM) && (pSWM->UsingFullFeatureSet() == false))
		{
			// So the user has just changed from FULL to REDUCED
			// Make sure only one DB is selected

			int iCount = m_LC_Databases.GetItemCount();
			bool bPrevSel = false;

			for (int i = 0; i < iCount; i++) 
			{
				UINT nState = m_LC_Databases.GetItemState(i, LVIS_STATEIMAGEMASK);
				nState >>= 12;
				nState--;
				if (nState) // If nState is > 0, then this item is selected
				{
					if (bPrevSel)
					{
						// This is the second or higher selcted, so unselect it
						m_LC_Databases.SetItemState(i, INDEXTOSTATEIMAGEMASK(1), 
								LVIS_STATEIMAGEMASK);	//unselect
					}
					else
					{
						bPrevSel = true;
					}
				}
			}
		}
	}
}


bool   DSRightView::InitShortcuts()
{
	DSSHORTCUT[SC_RV_NEWDATABASE] = 'n';
    DSSHORTCUT[SC_RV_MODIFYDATABASE] = 'm';
    DSSHORTCUT[SC_RV_DELETEDATABASE] = 'd';
	
	unsigned char sc = 0;
	
	sc = GetDlgShortcutChar(this,IDD_NDS_PB_NEWDATABASE);
	if( sc >0)
		DSSHORTCUT[SC_RV_NEWDATABASE] = sc;

	sc = GetDlgShortcutChar(this,IDD_NDS_PB_MODIFYDATABASE);
	if( sc >0)
		DSSHORTCUT[SC_RV_MODIFYDATABASE] = sc;


	sc = GetDlgShortcutChar(this,IDD_NDS_PB_DELETEDATABASE);
	if( sc >0)
		DSSHORTCUT[SC_RV_DELETEDATABASE] = sc;


	return TRUE;
}
