/*-------
 * Module:			setup.c
 *
 * Description:		This module contains the setup functions for
 *					adding/modifying a Data Source in the ODBC.INI portion
 *					of the registry.
 *
 * Classes:			n/a
 *
 * API functions:	ConfigDSN
 *
 * Comments:		See "notice.txt" for copyright and license information.
 *-------
 */

#include  "psqlodbc.h"
#include  "connection.h"
#include  <windows.h>
#include  <windowsx.h>
#include  <odbcinst.h>
#include  <string.h>
#include  <stdlib.h>
#include  "resource.h"
#include  "dlg_specific.h"


#define INTFUNC  __stdcall

extern HINSTANCE NEAR s_hModule;/* Saved module handle. */
extern GLOBAL_VALUES globals;

/* Constants */
#define MIN(x,y)	  ((x) < (y) ? (x) : (y))

#ifdef WIN32
#define MAXPGPATH		(255+1)
#endif

#define MAXKEYLEN		(15+1)	/* Max keyword length */
#define MAXDESC			(255+1) /* Max description length */
#define MAXDSNAME		(32+1)	/* Max data source name length */


/* Globals */
/* NOTE:  All these are used by the dialog procedures */
typedef struct tagSETUPDLG
{
	HWND		hwndParent;		/* Parent window handle */
	LPCSTR		lpszDrvr;		/* Driver description */
	ConnInfo	ci;
	char		szDSN[MAXDSNAME];		/* Original data source name */
	BOOL		fNewDSN;		/* New data source flag */
	BOOL		fDefault;		/* Default data source flag */

}			SETUPDLG, FAR *LPSETUPDLG;



/* Prototypes */
void INTFUNC CenterDialog(HWND hdlg);
int CALLBACK ConfigDlgProc(HWND hdlg, WORD wMsg, WPARAM wParam, LPARAM lParam);
void INTFUNC ParseAttributes(LPCSTR lpszAttributes, LPSETUPDLG lpsetupdlg);
BOOL INTFUNC SetDSNAttributes(HWND hwnd, LPSETUPDLG lpsetupdlg);


/*--------
 *	ConfigDSN
 *
 *	Description:	ODBC Setup entry point
 *				This entry point is called by the ODBC Installer
 *				(see file header for more details)
 *	Input	 :	hwnd ----------- Parent window handle
 *				fRequest ------- Request type (i.e., add, config, or remove)
 *				lpszDriver ----- Driver name
 *				lpszAttributes - data source attribute string
 *	Output	 :	TRUE success, FALSE otherwise
 *--------
 */
BOOL		CALLBACK
ConfigDSN(HWND hwnd,
		  WORD fRequest,
		  LPCSTR lpszDriver,
		  LPCSTR lpszAttributes)
{
	BOOL		fSuccess;		/* Success/fail flag */
	GLOBALHANDLE hglbAttr;
	LPSETUPDLG	lpsetupdlg;


	/* Allocate attribute array */
	hglbAttr = GlobalAlloc(GMEM_MOVEABLE | GMEM_ZEROINIT, sizeof(SETUPDLG));
	if (!hglbAttr)
		return FALSE;
	lpsetupdlg = (LPSETUPDLG) GlobalLock(hglbAttr);

	/* Parse attribute string */
	if (lpszAttributes)
		ParseAttributes(lpszAttributes, lpsetupdlg);

	/* Save original data source name */
	if (lpsetupdlg->ci.dsn[0])
		lstrcpy(lpsetupdlg->szDSN, lpsetupdlg->ci.dsn);
	else
		lpsetupdlg->szDSN[0] = '\0';

	/* Remove data source */
	if (ODBC_REMOVE_DSN == fRequest)
	{
		/* Fail if no data source name was supplied */
		if (!lpsetupdlg->ci.dsn[0])
			fSuccess = FALSE;

		/* Otherwise remove data source from ODBC.INI */
		else
			fSuccess = SQLRemoveDSNFromIni(lpsetupdlg->ci.dsn);
	}
	/* Add or Configure data source */
	else
	{
		/* Save passed variables for global access (e.g., dialog access) */
		lpsetupdlg->hwndParent = hwnd;
		lpsetupdlg->lpszDrvr = lpszDriver;
		lpsetupdlg->fNewDSN = (ODBC_ADD_DSN == fRequest);
		lpsetupdlg->fDefault = !lstrcmpi(lpsetupdlg->ci.dsn, INI_DSN);

		/*
		 * Display the appropriate dialog (if parent window handle
		 * supplied)
		 */
		if (hwnd)
		{
			/* Display dialog(s) */
			fSuccess = (IDOK == DialogBoxParam(s_hModule,
											 MAKEINTRESOURCE(DLG_CONFIG),
											   hwnd,
											   ConfigDlgProc,
											 (LONG) (LPSTR) lpsetupdlg));
		}
		else if (lpsetupdlg->ci.dsn[0])
			fSuccess = SetDSNAttributes(hwnd, lpsetupdlg);
		else
			fSuccess = FALSE;
	}

	GlobalUnlock(hglbAttr);
	GlobalFree(hglbAttr);

	return fSuccess;
}


