/*****************************************************************************
* 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
*
*****************************************************************************/

// x25cfg.cpp : implementation file
//

#include "stdafx.h"
#include "resource.h"
#include "defs.h"
#include "x25reg.h"
#include "x25incs.h"
#include "x25cfg.h"
#include "utils.h"


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

extern BOOL FieldPreTranslateMessage(CWnd* pParent, MSG* pMsg);
//extern void AddRouterPorts(const CString& szAlias,int ports);

// some utility functions.
#define NumPC(pX25) ( pX25->HPC == 0 && pX25->LPC == 0 ? 0 : pX25->HPC - pX25->LPC + 1 )
#define NumTC(pX25) ( pX25->HTC == 0 && pX25->LTC == 0 ? 0 : pX25->HTC - pX25->LTC + 1 )
#define NumOC(pX25) ( pX25->HOC == 0 && pX25->LOC == 0 ? 0 : pX25->HOC - pX25->LOC + 1 )
#define NumIC(pX25) ( pX25->HIC == 0 && pX25->LIC == 0 ? 0 : pX25->HIC - pX25->LIC + 1 )

static enum CHANNELTYPE {BOTHTYPE=0,PVC,SVC};

// return total # of channels for either PVC,SVC or both
static short GetNumChannels(X25 const * const pX25, CHANNELTYPE type)
{
	// find all switched channels
	DWORD vc = NumTC(pX25) + NumIC(pX25) + NumOC(pX25);
	// find total PVC channels - This # is different than total configured PVC's
	DWORD pvc = NumPC(pX25);
	
	return short(type == BOTHTYPE ? vc + pvc : (type == PVC ? pvc : vc));
}

//
// NOTE: NOTE:
// This kludge depends on the dangerous assumption that the pages have been added
// in a certain order and that we are dealing with a specific set of resources.
//
static BOOL CheckX25CfgValidity(X25 const * const pX25, const CPropertyPage* pPage)
{
	BOOL focus = FALSE;
	CPropertySheet *pSheet = (CPropertySheet*)(pPage->GetParent());
	// x.25 address must be non-empty
	if (pX25->lsap_address.IsEmpty())
	{
      // ATTENTION: Hardcoded index for General Page
		if (pSheet->SetActivePage(0))
			focus = TRUE;
		AfxMessageBox(IDS_NoX25Address);
		if (focus)
			pSheet->GetActivePage()->GetDlgItem(IDC_X25_LOCALADDRESS)->SetFocus();
		return FALSE;
	}

	// x.25 should use either SVC's or PVC's
	if (GetNumChannels(pX25, BOTHTYPE) == 0)
	{
      // ATTENTION: Hardcoded index for Channels Page
		if (pSheet->SetActivePage(1))
				focus = TRUE;
		AfxMessageBox(IDS_NOCIRCUITS);
		if (focus)
			pSheet->GetActivePage()->GetDlgItem(IDC_X25_HTC)->SetFocus();
		return FALSE;
	}

	return TRUE;

}

// when the user changes from Mod 128 to Mod 8 some params may
// be out of range so they are clipped in range
static void ResetSeqNumDependants(X25 * const pX25)
{
	LPBYTE WMap = pX25->thclass_wmap;

	for (short i = 0; i < 16; i++)
		WMap[i] = __min(WMap[i], 7);
	   
	pX25->LOCMAXWSIZE = __min(pX25->LOCMAXWSIZE,7);
	pX25->REMMAXWSIZE = __min(pX25->REMMAXWSIZE,7);
	pX25->LOCDEFWSIZE = __min(pX25->LOCDEFWSIZE,7);
	pX25->REMDEFWSIZE = __min(pX25->REMDEFWSIZE,7);
}

static BOOL InRange(DWORD List[8], short i, short j)
{
	DWORD low1 = List[2 * i];
	DWORD high1 = List[2 * i + 1];

	DWORD low2 = List[2 * j];
	DWORD high2 = List[2 * j + 1];

	return	(low1 >= low2 && low1 <= high2 && high1 > 0 && high2 > 0) ||
					(low2 >= low1 && low2 <= high1 && high2 > 0 && high1 > 0);
}

static BOOL Overlap(DWORD List[8])
{
	for (short i = 0; i < 3; i++)
		for (short j = i + 1; j < 4; j++)
			if (InRange(List, i, j))
					return TRUE;

	return FALSE;
}

/////////////////////////////////////////////////////////////////////////////
// CX25Channel property page

IMPLEMENT_DYNCREATE(CX25Channel, CConfigWizPage)

CX25Channel::CX25Channel(X25 * const pX25) 
{
   ASSERT(NULL != pX25);
   m_pX25 = pX25; // caller's working copy
	Init();
	m_bWizardMode = FALSE;
	CConfigWizPage::Construct(IDD_X25_CHANNEL);
}

CX25Channel::CX25Channel(CConfigObject const * const pOwner, int const nState, X25 * const pX25)
{
   ASSERT(NULL != pX25);
   m_pX25 = pX25; // caller's working copy
	Init();
	m_bWizardMode = TRUE;
	CConfigWizPage::Construct(IDD_WIZ_X25_CHANNEL,0,pOwner,nState);
}


CX25Channel::~CX25Channel()
{
}

void CX25Channel::Init()
{
	m_HIC = 0;
	m_HOC = 0;
	m_HTC = 0x40;
	m_LIC = 0;
	m_LOC = 0;
	m_LTC = 0x400;
	m_HPC = 0;
	m_LPC = 0;
	m_nPortLimit = 0;
}

void CX25Channel::DoDataExchange(CDataExchange* pDX)
{
	CConfigWizPage::DoDataExchange(pDX);
	//{{AFX_DATA_MAP(CX25Channel)
	DDX_Text(pDX, IDC_X25_HIC, m_HIC);
	DDV_MinMaxDWord(pDX, m_HIC, 0, 256);
	DDX_Text(pDX, IDC_X25_HOC, m_HOC);
	DDV_MinMaxDWord(pDX, m_HOC, 0, 256);
	DDX_Text(pDX, IDC_X25_HTC, m_HTC);
	DDV_MinMaxDWord(pDX, m_HTC, 0, 256);
	DDX_Text(pDX, IDC_X25_LIC, m_LIC);
	DDV_MinMaxDWord(pDX, m_LIC, 0, 4095);
	DDX_Text(pDX, IDC_X25_LOC, m_LOC);
	DDV_MinMaxDWord(pDX, m_LOC, 0, 4095);
	DDX_Text(pDX, IDC_X25_LTC, m_LTC);
	DDV_MinMaxDWord(pDX, m_LTC, 0, 4095);
	DDX_Text(pDX, IDC_X25_HPC, m_HPC);
	DDV_MinMaxDWord(pDX, m_HPC, 0, 256);
	DDX_Text(pDX, IDC_X25_LPC, m_LPC);
	DDV_MinMaxDWord(pDX, m_LPC, 0, 4095);
	//}}AFX_DATA_MAP
	if (pDX->m_bSaveAndValidate) 
	{
		DWORD totalSVCNew = m_HTC + m_HOC + m_HIC;
		if (m_bWizardMode && ((totalSVCNew + m_HPC)==0))
		{
			AfxMessageBox(IDS_NOCIRCUITS);
			pDX->Fail();
		}
	
		DWORD HIC = m_LIC > 0 && m_HIC > 0 ? m_LIC + m_HIC - 1 : 0;
  		DWORD HTC = m_LTC > 0 && m_HTC > 0 ? m_LTC + m_HTC - 1 : 0;
  		DWORD HOC = m_LOC > 0 && m_HOC > 0 ? m_LOC + m_HOC - 1 : 0;
  		DWORD HPC = m_LPC > 0 && m_HPC > 0 ? m_LPC + m_HPC - 1 : 0;
		
		DWORD RangeList[8] = { m_LPC, HPC, m_LIC, HIC, m_LTC, HTC, m_LOC, HOC };

		if (Overlap(RangeList)) 
		{
			AfxMessageBox(IDS_OVERLAP);
			pDX->Fail();
		}

      
      // If any of the ranges result in a channel number greater than 4096,
      // inform the user and fail the validation...
#define MAX_CHANNEL_NUMBER 4096

      if (  (MAX_CHANNEL_NUMBER < (m_LIC + m_HIC)) ||
            (MAX_CHANNEL_NUMBER < (m_LTC + m_HTC)) ||
            (MAX_CHANNEL_NUMBER < (m_LOC + m_HOC)) ||
            (MAX_CHANNEL_NUMBER < (m_LPC + m_HPC))
         )
      {
			AfxMessageBox(IDS_CHANNEL_OUT_OF_RANGE);
			pDX->Fail();
      }

		// Inform user that changing this PVC start # and total count will require
		// deleting existing PVC's that fall out of range. This check is only done
		// if current LPC/HPC count is non-zero.
		if ( m_pX25->LPC && m_pX25->HPC && ((int)m_LPC > m_pX25->LPC || (int)HPC < m_pX25->HPC))
		{
			if (AfxMessageBox(IDS_ConfirmDelPVC, MB_YESNO | MB_DEFBUTTON2) == IDNO) 
			{
				pDX->PrepareEditCtrl(IDC_X25_LPC);
				pDX->Fail();
			}
		}
		// fill up the global data holder with dialog data if in wizard mode
		// Usually reload data gets called from OnKillActive which gets called
		// after SetActivePage is called to switch to another page. In wizard mode
		// the owner->NextWizardPage is called prior to SetActivePage and within
		// NextWizardPage we grab the global g_X25,g_LAPB structures. So to get
		// the correct data, we do this kludge here.
		if (m_bWizardMode)
			ReloadData();
	}
}


BEGIN_MESSAGE_MAP(CX25Channel, CConfigWizPage)
	//{{AFX_MSG_MAP(CX25Channel)
	//}}AFX_MSG_MAP
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CX25Channel message handlers

BOOL CX25Channel::OnKillActive() 
{
	BOOL bRetval = CConfigWizPage::OnKillActive();
	if (bRetval)
		ReloadData();
	return bRetval;

}


BOOL CX25Channel::OnApply() 
{
	if (CheckX25CfgValidity(m_pX25, this))
		return CConfigWizPage::OnApply();
	else
		return FALSE;
}


