/*
 * Copyright (c) 2001, 2002, 2003 Gary R. Van Sickle.
 * Copyright (c) 2005-2006 Tom N Harris.
 *
 *     This program is free software; you can redistribute it and/or modify
 *     it under the terms of the GNU General Public License as published by
 *     the Free Software Foundation; either version 2 of the License, or
 *     (at your option) any later version.
 *
 *     A copy of the GNU General Public License can be found at
 *     http://www.gnu.org/
 *
 * Written by Gary R. Van Sickle <g.r.vansickle@worldnet.att.net>
 * Written by Tom N Harris <telliamed@whoopdedo.org>
 *
 */

// This is the implementation of the PropertyPage class.  It works closely with the
// PropSheet class to implement a single page of the property sheet.

#include "win32.h"
#include "PropPage.h"
#include "PropSheet.h"
#include "resource.h"

using namespace Setup;

bool PropertyPage::DoOnceForSheet = true;

/*
  Sizing information for some controls that are common to all pages.
 */
static ControlAdjuster::ControlInfo DefaultControlsInfo[] = {
	{IDC_HEADICON, CP_RIGHT, CP_TOP},
	{IDC_HEADSEPARATOR, CP_STRETCH, CP_TOP},
	{0, CP_LEFT, CP_TOP}
};

PropertyPage::PropertyPage ()
	: m_proc(NULL),
	  m_cmdproc(NULL),
	  m_isFirst(false),
	  m_isLast(false)
{
	m_sizeProcessor.addControlInfo(DefaultControlsInfo);
}

PropertyPage::~PropertyPage()
{
}

bool PropertyPage::create(int TemplateID)
{
	return create(NULL, NULL, TemplateID);
}

bool PropertyPage::create(DLGPROC dlgproc, int TemplateID)
{
	return create(dlgproc, NULL, TemplateID);
}

bool
PropertyPage::create(DLGPROC dlgproc,
		     BOOL (*cproc)(HWND h, int id, HWND hwndctl, UINT code),
		     int TemplateID)
{
	m_psp.dwSize = sizeof(PROPSHEETPAGE);
	m_psp.dwFlags = 0;
	m_psp.hInstance = getInstance();
	m_psp.pfnDlgProc = FirstDialogProcReflector;
	m_psp.pszTemplate = MAKEINTRESOURCE(TemplateID);
	m_psp.lParam = reinterpret_cast<LPARAM>(this);
	m_psp.pfnCallback = NULL;

	m_proc = dlgproc;
	m_cmdproc = cproc;

	return true;
}

BOOL CALLBACK
PropertyPage::FirstDialogProcReflector(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
	PropertyPage* This;

	if (message != WM_INITDIALOG)
	{
		// Don't handle anything until we get a WM_INITDIALOG message, which
		// will have our 'this' pointer with it.
		return FALSE;
	}

	This = reinterpret_cast<PropertyPage*>(reinterpret_cast<PROPSHEETPAGE*>(lParam)->lParam);

	::SetWindowLongPtr(hwnd, DWLP_USER, reinterpret_cast<LONG_PTR>(This));
	::SetWindowLongPtr(hwnd, DWLP_DLGPROC, reinterpret_cast<LONG_PTR>(DialogProcReflector));

	This->setHWND(hwnd);
	return This->dialogProc(message, wParam, lParam);
}

BOOL CALLBACK
PropertyPage::DialogProcReflector(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
	PropertyPage* This;

	This = reinterpret_cast<PropertyPage*>(::GetWindowLongPtr(hwnd, DWLP_USER));

	return This->dialogProc(message, wParam, lParam);
}

