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


// ProtocolBRI.cpp: implementation of the CProtocolBRI class.
//
//////////////////////////////////////////////////////////////////////

#include "stdafx.h"
#include "ProtocolBRI.h"
#include "ObjectFactory.h"
#include "PageBRISwitch.h"
#include "PropAdvancedBRI.h"
#include "PropMSN.h"

#include "DigiIsdn.h"
#include "PortBChannel.h"

#include "Resource.h"

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

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

IMPLEMENT_DYNAMIC(CProtocolBRI, CProtocol)

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

      // Solve our identity crisis
      SetIdentity(DXB_REGVAL_PROTOCOL_ENUM_BRI);

      // Set our display name
      CString strDisplayName;
      AffirmThrow(strDisplayName.LoadString(IDS_DisplayName_BRI));
      SetDisplayName(strDisplayName);

      if ((m_BRIConfig.Data.switch_type == 0) ||
          ((m_BRIConfig.Data.switch_type != BRI_NONE) &&
           (m_BRIConfig.Data.switch_type != BRI_NI1) &&
           (m_BRIConfig.Data.switch_type != BRI_5ESS) &&
           (m_BRIConfig.Data.switch_type != BRI_DMS100) &&
           (m_BRIConfig.Data.switch_type != BRI_ETSI) &&
           (m_BRIConfig.Data.switch_type != BRI_JAPAN)))
         m_BRIConfig.Data.switch_type = BRI_5ESS;

      if ((m_BRIConfig.Data.auto_spid == 0) ||
          ((m_BRIConfig.Data.auto_spid != BRI_AUTOSPID_OFF) &&
           (m_BRIConfig.Data.auto_spid != BRI_AUTOSPID_ON)))
         m_BRIConfig.Data.auto_spid = BRI_AUTOSPID_OFF;

      if (m_DChanExtConfig.Data.mode == 0) m_DChanExtConfig.Data.mode = DCHAN_NORMAL;
      if (m_DChanExtConfig.Data.address_type == 0) m_DChanExtConfig.Data.address_type = DCHAN_ADDRESS_TYPE_UNKNOWN;
      if (m_DChanExtConfig.Data.numbering_plan == 0) m_DChanExtConfig.Data.numbering_plan = DCHAN_NUMBERING_PLAN_UNKNOWN;
      if (m_DChanExtConfig.Data.subaddress_type == 0) m_DChanExtConfig.Data.subaddress_type = DCHAN_SUBADDRESS_TYPE_NSAP;

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

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

      m_astrServices.Copy(m_astrServicesAllowed);

      // Give birth to our children
      for (int i = 0; i < m_astrServices.GetSize(); i++)
      {
         AffirmThrow(AddChild(m_astrServices[i]));
      }

#ifndef NT5
      AffirmThrow(UpdateBChannels(TRUE));
#endif

      // Init config mode stuff
      m_pwsSheet = NULL;
#ifndef NT5
      m_WizPageSwitch.Construct(CPageBRISwitch::WIZARD, this, WP_SWITCH);
      CString strTitle;
      AffirmThrow(strTitle.LoadString(IDS_Title_SwitchType));
      strTitle = GetParent()->GetDisplayName() + TEXT(" - ") + strTitle;
      m_WizPageSwitch.SetTitle(strTitle);

      m_WizPageMSN.SetOwner(this);
      m_WizPageMSN.SetState(WP_MSN);
      AffirmThrow(strTitle.LoadString(IDS_Title_MSN));
      strTitle = GetParent()->GetDisplayName() + TEXT(" - ") + strTitle;
      m_WizPageMSN.SetTitle(strTitle);
#endif
   }
   catch (CAffirmException ae)
   {
   }
}

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

BOOL CProtocolBRI::AddChild(void)
{
   BOOL fSuccess = FALSE;

   try
   {
      // Currently unimplemented
      AffirmThrow(FALSE);
      fSuccess = TRUE;
   }
   catch (CAffirmException ae)
   {
   }

   return fSuccess;
}

