/*****************************************************************************
* Copyright (c) 1990-2000 Digi International Inc., All Rights Reserved
* 
* This software contains proprietary and confidential information of Digi
* International Inc.  By accepting transfer of this copy, Recipient agrees
* to retain this software in confidence, to prevent disclosure to others,
* and to make no use of this software other than that for which it was
* delivered.  This is an unpublished copyrighted work of Digi International
* Inc.  Except as permitted by federal law, 17 USC 117, copying is strictly
* prohibited.
* 
* Restricted Rights Legend
*
* Use, duplication, or disclosure by the Government is subject to
* restrictions set forth in sub-paragraph (c)(1)(ii) of The Rights in
* Technical Data and Computer Software clause at DFARS 252.227-7031 or
* subparagraphs (c)(1) and (2) of the Commercial Computer Software -
* Restricted Rights at 48 CFR 52.227-19, as applicable.
*
* Digi International Inc. 11001 Bren Road East, Minnetonka, MN 55343
*
*****************************************************************************/


// CConfigWizSheet.cpp : implementation file
//

#include "stdafx.h"
#include "ConfigWizSheet.h"
#include "ConfigWizPage.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif


// PAGE PROPERTIES bit field
#define PERMANENT_PAGE	1
#define SKIP_PAGE       2


/////////////////////////////////////////////////////////////////////////////
// CConfigWizSheet

IMPLEMENT_DYNAMIC(CConfigWizSheet, CPropertySheet)

CConfigWizSheet::CConfigWizSheet(UINT nIDCaption, CWnd* pParentWnd, UINT iSelectPage)
	:CPropertySheet(nIDCaption, pParentWnd, iSelectPage)
{
	Construct();
}

CConfigWizSheet::CConfigWizSheet(LPCTSTR pszCaption, CWnd* pParentWnd, UINT iSelectPage)
	:CPropertySheet(pszCaption, pParentWnd, iSelectPage)
{
	Construct();
}

CConfigWizSheet::~CConfigWizSheet()
{
	m_PagePtrs.RemoveAll();	
	m_PageProperty.RemoveAll();
}


BEGIN_MESSAGE_MAP(CConfigWizSheet, CPropertySheet)
	//{{AFX_MSG_MAP(CConfigWizSheet)
	ON_WM_ERASEBKGND()
	ON_WM_DESTROY()
	ON_WM_PALETTECHANGED()
	ON_WM_QUERYNEWPALETTE()
	ON_WM_SETFOCUS()
	//}}AFX_MSG_MAP
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CConfigWizSheet message handlers


// common constructor code
void CConfigWizSheet::Construct()
{
	SetWizardMode();           // wizard mode turned on by default

	m_nPageIndex = -1;
	m_nInsertIndex = -1;

   m_strTitleBase = TEXT("");

   m_ptSheetBmpPlacement.x = 0;
   m_ptSheetBmpPlacement.y = 0;
   m_pSheetBmp = NULL;

   m_ptDfltPageBmpPlacement.x = 0;
   m_ptDfltPageBmpPlacement.y = 0;
   m_pDfltPageBmp = NULL;
}

// overridden virtual. 
INT_PTR CConfigWizSheet::DoModal() 
{
	// we have to have at least 1 page to start with
	if (m_PagePtrs.GetSize() == 0)
		return 0;
	// if no pages have been added to the underlying sheet,
	// add the first one.
	if (m_nPageIndex == -1)
	{
		WORD mask = m_PageProperty.GetAt(0);
		ASSERT(mask & PERMANENT_PAGE);
		WizForward();
	}

	return CPropertySheet::DoModal();
}

// Add a property page to our internal array
// fSkipOnBack if set to TRUE will skip this page when going backwards
// If the page already exists in our array, it will not be added
// Return TRUE if page was successfully added
BOOL CConfigWizSheet::AddPage(CConfigWizPage* pPage, BOOL fSkipOnBack /* = FALSE */, BOOL fPermanent /* = FALSE */)
{
	ASSERT_KINDOF(CConfigWizPage,pPage);
	BOOL bRetval = FALSE;
	try 
	{
		if (pPage && !FindPage(pPage))
		{
			m_PagePtrs.Add(pPage);
			WORD mask = 0;
			if (fPermanent)
				mask |= PERMANENT_PAGE;
			if (fSkipOnBack)
				mask |= SKIP_PAGE;
			m_PageProperty.Add(mask);
			bRetval = TRUE;
		}
	}
	catch(CMemoryException *e)
	{
		TRACE("Error adding page\n");
		e->Delete();
	}
	
	return bRetval;
}