BOOL CALLBACK
PropertyPage::dialogProc(UINT message, WPARAM wParam, LPARAM lParam)
{
	if (m_proc != NULL)
	{
		m_proc(getHWND(), message, wParam, lParam);
	}

	bool retval;

	switch (message)
	{
	  case WM_INITDIALOG:
	  {
		onInit();

		setTitleFont();
	
		// Call it here so it stores the initial client rect.
		m_sizeProcessor.updateSize(getHWND());

		// TRUE = Set focus to default control (in wParam).
		return TRUE;
		break;
	  }
	  case WM_NOTIFY:
		switch (reinterpret_cast<NMHDR FAR*>(lParam)->code)
		{
		  case PSN_APPLY:
			  ::SetWindowLong(getHWND(), DWL_MSGRESULT, PSNRET_NOERROR);
			  return TRUE;
			  break;
		  case PSN_SETACTIVE:
		  {
			if (DoOnceForSheet)
			{
				// Tell our parent PropSheet what its own HWND is.
				getOwner()->setHWNDFromPage(reinterpret_cast<NMHDR FAR*>(lParam)->hwndFrom);
				getOwner()->centerWindow();
				DoOnceForSheet = false;
			}

			getOwner()->adjustPageSize(getHWND());
	      
			// Set the wizard buttons apropriately
			DWORD buttons = m_isLast ? PSWIZB_FINISH : PSWIZB_NEXT;
			if (!m_isFirst)
				buttons |= PSWIZB_BACK;
			getOwner()->setButtons(buttons);

			if(!wantsActivation())
			{
				::SetWindowLong(getHWND(), DWL_MSGRESULT, -1);
				return TRUE;
			}

			onActivate();

			if (false /*unattended_mode*/) 
			{
				// -2 == disable unattended mode, display page
				// -1 == display page but stay in unattended mode (progress bars)
				// 0 == skip to next page
				// IDD_* == skip to specified page
				long nextwindow = onUnattended();
				if (nextwindow == InterruptAndDisplay)
				{
					//unattended_mode = false;
					::SetWindowLong(getHWND(), DWL_MSGRESULT, 0);
					return TRUE;
				}
				else if (nextwindow == DisplayPage)
				{
					::SetWindowLong(getHWND(), DWL_MSGRESULT, 0);
					return TRUE;
				}
				else if (nextwindow == SkipPage)
				{
					::SetWindowLong(getHWND(), DWL_MSGRESULT, -1);
					return TRUE;
				}
				else
				{
					::SetWindowLong(getHWND(), DWL_MSGRESULT, nextwindow);
					return TRUE;
				}
			} 
			else 
			{
				// 0 == Accept activation, -1 = Don't accept
				::SetWindowLong(getHWND(), DWL_MSGRESULT, 0);
				return TRUE;
			}

			break;
		  }
		  case PSN_KILLACTIVE:
			onDeactivate();
			// FALSE = Allow deactivation
			::SetWindowLong(getHWND(), DWL_MSGRESULT, FALSE);
			return TRUE;
			break;
		  case PSN_WIZNEXT:
		  {
			LONG retval;
			retval = onNext();
			::SetWindowLong(getHWND(), DWL_MSGRESULT, retval);
			return TRUE;
			break;
		  }
		  case PSN_QUERYCANCEL:
		  {
			retval = onCancel();
			// False = Allow the wizard to finish
			::SetWindowLong(getHWND(), DWL_MSGRESULT, retval);
			return TRUE;
			break;
		  }
		  case PSN_WIZBACK:
		  {
			LONG retval;
			retval = onBack();
			::SetWindowLong(getHWND(), DWL_MSGRESULT, retval);
			return TRUE;
			break;
		  }
		  case PSN_WIZFINISH:
			retval = onFinish();
			// False = Allow the wizard to finish
			::SetWindowLong(getHWND(), DWL_MSGRESULT, FALSE);
			return TRUE;
			break;
		  default:
			// Unrecognized notification
			return FALSE;
			break;
		}
		break;
	  case WM_COMMAND:
	  {
		bool retval;

		retval = onMessageCmd(LOWORD(wParam), (HWND)lParam, HIWORD(wParam));
		if (retval == true)
		{
			// Handled, return 0
			::SetWindowLong(getHWND(), DWL_MSGRESULT, 0);
			return TRUE;
		}
		else if (m_cmdproc != NULL)
		{
			return m_cmdproc(getHWND(), LOWORD(wParam), reinterpret_cast<HWND>(lParam), HIWORD(wParam));
		}
		break;
	  }
	  case WM_SIZE:
	  {
		m_sizeProcessor.updateSize(getHWND());
		break;
	  }
	  default:
		break;
	}

	if ((message >= WM_APP) && (message < 0xC000))
	{
		// It's a private app message
		return onMessageApp(message, wParam, lParam);
	}

	// Wasn't handled
	return FALSE;
}

void
PropertyPage::setTitleFont()
{
	// These font settings will just silently fail when the resource id
	// is not present on a page.
	// Set header title font of each internal page
	setDlgItemFont(IDC_STATIC_HEADER_TITLE, TEXT("MS Shell Dlg"), 8, FW_BOLD);
	// Set the font for the IDC_STATIC_WELCOME_TITLE
	setDlgItemFont(IDC_STATIC_WELCOME_TITLE, TEXT("Arial"), 12, FW_BOLD);
}

void
PropertyPage::enableNext(bool enable)
{
	DWORD buttons = m_isFirst ? 0 : PSWIZB_BACK;
	if (enable)
		buttons |= m_isLast ? PSWIZB_FINISH : PSWIZB_NEXT;
	getOwner()->setButtons(buttons);
}

