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


// Line.cpp: implementation of the CLine class.
//
//////////////////////////////////////////////////////////////////////

#include "stdafx.h"
#include "Line.h"

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

//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////

IMPLEMENT_DYNAMIC(CLine, CConfigObject)

CLine::CLine(HKEY const hKeyRoot, CString const & strRegPath, CConfigObject const * const pParent) : CConfigObject(hKeyRoot, strRegPath, pParent)
{
   try
   {
      AffirmThrow(m_hKey != NULL);
      AffirmThrow(pParent != NULL);

      SetType(CConfigObject::LINE);
      SetIdentity(strRegPath);

      // NOTE:
      //    Currently the registry path passed in to us is just a string
      //    representation of our line number.  If this ever changes, the
      //    code below must change also!
      SetLineNumber(atoi(strRegPath));

      m_dwMaxFrameSize = 0;
      m_dwLineSpeed = 0;
      m_dwClocking = EXTERNAL_CLOCKING;
      m_bSnidPrefixRequired = FALSE;
      m_dwConfiguredEndPoints = 0;
      m_dwFracT1Mask = 0;
      m_dwFracT1SpeedMask = 0;

      GetConfigData();
   }
   catch (CAffirmException ae)
   {
   }
}

CLine::~CLine()
{
   try
   {
   }
   catch (CAffirmException ae)
   {
   }
}

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

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

   try
   {
      AffirmThrow(RegReadStrValue(m_hKey, DXB_REGVAL_PROTOCOL, m_strProtocol));

      AffirmThrow(RegReadDWordValue(m_hKey, DXB_REGVAL_LINE_SNID, &m_dwSnid, 0));
      if (m_dwSnid == 0) 
      {
         WORD snidprefix = 0;

         if (m_bSnidPrefixRequired)
         {
            CAdapter* pAdapter = (CAdapter*)GetParent();
            AffirmThrow(pAdapter != NULL);
            snidprefix = pAdapter->GetVAdapterNum();
         }
         m_dwSnid = MAKELONG((GetLineNumber() + 1), snidprefix);
      }
      else if ((m_dwSnid & 0xffff) >= 0x40)
      {
         m_dwSnid -= 0x40;   // added for DataFire Prime adapters
      }

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

   return fSuccess;
}

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

   try
   {
      AffirmThrow(CConfigObject::SetParameters());

      AffirmThrow(RegWriteStrValue(m_hKey, DXB_REGVAL_PROTOCOL, m_strProtocol));

      CConfigObject* pAdapter = GetParent();
      AffirmThrow(pAdapter != NULL);
      CString strIdent(pAdapter->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))
      {
         DWORD dwSnid = m_dwSnid + 0x40;
         AffirmThrow(RegWriteDWordValue(m_hKey, DXB_REGVAL_LINE_SNID, dwSnid));
      }
      else
      {
         AffirmThrow(RegWriteDWordValue(m_hKey, DXB_REGVAL_LINE_SNID, m_dwSnid));
      }

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

   return fSuccess;
}