// Insert a property page in our internal array
// fSkipOnBack if set to TRUE will skip this page when going backwards
// Insertion is done at the point of current insertion index m_nInsertIndex;
// pages to the right of the insertion point will be shifted to the right by 1.
// If the page already exists in our array, it won't be inserted
// Returns TRUE on successful insertion
BOOL CConfigWizSheet::InsertPage(CConfigWizPage* pPage, BOOL fSkipOnBack /* = FALSE */, BOOL fPermanent /* = FALSE */)
{
	ASSERT_KINDOF(CConfigWizPage,pPage);
	BOOL bRetval = FALSE;
	try
	{
		if (pPage && !FindPage(pPage))
		{
			m_PagePtrs.InsertAt(m_nInsertIndex+1,pPage);
			WORD mask = 0;
			if (fPermanent)
				mask |= PERMANENT_PAGE;
			if (fSkipOnBack)
				mask |= SKIP_PAGE;

			m_PageProperty.InsertAt(m_nInsertIndex+1,mask);
			m_nInsertIndex++;
			bRetval = TRUE;
		}
	}
	catch(CMemoryException *e)
	{
		TRACE1("Error inserting page at index %d\n",m_nInsertIndex);
		e->Delete();
	}
	return bRetval;
}

// called when pressing the Next Button on the property sheet.
// The CConfigWizPage class gets the message, It then turns around and
// calls this method.
// This method will grab the next page, pointed to by the page index, from 
// the internal array and add it to the baseclass iff the page already doesnot exist. 
// This target page will then be made active.
void CConfigWizSheet::WizForward()
{
	// if no more entries to add, return.
	if (m_nPageIndex == m_PagePtrs.GetSize()-1)
		return;
	CPropertyPage* pPg = (CPropertyPage*)m_PagePtrs.GetAt(m_nPageIndex+1);
	// only add the page if it hasn't been already added
	if (m_nPageIndex == -1 || GetPageIndex(pPg) == -1)
	{
		CPropertySheet::AddPage(pPg);
	}
	++m_nPageIndex;
	m_nInsertIndex = m_nPageIndex;
	// called after m_nPageIndex is updated
	SetActivePage(pPg);
}

// called when pressing the back button
// 
void CConfigWizSheet::WizReverse()
{
	if (!m_nPageIndex)
		return;
	int nindex = m_nPageIndex; // track where we started
	// work backwords until 1st page with non-skip attribute found
	// we make sure to start checking from current page.
	BOOL bSkip,bRemove;
	CPtrArray delPages;
	do
	{
		ASSERT(m_nPageIndex >= 0);
		WORD mask = m_PageProperty.GetAt(m_nPageIndex);
		bRemove = (mask & PERMANENT_PAGE)?FALSE:TRUE;
		bSkip = (mask & SKIP_PAGE)?TRUE:FALSE;
		// remove this page if its temporary AND is the starting page or marked
		// as skippable.
		if (bRemove && (bSkip || m_nPageIndex == nindex))
		{
			// get the page pointer in question
			CPropertyPage* pPg = (CPropertyPage*)m_PagePtrs.GetAt(m_nPageIndex);
			// need to make sure that the page has not been deleted behind our
			// back.
			if (GetPageIndex(pPg) != -1)
				delPages.Add(pPg);
			bSkip = TRUE;  // if the latter part of the IF statement was TRUE
		}

		// if this is the first time through the loop and we did not force skip the
		// current page, we need to force the while to evaluate to TRUE.
		if (nindex == m_nPageIndex)
			bSkip = TRUE;

		if (bSkip)
			--m_nPageIndex;
	}
	while(bSkip);
	// walk through deleted page arrays and actually remove them
	INT_PTR ncount = delPages.GetSize();
	for(int i=0;i<ncount;i++)
	{
			RemovePage((CConfigWizPage*)delPages.GetAt(i));
	}
	delPages.RemoveAll();
	m_nInsertIndex = m_nPageIndex;
	CPropertyPage* pPg = (CPropertyPage*)m_PagePtrs.GetAt(m_nPageIndex);
	// called after m_nPageIndex is updated
	SetActivePage(pPg);
	
}

// this routine is called from CConfigWizPage::OnSetActive. It uses current page
// index m_nPageIndex to enable/disable Back button and to change Next to Finish.
// CAUTION: Calling SetActivePage will generate a call to OnSetActive. So its 
// imperative that m_nPageIndex be updated prior to calling SetActivePg.
void CConfigWizSheet::CheckButtonState()
{
	DWORD dwFlags = 0;
	if (m_nPageIndex > 0)
		dwFlags = PSWIZB_BACK;
	if (m_nPageIndex < m_PagePtrs.GetSize()-1)
		dwFlags |= PSWIZB_NEXT;
	else
		dwFlags |= PSWIZB_FINISH;
	SetWizardButtons(dwFlags);
}