void CX25Channel::ReloadData()
{
	m_pX25->LIC = m_HIC > 0 ? m_LIC : 0;
	m_pX25->HIC = m_LIC > 0 && m_HIC > 0 ? m_LIC + m_HIC - 1 : 0;
	m_pX25->LTC = m_HTC > 0 ? m_LTC : 0;
	m_pX25->HTC = m_LTC > 0 && m_HTC > 0 ? m_LTC + m_HTC - 1 : 0;
	m_pX25->LOC = m_HOC > 0 ? m_LOC : 0;
	m_pX25->HOC = m_LOC > 0 && m_HOC > 0 ? m_LOC + m_HOC - 1 : 0;

	m_pX25->LPC = m_HPC > 0 ? m_LPC : 0;
	m_pX25->HPC = m_LPC > 0 && m_HPC > 0 ? m_LPC + m_HPC - 1 : 0;

/*
	// old old stuff. Don't uncomment
	CRouter *router = theApp.GetRouter(RUNTIME_CLASS(CX25Router));

	router->SetAliasNumPorts(m_LC->GetX25CString(c_pszGUIValueAlias), m_LC->GetNumPorts(SVC));
*/	

}


BOOL CX25Channel::OnInitDialog() 
{
	m_LIC = (DWORD)m_pX25->LIC;
	m_HIC = (DWORD)NumIC(m_pX25);
	m_LTC = (DWORD)m_pX25->LTC;
	m_HTC = (DWORD)NumTC(m_pX25);
	m_LOC = (DWORD)m_pX25->LOC;
	m_HOC = (DWORD)NumOC(m_pX25);

	m_LPC = (DWORD)m_pX25->LPC;
	m_HPC = (DWORD)NumPC(m_pX25);


	CConfigWizPage::OnInitDialog();
	
	// TODO: Add extra initialization here
	
	return TRUE;  // return TRUE unless you set the focus to a control
	              // EXCEPTION: OCX Property Pages should return FALSE
}

/////////////////////////////////////////////////////////////////////////////
// CX25Counters property page

IMPLEMENT_DYNCREATE(CX25Counters, CPropertyPage)

CX25Counters::CX25Counters(X25 * const pX25):CPropertyPage(CX25Counters::IDD)
{
   ASSERT(NULL != pX25);
   m_pX25 = pX25;
	//{{AFX_DATA_INIT(CX25Counters)
	m_R20Value = 1;
	m_R22Value = 1;
	m_R23Value = 1;
	//}}AFX_DATA_INIT

   m_R20Value = m_pX25->R20value;
	m_R22Value = m_pX25->R22value;
	m_R23Value = m_pX25->R23value;
}


void CX25Counters::DoDataExchange(CDataExchange* pDX)
{
	CPropertyPage::DoDataExchange(pDX);
	//{{AFX_DATA_MAP(CX25Counters)
	DDX_Text(pDX, IDC_X25_R20VALUE, m_R20Value);
	DDV_MinMaxDWord(pDX, m_R20Value, 1, 255);
	DDX_Text(pDX, IDC_X25_R22VALUE, m_R22Value);
	DDV_MinMaxDWord(pDX, m_R22Value, 1, 255);
	DDX_Text(pDX, IDC_X25_R23VALUE, m_R23Value);
	DDV_MinMaxDWord(pDX, m_R23Value, 1, 255);
	//}}AFX_DATA_MAP
}


BEGIN_MESSAGE_MAP(CX25Counters, CPropertyPage)
	//{{AFX_MSG_MAP(CX25Counters)
		// NOTE: the ClassWizard will add message map macros here
	//}}AFX_MSG_MAP
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CX25Counters message handlers

BOOL CX25Counters::OnKillActive() 
{
	BOOL bRetval = CPropertyPage::OnKillActive();
	if (bRetval)
		ReloadData();
	return bRetval;	
}

BOOL CX25Counters::OnApply() 
{
	if (CheckX25CfgValidity(m_pX25, this))
		return CPropertyPage::OnApply();
	else
		return FALSE;
}

void CX25Counters::ReloadData()
{
	m_pX25->R20value = m_R20Value;
	m_pX25->R22value = m_R22Value;
	m_pX25->R23value = m_R23Value;

}
/////////////////////////////////////////////////////////////////////////////
// CX25General property page

IMPLEMENT_DYNCREATE(CX25General, CConfigWizPage)

CX25General::CX25General(X25 * const pX25)
{
   ASSERT(NULL != pX25);
   m_pX25 = pX25;
	Init();
	m_bWizardMode = FALSE;
	CConfigWizPage::Construct(IDD_X25_GENERAL);
}

CX25General::CX25General(CConfigObject const * const pOwner, int const nState, X25 * const pX25)
{
   ASSERT(NULL != pX25);
   m_pX25 = pX25;
	Init();
	m_bWizardMode = TRUE;
	CConfigWizPage::Construct(IDD_WIZ_X25_GENERAL,0,pOwner,nState);
}

CX25General::~CX25General()
{
}

void CX25General::Init()
{
	m_L3PLPMode = -1;
	m_ThisGFI = -1;
	m_LocalAddress = _T("");
	m_Vsn = -1;
}

void CX25General::DoDataExchange(CDataExchange* pDX)
{
	CConfigWizPage::DoDataExchange(pDX);
	//{{AFX_DATA_MAP(CX25General)
	DDX_Radio(pDX, IDC_X25_L3PLPMODE1, m_L3PLPMode);
	DDX_Radio(pDX, IDC_X25_LLCLASS1, m_ThisGFI);
	DDX_Text(pDX, IDC_X25_LOCALADDRESS, m_LocalAddress);
	DDX_Radio(pDX, IDC_X25_VER1, m_Vsn);
	//}}AFX_DATA_MAP
	DWORD SubModes = m_pX25->SUB_MODES;
	DDV_MaxChars(pDX, m_LocalAddress, (SubModes & SUB_TOA_NPI_FMT) == 0 ? 15 : 17);

	if (pDX->m_bSaveAndValidate)
	{
		int nlen = m_LocalAddress.GetLength();
		BOOL bFail = FALSE;
		if (!nlen && m_bWizardMode)
		{
			AfxMessageBox(IDS_NoX25Address);
			bFail = TRUE;
		}
		else
		for (int i = 0; i < nlen && !bFail ; i++)
		{
			if (!isdigit(m_LocalAddress[i])) 
			{
				AfxMessageBox(IDS_LOCALADDRESSERROR);
				bFail = TRUE;
			}
		}

		if (bFail)
		{
			pDX->PrepareEditCtrl(IDC_X25_LOCALADDRESS);
			pDX->Fail();
		}
		// see comments in CX25Channel::DoDataExchange.
		if (m_bWizardMode)
			ReloadData();

	}
}


BEGIN_MESSAGE_MAP(CX25General, CConfigWizPage)
	//{{AFX_MSG_MAP(CX25General)
	//}}AFX_MSG_MAP
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CX25General message handlers

BOOL CX25General::OnKillActive() 
{
	
	BOOL bRetval = CConfigWizPage::OnKillActive();
	if (bRetval)
		ReloadData();
	return bRetval;
}

BOOL CX25General::OnApply() 
{	
	if (CheckX25CfgValidity(m_pX25, this))
		return CConfigWizPage::OnApply();
	else
		return FALSE;
}


void CX25General::ReloadData()
{
	m_pX25->X25_VSN =  m_Vsn;
	m_pX25->L3PLPMODE = m_L3PLPMode;		
	m_pX25->THISGFI = m_ThisGFI == 0 ? G_8 : G_128;
	m_pX25->lsap_address = m_LocalAddress;


	switch (m_pX25->ll_class)	{
		case LC_LAPBDCE :	case LC_LAPBDTE :	
			m_pX25->ll_class = m_L3PLPMode == 0 ? LC_LAPBDCE : LC_LAPBDTE; break;
		case LC_LAPBXDCE :	case LC_LAPBXDTE :	
			m_pX25->ll_class = m_L3PLPMode == 0 ? LC_LAPBXDCE : LC_LAPBXDTE; break;
		}
}

BOOL CX25General::OnInitDialog() 
{
	m_Vsn	= m_pX25->X25_VSN;
	m_L3PLPMode = m_pX25->L3PLPMODE;		
	m_ThisGFI = m_pX25->THISGFI == G_128;
	m_LocalAddress = m_pX25->lsap_address;


	CConfigWizPage::OnInitDialog();
	
	// TODO: Add extra initialization here
	
	return TRUE;  // return TRUE unless you set the focus to a control
	              // EXCEPTION: OCX Property Pages should return FALSE
}

BOOL CX25General::OnCmdMsg(UINT nID, int nCode, void* pExtra, AFX_CMDHANDLERINFO* pHandlerInfo) 
{
	BOOL cond = FALSE, CallBase = FALSE;
	UINT msgID;
	int *Value = NULL;

	if (nCode == 0) {
		switch (nID) {
			case IDC_X25_VER1 :
				cond = m_pX25->CUG_CONTROL & EXTENDED;
				msgID = IDS_CUG1980;
				Value = &m_Vsn;
				break;
			case IDC_X25_VER2 : case IDC_X25_VER3 :
				cond = m_pX25->SNMODES & CCITT_CLEAR_LEN;
				msgID = IDS_DIAG1980;
				Value = &m_Vsn;
				break;
			case IDC_X25_LLCLASS1 :
				cond = m_pX25->THISGFI == G_128;
				msgID = IDS_CHANGESEQNUM;
				Value = &m_ThisGFI;
				break;
			default :
				CallBase = TRUE;
			}
		
		if (!CallBase) {
			int old = *Value;

			UpdateData(TRUE);
			if (cond)
				if (*Value != old && AfxMessageBox(msgID, MB_YESNO) == IDYES)
					switch (nID) {
						case IDC_X25_VER1 :
							m_pX25->CUG_CONTROL |= BASIC;
							m_pX25->CUG_CONTROL &= ~EXTENDED;
							break;
						case IDC_X25_VER2 : case IDC_X25_VER3 :
							m_pX25->SNMODES &= ~CCITT_CLEAR_LEN;
							break;
						case IDC_X25_LLCLASS1 :
							ResetSeqNumDependants(m_pX25);
						}
				else {
					*Value = old;
					UpdateData(FALSE);
					}
			}
		}
	else
		CallBase = TRUE;
	
	return CallBase ? CConfigWizPage::OnCmdMsg(nID, nCode, pExtra, pHandlerInfo) : TRUE;
}


/////////////////////////////////////////////////////////////////////////////
// CX25PacketInfo property page

IMPLEMENT_DYNCREATE(CX25PacketInfo, CPropertyPage)

