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


// LineCSU.cpp: implementation of the CLineCSU class.
//
//////////////////////////////////////////////////////////////////////

#include "stdafx.h"
#include "LineCSU.h"
#include "ObjectFactory.h"
#include "Helpers.h"

#include "Resource.h"

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

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

IMPLEMENT_DYNAMIC(CLineCSU, CLine)

CLineCSU::CLineCSU(HKEY const hKeyRoot, CString const & strRegPath, CConfigObject const * const pParent) : CLine(hKeyRoot, strRegPath, pParent)
{
   try
   {
      // Get parameters
      AffirmThrow(GetParameters());

      // Set what we can do
      SetAbility(CConfigObject::DOPROPERTIES);

      // Get our static config data
      AffirmThrow(GetConfigData());

      // Check for the special case of CSU and FR/PPP
      if (VerifyConfigFracT1())
      {
         UpdateFracT1Params();
      }

      // Init wiz mode stuff
      m_pwsSheet = NULL;

      for (int i = 0; i < ElementCount(m_apWizPages); i++)
      {
         m_apWizPages[i] = NULL;
      }

      struct
      {
         int nValueMapType;
         SValueMapCSU * pMap;
      }
      aValueMaps[] =
      {
         { SValueMapCSU::SPAN,                                          &m_aValueMaps[WP_SPAN],     },
         { SValueMapCSU::LBO,                                           &m_aValueMaps[WP_LBO],      },
         { SValueMapCSU::EGL,                                           &m_aValueMaps[WP_EGL],      },
         { SValueMapCSU::SHLEN,                                         &m_aValueMaps[WP_SHLEN],    },
         { m_fE1 ? SValueMapCSU::FRAMING_E1 : SValueMapCSU::FRAMING,    &m_aValueMaps[WP_FRAMING],  },
         { m_fE1 ? SValueMapCSU::ENCODING_E1 : SValueMapCSU::ENCODING,  &m_aValueMaps[WP_ENCODING], },
      };

      AffirmThrow(ElementCount(aValueMaps) == ElementCount(m_aValueMaps));

      for (i = 0; i < ElementCount(aValueMaps); i++)
      {
         SValueMapCSU * pMap = aValueMaps[i].pMap;
         AffirmThrow(pMap->Init(aValueMaps[i].nValueMapType));
      }

      // Init prop page stuff
      m_pPropCSU = NULL;
      m_pPropAdvCSU = NULL;
      m_pPropPageFracT1 = NULL;

      // Hard coded defaults
      if (m_fE1)
      {
         m_CSUConfig.Data.coding = LINE_CODE_HDB3;

         if ((m_CSUConfig.Data.framing == 0) ||
             ((m_CSUConfig.Data.framing != FRAME_CEPT_CRC4) &&
              (m_CSUConfig.Data.framing != FRAME_CEPT_WO_CRC4)))
            m_CSUConfig.Data.framing = FRAME_CEPT_CRC4;
      }
      else
      {
         if ((m_CSUConfig.Data.coding == 0) ||
             ((m_CSUConfig.Data.coding != LINE_CODE_B8ZS) &&
              (m_CSUConfig.Data.coding != LINE_CODE_AMI)))
            m_CSUConfig.Data.coding = LINE_CODE_B8ZS;

         if ((m_CSUConfig.Data.framing == 0) ||
             ((m_CSUConfig.Data.framing != FRAME_ESF) &&
              (m_CSUConfig.Data.framing != FRAME_D4)))
            m_CSUConfig.Data.framing = FRAME_ESF;
      }

      if ((m_CSUConfig.Data.if_type == 0) ||
          ((m_CSUConfig.Data.if_type != SHORT_HAUL) &&
           (m_CSUConfig.Data.if_type != LONG_HAUL)))
         m_CSUConfig.Data.if_type = SHORT_HAUL;

      if ((m_CSUConfig.Data.long_haul_lbo == 0) ||
          ((m_CSUConfig.Data.long_haul_lbo != LBO_00_0_DB) &&
           (m_CSUConfig.Data.long_haul_lbo != LBO_07_5_DB) &&
           (m_CSUConfig.Data.long_haul_lbo != LBO_15_0_DB) &&
           (m_CSUConfig.Data.long_haul_lbo != LBO_22_5_DB)))
         m_CSUConfig.Data.long_haul_lbo = LBO_00_0_DB;

      if ((m_CSUConfig.Data.eq_gain_limit == 0) ||
          ((m_CSUConfig.Data.eq_gain_limit != EGL_LOW) &&
           (m_CSUConfig.Data.eq_gain_limit != EGL_HIGH)))
         m_CSUConfig.Data.eq_gain_limit = EGL_LOW;

      if ((m_CSUConfig.Data.short_haul_len == 0) ||
          ((m_CSUConfig.Data.short_haul_len != SH_0_133) &&
           (m_CSUConfig.Data.short_haul_len != SH_133_266) &&
           (m_CSUConfig.Data.short_haul_len != SH_266_399) &&
           (m_CSUConfig.Data.short_haul_len != SH_399_533) &&
           (m_CSUConfig.Data.short_haul_len != SH_533_655)))
         m_CSUConfig.Data.short_haul_len = SH_0_133;


      if ((m_CSUConfig.Data.clocking == 0) ||
          ((m_CSUConfig.Data.clocking != TIMING_LOOP) &&
           (m_CSUConfig.Data.clocking != TIMING_LOCAL)))
         m_CSUConfig.Data.clocking = TIMING_LOOP;

      SetLineClocking((m_CSUConfig.Data.clocking == TIMING_LOCAL) ? INTERNAL_CLOCKING : EXTERNAL_CLOCKING);

      if ((m_CSUConfig.Data.jitter_atten == 0) ||
          ((m_CSUConfig.Data.jitter_atten != JITTER_AUTO) &&
           (m_CSUConfig.Data.jitter_atten != JITTER_RX) &&
           (m_CSUConfig.Data.jitter_atten != JITTER_TX) &&
           (m_CSUConfig.Data.jitter_atten != JITTER_NONE)))
         m_CSUConfig.Data.jitter_atten = JITTER_AUTO;
   }
   catch (CAffirmException ae)
   {
   }
}

