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

// PVC.cpp: implementation of the CPortFR  class
//
//////////////////////////////////////////////////////////////////////
#include "stdafx.h"
#include "pvc.h"
#include "ObjectFactory.h"
#include "RegHelpers.h"
#include "pvcreg.h"
#include "defs.h"
#include "PvcFRCfg.h"
#include "ServiceFR.h"
IMPLEMENT_DYNAMIC(CPortFR,CPortPVC)


CPortFR::CPortFR(HKEY const hKeyRoot, CString const strRegPath, CConfigObject const * const pParent)
      :CPortPVC(hKeyRoot,strRegPath,pParent)
{

	try 
	{
		m_nBaudRate = ((CServiceFR*)pParent)->GetLineSpeed();	// obtained from the parent
		m_szProtocol = DXB_REGVAL_PROTOCOL_ENUM_FRAMERELAY;
		m_nBE = 0;
		m_nModeOneRRPeriod = 0;
		m_nModeOneRRMax = 10;
		m_nCMP = 1;
		m_nCIR = m_nBaudRate;
		// Get protocol parameters
		AffirmThrow(GetParameters());

		// solve the identity crisis
		SetIdentity(DXB_REGVAL_PORT_TYPE_FR);

		// if this is a brand new object, its DLCI value will be 0
		// assign a valid DLCI
		if (!m_nDLCI)
      {
			AffirmThrow(AssignDLCI(m_nDLCI));
   		m_szDescription.Format(IDS_FRDEFDESC,(m_dwSnid & 0xffff),m_nDLCI);
      }

		// Set our Display Name
		SetName();

		SetAbility(CConfigObject::DOPROPERTIES);
	
		// get our static config data
		AffirmThrow(CPortPVC::GetConfigData());
	}
	catch(CAffirmException ae)
	{
	}

}

CPortFR::~CPortFR()
{

}



//////////////////////////////////////////////////////////////////////
// Get/Set parameters
//////////////////////////////////////////////////////////////////////

BOOL CPortFR::GetParameters(void)
{

    BOOL fSuccess = FALSE;

    try
    {

		// If the reads fail, all values will be set to default of 0.
		RegReadIntValue(m_hKey,PVC_REGVAL_DLCI,&m_nDLCI,0);
		// if we have a valid DLCI value, mark it as existing
		// and read rest of the params
		if (m_nDLCI)
		{

			AffirmThrow(CPortPVC::GetParameters());
			m_nPVCFlags = PVC_EXISTING;
			RegReadIntValue(m_hKey,PVC_REGVAL_CIR,&m_nCIR);
			RegReadIntValue(m_hKey,PVC_REGVAL_CMP,&m_nCMP);
			RegReadIntValue(m_hKey,PVC_REGVAL_BCMAX,&m_nBCMAX);
			RegReadIntValue(m_hKey,PVC_REGVAL_BCMIN,&m_nBCMIN);
			RegReadIntValue(m_hKey,PVC_REGVAL_BE,&m_nBE);
			RegReadIntValue(m_hKey,PVC_REGVAL_RRPERIOD,&m_nModeOneRRPeriod);
			RegReadIntValue(m_hKey,PVC_REGVAL_RRMAX,&m_nModeOneRRMax);
		}
		fSuccess = TRUE;
	}
	catch (CAffirmException ae)
	{
	}

	return fSuccess;
}