CX25PacketInfo::CX25PacketInfo(X25 * const pX25) : CPropertyPage(CX25PacketInfo::IDD)
{
   ASSERT(NULL != pX25);

   //{{AFX_DATA_INIT(CX25PacketInfo)
	m_LocDefWSize = 2;
	m_LocMaxWSize = 7;
	m_RemDefWSize = 2;
	m_RemMaxWSize = 7;
	m_LocMaxPktSize = _T("");
	m_LocDefPktSize = _T("");
	m_RemDefPktSize = _T("");
	m_RemMaxPktSize = _T("");
	m_MaxNSDULen = 256;
	//}}AFX_DATA_INIT
   m_pX25 = pX25;
}

CX25PacketInfo::~CX25PacketInfo()
{
}

void CX25PacketInfo::DoDataExchange(CDataExchange* pDX)
{
	CPropertyPage::DoDataExchange(pDX);
	int maxwsize = m_pX25->THISGFI == G_8 ? 7 : 127;
	//{{AFX_DATA_MAP(CX25PacketInfo)
	DDX_Text(pDX, IDC_X25_MAXNSDULEN, m_MaxNSDULen);
	DDV_MinMaxDWord(pDX, m_MaxNSDULen, 0, 3072);
	DDX_CBString(pDX, IDC_X25_LOCMAXPKTSIZE, m_LocMaxPktSize);
	DDX_CBString(pDX, IDC_X25_LOCDEFPKTSIZE, m_LocDefPktSize);
	DDX_CBString(pDX, IDC_X25_REMDEFPKTSIZE, m_RemDefPktSize);
	DDX_CBString(pDX, IDC_X25_REMMAXPKTSIZE, m_RemMaxPktSize);
	DDX_Text(pDX, IDC_X25_LOCMAXWSIZE, m_LocMaxWSize);
	DDV_MinMaxInt(pDX, m_LocMaxWSize, 2, maxwsize);
	DDX_Text(pDX, IDC_X25_REMMAXWSIZE, m_RemMaxWSize);
	DDV_MinMaxInt(pDX, m_RemMaxWSize, 2, maxwsize);
	DDX_Text(pDX, IDC_X25_LOCDEFWSIZE, m_LocDefWSize);
	DDV_MinMaxInt(pDX, m_LocDefWSize, 1, maxwsize);
	DDX_Text(pDX, IDC_X25_REMDEFWSIZE, m_RemDefWSize);
	DDV_MinMaxInt(pDX, m_RemDefWSize, 1, maxwsize);
	//}}AFX_DATA_MAP

}


BEGIN_MESSAGE_MAP(CX25PacketInfo, CPropertyPage)
	//{{AFX_MSG_MAP(CX25PacketInfo)
	ON_CBN_SELCHANGE(IDC_X25_LOCDEFPKTSIZE, OnSelchangeX25Locdefpktsize)
	ON_CBN_SELCHANGE(IDC_X25_LOCMAXPKTSIZE, OnSelchangeX25Locmaxpktsize)
	ON_CBN_SELCHANGE(IDC_X25_REMDEFPKTSIZE, OnSelchangeX25Remdefpktsize)
	ON_CBN_SELCHANGE(IDC_X25_REMMAXPKTSIZE, OnSelchangeX25Remmaxpktsize)
	ON_EN_UPDATE(IDC_X25_LOCDEFWSIZE, OnUpdateX25Locdefwsize)
	ON_EN_UPDATE(IDC_X25_LOCMAXWSIZE, OnUpdateX25Locmaxwsize)
	ON_EN_UPDATE(IDC_X25_REMDEFWSIZE, OnUpdateX25Remdefwsize)
	ON_EN_UPDATE(IDC_X25_REMMAXWSIZE, OnUpdateX25Remmaxwsize)
	//}}AFX_MSG_MAP
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CX25PacketInfo message handlers

void CX25PacketInfo::OnSelchangeX25Locdefpktsize() 
{
	// TODO: Add your control notification handler code here
	UpdateData(TRUE);
	int def = atoi(m_LocDefPktSize);
	int max = atoi(m_LocMaxPktSize);

	if (max < def) {
		m_LocMaxPktSize = m_LocDefPktSize;
		UpdateData(FALSE);
		}
}

void CX25PacketInfo::OnSelchangeX25Locmaxpktsize() 
{
	// TODO: Add your control notification handler code here
	UpdateData(TRUE);
	int def = atoi(m_LocDefPktSize);
	int max = atoi(m_LocMaxPktSize);

	if (max < def) {
		m_LocDefPktSize = m_LocMaxPktSize;
		UpdateData(FALSE);
		}
}

void CX25PacketInfo::OnSelchangeX25Remdefpktsize() 
{
	// TODO: Add your control notification handler code here
	UpdateData(TRUE);
	int def = atoi(m_RemDefPktSize);
	int max = atoi(m_RemMaxPktSize);

	if (max < def) {
		m_RemMaxPktSize = m_RemDefPktSize;
		UpdateData(FALSE);
		}
}

void CX25PacketInfo::OnSelchangeX25Remmaxpktsize() 
{
	// TODO: Add your control notification handler code here
	UpdateData(TRUE);
	int def = atoi(m_RemDefPktSize);
	int max = atoi(m_RemMaxPktSize);

	if (max < def) {
		m_RemDefPktSize = m_RemMaxPktSize;
		UpdateData(FALSE);
		}
}

void CX25PacketInfo::OnUpdateX25Locdefwsize() 
{
	// TODO: Add your control notification handler code here
	if (!UpdateData(TRUE))
		return;

	if (m_LocMaxWSize < m_LocDefWSize) {
		m_LocMaxWSize = m_LocDefWSize;
		UpdateData(FALSE);
		}
}

void CX25PacketInfo::OnUpdateX25Locmaxwsize() 
{
	// TODO: Add your control notification handler code here
	if (!UpdateData(TRUE))
		return;

	if (m_LocMaxWSize < m_LocDefWSize) {
		m_LocDefWSize = m_LocMaxWSize;
		UpdateData(FALSE);
		}
}

void CX25PacketInfo::OnUpdateX25Remdefwsize() 
{
	// TODO: Add your control notification handler code here
	if (!UpdateData(TRUE))
		return;

	if (m_RemMaxWSize < m_RemDefWSize) {
		m_RemMaxWSize = m_RemDefWSize;
		UpdateData(FALSE);
		}
}

void CX25PacketInfo::OnUpdateX25Remmaxwsize() 
{
	// TODO: Add your control notification handler code here
	if (!UpdateData(TRUE))
		return;

	if (m_RemMaxWSize < m_RemDefWSize) {
		m_RemDefWSize = m_RemMaxWSize;
		UpdateData(FALSE);
		}
}

BOOL CX25PacketInfo::OnKillActive() 
{
	BOOL bRetval = CPropertyPage::OnKillActive();
	if (bRetval)
		ReloadData();
	return bRetval;
}

BOOL CX25PacketInfo::OnApply() 
{
	if (CheckX25CfgValidity(m_pX25, this))
		return CPropertyPage::OnApply();
	else
		return FALSE;
}

void CX25PacketInfo::ReloadData()
{
	m_pX25->MAXNSDULEN = m_MaxNSDULen;
	m_pX25->LOCMAXWSIZE = m_LocMaxWSize;
	m_pX25->REMMAXWSIZE = m_RemMaxWSize;
	m_pX25->LOCDEFWSIZE = m_LocDefWSize;
	m_pX25->REMDEFWSIZE = m_RemDefWSize;


	for (DWORD i = 0, t = atol(m_LocMaxPktSize); t != 1; t >>= 1, i++);
	m_pX25->LOCMAXPKTSIZE = i;
		
	for (i = 0, t = atol(m_LocDefPktSize); t != 1; t = t >> 1, i++);
	m_pX25->LOCDEFPKTSIZE = i;

	for (i = 0, t = atol(m_RemDefPktSize); t != 1; t = t >> 1, i++);
	m_pX25->REMDEFPKTSIZE = i;
 	
	for (i = 0, t = atol(m_RemMaxPktSize); t != 1; t = t >> 1, i++);
	m_pX25->REMMAXPKTSIZE = i;

	/*
	// does this need to be done every time we switch tabs ??
	int size = g_X25Array.GetSize();
	for(i=0;i<size;i++) {
		PVCX25 pvc = g_X25Array.GetAt(i);
		if (pvc.AutoManage > 0)
		{
		// set defaults for PVC params that depend on X.25 params
			pvc.REMDEFWSIZE = m_pX25->REMDEFWSIZE;
			pvc.LOCDEFWSIZE = m_pX25->LOCDEFWSIZE;
			pvc.REMDEFPKTSIZE = m_pX25->REMDEFPKTSIZE;
			pvc.LOCDEFPKTSIZE = m_pX25->LOCDEFPKTSIZE;
			pvc.flags |= PVC_MODIFIED;
		}

		g_X25Array.SetAt(i,pvc); 
	}
	
	*/
}

BOOL CX25PacketInfo::OnInitDialog() 
{
	m_MaxNSDULen = m_pX25->MAXNSDULEN;

	m_LocMaxWSize = m_pX25->LOCMAXWSIZE;
	m_RemMaxWSize = m_pX25->REMMAXWSIZE;
	m_LocDefWSize = m_pX25->LOCDEFWSIZE;
	m_RemDefWSize = m_pX25->REMDEFWSIZE;

	m_LocDefPktSize.Format("%d", 1 << m_pX25->LOCDEFPKTSIZE);
	m_LocMaxPktSize.Format("%d", 1 << m_pX25->LOCMAXPKTSIZE);
	m_RemDefPktSize.Format("%d", 1 << m_pX25->REMDEFPKTSIZE);
	m_RemMaxPktSize.Format("%d", 1 << m_pX25->REMMAXPKTSIZE);

	CPropertyPage::OnInitDialog();
	
	// TODO: Add extra initialization here
	
	return TRUE;  // return TRUE unless you set the focus to a control
	              // EXCEPTION: OCX Property Pages should return FALSE
}

/////////////////////////////////////////////////////////////////////////////
// CX25SubModes property page

IMPLEMENT_DYNCREATE(CX25SubModes, CPropertyPage)