BOOL CProtocolBRI::AddChild(CString const & strChild)
{
   BOOL fSuccess = FALSE;

   try
   {
      INT_PTR iNewChild = m_apChildren.Add(NULL);

      // This registry path thingie needs a little explanation!
      //    Here's the layout so far:
      //       ...\DigiDxb?\Parameters\N           (where ? = the adapter instance, and
      //                                                  N = 0, 1, ... # of lines)
      //    The line service parameters reside at:
      //       ...\DigiDxb?\Parameters\XXXX\N      (where XXXX = the service name)
      //    So, pass in the hKey we were told to start at, and the XXXX\N reg path.

      CString strServiceRegPath = strChild + TEXT("\\") + m_strRegPath;
      AffirmThrow(NewConfigObject(&m_apChildren[iNewChild], CConfigObject::SERVICE, strChild, m_hKeyRoot, strServiceRegPath, this));
      AffirmThrow(m_apChildren[iNewChild] != NULL);

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

   return fSuccess;
}

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

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

   try
   {
      AffirmThrow(CProtocol::GetParameters());
      AffirmThrow(m_BRIConfig.Get(m_hKey));
      AffirmThrow(m_DChanExtConfig.Get(m_hKey));
      fSuccess = TRUE;
   }
   catch (CAffirmException ae)
   {
   }

   return fSuccess;
}

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

   try
   {
      AffirmThrow(CProtocol::SetParameters());
#ifndef NT5
      if (m_BRIConfig.Data.switch_type != BRI_ETSI)
      {
         memset((void *)m_BRIConfig.Data.directory, 0, sizeof(m_BRIConfig.Data.directory));

         SEnumDescendentsCriteria EnumCriteria(DXB_REGVAL_PORT_TYPE_BCHANNEL);
         CPortBChannel * pBChannel = NULL;
         while ((pBChannel = (CPortBChannel *)EnumDescendents(EnumCriteria)) != NULL)
         {
            int iDir = pBChannel->GetPortNumber();
            AffirmThrow(iDir >= 0);
            AffirmThrow(iDir < ElementCount(m_BRIConfig.Data.directory));

            CString strNumber;
            CString strSpid;
            CString strSubAddress;
            pBChannel->GetProperties(strNumber, strSpid, strSubAddress);

            strcpy((char *)m_BRIConfig.Data.directory[iDir].number, strNumber);
            strcpy((char *)m_BRIConfig.Data.directory[iDir].spid, strSpid);
            strcpy((char *)m_BRIConfig.Data.directory[iDir].sub_address, strSubAddress);
         }
      }
#endif
      AffirmThrow(m_BRIConfig.Set(m_hKey));
      AffirmThrow(m_DChanExtConfig.Set(m_hKey));
      fSuccess = TRUE;
   }
   catch (CAffirmException ae)
   {
   }

   return fSuccess;
}

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

   try
   {
      AffirmThrow(m_BRIConfig.Remove(m_hKey));
      AffirmThrow(m_DChanExtConfig.Remove(m_hKey));
      AffirmThrow(CProtocol::RemoveParameters(fRemoveKey));
      fSuccess = TRUE;
   }
   catch (CAffirmException ae)
   {
   }

   return fSuccess;
}

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

   try
   {
      AffirmThrow(pFrom != NULL);
      CProtocolBRI * pFromProtocol = (CProtocolBRI *) pFrom;

      m_BRIConfig = pFromProtocol->m_BRIConfig;
      m_DChanExtConfig = pFromProtocol->m_DChanExtConfig;

      AffirmThrow(CProtocol::CopyParameters(pFrom));

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

   return fSuccess;
}

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

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

   try
   {
      AffirmThrow(CProtocol::GetConfigData());
      fSuccess = TRUE;
   }
   catch (CAffirmException ae)
   {
   }

   return fSuccess;
}

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

BOOL CProtocolBRI::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;
#ifndef NT5
      m_WizPageSwitch.SetSwitchType(m_BRIConfig.Data.switch_type);
      m_WizPageSwitch.SetAutoSpid(m_BRIConfig.Data.auto_spid);
      AffirmThrow(m_pwsSheet->InsertPage(&m_WizPageSwitch, FALSE, TRUE));
#endif
      fSuccess = TRUE;
   }
   catch (CAffirmException ae)
   {
   }

   return fSuccess;
}

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

   try
   {
      AffirmThrow(pSheet != NULL);

      if (m_pwsSheet != NULL)
      {
         AffirmThrow(m_pwsSheet == pSheet);
         m_pwsSheet->RemovePage(&m_WizPageSwitch);
         m_pwsSheet->RemovePage(&m_WizPageMSN);
      }

      AffirmThrow(CProtocol::RemoveWizardPages(pSheet));

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

   return fSuccess;
}