BOOL CPortFR::SetParameters(void)
{
   BOOL fSuccess = FALSE;

   try
   {
	  m_nBCMAX = m_nCIR/2;
	  m_nBCMIN = m_nCIR/4;
      AffirmThrow(CPortPVC::SetParameters());
	  RegWriteIntValue(m_hKey,PVC_REGVAL_DLCI,m_nDLCI);
	  RegWriteIntValue(m_hKey,PVC_REGVAL_CIR,m_nCIR);
	  RegWriteIntValue(m_hKey,PVC_REGVAL_CMP,m_nCMP);
	  RegWriteIntValue(m_hKey,PVC_REGVAL_BCMAX,m_nBCMAX);
	  RegWriteIntValue(m_hKey,PVC_REGVAL_BCMIN,m_nBCMIN);
	  RegWriteIntValue(m_hKey,PVC_REGVAL_BE,m_nBE);
	  RegWriteIntValue(m_hKey,PVC_REGVAL_RRPERIOD,m_nModeOneRRPeriod);
	  RegWriteIntValue(m_hKey,PVC_REGVAL_RRMAX,m_nModeOneRRMax);
#ifdef NT5
	  RegWriteStrValue(m_hKey,DXB_REGVAL_PDO_HDWID,DXB_HDWID_PVCFR);
#endif
      fSuccess = TRUE;
   }
   catch (CAffirmException ae)
   {
   }

   return fSuccess;
}



//////////////////////////////////////////////////////////////////////
// UI config methods
//////////////////////////////////////////////////////////////////////

BOOL CPortFR::AddWizardPages(CConfigWizSheet * const pSheet)
{
	ASSERT(FALSE);
	return FALSE;
}

BOOL CPortFR::NextWizardPage(int const nState)
{
	ASSERT(FALSE);
	return FALSE;
}

BOOL CPortFR::DoProperties()
{
#define FRF9_RETRYPERIOD	3
#define FRF9_NORETRY		0

	BOOL fSuccess = FALSE;
	ASSERT(!(m_nPVCFlags & PVC_DELETE));
	try
	{
		AffirmThrow(m_nDLCI);
		// create proertysheet
		CString szTitle((LPCTSTR)IDS_FRPVC_TITLE);
		
		CPropertySheet sheet(szTitle);
		CFRProtocol protocol;

      // This data is shared between the pages, manage the storage at this level
      int nCIR = m_nCIR;
      CFRPVC pvc(&nCIR);
		CFRPVCAdvanced pvcadv(&nCIR);

      sheet.AddPage(&pvc);
		sheet.AddPage(&protocol);
		sheet.AddPage(&pvcadv);
		// change this flag to reflect whether this is new or existing PVC
		pvc.m_bConfig = (m_nPVCFlags & PVC_NEW)?TRUE:FALSE;
		pvc.m_nCIR = m_nCIR;
		pvc.m_bCompression = (m_nModeOneRRPeriod >0)?TRUE:FALSE;
		pvc.m_nBaudRate = m_nBaudRate;
		pvc.m_pPort = this;
		pvc.m_nDLCI = m_nDLCI;

		protocol.m_TCPIP = m_nTCPIP;
		protocol.m_IPX = m_nIPX;
		protocol.m_Ethernet = m_nEthernet;
		protocol.m_szIPAddress = m_szIPAddress;
		protocol.m_szSubnetMask = m_szSubnetMask;

		pvcadv.m_AutoManage = m_bAutoManage;
		pvcadv.m_BE = m_nBE;
		pvcadv.m_CMP = m_nCMP;
		pvcadv.m_RRPeriod = m_nModeOneRRPeriod;
		pvcadv.m_RRMax = m_nModeOneRRMax;
		pvcadv.m_NetworkAddress[0] = m_szNetworkAddress;
		pvcadv.m_nBaudRate = m_nBaudRate;	

 		if (sheet.DoModal() == IDOK)
		{
			m_nCIR = pvc.m_nCIR;
			if (m_nDLCI != (int)pvc.m_nDLCI)
			{
				m_nDLCI = pvc.m_nDLCI;
				SetName();
      		m_szDescription.Format(IDS_FRDEFDESC,(m_dwSnid & 0xffff),m_nDLCI);
			}

			m_nTCPIP = protocol.m_TCPIP;
			m_nIPX = protocol.m_IPX;
			m_nEthernet = protocol.m_Ethernet;
			m_szIPAddress = protocol.m_szIPAddress;
			m_szSubnetMask = protocol.m_szSubnetMask;

			m_bAutoManage = pvcadv.m_AutoManage;
			m_nCMP = pvcadv.m_CMP;
			m_nBE = pvcadv.m_BE;
			m_nModeOneRRPeriod = pvcadv.m_RRPeriod;
			m_nModeOneRRMax = pvcadv.m_RRMax;
			m_szNetworkAddress = pvcadv.m_NetworkAddress[0];

			if (pvc.m_bCompression == FALSE)
				m_nModeOneRRPeriod = FRF9_NORETRY;
			else if (!m_nModeOneRRPeriod)
				m_nModeOneRRPeriod = FRF9_RETRYPERIOD;

			if (m_bAutoManage)
				m_nBE = m_nBaudRate - m_nCIR;
            ASSERT(m_nBE >= 0);
			if (!m_nCIR && !m_nBE  /*&& !(Flags & FRS_LINK_FLAGS_FORCED_INJECTION)*/) 
				AfxMessageBox(IDS_INJECTIONWARNING);
			fSuccess = TRUE;
		}
	}
	catch (CAffirmException ae)
	{
	}

	return fSuccess;
}