CX25SubModes::CX25SubModes(X25 * const pX25) : CPropertyPage(CX25SubModes::IDD)
{
   ASSERT(NULL != pX25);
   m_pX25 = pX25;
	//{{AFX_DATA_INIT(CX25SubModes)
	m_RejNegReq = FALSE;
	m_CallRestriction = 0;
	m_WndPktNeg = 1;
	m_FastSelect = TRUE;
	m_PreventLocChg = FALSE;
	m_ReverseCharging = 1;
	m_TOANPIAddr = 1;
	//}}AFX_DATA_INIT
}

CX25SubModes::~CX25SubModes()
{
}

void CX25SubModes::DoDataExchange(CDataExchange* pDX)
{
	CPropertyPage::DoDataExchange(pDX);
	//{{AFX_DATA_MAP(CX25SubModes)
	DDX_Check(pDX, IDC_X25_BAR_EXTENDED, m_RejNegReq);
	DDX_Radio(pDX, IDC_X25_CallManagement, m_CallRestriction);
	DDX_Radio(pDX, IDC_X25_SUB_EXTENDED, m_WndPktNeg);
	DDX_Check(pDX, IDC_X25_SUB_FSELECT, m_FastSelect);
	DDX_Check(pDX, IDC_X25_SUB_LOC_CHG_PREV, m_PreventLocChg);
	DDX_Radio(pDX, IDC_X25_SUB_REVCHARGING, m_ReverseCharging);
	DDX_Radio(pDX, IDC_X25_SUB_TOA_NPI_FMT, m_TOANPIAddr);
	//}}AFX_DATA_MAP
	CString X25Address = m_pX25->lsap_address;

	if (pDX->m_bSaveAndValidate == TRUE && m_TOANPIAddr != 0 && X25Address.GetLength() > 15)
		if (AfxMessageBox(IDS_TRUNCATELOCALADDRESS, MB_YESNO) == IDNO) {
			pDX->PrepareCtrl(IDC_X25_SUB_TOA_NPI_FMT);
			pDX->Fail();
			}

}


BEGIN_MESSAGE_MAP(CX25SubModes, CPropertyPage)
	//{{AFX_MSG_MAP(CX25SubModes)
	ON_BN_CLICKED(IDC_X25_SUB_REVCHARGING, OnX25SubRevcharging)
	ON_BN_CLICKED(IDC_X25_SUB_EXTENDED, OnX25SubExtended)
	ON_BN_CLICKED(IDC_RefuseReverseChg, OnRefuseReverseChg)
	ON_BN_CLICKED(IDD_NegWndPktSizes, OnNegWndPktSizes)
	ON_BN_CLICKED(IDC_Advanced, OnAdvanced)
	//}}AFX_MSG_MAP
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CX25SubModes message handlers

void CX25SubModes::OnX25SubRevcharging() 
{
	// TODO: Add your control notification handler code here
	GetDlgItem(IDC_X25_SUB_LOC_CHG_PREV)->EnableWindow(FALSE);
}

void CX25SubModes::OnX25SubExtended() 
{
	// TODO: Add your control notification handler code here
	GetDlgItem(IDC_X25_BAR_EXTENDED)->EnableWindow(TRUE);
}

void CX25SubModes::OnRefuseReverseChg() 
{
	// TODO: Add your control notification handler code here
	GetDlgItem(IDC_X25_SUB_LOC_CHG_PREV)->EnableWindow(TRUE);
}

void CX25SubModes::OnNegWndPktSizes() 
{
	// TODO: Add your control notification handler code here
	GetDlgItem(IDC_X25_BAR_EXTENDED)->EnableWindow(FALSE);
}


BOOL CX25SubModes::OnKillActive() 
{
	BOOL bRetval = CPropertyPage::OnKillActive();
	if (bRetval)
		ReloadData();
	return bRetval;
}


BOOL CX25SubModes::OnApply() 
{
	if (CheckX25CfgValidity(m_pX25, this))
		return CPropertyPage::OnApply();
	else
		return FALSE;
}

void CX25SubModes::ReloadData()
{
	DWORD SubModes = 0;

	if (m_WndPktNeg)
		SubModes |= SUB_EXTENDED;
	else if (m_RejNegReq)
		SubModes |= BAR_EXTENDED;
   
	if (m_ReverseCharging == 0)
		SubModes |= SUB_REVCHARGE;
	else if (m_PreventLocChg)
		SubModes |= SUB_LOC_CHG_PREV;
   
	if (m_FastSelect)
		SubModes |= SUB_FSELECT;
   
	if (m_CallRestriction == 1)
		SubModes |= BAR_INCALL;
	else if (m_CallRestriction == 2)
		SubModes |= BAR_OUTCALL;
   
	if (m_TOANPIAddr == 0)
		SubModes |= SUB_TOA_NPI_FMT;
	else {
		CString X25Address = m_pX25->lsap_address;

		if (X25Address.GetLength() > 15)
			m_pX25->lsap_address = X25Address.Left(15);

		if(m_TOANPIAddr == 1)
			SubModes |= BAR_TOA_NPI_FMT;
		}

	m_pX25->SUB_MODES = SubModes;

}

BOOL CX25SubModes::OnInitDialog() 
{
	DWORD SubModes = m_pX25->SUB_MODES;

	BOOL m_BarIncall = (SubModes & BAR_INCALL) > 0;
	BOOL m_BarOutcall = (SubModes & BAR_OUTCALL) > 0;

	BOOL m_TOANPIFMT = (SubModes & SUB_TOA_NPI_FMT) > 0;
	BOOL m_BarTOANPIFMT = (SubModes & BAR_TOA_NPI_FMT) > 0;

	m_RejNegReq = (SubModes & BAR_EXTENDED) > 0;
	m_CallRestriction = m_BarIncall ? 1 : (m_BarOutcall ? 2 : 0);
	m_WndPktNeg = (SubModes & SUB_EXTENDED) > 0;
	m_FastSelect = (SubModes & SUB_FSELECT) > 0;
	m_PreventLocChg = (SubModes & SUB_LOC_CHG_PREV) > 0;
	m_ReverseCharging = 1 - ((SubModes & SUB_REVCHARGE) > 0);
	m_TOANPIAddr = m_TOANPIFMT ? 0 : (m_BarTOANPIFMT ? 1 : 2);

	CPropertyPage::OnInitDialog();
	
	if (m_ReverseCharging == 0)
		OnX25SubRevcharging();

	if (m_WndPktNeg)
		OnNegWndPktSizes();
	
	return TRUE;  // return TRUE unless you set the focus to a control
	              // EXCEPTION: OCX Property Pages should return FALSE
}

void CX25SubModes::OnAdvanced() 
{
	CString pageName;
	GetWindowText(pageName);

	CX25CUG pageCUG;
	CPropertySheet sheet(pageName);

	sheet.AddPage(&pageCUG);
	sheet.DoModal();
	
}

/////////////////////////////////////////////////////////////////////////////
// CX25SNModes property page

IMPLEMENT_DYNCREATE(CX25SNModes, CPropertyPage)

CX25SNModes::CX25SNModes(X25 * const pX25) : CPropertyPage(CX25SNModes::IDD)
{
   ASSERT(NULL != pX25);
   m_pX25 = pX25;
	//{{AFX_DATA_INIT(CX25SNModes)
	m_AccNoDiag = FALSE;
	m_BarDiag = FALSE;
	m_CCITTClearLen = FALSE;
	m_DiscNZDiag = FALSE;
	m_UseDiag = FALSE;
	m_NetMode = -1;
	m_NegToDeg = -1;
	//}}AFX_DATA_INIT
}

CX25SNModes::~CX25SNModes()
{
}

void CX25SNModes::DoDataExchange(CDataExchange* pDX)
{
	CPropertyPage::DoDataExchange(pDX);
	//{{AFX_DATA_MAP(CX25SNModes)
	DDX_Control(pDX, IDC_X25_CCITT_CLEAR_LEN, m_CCITT_CLR_LEN_BUTTON);
	DDX_Check(pDX, IDC_X25_ACC_NODIAG, m_AccNoDiag);
	DDX_Check(pDX, IDC_X25_BAR_DIAG, m_BarDiag);
	DDX_Check(pDX, IDC_X25_CCITT_CLEAR_LEN, m_CCITTClearLen);
	DDX_Check(pDX, IDC_X25_DISC_NZ_DIAG, m_DiscNZDiag);
	DDX_Check(pDX, IDC_X25_USE_DIAG, m_UseDiag);
	DDX_CBIndex(pDX, IDC_X25_NET_MODE, m_NetMode);
	DDX_Radio(pDX, IDC_THCLASS_NEG_TO_DEF, m_NegToDeg);
	//}}AFX_DATA_MAP
}


BEGIN_MESSAGE_MAP(CX25SNModes, CPropertyPage)
	//{{AFX_MSG_MAP(CX25SNModes)
	ON_BN_CLICKED(IDC_X25_BAR_DIAG, OnX25BarDiag)
	ON_BN_CLICKED(IDC_Advanced, OnAdvanced)
	//}}AFX_MSG_MAP
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CX25SNModes message handlers

void CX25SNModes::OnX25BarDiag() 
{
	// TODO: Add your control notification handler code here
	UpdateData(TRUE);
	GetDlgItem(IDC_X25_DISC_NZ_DIAG)->EnableWindow(m_BarDiag);
}

void CX25SNModes::OnAdvanced() 
{
	CString pageName;
	GetWindowText(pageName);

	CX25DBit pageDBit(m_pX25);
	CPropertySheet sheet(pageName);

	sheet.AddPage(&pageDBit);
	sheet.DoModal();
	
}


BOOL CX25SNModes::OnKillActive() 
{
	BOOL bRetval = CPropertyPage::OnKillActive();	
	if (bRetval)
		ReloadData();
	return bRetval;
}

BOOL CX25SNModes::OnApply() 
{
	if (CheckX25CfgValidity(m_pX25, this))
		return CPropertyPage::OnApply();
	else
		return FALSE;
}

void CX25SNModes::ReloadData()
{
	if (m_NetMode == 0)
		switch (m_pX25->X25_VSN) {
			case 0 : m_pX25->Net_Mode = X25_80; break;
			case 1 : m_pX25->Net_Mode = X25_84; break;
			case 2 : m_pX25->Net_Mode = X25_88; break;
			}
	else
		m_pX25->Net_Mode = m_NetMode + 4;

	DWORD SNModes = 0;

	if (!m_BarDiag)
		SNModes |= BAR_DIAG;
	else if (m_DiscNZDiag)
		SNModes |= DISC_NZ_DIAG;
 	if (m_UseDiag)
		SNModes |= USE_DIAG;      

	if (m_AccNoDiag)
		SNModes |= ACC_NODIAG;
	if (m_CCITTClearLen)
		SNModes |= CCITT_CLEAR_LEN;

	m_pX25->SNMODES = SNModes;
      
	m_pX25->thclass_neg_to_def =  m_NegToDeg;
}