BOOL CProtocolBRI::HandleWizSwitch(void)
{
   BOOL fSuccess = FALSE;

   try
   {
      AffirmThrow(m_pwsSheet != NULL);

      m_BRIConfig.Data.switch_type = m_WizPageSwitch.GetSwitchType();
      m_BRIConfig.Data.auto_spid = m_WizPageSwitch.GetAutoSpid();

      for (int i = 0; i < GetChildCount(); i++)
      {
         CConfigObject * pChild = GetChild(i);
         AffirmThrow(pChild != NULL);
         AffirmThrow(pChild->RemoveWizardPages(m_pwsSheet));
      }

      AffirmThrow(UpdateBChannels());

      if (m_BRIConfig.Data.switch_type == BRI_ETSI)
      {
         // do MSN  page
         AffirmThrow(m_WizPageMSN.SetMSN(m_BRIConfig.Data.directory, ElementCount(m_BRIConfig.Data.directory)));
         AffirmThrow(m_pwsSheet->InsertPage(&m_WizPageMSN));
      }
      else
      {
         // let B Channels add their pages
         for (i = 0; i < GetChildCount(); i++)
         {
            CConfigObject * pChild = GetChild(i);
            AffirmThrow(pChild != NULL);
            AffirmThrow(pChild->AddWizardPages(m_pwsSheet));
         }
      }

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

   return fSuccess;
}

BOOL CProtocolBRI::HandleWizMSN(void)
{
   BOOL fSuccess = FALSE;

   try
   {
      AffirmThrow(m_pwsSheet != NULL);
      AffirmThrow(m_BRIConfig.Data.switch_type == BRI_ETSI);
      AffirmThrow(m_WizPageMSN.GetMSN(m_BRIConfig.Data.directory, ElementCount(m_BRIConfig.Data.directory)));
      fSuccess = TRUE;
   }
   catch (CAffirmException ae)
   {
   }

   return fSuccess;
}

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

   try
   {
      switch (nState)
      {
         case WP_SWITCH: AffirmThrow(HandleWizSwitch()); break;
         case WP_MSN: AffirmThrow(HandleWizMSN()); break;
         default: AffirmThrow(FALSE); break;
      }

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

   return fSuccess;
}

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

   try
   {
      CString str = TEXT("");

#ifndef NT5
      // Switch type
      SValueMap SwitchMap;
      AffirmThrow(SwitchMap.Init(SValueMap::MAP_BRI_SWITCH));
      str.Format(IDS_Information_SwitchFormat,
                 SwitchMap.DisplayNameFromValue(m_BRIConfig.Data.switch_type));
      strInfo += str;

      if (m_BRIConfig.Data.switch_type != BRI_ETSI)
      {
         // Auto SPID
#if defined(SUPPORT_AUTOSPID)
         CString strAutoSpid;
         strAutoSpid.LoadString((m_BRIConfig.Data.auto_spid == BRI_AUTOSPID_ON) ? IDS_On : IDS_Off);
         str.Format(IDS_Information_AutoSpidFormat, strAutoSpid);
#else
         str = TEXT("");
#endif
      }
      else
      {
         str.LoadString(IDS_Information_MSN);
         for (int i = 0; i < ElementCount(m_BRIConfig.Data.directory); i++)
         {
            if (m_BRIConfig.Data.directory[i].number[0] != '\0')
            {
               CString strMSN;
               strMSN.Format(TEXT("\t%s\n"), m_BRIConfig.Data.directory[i].number);
               str += strMSN;
            }
         }
      }
      strInfo += str;

      strInfo += TEXT("\n");
#endif
      // Address Type
      SValueMap AddrMap;
      AffirmThrow(AddrMap.Init(SValueMap::MAP_DCHAN_ADDRTYPE));
      str.Format(IDS_Information_AddressTypeFormat,
                 AddrMap.DisplayNameFromValue(m_DChanExtConfig.Data.address_type));
      strInfo += str;

      // Numbering Plan
      SValueMap NumPlanMap;
      AffirmThrow(NumPlanMap.Init(SValueMap::MAP_DCHAN_NUMPLAN));
      str.Format(IDS_Information_NumberingPlanFormat,
                 NumPlanMap.DisplayNameFromValue(m_DChanExtConfig.Data.numbering_plan));
      strInfo += str;

      // Subaddress Type
      SValueMap SubAddrMap;
      AffirmThrow(SubAddrMap.Init(SValueMap::MAP_DCHAN_SUBADDRTYPE));
      str.Format(IDS_Information_SubaddressTypeFormat,
                 SubAddrMap.DisplayNameFromValue(m_DChanExtConfig.Data.subaddress_type));
      strInfo += str;
   }
   catch (CAffirmException ae)
   {
   }

   return strInfo;
}

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

   try
   {
      CPropertySheet PropSheet(GetDisplayName());
#ifndef NT5
      CPropMSN PropMSN;

      if (m_BRIConfig.Data.switch_type == BRI_ETSI)
         AffirmThrow(PropMSN.SetMSN(m_BRIConfig.Data.directory, ElementCount(m_BRIConfig.Data.directory)));

      CPageBRISwitch PropPageSwitch(CPageBRISwitch::PROPPAGE);
      PropPageSwitch.SetSwitchType(m_BRIConfig.Data.switch_type);
      PropPageSwitch.SetAutoSpid(m_BRIConfig.Data.auto_spid);
      PropPageSwitch.SetMSNInfo(&PropSheet, &PropMSN);
      PropSheet.AddPage(&PropPageSwitch);
#endif
      CPropAdvancedBRI PropPageAdvBRI;
      AffirmThrow(PropPageAdvBRI.SetDChanExtConfig(&m_DChanExtConfig.Data));

      PropSheet.AddPage(&PropPageAdvBRI);
      
      PropSheet.m_psh.dwFlags |= PSH_NOAPPLYNOW;
      if (PropSheet.DoModal() == IDOK)
      {
#ifndef NT5
         m_BRIConfig.Data.switch_type = PropPageSwitch.GetSwitchType();
         m_BRIConfig.Data.auto_spid = PropPageSwitch.GetAutoSpid();
         if (m_BRIConfig.Data.switch_type == BRI_ETSI)
            AffirmThrow(PropMSN.GetMSN(m_BRIConfig.Data.directory, ElementCount(m_BRIConfig.Data.directory)));
         AffirmThrow(UpdateBChannels());
#endif
         AffirmThrow(PropPageAdvBRI.GetDChanExtConfig(&m_DChanExtConfig.Data));



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

   return fThingsHaveChanged;
}

BOOL CProtocolBRI::UpdateBChannels(BOOL const fSetProperties /* = FALSE */)
{
   BOOL fSuccess = FALSE;

   try
   {
      BOOL fEnableBChannelProperties = (m_BRIConfig.Data.switch_type != BRI_ETSI);

      // For ETSI, we don't use SPIDs either, this is moot since Props were disabled above...
      BOOL fEnableBChannelSpid = (m_BRIConfig.Data.switch_type != BRI_JAPAN) && (m_BRIConfig.Data.auto_spid == BRI_AUTOSPID_OFF);

      // Japan (INS64) is the only switch that uses sub addresses
      BOOL fEnableBChannelSubAddress = (m_BRIConfig.Data.switch_type == BRI_JAPAN);

      SEnumDescendentsCriteria EnumCriteria(DXB_REGVAL_PORT_TYPE_BCHANNEL);
      CPortBChannel * pBChannel = NULL;
      while ((pBChannel = (CPortBChannel *)EnumDescendents(EnumCriteria)) != NULL)
      {
         int iDir = pBChannel->GetPortNumber();
         AffirmThrow(iDir >= 0);
         AffirmThrow(iDir < ElementCount(m_BRIConfig.Data.directory));

         if (fSetProperties)
            pBChannel->SetProperties(m_BRIConfig.Data.directory[iDir].number, m_BRIConfig.Data.directory[iDir].spid, m_BRIConfig.Data.directory[iDir].sub_address);

         pBChannel->EnableProperties(fEnableBChannelProperties);
         if (fEnableBChannelProperties)
         {
            pBChannel->EnableSpid(fEnableBChannelSpid);
            pBChannel->EnableSubAddress(fEnableBChannelSubAddress);
         }

      }

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

   return fSuccess;
}
