/*****************************************************************************
* 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 CPortPVC class
//
//////////////////////////////////////////////////////////////////////
#include "stdafx.h"
#include "resource.h"
#include "pvc.h"
#include "ObjectFactory.h"
#include "pvcreg.h"
#include "reghelpers.h"
#include "utils.h"
#include "ServiceBase.h"

#ifdef NT5
#include "DriverServices.h"
#endif

static LPCTSTR tszDefNetworkAddress  = _T("44-49-47-49-30-31");
static LPCTSTR tszDefIPAddress = _T("0.0.0.0");
static LPCTSTR tszDefSubnetMask = _T("255.255.255.0");

IMPLEMENT_DYNAMIC(CPortPVC, CPort)

CPortPVC::CPortPVC(HKEY const hKeyRoot, CString const strRegPath, CConfigObject const * const pParent)
      :CPort(hKeyRoot,strRegPath,pParent)
{
	m_szNetworkAddress = tszDefNetworkAddress;
	m_szIPAddress = tszDefIPAddress;
	m_szSubnetMask = tszDefSubnetMask;
	m_bAutoManage = TRUE;
	m_nEthernet = m_nIPX = 0;
	m_nTCPIP = 1;
	m_nPVCFlags = PVC_NEW;
	// obtain SNID number from parent
	m_dwSnid = ((CServiceBase*)pParent)->GetSnid();
	m_szDescription.Empty();
	try
	{


		// get our static config data
		AffirmThrow(CPort::GetConfigData());


	}
	catch (CAffirmException ae)
	{
	}

}

CPortPVC::~CPortPVC()
{
	// its possible for empty keys to be created. If they are empty
	// we need to remove them. Otherwise, the next time around, the parent will
	// try to construct an object that does not really exist.
	if (m_hKey)
	{
		RegReadIntValue(m_hKey,PVC_REGVAL_AUTOMANAGE,&m_bAutoManage,999);
		if (m_bAutoManage == 999)
			RegDeleteKey(m_hKeyRoot,m_strRegPath);
	}
}


CPortPVC& CPortPVC::operator=(const CPortPVC& rhs)
{
	if (this != &rhs)
	{
		// need to use/implement CopyParameters()
//		CPort::operator=(rhs);
		m_szNetworkAddress = rhs.m_szNetworkAddress;
		m_dwSnid = rhs.m_dwSnid;
		m_szDescription = rhs.m_szDescription;
		m_szProtocol = rhs.m_szProtocol;
		m_bAutoManage = rhs.m_bAutoManage;
		m_nTCPIP = rhs.m_nTCPIP;
		m_nEthernet = rhs.m_nEthernet;
		m_nIPX = rhs.m_nIPX;
		m_szSubnetMask = rhs.m_szSubnetMask;
		m_szIPAddress = rhs.m_szIPAddress;
		m_nPVCFlags = rhs.m_nPVCFlags;
	}
	return *this;
}

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

BOOL CPortPVC::GetParameters(void)
{
   BOOL fSuccess = FALSE;

   try
   {
      AffirmThrow(CPort::GetParameters());
	  RegReadStrValue(m_hKey,PVC_REGVAL_NETADDR,m_szNetworkAddress);
	  RegReadStrValue(m_hKey,PVC_REGVAL_DESCRIPTION,m_szDescription);
	  // need to read TCP address
	  RegReadIntValue(m_hKey,PVC_REGVAL_AUTOMANAGE,&m_bAutoManage);
	  RegReadIntValue(m_hKey,PVC_REGVAL_TCPIP,&m_nTCPIP);
	  RegReadIntValue(m_hKey,PVC_REGVAL_IPX,&m_nIPX);
	  RegReadIntValue(m_hKey,PVC_REGVAL_ETHERNET,&m_nEthernet);
#ifndef NT5
	  HKEY hsubkey;
	  AffirmThrow(RegCreateKey(m_hKey,PVC_REGKEY_TCPIP,&hsubkey));
	  CStringArray array;
	  RegReadMultiStrValue(hsubkey,PVC_REGVAL_IPADDR,array);
	  m_szIPAddress = array[0];
	  RegReadMultiStrValue(hsubkey,PVC_REGVAL_SUBNETMASK,array);
	  m_szSubnetMask = array[0];
	  RegCloseKey(hsubkey);
#endif
      fSuccess = TRUE;
   }
   catch (CAffirmException ae)
   {
   }

   return fSuccess;
}

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

   try
   {
      AffirmThrow(CPort::SetParameters());
	  RegWriteStrValue(m_hKey,PVC_REGVAL_NETADDR,m_szNetworkAddress);
	  RegWriteStrValue(m_hKey,PVC_REGVAL_DESCRIPTION,m_szDescription);
	  RegWriteStrValue(m_hKey,PVC_REGVAL_PROTOCOL,m_szProtocol);
#if defined NT5
     {
     CConfigObject* pParent = GetParent(); // Get Service
	  AffirmThrow(pParent != NULL);
     pParent = pParent->GetParent();       // Get Protocol
	  AffirmThrow(pParent != NULL);
	  pParent = pParent->GetParent();		 // Get Line
	  AffirmThrow(pParent != NULL);
	  pParent = pParent->GetParent();		 // Get Adapter
	  AffirmThrow(pParent != NULL);
	  
	  CString strIdent(pParent->GetIdentity());
	  if (!strIdent.CompareNoCase(DXB_REGVAL_ADAPTER_ENUM_PRIME_T1_PCI) ||
		  !strIdent.CompareNoCase(DXB_REGVAL_ADAPTER_ENUM_PRIME_E1_PCI) ||
		  !strIdent.CompareNoCase(DXB_REGVAL_ADAPTER_ENUM_PRIME_ISA))
	  {
		  TRACE("**** CPortPVC::Set m_dwSnid = %d ***** \n",m_dwSnid);
		  DWORD dwSnid = m_dwSnid + 0x40;
		  AffirmThrow(RegWriteDWordValue(m_hKey, DXB_REGVAL_LINE_SNID, dwSnid));
	  }
	  else
         AffirmThrow(RegWriteIntValue(m_hKey,PVC_REGVAL_SNID,m_dwSnid));
     }
#else // #if defined NT5
     RegWriteIntValue(m_hKey,PVC_REGVAL_SNID,m_dwSnid);
#endif // #if defined NT5
	  RegWriteIntValue(m_hKey,PVC_REGVAL_AUTOMANAGE,m_bAutoManage);
	  RegWriteIntValue(m_hKey,PVC_REGVAL_TCPIP,m_nTCPIP);
	  RegWriteIntValue(m_hKey,PVC_REGVAL_IPX,m_nIPX);
	  RegWriteIntValue(m_hKey,PVC_REGVAL_ETHERNET,m_nEthernet);
#ifndef NT5
	  HKEY hsubkey;
	  AffirmThrow(RegCreateKey(m_hKey,PVC_REGKEY_TCPIP,&hsubkey));
	  CStringArray array;
	  array.SetAtGrow(0,m_szIPAddress);
	  AffirmThrow(array.GetSize() == 1);
	  RegWriteMultiStrValue(hsubkey,PVC_REGVAL_IPADDR,array);
	  array[0] = m_szSubnetMask;
	  RegWriteMultiStrValue(hsubkey,PVC_REGVAL_SUBNETMASK,array);

	  // write these values to statisfy RRAS.
	  if (!RegKeyExists(hsubkey,PVC_REGVAL_DHCP))
		  RegWriteIntValue(hsubkey,PVC_REGVAL_DHCP,0);
	  if (!RegKeyExists(hsubkey,PVC_REGVAL_BROADCAST))
		  RegWriteIntValue(hsubkey,PVC_REGVAL_BROADCAST,0);
	  if (!RegKeyExists(hsubkey,PVC_REGVAL_LLINTERFACE))
	  {
		  CString strTemp;
		  RegReadStrValue(hsubkey,PVC_REGVAL_LLINTERFACE,strTemp);
	  }


	  RegCloseKey(hsubkey);
#endif
      fSuccess = TRUE;
   }
   catch (CAffirmException ae)
   {
   }

   return fSuccess;
}


BOOL CPortPVC::RemoveParameters(BOOL fRemoveKey)
{

    BOOL fSuccess = FALSE;

    try
	{
#ifdef NT5
		CString strInstance;
		RegReadStrValue(m_hKey,DXB_REGVAL_REGINSTANCE,strInstance);
		if (!strInstance.IsEmpty())
			DeleteService(strInstance);
#endif
		AffirmThrow(CPort::RemoveParameters(fRemoveKey));
		// remove ourselves from the registry. This will
		// remove all subkeys and values etc.
		AffirmThrow(RegDelKey(m_hKeyRoot,m_strRegPath));
		
		fSuccess = TRUE;
	}
	catch (CAffirmException ae)
	{
	}

	return fSuccess;
}



/*
global routine used by pages that have IP address or Network addresses in
them. This only works becuase the control ID's are known and hardcoded. If
you use this routine and don't use the correct control ID the DLL might
explode.

the user can enter only digits and some other editing and tabbing keys

for IP addresses there are 4 edit controls. When the user press '.' or when
three digits are typed the focus is automatically advanced to the next edit control

for network addresses there are 6 edit controls. When the user press '-' or when
two digits are typed the focus is automatically advanced to the next edit control
*/