BOOL CX25SNModes::OnInitDialog() 
{
	DWORD NetMode = m_pX25->Net_Mode;

	m_NetMode = NetMode >= PSS ? NetMode - 4 : 0;

	DWORD SNModes = m_pX25->SNMODES;

	m_BarDiag = (SNModes & BAR_DIAG) == 0;
	m_DiscNZDiag = (SNModes & DISC_NZ_DIAG) > 0; 
	m_UseDiag = (SNModes & USE_DIAG) > 0;
	m_AccNoDiag = (SNModes & ACC_NODIAG) > 0;
	m_CCITTClearLen = (SNModes & CCITT_CLEAR_LEN) > 0;

	m_NegToDeg	= m_pX25->thclass_neg_to_def;

	CPropertyPage::OnInitDialog();
	
	// TODO: Add extra initialization here
	
	return TRUE;  // return TRUE unless you set the focus to a control
	              // EXCEPTION: OCX Property Pages should return FALSE
}

/////////////////////////////////////////////////////////////////////////////
// CX25International property page
IMPLEMENT_DYNCREATE(CX25International, CPropertyPage)


CX25International::CX25International(X25 * const pX25): CPropertyPage(CX25International::IDD)
{
   ASSERT(NULL != pX25);
   m_pX25 = pX25;
	//{{AFX_DATA_INIT(CX25International)
	m_DNIC = 0;
	m_X25PrtyEncodeControl = FALSE;
	m_ForceValueEnable = FALSE;
	m_IntlAddrRecognValue = 0;
	m_PrtyEncodeControlValue = 0;
	m_X25PrtyPktForcedValue = 0;
	//}}AFX_DATA_INIT
}


void CX25International::DoDataExchange(CDataExchange* pDX)
{
	CPropertyPage::DoDataExchange(pDX);
	//{{AFX_DATA_MAP(CX25International)
	DDX_Control(pDX, IDC_X25_PRTY_PKT_FORCED_VALUE, m_ForcedValueBox);
	DDX_Text(pDX, IDC_X25_DNIC, m_DNIC);
	DDV_MinMaxDWord(pDX, m_DNIC, 0, 9999);
	DDX_Check(pDX, IDC_X25_PRIORISED_PRTY_ENCODE, m_X25PrtyEncodeControl);
	DDX_Check(pDX, IDC_FORCE_VALUE_ENABLE, m_ForceValueEnable);
	DDX_Radio(pDX, IDC_X25_INTL_ADDR_RECOGN1, m_IntlAddrRecognValue);
	DDX_Radio(pDX, IDC_X25_PRIORISED_PRTY_ENCODE1, m_PrtyEncodeControlValue);
	DDX_CBIndex(pDX, IDC_X25_PRTY_PKT_FORCED_VALUE, m_X25PrtyPktForcedValue);
	//}}AFX_DATA_MAP
}


BEGIN_MESSAGE_MAP(CX25International, CPropertyPage)
	//{{AFX_MSG_MAP(CX25International)
	ON_BN_CLICKED(IDC_X25_INTL_ADDR_RECOGN1, OnX25IntlAddrRecogn1)
	ON_BN_CLICKED(IDC_X25_INTL_ADDR_RECOGN3, OnX25IntlAddrRecogn3)
	ON_BN_CLICKED(IDC_X25_INTL_ADDR_RECOGN4, OnX25IntlAddrRecogn4)
	ON_BN_CLICKED(IDC_X25_PRIORISED_PRTY_ENCODE, OnX25PriorisedPrtyEncode)
	ON_BN_CLICKED(IDC_FORCE_VALUE_ENABLE, OnForceValueEnable)
	//}}AFX_MSG_MAP
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CX25International message handlers

void CX25International::OnX25IntlAddrRecogn1() 
{
	// TODO: Add your control notification handler code here
   GetDlgItem( IDC_X25_DNIC )->EnableWindow( TRUE );
}

void CX25International::OnX25IntlAddrRecogn3() 
{
	// TODO: Add your control notification handler code here
   GetDlgItem( IDC_X25_DNIC )->EnableWindow( FALSE );
}

void CX25International::OnX25IntlAddrRecogn4() 
{
	// TODO: Add your control notification handler code here
   GetDlgItem( IDC_X25_DNIC )->EnableWindow( FALSE );
}

void CX25International::OnX25PriorisedPrtyEncode() 
{
	// TODO: Add your control notification handler code here
	UpdateData(TRUE);
	
	CWnd *wnd = GetDlgItem(IDC_X25_PRIORISED_PRTY_ENCODE);
	for (wnd = wnd->GetWindow(GW_HWNDNEXT); wnd; wnd = wnd->GetWindow(GW_HWNDNEXT)) {
		if (wnd->GetDlgCtrlID() == IDC_X25_DNIC)
			wnd->EnableWindow(m_X25PrtyEncodeControl && m_IntlAddrRecognValue == 0);
		else if (wnd->GetDlgCtrlID() == IDC_X25_PRTY_PKT_FORCED_VALUE)
			wnd->EnableWindow(m_X25PrtyEncodeControl && m_ForceValueEnable);
		else
			wnd->EnableWindow(m_X25PrtyEncodeControl);
		}
}

void CX25International::OnForceValueEnable() 
{
	// TODO: Add your control notification handler code here
	UpdateData(TRUE);
	m_ForcedValueBox.EnableWindow(m_ForceValueEnable);
}

BOOL CX25International::OnKillActive() 
{
	BOOL bRetval = CPropertyPage::OnKillActive();
	if (bRetval)
		ReloadData();
	return bRetval;
}

BOOL CX25International::OnApply() 
{
	if (CheckX25CfgValidity(m_pX25, this))
		return CPropertyPage::OnApply();
	else
		return FALSE;
}

void CX25International::ReloadData()
{
	m_pX25->intl_prioritised =  m_X25PrtyEncodeControl;
	m_pX25->intl_addr_recogn =  m_IntlAddrRecognValue + 1;

	DWORD high = m_DNIC / 1000;
	m_DNIC %= 1000;
	m_pX25->dnic1 =  (high << 4) + m_DNIC / 100;	
	m_DNIC %= 100;
	m_pX25->dnic2 = (m_DNIC / 10 << 4) + (m_DNIC % 10);
	m_pX25->prty_encode_control = m_PrtyEncodeControlValue;
	m_pX25->prty_pkt_forced_value = m_ForceValueEnable ? m_X25PrtyPktForcedValue + 4 : 0;	
}

BOOL CX25International::OnInitDialog() 
{
	m_X25PrtyEncodeControl = m_pX25->intl_prioritised;

	m_IntlAddrRecognValue = m_pX25->intl_addr_recogn - 1;
	
	DWORD DNIC1 = m_pX25->dnic1;
	DWORD DNIC2 = m_pX25->dnic2;

	m_DNIC = (DNIC1 >> 4) * 1000;
	m_DNIC += (DNIC1 & 0x0F) * 100;
	m_DNIC += (DNIC2 >> 4) * 10;
	m_DNIC += (DNIC2 & 0x0F);

	m_PrtyEncodeControlValue = m_pX25->prty_encode_control;
	int ppfv = m_pX25->prty_pkt_forced_value;
	m_ForceValueEnable = ppfv > 0;
	m_X25PrtyPktForcedValue = m_ForceValueEnable ? ppfv - 4 : 0;

	CPropertyPage::OnInitDialog();
	OnX25PriorisedPrtyEncode();
	if(m_X25PrtyEncodeControl) {
		if (m_IntlAddrRecognValue == 0)
			OnX25IntlAddrRecogn1();
		else
			OnX25IntlAddrRecogn3();
		OnForceValueEnable();
		}

	
	return TRUE;  // return TRUE unless you set the focus to a control
	              // EXCEPTION: OCX Property Pages should return FALSE
}


/////////////////////////////////////////////////////////////////////////////
// CX25Timer property page

IMPLEMENT_DYNCREATE(CX25Timer, CPropertyPage)

CX25Timer::CX25Timer(X25 * const pX25) : CPropertyPage(CX25Timer::IDD)
{
   ASSERT(NULL != pX25);
   m_pX25 = pX25;
	//{{AFX_DATA_INIT(CX25Timer)
	m_AckDelay = 0;
	m_T20Value = 0;
	m_T21Value = 0;
	m_T22Value = 0;
	m_T23Value = 0;
	m_T25Value = 0;
	m_T26Value = 0;
	m_TValue = 0;
	//}}AFX_DATA_INIT
}

CX25Timer::~CX25Timer()
{
}

void CX25Timer::DoDataExchange(CDataExchange* pDX)
{
	CPropertyPage::DoDataExchange(pDX);
	//{{AFX_DATA_MAP(CX25Timer)
	DDX_Text(pDX, IDC_X25_ACKDELAY, m_AckDelay);
	DDV_MinMaxDWord(pDX, m_AckDelay, 0, 32000);
	DDX_Text(pDX, IDC_X25_T20VALUE, m_T20Value);
	DDV_MinMaxDWord(pDX, m_T20Value, 0, 32000);
	DDX_Text(pDX, IDC_X25_T21VALUE, m_T21Value);
	DDV_MinMaxDWord(pDX, m_T21Value, 0, 32000);
	DDX_Text(pDX, IDC_X25_T22VALUE, m_T22Value);
	DDV_MinMaxDWord(pDX, m_T22Value, 0, 32000);
	DDX_Text(pDX, IDC_X25_T23VALUE, m_T23Value);
	DDV_MinMaxDWord(pDX, m_T23Value, 0, 32000);
	DDX_Text(pDX, IDC_X25_T25VALUE, m_T25Value);
	DDV_MinMaxDWord(pDX, m_T25Value, 0, 32000);
	DDX_Text(pDX, IDC_X25_T26VALUE, m_T26Value);
	DDV_MinMaxDWord(pDX, m_T26Value, 0, 32000);
	DDX_Text(pDX, IDC_X25_TVALUE, m_TValue);
	DDV_MinMaxDWord(pDX, m_TValue, 0, 32000);
	//}}AFX_DATA_MAP
}