// explicitly remove a page from our array and also from the underlying baseclass
// 
// input: provide pointer to page targeted for removal. 
BOOL CConfigWizSheet::RemovePage(CConfigWizPage* pPg)
{
	ASSERT_KINDOF(CConfigWizPage,pPg);
	if (pPg == NULL)
		return FALSE;
	// TRACE("RemovePage=%d\n",m_PagePtrs.GetSize());
	for(int i=0;i<m_PagePtrs.GetSize();i++)
	{
		if (pPg == (CConfigWizPage*)m_PagePtrs.GetAt(i))
		{
			m_PagePtrs.RemoveAt(i);
			m_PageProperty.RemoveAt(i);
			if (GetPageIndex(pPg) != -1)
				CPropertySheet::RemovePage((CPropertyPage*)pPg);
			return TRUE;
		}
	}
	return FALSE;
}

// support routine. Returns TRUE if a page pointer exists in our 
// local array.
BOOL CConfigWizSheet::FindPage(const CConfigWizPage* pPg) const
{
	for(int i=0;i<m_PagePtrs.GetSize();i++)
	{
		if (pPg == (CConfigWizPage*)m_PagePtrs.GetAt(i))
			return TRUE;
	}
	return FALSE;
}

BOOL CConfigWizSheet::OnInitDialog() 
{
	BOOL bResult = CPropertySheet::OnInitDialog();

   CenterWindow(GetDesktopWindow());
	
	return bResult;
}

void CConfigWizSheet::SetSheetBitmap(CDib const * const pBmp, CPoint const & ptPlacement)
{
   try
   {
      AffirmThrow(pBmp != NULL);

      m_pSheetBmp = (CDib *) pBmp;
      m_ptSheetBmpPlacement = ptPlacement;
   }
   catch (CAffirmException ae)
   {
   }
}

void CConfigWizSheet::SetDefaultPageBitmap(CDib const * const pBmp, CPoint const & ptPlacement)
{
   try
   {
      AffirmThrow(pBmp != NULL);

      m_pDfltPageBmp = (CDib *) pBmp;
      m_ptDfltPageBmpPlacement = ptPlacement;
   }
   catch (CAffirmException ae)
   {
   }
}

BOOL CConfigWizSheet::OnEraseBkgnd(CDC* pDC) 
{
	CPropertySheet::OnEraseBkgnd(pDC);

   try
   {
      if (m_pSheetBmp != NULL)
      {
         AffirmThrow(pDC != NULL);
         CRect rc(m_ptSheetBmpPlacement, m_pSheetBmp->GetSize());
         m_pSheetBmp->Draw(*pDC, &rc);
      }
   }
   catch (CAffirmException ae)
   {
   }
	
	return TRUE;      // Erasing is all done
}

void CConfigWizSheet::OnDestroy() 
{
   // NOTE: call our app's WinHelp(), not CWnd's
   TRACE("CConfigWizSheet::OnDestroy()\n");
#ifndef NT5
   AfxGetApp()->WinHelp(0, HELP_QUIT);
#endif
   CPropertySheet::OnDestroy();
}

int CConfigWizSheet::DoRealizePalette(BOOL const fForeground)
{
   TRACE("CConfigWizSheet::DoRealizePalette()\n");

   int nColorsChanged = 0;

   CConfigWizPage * pActivePage = (CConfigWizPage *)GetActivePage();
   if (pActivePage != NULL) nColorsChanged = pActivePage->DoRealizePalette(fForeground);

   try
   {
      if (m_pSheetBmp != NULL)
      {
         // Selet palette into client DC and realize it
         CClientDC dc(this);

         CPalette * pPal = m_pSheetBmp->GetPalette();
         AffirmThrow(pPal != NULL);

         CPalette * pOldPal = dc.SelectPalette(pPal, !fForeground);

         nColorsChanged = dc.RealizePalette();

         if (nColorsChanged > 0)
            Invalidate(FALSE);	// tell Windows to repaint

         if (pOldPal)
            dc.SelectPalette(pOldPal, TRUE);
      }
   }
   catch (CAffirmException ae)
   {
   }

   return nColorsChanged;
}

void CConfigWizSheet::OnPaletteChanged(CWnd* pFocusWnd) 
{
	// CPropertySheet::OnPaletteChanged(pFocusWnd);
   TRACE("CConfigWizSheet::OnPaletteChanged()\n");
   if (pFocusWnd != this)
      DoRealizePalette(FALSE);
}

BOOL CConfigWizSheet::OnQueryNewPalette() 
{
	// return CPropertySheet::OnQueryNewPalette();
   TRACE("CConfigWizSheet::OnQueryNewPalette()\n");
   return DoRealizePalette(TRUE);
}

void CConfigWizSheet::OnSetFocus(CWnd* pOldWnd) 
{
   TRACE("CConfigWizSheet::OnSetFocus()\n");
	CPropertySheet::OnSetFocus(pOldWnd);
   DoRealizePalette(TRUE);
}