BOOL FieldPreTranslateMessage(CWnd *Parent, MSG* pMsg) 
{

	static BOOL bPreviousFocusChange = FALSE;

	// TODO: Add your specialized code here and/or call the base class
	if (pMsg->message == WM_KEYDOWN && (::GetAsyncKeyState(VK_CONTROL) & 0x8000) == 0 &&
			pMsg->wParam != VK_ESCAPE && pMsg->wParam != VK_RETURN) {
		CEdit *wnd = (CEdit *)CWnd::GetFocus();
		int ID = 0;

		if (wnd != NULL)
			ID = wnd->GetDlgCtrlID();
			
		BOOL IsIP = ID >= IDC_IPAddress && ID <= IDC_SubnetMask5;
		BOOL IsNetAdd = ID >= IDC_NetworkAddress && ID <= IDC_NetworkAddress6;

		if (IsIP || IsNetAdd) {
			CEdit *newFocus = (CEdit *)Parent->GetNextDlgTabItem(wnd);
			ASSERT_VALID(newFocus);

			VERIFY(::TranslateMessage(pMsg));
			MSG charMsg;
			if (::PeekMessage(&charMsg, NULL, WM_CHAR, WM_CHAR, PM_REMOVE)) {
				CString text;
				wnd->GetWindowText(text);

				DWORD_PTR sel = wnd->GetSel();
				BOOL MoveFocus = FALSE;

				if (IsIP) {
					if (text.GetLength() - (HIWORD(sel) - LOWORD(sel)) == 2 && isdigit(int(charMsg.wParam))) {
						wnd->SendMessage(WM_CHAR, charMsg.wParam, charMsg.lParam);
						MoveFocus = TRUE;
					}

					if (charMsg.wParam == _T('.') && text.GetLength() > 0 && !bPreviousFocusChange)				
						MoveFocus = TRUE;
					}
				else if (IsNetAdd) {
					if (text.GetLength() - (HIWORD(sel) - LOWORD(sel)) == 1 && isxdigit(int(charMsg.wParam))) {
						wnd->SendMessage(WM_CHAR, charMsg.wParam, charMsg.lParam);
						MoveFocus = TRUE;
						}

					if (charMsg.wParam == _T('-') && text.GetLength() > 0 && !bPreviousFocusChange)				
						MoveFocus = TRUE;
					}
				
				if (MoveFocus) {
					bPreviousFocusChange = TRUE;
					newFocus->SetFocus();
					newFocus->SetSel(0, -1);
					return TRUE;
					}
				else
					bPreviousFocusChange = FALSE;
					switch(charMsg.wParam) {
						case VK_TAB : case VK_BACK :
							break;
						default :
							if ((IsIP && !isdigit(int(charMsg.wParam))) || (IsNetAdd && !isxdigit(int(charMsg.wParam))))
								return TRUE;
						}
				}
			}
		}
	
	return FALSE;
}

void CPortPVC::ParentUpdate(void)
{

}