BEGIN_MESSAGE_MAP(CX25Timer, CPropertyPage)
	//{{AFX_MSG_MAP(CX25Timer)
	//}}AFX_MSG_MAP
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CX25Timer message handlers

void CX25Timer::OnOK() 
{
	m_pX25->ACKDELAY = m_AckDelay;
	m_pX25->T20value = m_T20Value;
	m_pX25->T21value = m_T21Value;
	m_pX25->T22value = m_T22Value;
	m_pX25->T23value = m_T23Value;
	m_pX25->T25value = m_T25Value;
	m_pX25->T26value = m_T26Value;
	m_pX25->Tvalue =	m_TValue;
	
	CPropertyPage::OnOK();
}

BOOL CX25Timer::OnInitDialog() 
{
	m_AckDelay = m_pX25->ACKDELAY;
	m_T20Value = m_pX25->T20value;
	m_T21Value = m_pX25->T21value;
	m_T22Value = m_pX25->T22value;
	m_T23Value = m_pX25->T23value;
	m_TValue = m_pX25->Tvalue;
	m_T25Value = m_pX25->T25value;
	m_T26Value = m_pX25->T26value;

	CPropertyPage::OnInitDialog();
	
	// TODO: Add extra initialization here
	
	return TRUE;  // return TRUE unless you set the focus to a control
	              // EXCEPTION: OCX Property Pages should return FALSE
}

/////////////////////////////////////////////////////////////////////////////
// CX25ThroughPutClass property page

IMPLEMENT_DYNCREATE(CX25ThroughPutClass, CPropertyPage)

CX25ThroughPutClass::CX25ThroughPutClass(X25 * const pX25) : CPropertyPage(CX25ThroughPutClass::IDD)
{
   ASSERT(NULL != pX25);
   m_pX25 = pX25;
	//{{AFX_DATA_INIT(CX25ThroughPutClass)
	m_LocDefThClass = -1;
	m_LocMaxThClass = -1;
	m_LocMinThClass = -1;
	m_RemDefThClass = -1;
	m_RemMaxThClass = -1;
	m_RemMinThClass = -1;
	//}}AFX_DATA_INIT
}

CX25ThroughPutClass::~CX25ThroughPutClass()
{
}

void CX25ThroughPutClass::DoDataExchange(CDataExchange* pDX)
{
	CPropertyPage::DoDataExchange(pDX);
	//{{AFX_DATA_MAP(CX25ThroughPutClass)
	DDX_CBIndex(pDX, IDC_X25_LOCDEFTHCLASS, m_LocDefThClass);
	DDX_CBIndex(pDX, IDC_X25_LOCMAXTHCLASS, m_LocMaxThClass);
	DDX_CBIndex(pDX, IDC_X25_LOCMINTHCLASS, m_LocMinThClass);
	DDX_CBIndex(pDX, IDC_X25_REMDEFTHCLASS, m_RemDefThClass);
	DDX_CBIndex(pDX, IDC_X25_REMMAXTHCLASS, m_RemMaxThClass);
	DDX_CBIndex(pDX, IDC_X25_REMMINTHCLASS, m_RemMinThClass);
	//}}AFX_DATA_MAP
}


BEGIN_MESSAGE_MAP(CX25ThroughPutClass, CPropertyPage)
	//{{AFX_MSG_MAP(CX25ThroughPutClass)
	ON_CBN_SELCHANGE(IDC_X25_LOCDEFTHCLASS, OnSelchangeX25Locdefthclass)
	ON_CBN_SELCHANGE(IDC_X25_LOCMAXTHCLASS, OnSelchangeX25Locmaxthclass)
	ON_CBN_SELCHANGE(IDC_X25_LOCMINTHCLASS, OnSelchangeX25Locminthclass)
	ON_CBN_SELCHANGE(IDC_X25_REMDEFTHCLASS, OnSelchangeX25Remdefthclass)
	ON_CBN_SELCHANGE(IDC_X25_REMMAXTHCLASS, OnSelchangeX25Remmaxthclass)
	ON_CBN_SELCHANGE(IDC_X25_REMMINTHCLASS, OnSelchangeX25Remminthclass)
	ON_BN_CLICKED(IDC_Advanced, OnAdvanced)
	//}}AFX_MSG_MAP
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CX25ThroughPutClass message handlers

void CX25ThroughPutClass::OnSelchangeX25Locdefthclass() 
{
	// TODO: Add your control notification handler code here
	UpdateData(TRUE);
	if (m_LocDefThClass < 3 || m_LocDefThClass > 12)
		return;

	if (m_LocDefThClass > m_LocMaxThClass && m_LocMaxThClass >= 3 && m_LocMaxThClass <= 12) {
		m_LocMaxThClass = m_LocDefThClass;
		UpdateData(FALSE);
		}

	if (m_LocDefThClass < m_LocMinThClass && m_LocMinThClass >= 3 && m_LocMinThClass <= 12) {
		m_LocMinThClass = m_LocDefThClass;
		UpdateData(FALSE);
		}
}

void CX25ThroughPutClass::OnSelchangeX25Locmaxthclass() 
{
	// TODO: Add your control notification handler code here
	UpdateData(TRUE);
	if (m_LocMaxThClass < 3 || m_LocMaxThClass > 12)
		return;

	if (m_LocMaxThClass < m_LocDefThClass && m_LocDefThClass >= 3 && m_LocDefThClass <= 12) {
		m_LocDefThClass = m_LocMaxThClass;
		UpdateData(FALSE);
		}

	if (m_LocMaxThClass < m_LocMinThClass && m_LocMinThClass >= 3 && m_LocMinThClass <= 12) {
		m_LocMinThClass = m_LocMaxThClass;
		UpdateData(FALSE);
		}
}

void CX25ThroughPutClass::OnSelchangeX25Locminthclass() 
{
	// TODO: Add your control notification handler code here
	UpdateData(TRUE);
	if (m_LocMinThClass < 3 || m_LocMinThClass > 12)
		return;

	if (m_LocMinThClass > m_LocDefThClass && m_LocDefThClass >= 3 && m_LocDefThClass <= 12) {
		m_LocDefThClass = m_LocMinThClass;
		UpdateData(FALSE);
		}

	if (m_LocMinThClass > m_LocMaxThClass && m_LocMaxThClass >= 3 && m_LocMaxThClass <= 12) {
		m_LocMaxThClass = m_LocMinThClass;
		UpdateData(FALSE);
		}
}

void CX25ThroughPutClass::OnSelchangeX25Remdefthclass() 
{
	// TODO: Add your control notification handler code here
	UpdateData(TRUE);
	if (m_RemDefThClass < 3 || m_RemDefThClass > 12)
		return;

	if (m_RemDefThClass > m_RemMaxThClass && m_RemMaxThClass >= 3 && m_RemMaxThClass <= 12) {
		m_RemMaxThClass = m_RemDefThClass;
		UpdateData(FALSE);
		}

	if (m_RemDefThClass < m_RemMinThClass && m_RemMinThClass >= 3 && m_RemMinThClass <= 12) {
		m_RemMinThClass = m_RemDefThClass;
		UpdateData(FALSE);
		}
}

void CX25ThroughPutClass::OnSelchangeX25Remmaxthclass() 
{
	// TODO: Add your control notification handler code here
	UpdateData(TRUE);
	if (m_RemMaxThClass < 3 || m_RemMaxThClass > 12)
		return;

	if (m_RemMaxThClass < m_RemDefThClass && m_RemDefThClass >= 3 && m_RemDefThClass <= 12) {
		m_RemDefThClass = m_RemMaxThClass;
		UpdateData(FALSE);
		}

	if (m_RemMaxThClass < m_RemMinThClass && m_RemMinThClass >= 3 && m_RemMinThClass <= 12) {
		m_RemMinThClass = m_RemMaxThClass;
		UpdateData(FALSE);
		}
}

void CX25ThroughPutClass::OnSelchangeX25Remminthclass() 
{
	// TODO: Add your control notification handler code here
	UpdateData(TRUE);
	if (m_RemMinThClass < 3 || m_RemMinThClass > 12)
		return;

	if (m_RemMinThClass > m_RemDefThClass && m_RemDefThClass >= 3 && m_RemDefThClass <= 12) {
		m_RemDefThClass = m_RemMinThClass;
		UpdateData(FALSE);
		}

	if (m_RemMinThClass > m_RemMaxThClass && m_RemMaxThClass >= 3 && m_RemMaxThClass <= 12) {
		m_RemMaxThClass = m_RemMinThClass;
		UpdateData(FALSE);
		}
}


BOOL CX25ThroughPutClass::OnKillActive() 
{
	BOOL bRetval = CPropertyPage::OnKillActive();
	if (bRetval)
		ReloadData();
	return bRetval;
}

BOOL CX25ThroughPutClass::OnApply() 
{
	
	if (CheckX25CfgValidity(m_pX25, this))
		return CPropertyPage::OnApply();
	else
		return FALSE;
}

void CX25ThroughPutClass::ReloadData()
{
	m_pX25->locmaxthclass = m_LocMaxThClass;
	m_pX25->remmaxthclass = m_RemMaxThClass;
	m_pX25->locdefthclass = m_LocDefThClass; 
	m_pX25->remdefthclass = m_RemDefThClass; 
	m_pX25->locminthclass = m_LocMinThClass; 
	m_pX25->remminthclass = m_RemMinThClass; 
}

BOOL CX25ThroughPutClass::OnInitDialog() 
{
	m_LocMaxThClass = m_pX25->locmaxthclass;
	m_RemMaxThClass = m_pX25->remmaxthclass;
	m_LocDefThClass = m_pX25->locdefthclass;
	m_RemDefThClass = m_pX25->remdefthclass;
	m_LocMinThClass = m_pX25->locminthclass;
	m_RemMinThClass = m_pX25->remminthclass;

	CPropertyPage::OnInitDialog();
	
	// TODO: Add extra initialization here
	
	return TRUE;  // return TRUE unless you set the focus to a control
	              // EXCEPTION: OCX Property Pages should return FALSE
}

void CX25ThroughPutClass::OnAdvanced() 
{
	CString pageName;
	GetWindowText(pageName);

	CPropertySheet sheet(pageName);
	CX25ThClassAdvanced advpage(m_pX25);
	sheet.AddPage(&advpage);
	sheet.DoModal();
}

/////////////////////////////////////////////////////////////////////////////
// CX25CUG property page

IMPLEMENT_DYNCREATE(CX25CUG, CPropertyPage)