// supply static PORT information
// DLCI, CIR & Description
CString CPortFR::GetInformationText(void)
{
	CString strInfo;
#if defined NT5
	strInfo.Format(IDS_FRPVCINFO_W2K_FMT,m_szDescription,m_nDLCI,m_nCIR);
#else // #if defined NT5
	strInfo.Format(IDS_FRPVCINFO_FMT,m_szDescription,m_nDLCI,m_nCIR,m_szIPAddress,m_szSubnetMask);
#endif // #if defined NT5
	return strInfo;
}


// return TRUE if the passed in DLCI value is unique otherwise FALSE;
BOOL CPortFR::ValidateDLCI(int nDLCI) const
{
	BOOL bSuccess = TRUE;
	CConfigObject* pParent = GetParent();
	ASSERT(pParent);
	INT_PTR nSiblings = pParent->GetChildCount();
	for(int i=0;i<nSiblings && bSuccess;i++)
	{
		CPortFR* pSib = (CPortFR*)(pParent->GetChild(i));
		ASSERT(pSib);
		if (pSib != this && nDLCI == pSib->m_nDLCI)
			bSuccess = FALSE;
	}

	return bSuccess;

}

// this routine is only called from the ctor. Starting with the min DLCI value
// routine searches through entire collection to find a unique DLCI value
// Returns TRUE if successfull.
BOOL CPortFR::AssignDLCI(int& rDLCI)
{
	CConfigObject* pParent = GetParent();
	ASSERT(pParent);
	INT_PTR nSiblings = pParent->GetChildCount();
	if (!nSiblings)
	{
		rDLCI = MIN_DLCI;
		return TRUE;
	}
	BOOL bSuccess = FALSE;
	for(int nDLCI = MIN_DLCI;nDLCI <= MAX_DLCI && !bSuccess;nDLCI++)
	{
		for(int nSibIndex = 0;nSibIndex < nSiblings; nSibIndex++)
		{
			CPortFR* pSibling = (CPortFR*)(pParent->GetChild(nSibIndex));
			ASSERT(pSibling);
			if (pSibling->m_nDLCI == nDLCI)
			{
				break;
			}
		}
		if (nSibIndex == nSiblings)
		{
			rDLCI = nDLCI;
			bSuccess = TRUE;
		}
	}
	
	return bSuccess;
}

// set our display name
void CPortFR::SetName() 
{
	CString szDisplayName;
	CString szfmt((LPCTSTR)IDS_PVCDLCI_FMT);
	szDisplayName.Format(szfmt,m_nDLCI);
	SetDisplayName(szDisplayName);
}

// parent has changed. The only thing that really affects PVC (from parent)
// is line speed.
void CPortFR::ParentUpdate(void)
{
	CPortPVC::ParentUpdate();
	m_nBaudRate = ((CServiceFR*)GetParent())->GetLineSpeed();	// obtained from the parent
	if ((m_nBE + m_nCIR) > m_nBaudRate)
	{
		m_nBE = 0;
		m_nCIR = m_nBaudRate;
	}

}