BOOL CLine::CopyParameters(CConfigObject const * const pFrom)
{
   BOOL fSuccess = FALSE;

   try
   {
      AffirmThrow(pFrom != NULL);
      CLine * pFromLine = (CLine *) pFrom;

      if (m_strProtocol != pFromLine->m_strProtocol)
         SwitchProtocol(pFromLine->m_strProtocol);

      AffirmThrow(CConfigObject::CopyParameters(pFrom));

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

   return fSuccess;
}

//////////////////////////////////////////////////////////////////////
// Config data
//////////////////////////////////////////////////////////////////////

BOOL CLine::BuildConfigDataRegPath(CString & strRegPath)
{
   BOOL fSuccess = FALSE;

   try
   {
      CConfigObject * pParent = GetParent();
      AffirmThrow(pParent != NULL);
      
      AffirmThrow(pParent->BuildConfigDataRegPath(strRegPath));
      // NOTE: Lines do not modify the config data reg path!
      // strRegPath += TEXT("\\") + GetIdentity();

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

   return fSuccess;
}

BOOL CLine::GetConfigData(void)
{
   BOOL fSuccess = FALSE;

   try
   {
      CString strConfigDataRegPath;
      AffirmThrow(BuildConfigDataRegPath(strConfigDataRegPath));

      HKEY hConfigData = NULL;
      AffirmThrow(RegOpenKey(HKEY_LOCAL_MACHINE, strConfigDataRegPath, &hConfigData));
      AffirmThrow(hConfigData != NULL);

      try
      {
         AffirmThrow(RegReadMultiStrValue(hConfigData, DXB_REGVAL_PROTOCOLS_ALLOWED, m_astrProtocolsAllowed));
         AffirmThrow(RegReadBoolValue(hConfigData, DXB_REGVAL_SNID_PREFIX_REQUIRED, &m_bSnidPrefixRequired, FALSE));
      }
      catch (CAffirmException ae)
      {
      }

      RegCloseKey(hConfigData);

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

   return fSuccess;
}

BOOL CLine::IsValidProtocol(CString const & strProtocol)
{
   BOOL fValid = FALSE;

   try
   {
      for (int i = 0; i < m_astrProtocolsAllowed.GetSize(); i++)
      {
         if (strProtocol == m_astrProtocolsAllowed[i])
         {
            fValid = TRUE;
            break;
         }
      }
   }
   catch (CAffirmException ae)
   {
   }

   return fValid;
}

BOOL CLine::SwitchProtocol(CString const & strNewProtocol)
{
   BOOL fSuccess = FALSE;

   try
   {
      AffirmThrow(IsValidProtocol(strNewProtocol));

      if (m_strProtocol != strNewProtocol)
      {
         BOOL fFoundOldProtocolInTheTrash = FALSE;
         CConfigObject * pOldProtocolFromTrash = NULL;

         // 1st see if there's one in the trash
         for (int i = 0; i < m_apTrash.GetSize(); i++)
         {
            AffirmThrow(m_apTrash[i] != NULL);

            if (m_apTrash[i]->GetIdentity() == strNewProtocol)
            {
               // Found one, so just do a switch-a-roo
               fFoundOldProtocolInTheTrash = TRUE;
               pOldProtocolFromTrash = m_apTrash[i];
               m_apTrash.RemoveAt(i);
               break;
            }
         }

         // Dump the current protocol in the trash
         // but remember what it is in case we have to
         // recover it
         INT_PTR iTrashedProtocol = m_apTrash.Add(m_apChildren[0]);

         // notify child that it has been placed in the trash
         m_apChildren[0]->ObjectToTrash();

         // also stash the protocol name
         CString strTrashedProtocol = m_strProtocol;

         // Now set the new one
         m_strProtocol = strNewProtocol;

         if (fFoundOldProtocolInTheTrash)
         {
            AffirmThrow(pOldProtocolFromTrash != NULL);
            m_apChildren[0] = pOldProtocolFromTrash;

            // inform this protocol that we have gotten it back from the trash
            m_apChildren[0]->ObjectFromTrash();
         }
         else
         {
            m_apChildren.RemoveAll();

            if (!AddChild())
            {
               // recover from the trash, the protocol that we originally had
               m_strProtocol = strTrashedProtocol;
               m_apChildren.RemoveAll();
               m_apChildren.Add(m_apTrash[iTrashedProtocol]);
               m_apChildren[0]->ObjectFromTrash();
               m_apTrash.RemoveAt(iTrashedProtocol);
            }
            else
            {
               // make sure that newly configured protocol
               // is the same name as what we are using
               // this is kludgy and needs some more thought
               CString strIdentity(m_apChildren[0]->GetIdentity());
               if (m_strProtocol != strIdentity)
               {
                  m_strProtocol = strIdentity;
                  TRACE("***** DIFFERENT PROTOCOL THAN ASKED FOR %s *****\n", strIdentity);
               }
            }
         }

         AffirmThrow(m_apChildren[0] != NULL);
      }

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

   return fSuccess;
}