CX25CUG::CX25CUG() : CPropertyPage(CX25CUG::IDD)
{
	//{{AFX_DATA_INIT(CX25CUG)
	m_BarCUGIn = FALSE;
	m_CUG = -1;
	m_CugFormat = -1;
	m_CUGIA = FALSE;
	m_Pref = FALSE;
	//}}AFX_DATA_INIT
}

CX25CUG::~CX25CUG()
{
}

void CX25CUG::DoDataExchange(CDataExchange* pDX)
{
	CPropertyPage::DoDataExchange(pDX);
	//{{AFX_DATA_MAP(CX25CUG)
	DDX_Control(pDX, IDD_X25_CUG_EXTENDED, m_CUGFormatButton);
	DDX_Check(pDX, IDC_X25_SUB_BAR_CUG_IN, m_BarCUGIn);
	DDX_Radio(pDX, IDC_X25_SUB_CUG, m_CUG);
	DDX_Radio(pDX, IDC_X25_SUB_CUG_FORMAT, m_CugFormat);
	DDX_Check(pDX, IDC_X25_SUB_CUGIA, m_CUGIA);
	DDX_Check(pDX, IDC_X25_SUB_PREF, m_Pref);
	//}}AFX_DATA_MAP
}


BEGIN_MESSAGE_MAP(CX25CUG, CPropertyPage)
	//{{AFX_MSG_MAP(CX25CUG)
		// NOTE: the ClassWizard will add message map macros here
	//}}AFX_MSG_MAP
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CX25CUG message handlers
/////////////////////////////////////////////////////////////////////////////
// CX25DBit property page

IMPLEMENT_DYNCREATE(CX25DBit, CPropertyPage)

CX25DBit::CX25DBit(X25 * const pX25) : CPropertyPage(CX25DBit::IDD)
{
   ASSERT(NULL != pX25);
   m_pX25 = pX25;
	//{{AFX_DATA_INIT(CX25DBit)
	m_AcceptIn = -1;
	m_DataIn = -1;
	//}}AFX_DATA_INIT
}

CX25DBit::~CX25DBit()
{
}

void CX25DBit::DoDataExchange(CDataExchange* pDX)
{
	CPropertyPage::DoDataExchange(pDX);
	//{{AFX_DATA_MAP(CX25DBit)
	DDX_CBIndex(pDX, IDC_X25_DBIT_ACCEPT_IN, m_AcceptIn);
	DDX_CBIndex(pDX, IDC_X25_DBIT_DATA_IN, m_DataIn);
	//}}AFX_DATA_MAP
}


BEGIN_MESSAGE_MAP(CX25DBit, CPropertyPage)
	//{{AFX_MSG_MAP(CX25DBit)
	//}}AFX_MSG_MAP
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CX25DBit message handlers



void CX25DBit::OnOK() 
{
	DWORD DBitControl = 0;

  switch (m_AcceptIn) {
  	case 1:	DBitControl |= CC_IN_ZERO; break;
    case 2:	DBitControl |= CC_IN_CLR;	break;
    }

  switch (m_DataIn) {
    case 1:	DBitControl |= DT_IN_ZERO; break;
    case 2:	DBitControl |= DT_IN_RST;	break;
    }

  m_pX25->dbit_control = DBitControl;
	
	CPropertyPage::OnOK();
}

BOOL CX25DBit::OnInitDialog() 
{
	DWORD DBitControl = m_pX25->dbit_control;

	m_AcceptIn =  0;
	if (DBitControl & CC_IN_CLR)
		m_AcceptIn =  2;
	else if (DBitControl & CC_IN_ZERO)
		m_AcceptIn =  1;

	m_DataIn = 0;
	if (DBitControl & DT_IN_RST)
		m_DataIn = 2;
	else if (DBitControl & DT_IN_ZERO)
		m_DataIn = 1;

	CPropertyPage::OnInitDialog();
	
	// TODO: Add extra initialization here
	
	return TRUE;  // return TRUE unless you set the focus to a control
	              // EXCEPTION: OCX Property Pages should return FALSE
}




/////////////////////////////////////////////////////////////////////////////
// CGetWindowSize dialog


CGetWindowSize::CGetWindowSize(CWnd* pParent /*=NULL*/)
	: CDialog(CGetWindowSize::IDD, pParent)
{
	//{{AFX_DATA_INIT(CGetWindowSize)
	m_WindowSize = 0;
	//}}AFX_DATA_INIT
}


void CGetWindowSize::DoDataExchange(CDataExchange* pDX)
{
	CDialog::DoDataExchange(pDX);
	CEdit *edit = (CEdit *)GetDlgItem(IDC_WindowSize);
	CString txt;

	if (edit != NULL)
		edit->GetWindowText(txt);

	CString ThDef;
	ThDef.LoadString(IDS_ThClassMapDefName);

	if (pDX->m_bSaveAndValidate)
		if (txt.CompareNoCase(ThDef) == 0)
			m_WindowSize = 0;
		else {
			DDX_Text(pDX, IDC_WindowSize, m_WindowSize);
			DDV_MinMaxDWord(pDX, m_WindowSize, 0, m_MaxWindowSize);
			}


	//{{AFX_DATA_MAP(CGetWindowSize)
		// NOTE: the ClassWizard will add DDX and DDV calls here
	//}}AFX_DATA_MAP

	if (!pDX->m_bSaveAndValidate) {
		DDX_Text(pDX, IDC_WindowSize, m_WindowSize);
		if (m_WindowSize == 0)
			edit->SetWindowText(ThDef);
		}
}


BEGIN_MESSAGE_MAP(CGetWindowSize, CDialog)
	//{{AFX_MSG_MAP(CGetWindowSize)
		// NOTE: the ClassWizard will add message map macros here
	//}}AFX_MSG_MAP
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CGetWindowSize message handlers

/////////////////////////////////////////////////////////////////////////////
// CX25ThClassAdvanced property page

IMPLEMENT_DYNCREATE(CX25ThClassAdvanced, CPropertyPage)

CX25ThClassAdvanced::CX25ThClassAdvanced(X25 * const pX25) : CPropertyPage(CX25ThClassAdvanced::IDD)
{
   ASSERT(NULL != pX25);
   m_pX25 = pX25;
	//{{AFX_DATA_INIT(CX25ThClassAdvanced)
	m_Type = -1;
	//}}AFX_DATA_INIT
}

CX25ThClassAdvanced::~CX25ThClassAdvanced()
{
}

void CX25ThClassAdvanced::DoDataExchange(CDataExchange* pDX)
{
	CPropertyPage::DoDataExchange(pDX);
	//{{AFX_DATA_MAP(CX25ThClassAdvanced)
	DDX_Control(pDX, IDC_PacketList, m_PacketBox);
	DDX_Control(pDX, IDC_WindowMapList, m_WindowMapList);
	DDX_Control(pDX, IDC_PacketMapList, m_PacketMapList);
	DDX_CBIndex(pDX, IDC_THCLASS_TYPE, m_Type);
	//}}AFX_DATA_MAP
}


BEGIN_MESSAGE_MAP(CX25ThClassAdvanced, CPropertyPage)
	//{{AFX_MSG_MAP(CX25ThClassAdvanced)
	ON_CBN_SELCHANGE(IDC_THCLASS_TYPE, OnSelchangeThclassType)
	//}}AFX_MSG_MAP
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CX25ThClassAdvanced message handlers

void CX25ThClassAdvanced::OnSelchangeThclassType() 
{
	// TODO: Add your control notification handler code here
	UpdateData(TRUE);
	m_PacketMapList.EnableWindow(m_Type > 0);
	m_WindowMapList.EnableWindow(m_Type > 0);
}


void CX25ThClassAdvanced::DoSetWindowMap(DWORD ThisGFI)
{
	CGetWindowSize dlg;

	dlg.m_MaxWindowSize = ThisGFI == G_8 ? 7 : 127;

	int Sel = m_WindowMapList.GetCurSel();
	if (Sel > LB_ERR) {
		dlg.m_WindowSize = (unsigned long)m_WindowMapList.GetItemData(Sel);

		CString ThDef;
		ThDef.LoadString(IDS_ThClassMapDefName);

		if (dlg.DoModal() == IDOK) {
			CString thLevel;
			TCHAR buf[16];

			thLevel.Format(IDS_ThClassLevel0 + Sel, dlg.m_WindowSize == 0
													? (LPCTSTR)ThDef
													: _ultoa(dlg.m_WindowSize, buf, 10)
													);
			int index = m_WindowMapList.InsertString(Sel, thLevel);
			m_WindowMapList.SetItemData(index, dlg.m_WindowSize);
			m_WindowMapList.DeleteString(Sel+1);
			}
		}
}

void CX25ThClassAdvanced::DoSetPacketMap()
{
	int Sel = m_PacketMapList.GetCurSel();
	int Top = m_PacketMapList.GetTopIndex();
	ULONG_PTR Data = m_PacketMapList.GetItemData(Sel);

	CRect rect;
	m_PacketMapList.GetWindowRect(rect);
	ScreenToClient(rect);

	CRect rectEdit;
	m_PacketBox.GetWindowRect(rectEdit);
	ScreenToClient(rectEdit);

	if (Sel > LB_ERR) {
		int x = rect.right - rectEdit.Width() - GetSystemMetrics(SM_CXVSCROLL);
		int y = rect.top + m_Height * (Sel - Top);

		m_PacketBox.SetCurSel(Data == 0 ? 0 : Data - 6);
		m_PacketBox.SetWindowPos(&CWnd::wndTop, x, y, 0, 0, SWP_NOSIZE | SWP_SHOWWINDOW);
		m_PacketBox.SetFocus();
		m_PacketBox.ShowDropDown();
		}
}


void CX25ThClassAdvanced::OnOK() 
{
	m_pX25->thclass_type = m_Type;


	LPBYTE WMap = m_pX25->thclass_wmap;
	LPBYTE PMap = m_pX25->thclass_pmap;

	for (short i = 0; i < 16; i++) {
		WMap[i] = (BYTE)m_WindowMapList.GetItemData(i);
		PMap[i] = (BYTE)m_PacketMapList.GetItemData(i);
		}
	
	
	CPropertyPage::OnOK();
}