/*-------
 * CenterDialog
 *
 *		Description:  Center the dialog over the frame window
 *		Input	   :  hdlg -- Dialog window handle
 *		Output	   :  None
 *-------
 */
void		INTFUNC
CenterDialog(HWND hdlg)
{
	HWND		hwndFrame;
	RECT		rcDlg,
				rcScr,
				rcFrame;
	int			cx,
				cy;

	hwndFrame = GetParent(hdlg);

	GetWindowRect(hdlg, &rcDlg);
	cx = rcDlg.right - rcDlg.left;
	cy = rcDlg.bottom - rcDlg.top;

	GetClientRect(hwndFrame, &rcFrame);
	ClientToScreen(hwndFrame, (LPPOINT) (&rcFrame.left));
	ClientToScreen(hwndFrame, (LPPOINT) (&rcFrame.right));
	rcDlg.top = rcFrame.top + (((rcFrame.bottom - rcFrame.top) - cy) >> 1);
	rcDlg.left = rcFrame.left + (((rcFrame.right - rcFrame.left) - cx) >> 1);
	rcDlg.bottom = rcDlg.top + cy;
	rcDlg.right = rcDlg.left + cx;

	GetWindowRect(GetDesktopWindow(), &rcScr);
	if (rcDlg.bottom > rcScr.bottom)
	{
		rcDlg.bottom = rcScr.bottom;
		rcDlg.top = rcDlg.bottom - cy;
	}
	if (rcDlg.right > rcScr.right)
	{
		rcDlg.right = rcScr.right;
		rcDlg.left = rcDlg.right - cx;
	}

	if (rcDlg.left < 0)
		rcDlg.left = 0;
	if (rcDlg.top < 0)
		rcDlg.top = 0;

	MoveWindow(hdlg, rcDlg.left, rcDlg.top, cx, cy, TRUE);
	return;
}

/*-------
 * ConfigDlgProc
 *	Description:	Manage add data source name dialog
 *	Input	 :	hdlg --- Dialog window handle
 *				wMsg --- Message
 *				wParam - Message parameter
 *				lParam - Message parameter
 *	Output	 :	TRUE if message processed, FALSE otherwise
 *-------
 */
int			CALLBACK
ConfigDlgProc(HWND hdlg,
			  WORD wMsg,
			  WPARAM wParam,
			  LPARAM lParam)
{
	switch (wMsg)
	{
			/* Initialize the dialog */
			case WM_INITDIALOG:
			{
				LPSETUPDLG	lpsetupdlg = (LPSETUPDLG) lParam;
				ConnInfo   *ci = &lpsetupdlg->ci;

				/* Hide the driver connect message */
				ShowWindow(GetDlgItem(hdlg, DRV_MSG_LABEL), SW_HIDE);

				SetWindowLong(hdlg, DWL_USER, lParam);
				CenterDialog(hdlg);		/* Center dialog */

				/*
				 * NOTE: Values supplied in the attribute string will
				 * always
				 */
				/* override settings in ODBC.INI */

				/* Get the rest of the common attributes */
				getDSNinfo(ci, CONN_DONT_OVERWRITE);

				/* Fill in any defaults */
				getDSNdefaults(ci);

				/* Initialize dialog fields */
				SetDlgStuff(hdlg, ci);

				if (lpsetupdlg->fDefault)
				{
					EnableWindow(GetDlgItem(hdlg, IDC_DSNAME), FALSE);
					EnableWindow(GetDlgItem(hdlg, IDC_DSNAMETEXT), FALSE);
				}
				else
					SendDlgItemMessage(hdlg, IDC_DSNAME,
							 EM_LIMITTEXT, (WPARAM) (MAXDSNAME - 1), 0L);

				SendDlgItemMessage(hdlg, IDC_DESC,
							   EM_LIMITTEXT, (WPARAM) (MAXDESC - 1), 0L);
				return TRUE;	/* Focus was not set */
			}

			/* Process buttons */
		case WM_COMMAND:
			switch (GET_WM_COMMAND_ID(wParam, lParam))
			{

					/*
					 * Ensure the OK button is enabled only when a data
					 * source name
					 */
					/* is entered */
				case IDC_DSNAME:
					if (GET_WM_COMMAND_CMD(wParam, lParam) == EN_CHANGE)
					{
						char		szItem[MAXDSNAME];	/* Edit control text */

						/* Enable/disable the OK button */
						EnableWindow(GetDlgItem(hdlg, IDOK),
									 GetDlgItemText(hdlg, IDC_DSNAME,
												szItem, sizeof(szItem)));
						return TRUE;
					}
					break;

					/* Accept results */
				case IDOK:
					{
						LPSETUPDLG	lpsetupdlg;

						lpsetupdlg = (LPSETUPDLG) GetWindowLong(hdlg, DWL_USER);
						/* Retrieve dialog values */
						if (!lpsetupdlg->fDefault)
							GetDlgItemText(hdlg, IDC_DSNAME,
										   lpsetupdlg->ci.dsn,
										   sizeof(lpsetupdlg->ci.dsn));
						/* Get Dialog Values */
						GetDlgStuff(hdlg, &lpsetupdlg->ci);

						/* Update ODBC.INI */
						SetDSNAttributes(hdlg, lpsetupdlg);
					}

					/* Return to caller */
				case IDCANCEL:
					EndDialog(hdlg, wParam);
					return TRUE;

				case IDC_DRIVER:
					DialogBoxParam(s_hModule, MAKEINTRESOURCE(DLG_OPTIONS_DRV),
								hdlg, driver_optionsProc, (LPARAM) NULL);

					return TRUE;

				case IDC_DATASOURCE:
					{
						LPSETUPDLG	lpsetupdlg;

						lpsetupdlg = (LPSETUPDLG) GetWindowLong(hdlg, DWL_USER);

						DialogBoxParam(s_hModule, MAKEINTRESOURCE(DLG_OPTIONS_DS),
						 hdlg, ds_optionsProc, (LPARAM) &lpsetupdlg->ci);

						return TRUE;
					}
			}
			break;
	}

	/* Message not processed */
	return FALSE;
}