CLineCSU::~CLineCSU()
{
   try
   {
      for (int i = 0; i < ElementCount(m_apWizPages); i++)
      {
         if (m_apWizPages[i] != NULL) delete m_apWizPages[i];
      }

      if (m_pPropCSU != NULL) delete m_pPropCSU;
      if (m_pPropAdvCSU != NULL) delete m_pPropAdvCSU;
      if (m_pPropPageFracT1 != NULL) delete m_pPropPageFracT1;

   }
   catch (CAffirmException ae)
   {
   }
}

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

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

   try
   {
      AffirmThrow(CLine::GetParameters());
      AffirmThrow(m_CSUConfig.Get(m_hKey));
      AffirmThrow(m_FracT1Config.Get(m_hKey));

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

   return fSuccess;
}

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

   try
   {
      AffirmThrow(CLine::SetParameters());
      AffirmThrow(m_CSUConfig.Set(m_hKey));

      if (VerifyConfigFracT1())
         AffirmThrow(m_FracT1Config.Set(m_hKey));

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

   return fSuccess;
}

BOOL CLineCSU::RemoveParameters(BOOL fRemoveKey /* = FALSE */)
{
   BOOL fSuccess = FALSE;

   try
   {
      AffirmThrow(m_CSUConfig.Remove(m_hKey));
      if (VerifyConfigFracT1())
         AffirmThrow(m_FracT1Config.Remove(m_hKey));
      AffirmThrow(CLine::RemoveParameters(fRemoveKey));

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

   return fSuccess;
}

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

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

      m_CSUConfig = pFromLine->m_CSUConfig;

      m_FracT1Config = pFromLine->m_FracT1Config;

      AffirmThrow(CLine::CopyParameters(pFrom));

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

   return fSuccess;
}

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

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

   try
   {
      AffirmThrow(CLine::GetConfigData());

      CString strConfigDataRegPath;
      AffirmThrow(BuildConfigDataRegPath(strConfigDataRegPath));

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

      try
      {
         DWORD dwLineSpeed = 0;
         AffirmThrow(RegReadDWordValue(hConfigData, DXB_REGVAL_ISDN_LINESPEED, &dwLineSpeed));
         SetLineSpeed(dwLineSpeed);
         AffirmThrow(RegReadDWordValue(hConfigData, DXB_REGVAL_CSU_FRACT1_CAPABLE, &m_fFracT1Capable, DXB_REGVAL_CSU_FRACT1_CAPABLE_DEFAULT));
         TRACE("CLineCSU::GetConfigData: " DXB_REGVAL_CSU_FRACT1_CAPABLE " 0x%x\n", m_fFracT1Capable);
      }
      catch (CAffirmException ae)
      {
      }

      RegCloseKey(hConfigData);

      m_fE1 = FALSE;
      for (int i = 0; i < m_astrProtocolsAllowed.GetSize(); i++)
      {
         if (m_astrProtocolsAllowed[i] == DXB_REGVAL_PROTOCOL_ENUM_E1)
         {
            m_fE1 = TRUE;
            break;
         }
      }

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

   return fSuccess;
}

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