BOOL CX25ThClassAdvanced::OnInitDialog() 
{
	m_Type = m_pX25->thclass_type;
	CPropertyPage::OnInitDialog();

	m_WindowMapList.ResetContent();
	m_PacketMapList.ResetContent();
	
	CDC *dc = GetDC();
	TEXTMETRIC tm;

	dc->GetTextMetrics(&tm);
	ReleaseDC(dc);
	
	m_Height = tm.tmAscent;
	
	int xunit = LOWORD(GetDialogBaseUnits());
	m_WindowMapList.SetTabStops((tm.tmAveCharWidth * 12 * 4) / xunit);
	m_PacketMapList.SetTabStops((tm.tmAveCharWidth * 12 * 4) / xunit);

	CString ThDef;
	ThDef.LoadString(IDS_ThClassMapDefName);

	for (short i = 0; i < 16; i++) {
		CString thLevel;
		TCHAR buf[16];

		LPBYTE WMap = m_pX25->thclass_wmap;
		LPBYTE PMap = m_pX25->thclass_pmap;

		thLevel.Format(IDS_ThClassLevel0 + i, WMap[i] == 0
												? (LPCTSTR)ThDef
												: _ultoa(WMap[i], buf, 10)
												);
		int index = m_WindowMapList.AddString(thLevel);
		m_WindowMapList.SetItemData(index, WMap[i]);

		thLevel.Format(IDS_ThClassLevel0 + i, PMap[i] == 0
												? (LPCTSTR)ThDef
												: _ultoa(1 << PMap[i], buf, 10)
												);
		index = m_PacketMapList.AddString(thLevel);
		m_PacketMapList.SetItemData(index, PMap[i]);
		}

	OnSelchangeThclassType();
	
	// TODO: Add extra initialization here
	
	return TRUE;  // return TRUE unless you set the focus to a control
	              // EXCEPTION: OCX Property Pages should return FALSE
}



BOOL CX25ThClassAdvanced::OnCmdMsg(UINT nID, int nCode, void* pExtra, AFX_CMDHANDLERINFO* pHandlerInfo) 
{
	if (nID == IDC_PacketList) {
		switch (nCode) {
			case CBN_SELENDOK : {
				CString ThDef;
				ThDef.LoadString(IDS_ThClassMapDefName);

				int Sel = m_PacketMapList.GetCurSel();
				int Packet = m_PacketBox.GetCurSel();
				CString thLevel;
				TCHAR buf[16];

				if (Packet > 0)
					Packet += 6;

				thLevel.Format(IDS_ThClassLevel0 + Sel, Packet == 0
														? (LPCTSTR)ThDef
														: _ultoa(1 << Packet, buf, 10)
														);
				int index = m_PacketMapList.InsertString(Sel, thLevel);
				m_PacketMapList.SetItemData(index, Packet);
				m_PacketMapList.DeleteString(Sel+1);
				}
				// fall through
			case CBN_CLOSEUP :
				m_PacketBox.ShowWindow(SW_HIDE);
			default :
				;
			}
		}
	else if (nCode == BN_CLICKED) {
		if (nID == IDC_ChangeWindowMap)
			DoSetWindowMap(m_pX25->THISGFI);
		else if (nID == IDC_ChangePacketMap)
			DoSetPacketMap();
		}
	else if (nCode == LBN_DBLCLK)
		if (nID == IDC_WindowMapList)
			DoSetWindowMap(m_pX25->THISGFI);
		else if (nID == IDC_PacketMapList)
			DoSetPacketMap();

	return CPropertyPage::OnCmdMsg(nID, nCode, pExtra, pHandlerInfo);
	
}



/////////////////////////////////////////////////////////////////////////////
// CLAPB property page

IMPLEMENT_DYNCREATE(CLAPB, CPropertyPage)

CLAPB::CLAPB(LAPB * const pLAPB, X25 * const pX25) : CPropertyPage(CLAPB::IDD)
{
   ASSERT(NULL != pLAPB);
   ASSERT(NULL != pX25);
   m_pLAPB = pLAPB;
   m_pX25 = pX25;
	//{{AFX_DATA_INIT(CLAPB)
	m_LAPBAckDelay = 4;
	m_N2 = 10;
	m_T1 = 10;
	m_TIdle = 250;
	m_TXWindow = 7;
	m_LAPBLLClass = 0;
	//}}AFX_DATA_INIT
}

CLAPB::~CLAPB()
{
}

void CLAPB::DoDataExchange(CDataExchange* pDX)
{
	CPropertyPage::DoDataExchange(pDX);
	//{{AFX_DATA_MAP(CLAPB)
	DDX_Text(pDX, IDC_LAPB_ACKDELAY, m_LAPBAckDelay);
	DDV_MinMaxDWord(pDX, m_LAPBAckDelay, 0, 3000);
	DDX_Text(pDX, IDC_LAPB_N2, m_N2);
	DDV_MinMaxDWord(pDX, m_N2, 1, 255);
	DDX_Text(pDX, IDC_LAPB_T1, m_T1);
	DDV_MinMaxDWord(pDX, m_T1, 1, 3000);
	DDX_Text(pDX, IDC_LAPB_TIDLE, m_TIdle);
	DDV_MinMaxDWord(pDX, m_TIdle, 0, 32000);
	DDX_Text(pDX, IDC_LAPB_TXWINDOW, m_TXWindow);
	DDX_Radio(pDX, IDC_LAPB_LLCLASS, m_LAPBLLClass);
	//}}AFX_DATA_MAP
	int max = m_LAPBLLClass == 0 ? 7 : 127;
	DDX_Text(pDX, IDC_LAPB_TXWINDOW, m_TXWindow);
	DDV_MinMaxDWord(pDX, m_TXWindow, 1, max);

}


BEGIN_MESSAGE_MAP(CLAPB, CPropertyPage)
	//{{AFX_MSG_MAP(CLAPB)
	//}}AFX_MSG_MAP
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CLAPB message handlers
BOOL CLAPB::OnInitDialog() 
{
	m_N2 = m_pLAPB->N2;
	m_T1 = m_pLAPB->T1;
	m_TIdle = m_pLAPB->Tidle;
	m_LAPBAckDelay = m_pLAPB->ack_delay;
	m_TXWindow = m_pLAPB->tx_window;

	switch (m_pX25->ll_class)	{
		case LC_LAPBDCE :	
		case LC_LAPBDTE :	
			m_LAPBLLClass = 0; break;
		case LC_LAPBXDCE :	
		case LC_LAPBXDTE :	
			m_LAPBLLClass = 1; break;
		}

	CPropertyPage::OnInitDialog();
	
	// TODO: Add extra initialization here
	
	return TRUE;  // return TRUE unless you set the focus to a control
	              // EXCEPTION: OCX Property Pages should return FALSE
}

void CLAPB::OnOK() 
{
	m_pLAPB->N2 = m_N2;
	m_pLAPB->T1 = m_T1;
	m_pLAPB->Tidle = m_TIdle;
	m_pLAPB->ack_delay = m_LAPBAckDelay;
	m_pLAPB->tx_window = m_TXWindow;
	m_pLAPB->notack_max = m_TXWindow;


	DWORD LLClass = 0;

	switch(m_pX25->L3PLPMODE) {
		case 0: // DCE
			LLClass = m_LAPBLLClass == 0 ? LC_LAPBDCE : LC_LAPBXDCE;
			break;
		case 1: // DTE
		case 2: // DXE
			LLClass = m_LAPBLLClass == 0 ? LC_LAPBDTE : LC_LAPBXDTE;
			break;
		}

	m_pX25->ll_class = LLClass;	
	CPropertyPage::OnOK();
}

/////////////////////////////////////////////////////////////////////////////
// CLAPBNetwork property page

IMPLEMENT_DYNCREATE(CLAPBNetwork, CPropertyPage)

CLAPBNetwork::CLAPBNetwork(LAPB * const pLAPB) : CPropertyPage(CLAPBNetwork::IDD)
{
   ASSERT(NULL != pLAPB);
   m_pLAPB = pLAPB;
	//{{AFX_DATA_INIT(CLAPBNetwork)
	m_FRMRError = FALSE;
	m_INVRSPError = FALSE;
	m_IGNUAError = FALSE;
	m_NODMADM = FALSE;
	m_SFrameBit = FALSE;
	//}}AFX_DATA_INIT
}

CLAPBNetwork::~CLAPBNetwork()
{
}

void CLAPBNetwork::DoDataExchange(CDataExchange* pDX)
{
	CPropertyPage::DoDataExchange(pDX);
	//{{AFX_DATA_MAP(CLAPBNetwork)
	DDX_Check(pDX, IDC_LAPB_FRMR_FRMR_ERROR, m_FRMRError);
	DDX_Check(pDX, IDC_LAPB_FRMR_INVRSP_ERROR, m_INVRSPError);
	DDX_Check(pDX, IDC_LAPB_IGN_UA_ERROR, m_IGNUAError);
	DDX_Check(pDX, IDC_LAPB_NO_DM_ADM, m_NODMADM);
	DDX_Check(pDX, IDC_LAPB_SFRAME_PBIT, m_SFrameBit);
	//}}AFX_DATA_MAP

}


BEGIN_MESSAGE_MAP(CLAPBNetwork, CPropertyPage)
	//{{AFX_MSG_MAP(CLAPBNetwork)
	//}}AFX_MSG_MAP
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CLAPBNetwork message handlers


void CLAPBNetwork::OnOK() 
{
	DWORD LLConform = 0;

	if (m_IGNUAError)
  		LLConform |= IGN_UA_ERROR;

	if (m_FRMRError)
		LLConform |= FRMR_FRMR_ERROR;

	if (m_INVRSPError)
		LLConform |= FRMR_INVRSP_ERROR;

	if (m_SFrameBit)
		LLConform |= SFRAME_PBIT;

	if (m_NODMADM)
		LLConform |= NO_DM_ADM;

	m_pLAPB->llconform = LLConform;
	
	CPropertyPage::OnOK();
}

BOOL CLAPBNetwork::OnInitDialog() 
{

	DWORD LLConform = m_pLAPB->llconform;

	m_IGNUAError = (LLConform & IGN_UA_ERROR) > 0;
	m_FRMRError	= (LLConform & FRMR_FRMR_ERROR) > 0;
	m_INVRSPError = (LLConform & FRMR_INVRSP_ERROR) > 0;
	m_SFrameBit = (LLConform & SFRAME_PBIT) > 0;
	m_NODMADM = (LLConform & NO_DM_ADM) > 0;

	CPropertyPage::OnInitDialog();
	
	// TODO: Add extra initialization here
	
	return TRUE;  // return TRUE unless you set the focus to a control
	              // EXCEPTION: OCX Property Pages should return FALSE
}