/*-------
 * ParseAttributes
 *
 *	Description:	Parse attribute string moving values into the aAttr array
 *	Input	 :	lpszAttributes - Pointer to attribute string
 *	Output	 :	None (global aAttr normally updated)
 *-------
 */
void		INTFUNC
ParseAttributes(LPCSTR lpszAttributes, LPSETUPDLG lpsetupdlg)
{
	LPCSTR		lpsz;
	LPCSTR		lpszStart;
	char		aszKey[MAXKEYLEN];
	int			cbKey;
	char		value[MAXPGPATH];

	memset(&lpsetupdlg->ci, 0, sizeof(ConnInfo));

	for (lpsz = lpszAttributes; *lpsz; lpsz++)
	{

		/*
		 * Extract key name (e.g., DSN), it must be terminated by an
		 * equals
		 */
		lpszStart = lpsz;
		for (;; lpsz++)
		{
			if (!*lpsz)
				return;			/* No key was found */
			else if (*lpsz == '=')
				break;			/* Valid key found */
		}
		/* Determine the key's index in the key table (-1 if not found) */
		cbKey = lpsz - lpszStart;
		if (cbKey < sizeof(aszKey))
		{
			_fmemcpy(aszKey, lpszStart, cbKey);
			aszKey[cbKey] = '\0';
		}

		/* Locate end of key value */
		lpszStart = ++lpsz;
		for (; *lpsz; lpsz++)
			;

		/* lpsetupdlg->aAttr[iElement].fSupplied = TRUE; */
		_fmemcpy(value, lpszStart, MIN(lpsz - lpszStart + 1, MAXPGPATH));

		mylog("aszKey='%s', value='%s'\n", aszKey, value);

		/* Copy the appropriate value to the conninfo  */
		copyAttributes(&lpsetupdlg->ci, aszKey, value);
	}
	return;
}


/*--------
 * SetDSNAttributes
 *
 *	Description:	Write data source attributes to ODBC.INI
 *	Input	 :	hwnd - Parent window handle (plus globals)
 *	Output	 :	TRUE if successful, FALSE otherwise
 *--------
 */
BOOL		INTFUNC
SetDSNAttributes(HWND hwndParent, LPSETUPDLG lpsetupdlg)
{
	LPCSTR		lpszDSN;		/* Pointer to data source name */

	lpszDSN = lpsetupdlg->ci.dsn;

	/* Validate arguments */
	if (lpsetupdlg->fNewDSN && !*lpsetupdlg->ci.dsn)
		return FALSE;

	/* Write the data source name */
	if (!SQLWriteDSNToIni(lpszDSN, lpsetupdlg->lpszDrvr))
	{
		if (hwndParent)
		{
			char		szBuf[MAXPGPATH];
			char		szMsg[MAXPGPATH];

			LoadString(s_hModule, IDS_BADDSN, szBuf, sizeof(szBuf));
			wsprintf(szMsg, szBuf, lpszDSN);
			LoadString(s_hModule, IDS_MSGTITLE, szBuf, sizeof(szBuf));
			MessageBox(hwndParent, szMsg, szBuf, MB_ICONEXCLAMATION | MB_OK);
		}
		return FALSE;
	}

	/* Update ODBC.INI */
	writeDSNinfo(&lpsetupdlg->ci);

	/* If the data source name has changed, remove the old name */
	if (lstrcmpi(lpsetupdlg->szDSN, lpsetupdlg->ci.dsn))
		SQLRemoveDSNFromIni(lpsetupdlg->szDSN);
	return TRUE;
}