BOOL CLineCSU::AddWizardPages(CConfigWizSheet * const pSheet)
{
   BOOL fSuccess = FALSE;

   try
   {
      AffirmThrow(pSheet != NULL);

#if defined(_DEBUG)
      if ((m_pwsSheet != NULL) && (m_pwsSheet != pSheet))
         TRACE("AddWizardPages() called for different sheet!\n");
#endif

		m_pwsSheet = pSheet;

      struct
      {
         UINT nTitleId;
         UINT nInstructionId;

         int nState;

         UINT nHelpID;

         CConfigWizPage ** ppWizPage;

         SValueMapCSU * pMap;

         DWORD dwDefaultValue;
      }
      aWizPages[] =
      {
         { IDS_Title_Span,       IDS_Instruction_Span,         WP_SPAN,       IDH_WizPageSpan,        &m_apWizPages[WP_SPAN],          &m_aValueMaps[WP_SPAN],       m_CSUConfig.Data.if_type         },
         { IDS_Title_LBO,        IDS_Instruction_LBO,          WP_LBO,        IDH_WizPageLBO,         &m_apWizPages[WP_LBO],           &m_aValueMaps[WP_LBO],        m_CSUConfig.Data.long_haul_lbo   },
         { IDS_Title_EGL,        IDS_Instruction_EGL,          WP_EGL,        IDH_WizPageEGL,         &m_apWizPages[WP_EGL],           &m_aValueMaps[WP_EGL],        m_CSUConfig.Data.eq_gain_limit   },
         { IDS_Title_SHLen,      IDS_Instruction_SHLen,        WP_SHLEN,      IDH_WizPageSHLen,       &m_apWizPages[WP_SHLEN],         &m_aValueMaps[WP_SHLEN],      m_CSUConfig.Data.short_haul_len  },
         { IDS_Title_Framing,    IDS_Instruction_Framing,      WP_FRAMING,    IDH_WizPageFraming,     &m_apWizPages[WP_FRAMING],       &m_aValueMaps[WP_FRAMING],    m_CSUConfig.Data.framing         },
         { IDS_Title_Encoding,   IDS_Instruction_Encoding,     WP_ENCODING,   IDH_WizPageEncoding,    &m_apWizPages[WP_ENCODING],      &m_aValueMaps[WP_ENCODING],   m_CSUConfig.Data.coding          },
      };

      AffirmThrow(ElementCount(aWizPages) == ElementCount(m_apWizPages));

      CString strTitle;
      CString strInstruction;

      for (int i = 0; i < ElementCount(aWizPages); i++)
      {
         if (*(aWizPages[i].ppWizPage) == NULL)
         {
            AffirmThrow(strTitle.LoadString(aWizPages[i].nTitleId));
            AffirmThrow(strInstruction.LoadString(aWizPages[i].nInstructionId));

            strTitle = GetDisplayName() + TEXT(" - ") + strTitle;

            SValueMapCSU * pMap = aWizPages[i].pMap;
            AffirmThrow(pMap != NULL);

            CConfigWizPage ** ppWizPage = aWizPages[i].ppWizPage;
            AffirmThrow(ppWizPage != NULL);

            *ppWizPage = new CWizPageRadioButtons(this, aWizPages[i].nState, strTitle, strInstruction);
            AffirmThrow(*ppWizPage != NULL);
            AffirmThrow((*ppWizPage)->SetValues(pMap->astrDisplayNames, pMap->ToIndex(aWizPages[i].dwDefaultValue, 0)));

            (*ppWizPage)->SetHelpID(aWizPages[i].nHelpID);
         }
      }

      CConfigWizPage * pStartingPage = m_fE1 ? m_apWizPages[WP_FRAMING] : m_apWizPages[WP_SPAN];
      AffirmThrow(pStartingPage != NULL);
      AffirmThrow(m_pwsSheet->InsertPage(pStartingPage));

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

   return fSuccess;
}

BOOL CLineCSU::RemoveWizardPages(CConfigWizSheet * const pSheet)
{
   BOOL fSuccess = FALSE;

   try
   {
      AffirmThrow(pSheet != NULL);

      if (m_pwsSheet != NULL)
      {
         AffirmThrow(m_pwsSheet == pSheet);

         for (int i = 0; i < ElementCount(m_apWizPages); i++)
         {
            if (m_apWizPages[i] != NULL) m_pwsSheet->RemovePage(m_apWizPages[i]);
         }

         if (VerifyConfigFracT1()) m_pwsSheet->RemovePage(m_pPropPageFracT1);
      }

      AffirmThrow(CLine::RemoveWizardPages(pSheet));

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

   return fSuccess;
}

BOOL CLineCSU::HandleWizSpan(void)
{
   BOOL fSuccess = FALSE;

   try
   {
      AffirmThrow(!m_fE1);
      AffirmThrow(m_pwsSheet != NULL);

      int iChoice = m_apWizPages[WP_SPAN]->GetChoice();
      m_CSUConfig.Data.if_type = m_aValueMaps[WP_SPAN].FromIndex(iChoice);

      AffirmThrow(m_pwsSheet->InsertPage((m_CSUConfig.Data.if_type == SHORT_HAUL) ?
                                         m_apWizPages[WP_SHLEN] : m_apWizPages[WP_LBO]));

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

   return fSuccess;
}

BOOL CLineCSU::HandleWizLBO(void)
{
   BOOL fSuccess = FALSE;

   try
   {
      AffirmThrow(!m_fE1);
      AffirmThrow(m_pwsSheet != NULL);

      int iChoice = m_apWizPages[WP_LBO]->GetChoice();
      m_CSUConfig.Data.long_haul_lbo = m_aValueMaps[WP_LBO].FromIndex(iChoice);

      AffirmThrow(m_pwsSheet->InsertPage(m_apWizPages[WP_EGL]));

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

   return fSuccess;
}

BOOL CLineCSU::HandleWizEGL(void)
{
   BOOL fSuccess = FALSE;

   try
   {
      AffirmThrow(!m_fE1);
      AffirmThrow(m_pwsSheet != NULL);

      int iChoice = m_apWizPages[WP_EGL]->GetChoice();
      m_CSUConfig.Data.eq_gain_limit = m_aValueMaps[WP_EGL].FromIndex(iChoice);

      AffirmThrow(m_pwsSheet->InsertPage(m_apWizPages[WP_FRAMING]));

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

   return fSuccess;
}

BOOL CLineCSU::HandleWizSHLen(void)
{
   BOOL fSuccess = FALSE;

   try
   {
      AffirmThrow(!m_fE1);
      AffirmThrow(m_pwsSheet != NULL);

      int iChoice = m_apWizPages[WP_SHLEN]->GetChoice();
      m_CSUConfig.Data.short_haul_len = m_aValueMaps[WP_SHLEN].FromIndex(iChoice);

      AffirmThrow(m_pwsSheet->InsertPage(m_apWizPages[WP_FRAMING]));

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

   return fSuccess;
}

BOOL CLineCSU::HandleWizFraming(void)
{
   BOOL fSuccess = FALSE;

   try
   {
      AffirmThrow(m_pwsSheet != NULL);

      int iChoice = m_apWizPages[WP_FRAMING]->GetChoice();
      m_CSUConfig.Data.framing = m_aValueMaps[WP_FRAMING].FromIndex(iChoice);

      if (m_fE1)
      {
         // Last page, let our protocol child do its thing
	      AffirmThrow(m_apChildren[0] != NULL);
	      AffirmThrow(m_apChildren[0]->AddWizardPages(m_pwsSheet));
      }
      else
      {
         AffirmThrow(m_pwsSheet->InsertPage(m_apWizPages[WP_ENCODING]));
      }

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

   return fSuccess;
}

BOOL CLineCSU::HandleWizEncoding(void)
{
   BOOL fSuccess = FALSE;
   CString strTitle;

   try
   {
      AffirmThrow(!m_fE1);
      AffirmThrow(m_pwsSheet != NULL);

      int iChoice = m_apWizPages[WP_ENCODING]->GetChoice();
      m_CSUConfig.Data.coding = m_aValueMaps[WP_ENCODING].FromIndex(iChoice);

      // If we're doing FRAC T1, add that page, else do the children
      if (VerifyConfigFracT1())
      {
         TRACE("CLineCSU::HandleWizEncoding:Adding m_pPropPageFracT1\n");
         if (m_pPropPageFracT1 != NULL) delete m_pPropPageFracT1;
         AffirmThrow(strTitle.LoadString(IDS_Title_FracT1));
         strTitle = GetDisplayName() + TEXT(" - ") + strTitle;
         m_pPropPageFracT1 = new CPropPageFracT1(this, WP_FRAC_T1, strTitle, strTitle);
         m_pPropPageFracT1->SetBitMaskValues(m_FracT1Config.TimeSlotMask, m_FracT1Config.SpeedMask);
         m_pwsSheet->InsertPage(m_pPropPageFracT1);
      }
      else
      {
         // Last page, let our protocol child do its thing
         AffirmThrow(m_apChildren[0] != NULL);
	      AffirmThrow(m_apChildren[0]->AddWizardPages(m_pwsSheet));
      }

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

   return fSuccess;
}

BOOL CLineCSU::HandleWizFracT1(void)
{
   BOOL fSuccess = FALSE;

   try
   {
      AffirmThrow(m_pPropPageFracT1 != NULL);
      AffirmThrow(m_pwsSheet != NULL);
      AffirmThrow(VerifyConfigFracT1());
      m_pPropPageFracT1->GetBitMaskValues(&m_FracT1Config.TimeSlotMask, &m_FracT1Config.SpeedMask);
      UpdateFracT1Params();

      // Last page, let our protocol child do its thing
	   AffirmThrow(m_apChildren[0] != NULL);
	   AffirmThrow(m_apChildren[0]->AddWizardPages(m_pwsSheet));

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

   return fSuccess;
}

BOOL CLineCSU::NextWizardPage(int const nState)
{
   BOOL fSuccess = FALSE;

   try
   {
      switch (nState)
      {
         case WP_SPAN:        AffirmThrow(HandleWizSpan());       break;
         case WP_LBO:         AffirmThrow(HandleWizLBO());        break;
         case WP_EGL:         AffirmThrow(HandleWizEGL());        break;
         case WP_SHLEN:       AffirmThrow(HandleWizSHLen());      break;
         case WP_FRAMING:     AffirmThrow(HandleWizFraming());    break;
         case WP_ENCODING:    AffirmThrow(HandleWizEncoding());   break;
         case WP_FRAC_T1:     AffirmThrow(HandleWizFracT1());     break;
         default: AffirmThrow(FALSE); break;
      }

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

   return fSuccess;
}

CString CLineCSU::GetInformationText(void)
{
   CString strInfo = TEXT("");

   try
   {
      CString str;

      if (!m_fE1)
      {
         str.Format(IDS_Information_SpanFormat,
                    m_aValueMaps[WP_SPAN].DisplayNameFromValue(m_CSUConfig.Data.if_type));
         strInfo += StripUnderscores(str);

         if (m_CSUConfig.Data.if_type == SHORT_HAUL)
         {
            str.Format(IDS_Information_SHLenFormat,
                       m_aValueMaps[WP_SHLEN].DisplayNameFromValue(m_CSUConfig.Data.short_haul_len));
            strInfo += StripUnderscores(str);
         }
         else
         {
            str.Format(IDS_Information_LBOFormat,
                       m_aValueMaps[WP_LBO].DisplayNameFromValue(m_CSUConfig.Data.long_haul_lbo));
            strInfo += StripUnderscores(str);

            str.Format(IDS_Information_EGLFormat,
                       m_aValueMaps[WP_EGL].DisplayNameFromValue(m_CSUConfig.Data.eq_gain_limit));
            strInfo += StripUnderscores(str);
         }
      }

      str.Format(IDS_Information_FramingFormat,
                 m_aValueMaps[WP_FRAMING].DisplayNameFromValue(m_CSUConfig.Data.framing));
      strInfo += StripUnderscores(str);

      str.Format(IDS_Information_EncodingFormat,
                 m_aValueMaps[WP_ENCODING].DisplayNameFromValue(m_CSUConfig.Data.coding));
      strInfo += StripUnderscores(str);
   }
   catch (CAffirmException ae)
   {
   }

   return strInfo;
}

BOOL CLineCSU::DoProperties(void)
{
   BOOL fThingsHaveChanged = FALSE;

   try
   {
      CPropertySheet PropSheet(GetDisplayName());

      AffirmThrow(AddPropertyPages(&PropSheet));

      PropSheet.m_psh.dwFlags |= PSH_NOAPPLYNOW;
      if (PropSheet.DoModal() == IDOK)
      {
         AffirmThrow(GetPropertiesFromPages());
         fThingsHaveChanged = TRUE;
      }
   }
   catch (CAffirmException ae)
   {
   }

   return fThingsHaveChanged;
}

BOOL CLineCSU::AddPropertyPages(CPropertySheet * const pSheet)
{
   BOOL fSuccess = FALSE;

   try
   {
      AffirmThrow(pSheet != NULL);

      // Setup CSU property page
      if (m_pPropCSU != NULL) delete m_pPropCSU;
      m_pPropCSU = new CPropCSU();

      SValueMapCSU * pmapFraming = &m_aValueMaps[WP_FRAMING];
      SValueMapCSU * pmapEncoding = &m_aValueMaps[WP_ENCODING];
      CStringArray astrDisplayNames;

      astrDisplayNames.RemoveAll();
      for (int i = 0; i < pmapFraming->astrDisplayNames.GetSize(); i++)
         astrDisplayNames.Add(StripUnderscores(pmapFraming->astrDisplayNames[i]));
      m_pPropCSU->SetFramingValues(astrDisplayNames, pmapFraming->ToIndex(m_CSUConfig.Data.framing));

      astrDisplayNames.RemoveAll();
      for (i = 0; i < pmapEncoding->astrDisplayNames.GetSize(); i++)
         astrDisplayNames.Add(StripUnderscores(pmapEncoding->astrDisplayNames[i]));

      m_pPropCSU->SetEncodingValues(astrDisplayNames, pmapEncoding->ToIndex(m_CSUConfig.Data.coding));

		m_pPropCSU->ShowSpan(!m_fE1);
      m_pPropCSU->SetSpan(m_CSUConfig.Data.if_type);
      m_pPropCSU->SetLBO(m_CSUConfig.Data.long_haul_lbo);
      m_pPropCSU->SetEGL(m_CSUConfig.Data.eq_gain_limit);
      m_pPropCSU->SetSHLen(m_CSUConfig.Data.short_haul_len);

      // Setup the fractional T1 Prop Page
      // Verify whether or not we are the special case of CSU and FR/PPP
      if (VerifyConfigFracT1())
      {
         if (m_pPropPageFracT1 != NULL) delete m_pPropPageFracT1;
         m_pPropPageFracT1 = new CPropPageFracT1();
         m_pPropPageFracT1->SetBitMaskValues(m_FracT1Config.TimeSlotMask, m_FracT1Config.SpeedMask);
      }

      // Setup advanced CSU property page
      if (m_pPropAdvCSU != NULL) delete m_pPropAdvCSU;
      m_pPropAdvCSU = new CPropAdvCSU();

      m_pPropAdvCSU->SetJitter(m_CSUConfig.Data.jitter_atten);
      m_pPropAdvCSU->SetClocking(m_CSUConfig.Data.clocking);

      pSheet->AddPage(m_pPropCSU);

      // VerifyConfigFracT1() was called above, use the member flag here...
      if (m_fConfigFracT1)
         pSheet->AddPage(m_pPropPageFracT1);

      pSheet->AddPage(m_pPropAdvCSU);

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

   return fSuccess;
}

BOOL CLineCSU::GetPropertiesFromPages(void)
{
   BOOL fSuccess = FALSE;

   try
   {
      AffirmThrow(m_pPropCSU != NULL);
      AffirmThrow(m_pPropAdvCSU != NULL);

      m_CSUConfig.Data.framing = m_aValueMaps[WP_FRAMING].FromIndex(m_pPropCSU->GetFramingIndex());
      m_CSUConfig.Data.coding = m_aValueMaps[WP_ENCODING].FromIndex(m_pPropCSU->GetEncodingIndex());
      m_CSUConfig.Data.if_type = m_pPropCSU->GetSpan();
      m_CSUConfig.Data.long_haul_lbo = m_pPropCSU->GetLBO();
      m_CSUConfig.Data.eq_gain_limit = m_pPropCSU->GetEGL();
      m_CSUConfig.Data.short_haul_len = m_pPropCSU->GetSHLen();
      m_CSUConfig.Data.jitter_atten = m_pPropAdvCSU->GetJitter();
      m_CSUConfig.Data.clocking = m_pPropAdvCSU->GetClocking();

      if (VerifyConfigFracT1())
      {
         AffirmThrow(m_pPropPageFracT1 != NULL);
         m_pPropPageFracT1->GetBitMaskValues(&m_FracT1Config.TimeSlotMask, &m_FracT1Config.SpeedMask);
         UpdateFracT1Params();
      }

      SetLineClocking((m_CSUConfig.Data.clocking == TIMING_LOCAL) ? INTERNAL_CLOCKING : EXTERNAL_CLOCKING);

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

   return fSuccess;
}

DWORD CLineCSU::FigureEndPoints(DWORD const Mask)
{
   DWORD Bit, BitCount = 0;

   for (Bit=1; Bit != 0; Bit <<=1)
   {
      if (0 != (Mask & Bit))
         BitCount++;
   }

   return BitCount;
}

BOOL CLineCSU::VerifyConfigFracT1(void)
{
   // Once the config changes, we need to reverify this....
   // Check for the special case of CSU and PPP/FR
   // Other protocols should be added here if/when they are supported
   m_fConfigFracT1 = m_fFracT1Capable &&
                     (  (m_strProtocol == DXB_REGVAL_PROTOCOL_ENUM_FRAMERELAY) ||
                        (m_strProtocol == DXB_REGVAL_PROTOCOL_ENUM_PPP) );

   return m_fConfigFracT1;
}

DWORD CLineCSU::FigureAggregateLineSpeed(DWORD const SlotMask, DWORD const SpeedMask)
{
   DWORD Bit, Speed = 0;

   for (Bit=1; Bit != 0; Bit <<=1)
   {
      if (0 != (SlotMask & Bit))
      {
         // Timeslot in use, check its speed
         Speed += ( 0 == (SpeedMask & Bit) ? 64000 : 56000 );
      }
   }

   return Speed;
}

void CLineCSU::UpdateFracT1Params(void)
{
   SetConfiguredEndPoints(FigureEndPoints(m_FracT1Config.TimeSlotMask));
   SetFracT1Mask(m_FracT1Config.TimeSlotMask);
   SetFracT1SpeedMask(m_FracT1Config.SpeedMask);
   SetLineSpeed(FigureAggregateLineSpeed(m_FracT1Config.TimeSlotMask, m_FracT1Config.SpeedMask));

   // Make the changes known throughout
   for(int i=0;i<GetChildCount();i++)
		m_apChildren[i]->ParentUpdate();
}
