/*****************************************************************************
* Copyright (c) 1990-98 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  CPortX25 class
//
//////////////////////////////////////////////////////////////////////
#include "stdafx.h"
#include "pvc.h"
#include "ObjectFactory.h"
#include "RegHelpers.h"
#include "pvcreg.h"
#include "defs.h"
#include "ServiceX25.h"
#include "PvcX25Cfg.h"

IMPLEMENT_DYNAMIC(CPortX25,CPortPVC)


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

	m_nChannel = 0;
	m_szProtocol = DXB_REGVAL_PROTOCOL_ENUM_X25;
	((CServiceX25*)pParent)->GetPacketandWindowData(m_nRemDefWsize,m_nRemDefPktsize,
		                                 m_nLocDefWsize,m_nLocDefPktsize);

	try
	{
		// Get protocol parameters
		AffirmThrow(GetParameters());

		// solve the identity crisis
		SetIdentity(DXB_REGVAL_PORT_TYPE_X25);

		// if this is a brand new object, its Channel value will be 0
		// assign a valid Channel
		if (!m_nChannel)
			AffirmThrow(AssignChannel(m_nChannel));

		// Display Name (for tree node, etc.)
		SetName();
      // Description, used by RAS and our UI
		SetDescription();

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

}

CPortX25::~CPortX25()
{

}



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

BOOL CPortX25::GetParameters(void)
{

    BOOL fSuccess = FALSE;

    try
    {

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

			AffirmThrow(CPortPVC::GetParameters());
			m_nPVCFlags = PVC_EXISTING;
			RegReadIntValue(m_hKey,PVC_REGVAL_REMOTE_WND,&m_nRemDefWsize);
			RegReadIntValue(m_hKey,PVC_REGVAL_LOCAL_WND,&m_nLocDefWsize);
			RegReadIntValue(m_hKey,PVC_REGVAL_REMOTE_PKT,&m_nRemDefPktsize);
			RegReadIntValue(m_hKey,PVC_REGVAL_LOCAL_PKT,&m_nLocDefPktsize);
		}
		fSuccess = TRUE;
	}
	catch (CAffirmException ae)
	{
	}

	return fSuccess;
}

BOOL CPortX25::SetParameters(void)
{

    BOOL fSuccess = FALSE;
    try
    {
		AffirmThrow(CPortPVC::SetParameters());
		RegWriteIntValue(m_hKey,PVC_REGVAL_CHANNEL,m_nChannel);
		RegWriteIntValue(m_hKey,PVC_REGVAL_REMOTE_WND,m_nRemDefWsize);
		RegWriteIntValue(m_hKey,PVC_REGVAL_LOCAL_WND,m_nLocDefWsize);
		RegWriteIntValue(m_hKey,PVC_REGVAL_REMOTE_PKT,m_nRemDefPktsize);
		RegWriteIntValue(m_hKey,PVC_REGVAL_LOCAL_PKT,m_nLocDefPktsize);
      RegWriteStrValue(m_hKey,DXB_REGVAL_DESCRIPTION,m_szDescription);
#ifdef NT5
	  RegWriteStrValue(m_hKey,DXB_REGVAL_PDO_HDWID,DXB_HDWID_PVCX25);
#endif
      // We need to look at our parent line...
      // Port<-Service<-Protocol<-Line<-Adapter
      CLine * pLine = (CLine *)GetParent()->GetParent()->GetParent();
      AffirmThrow(pLine != NULL);
      AffirmThrow(RegWriteDWordValue(m_hKey, DXB_REGVAL_LINESPEED, pLine->GetLineSpeed()));

		fSuccess = TRUE;
   }
   catch (CAffirmException ae)
   {
   }

   return fSuccess;
}



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

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

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

BOOL CPortX25::DoProperties()
{

	BOOL fSuccess = FALSE;
	ASSERT(!(m_nPVCFlags & PVC_DELETE));
	try
	{
		AffirmThrow(m_nChannel);

      // Did we just get added?
      BOOL fNewConfig = (PVC_NEW == (m_nPVCFlags & PVC_NEW));

      // We need to ask our owning service some questions
      CServiceX25* pParent = (CServiceX25*)GetParent();

		// create propertysheet
		CString szTitle;
      if (fNewConfig) {
         // We're adding a new PVC, genero title
   		szTitle.LoadString(IDS_X25PVC_TITLE);
      } else {
         // We're configuring an existing PVC, identify it in the title
         szTitle = m_szDescription;
      }


      CPropertySheet sheet(szTitle);
		CX25PVC pvc;
		CX25PVCAdvanced pvcadv;

      // For W2K, this page is meaningless if the PVC is already configured
      // If the user wishes to change the PVC channel, they really need to delete
      // this PVC and add a new one with the new channel
#if defined NT5
      if (fNewConfig)
#endif // #if defined NT5
      {
         sheet.AddPage(&pvc);
		   pvc.m_szDescription = m_szDescription;
		   pvc.m_nChannel = m_nChannel;
		   pvc.m_bConfig = fNewConfig;
		   pvc.m_szIPAddress = m_szIPAddress;
		   pvc.m_szSubnetMask = m_szSubnetMask;
		   pvc.m_pPort = this;
		   DWORD start,count;
		   pParent->GetPVCChannelData(start,count);
		   pvc.m_nChannelStart = start;
		   pvc.m_nChannelEnd = start+count-1;
      }

      // Always show the advanced page...
      sheet.AddPage(&pvcadv);
		pvcadv.m_AutoManage = m_bAutoManage;
		pvcadv.m_LocPacket = m_nLocDefPktsize;
		pvcadv.m_LocWindow = m_nLocDefWsize;
		pvcadv.m_RemPacket = m_nRemDefPktsize;
		pvcadv.m_RemWindow = m_nRemDefWsize;
		pvcadv.m_NetworkAddress[0] = m_szNetworkAddress;	
		pvcadv.m_nMaxWsize = pParent->GetWindowSize();

 		if (sheet.DoModal() == IDOK)
		{
#if defined NT5
         if (fNewConfig)
#endif //#if defined NT5
         {
            if (m_nChannel != (int)pvc.m_nChannel)
            {
               m_nChannel = pvc.m_nChannel;
               SetName();
               SetDescription();
            }

            m_szIPAddress = pvc.m_szIPAddress;
            m_szSubnetMask = pvc.m_szSubnetMask;
         }

			m_bAutoManage = pvcadv.m_AutoManage;
			m_nLocDefPktsize = pvcadv.m_LocPacket;
			m_nLocDefWsize = pvcadv.m_LocWindow;
			m_nRemDefPktsize = pvcadv.m_RemPacket;
			m_nRemDefWsize = pvcadv.m_RemWindow;
			m_szNetworkAddress = pvcadv.m_NetworkAddress[0];

			fSuccess = TRUE;
		}
	}
	catch (CAffirmException ae)
	{
	}

	return fSuccess;
}


// supply static PORT information
// DLCI, CIR & Description
CString CPortX25::GetInformationText(void)
{
	CString strInfo;
#if defined NT5
	strInfo.Format(IDS_X25PVCINFO_W2K_FMT, m_szDescription, m_nChannel);
#else // #if defined NT5
	CString szFmt((LPCTSTR)IDS_X25PVCINFO_FMT);
	strInfo.Format(szFmt,m_nChannel,m_szIPAddress,m_szSubnetMask);
#endif // #if defined NT5

	return strInfo;
}


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

	return bSuccess;

}

// this routine is only called from the ctor. Starting with the min Channel value
// routine searches through entire collection to find a unique Channel value
// Returns TRUE if successfull.
BOOL CPortX25::AssignChannel(int& rChannel)
{
	CServiceX25* pParent = (CServiceX25*)GetParent();
	ASSERT(pParent);
	DWORD nChannel,nCount; 
	pParent->GetPVCChannelData(nChannel,nCount);
	ASSERT(nChannel && nCount);
	INT_PTR nSiblings = pParent->GetChildCount();
	if (!nSiblings)
	{
		rChannel =nChannel;
		return TRUE;
	}

	BOOL bSuccess = FALSE;
	do
	{
		for(int nSibIndex = 0;nSibIndex < nSiblings; nSibIndex++)
		{
			CPortX25* pSibling = (CPortX25*)(pParent->GetChild(nSibIndex));
			ASSERT(pSibling);
			// if target channel exists in the list, increment target channel
			// and restart the loop
			if (pSibling->m_nChannel == (int)nChannel)
			{
				++nChannel;
				break;
			}
		}	
		// no channels matched. We found a unused channel
		if (nSibIndex == nSiblings)
		{
			rChannel = nChannel;
			bSuccess = TRUE;
		}
	}while(--nCount && !bSuccess);

	return bSuccess;
}

// set our display name
void CPortX25::SetName() 
{
	CString szDisplayName;
	CString szFmt((LPCTSTR)IDS_PVCCHANNEL_FMT);
	szDisplayName.Format(szFmt,m_nChannel);
	SetDisplayName(szDisplayName);
}

// set our description
void CPortX25::SetDescription() 
{
   CString szfmt((LPCTSTR)IDS_X25DEFDESC);
	m_szDescription.Format(szfmt,(m_dwSnid & 0xffff),m_nChannel);
}

void CPortX25::SetWindowSize(int remwndsize,int locwndsize)
{
#define MIN_WINDOWSIZE 7
	m_nRemDefWsize = __min(remwndsize,MIN_WINDOWSIZE);
	m_nLocDefWsize = __min(locwndsize,MIN_WINDOWSIZE);
}

BOOL CPortX25::ValidateChannelRange(DWORD nChannelStart,DWORD nChannelEnd)
{
	BOOL bResult = TRUE;
	// if the PVC's channel is on either end of current PVC channel range
	// return FALSE;
	if (m_nChannel < (int)nChannelStart || m_nChannel > (int)nChannelEnd)
		bResult = FALSE;

	return bResult;
}
