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


#include "stdafx.h"
#include "ValueMap.h"

#include "dxbtypes.h"
#include "mgmthlc.h"

#include "Resource.h"


typedef struct
{
   union
   {
      struct
      {
         DWORD dwValue;
         UINT nDisplayNameId;
      };

      struct
      {
         int nMin;
         int nMax;
      };
   };
}
VALUEMAP;


// CT1 Signaling Map : This map should only be used for T1!
//
//////////////////////////////////////////////////////////////////////

static VALUEMAP const g_CT1SignalingMap[] =
{
   { CT1_GROUND_START,  IDS_Signaling_Ground    },
   { CT1_LOOP_START,    IDS_Signaling_Loop      },
   { CT1_WINK_START,    IDS_Signaling_Wink      },
   { CT1_IMMED_START,   IDS_Signaling_Immediate },
};

// CT1 Wink Digits Map : This map should only be used for T1 + Wink Start!
//
//////////////////////////////////////////////////////////////////////
#pragma message("NOTE: NOTE: Wink digits range has NOT been defined yet!")
#define WINK_MIN 0
#define WINK_MAX 20

static VALUEMAP const g_CT1WinkDigitsRange[] =
{
   { WINK_MIN,  WINK_MAX },
};

// PRI Switch Map
//
//////////////////////////////////////////////////////////////////////

static VALUEMAP const g_PRISwitchMap[] =
{
   { PRI_5ESS,    IDS_Switch_5ESS    },
   { PRI_DMS100,  IDS_Switch_DMS100  },
   { PRI_JAPAN,   IDS_Switch_INS1500 },
   { PRI_NI2,     IDS_Switch_NI2     },
};

static VALUEMAP const g_E1SwitchMap[] =
{
   { PRI_ETSI,    IDS_Switch_ETSI   },
};

// E1R2 Mappings
//
//////////////////////////////////////////////////////////////////////

static VALUEMAP const g_E1R2SwitchMap[] =
{
	{ E1_R2,			IDS_Switch_E1R2		  },
};

static VALUEMAP const g_E1R2SwitchTypeMap[] =
{
	{ R2_ARGENTINA,				R2_Switch_Argentina				 },
	//{ R2_AUSTRALIA,				R2_Switch_Australia				 },
	{ R2_BRAZIL,				R2_Switch_Brazil				 },
	//{ R2_CHINA,					R2_Switch_China					 },
	//{ R2_COLUMBIA,				R2_Switch_Colombia				 },
	//{ R2_COSTA_RICA,			R2_Switch_Costa_Rica			 },
	//{ R2_,					R2_Switch_Croatia				 },
	//{ R2_CZECH,					R2_Switch_Czech_Republic		 },
	//{ R2_,					R2_Switch_Denmark				 },
	//{ R2_ECUADOR_ITU,			R2_Switch_Ecuador_ITU			 },
	//{ R2_ECUADOR_LME,			R2_Switch_Ecuador_LME			 },
	//{ R2_,					R2_Switch_Finland				 },
	//{ R2_,					R2_Switch_Germany				 },
	//{ R2_GREECE,				R2_Switch_Greece				 },
	//{ R2_GUATEMALA,				R2_Switch_Guatemala				 },
	//{ R2_HONG_KONG,				R2_Switch_Hong_Kong_ITU			 },
	//{ R2_,					R2_Switch_Hong_Kong_NonITU		 },
	//{ R2_INDIA,					R2_Switch_India					 },
	//{ R2_INDONESIA,				R2_Switch_Indonesia				 },
	//{ R2_ISRAEL,				R2_Switch_Israel				 },
	{ R2_ITU,					R2_Switch_ITU				 },
	//{ R2_KOREA,					R2_Switch_Korea					 },
	//{ R2_MALAYSIA,				R2_Switch_Malaysia				 },
	//{ R2_MEXICO_TELMEX,			R2_Switch_Mexico_TELMEX			 },
	//{ R2_MEXICO_TELNOR,			R2_Switch_Mexico_TELNOR			 },
	//{ R2_NEW_ZEALAND,			R2_Switch_New_Zealand			 },
	//{ R2_PARAGUAY,				R2_Switch_Paraguay				 },
	//{ R2_PERU,					R2_Switch_Peru					 },
	//{ R2_PHILLIPPINES,			R2_Switch_Philippines			 },
	//{ R2_SAUDI_ARABIA,			R2_Switch_Saudi_Arabia			 },
	//{ R2_SINGAPORE,				R2_Switch_Singapore				 },
	//{ R2_SOUTH_AFRICA_PANAFTEL,		R2_Switch_South_Africa_PANAFTEL	 },
	//{ R2_THAILAND,				R2_Switch_Thailand				 },
	//{ R2_URUGUAY,				R2_Switch_Uruguay				 },
	//{ R2_VENEZUELA,				R2_Switch_Venezuela				 },
	//{ R2_VIETNAM,				R2_Switch_Vietnam				 },
};

static VALUEMAP const g_E1R2CDBitsMap[] =
{
   { E1_R2_D_BIT,  IDS_Type_R2_CDBITS   },
};

static VALUEMAP const g_E1R2DNISMap[] =
{
   { 0,					IDS_Digits_MinDNIS   },
   { R2_END_OF_PULSING,	IDS_Digits_MaxDNIS   },
};

static VALUEMAP const g_E1R2ANIMap[] =
{
   { 0,						IDS_Digits_MinANI   },
   { R2_END_OF_PULSING,		IDS_Digits_MaxANI   },
   { 0,						IDS_Digits_SendANI  },
};

static VALUEMAP const g_E1R2SignalMap[] =
{
   { MF_R2_BW_5,		IDS_Signal_ANISig	  },
   { MF_R2_BW_6,		IDS_Signal_AnswerSig  },
   { MF_R2_BW_3,		IDS_Signal_BusySig	  },
   { MF_R2_BW_5,		IDS_Signal_EndDNIS	  },
};

static VALUEMAP const g_E1R2OutgoingMap[] =
{
	{ MF_R2_NATIONAL_SUBSCRIBER,				IDS_E1R2OutType_Natl			},
	{ MF_R2_NATIONAL_PRIORITY_SUBSCRIBER,		IDS_E1R2OutType_NatlPriSubr		},
	{ MF_R2_NATIONAL_MAINTENANCE_EQUIPMENT,		IDS_E1R2OutType_NatlMaintEqmt   },
	{ MF_R2_NATIONAL_OPERATOR,					IDS_E1R2OutType_NatlOper		},
	{ MF_R2_INTERNATIONAL_SUBSCRIBER,			IDS_E1R2OutType_IntlSubr		},
	{ MF_R2_INTERNATIONAL_DATA_TRANSMISSION,	IDS_E1R2OutType_IntlDataTrans   },
	{ MF_R2_INTERNATIONAL_PRIORITY_SUBSCRIBER,	IDS_E1R2OutType_IntlPriSubr		},
};

// BRI Switch Map
//
//////////////////////////////////////////////////////////////////////

static VALUEMAP const g_BRISwitchMap[] =
{
   { BRI_5ESS,    IDS_Switch_5ESS    },
   { BRI_DMS100,  IDS_Switch_DMS100  },
   { BRI_ETSI,    IDS_Switch_ETSI    },
   { BRI_JAPAN,   IDS_Switch_INS64   },
   { BRI_NI1,     IDS_Switch_NI1     },
};

// DChan Address Type
//
//////////////////////////////////////////////////////////////////////

static VALUEMAP const g_DChanAddressType[] =
{
   { DCHAN_ADDRESS_TYPE_UNKNOWN,    IDS_DChanAddrType_Unknown  },
   { DCHAN_ADDRESS_TYPE_INTL,       IDS_DChanAddrType_Intl     },
   { DCHAN_ADDRESS_TYPE_NATIONAL,   IDS_DChanAddrType_National },
   { DCHAN_ADDRESS_TYPE_NETWORK,    IDS_DChanAddrType_Network  },
   { DCHAN_ADDRESS_TYPE_SUBSCR,     IDS_DChanAddrType_Subscr   },
   { DCHAN_ADDRESS_TYPE_ABBREV,     IDS_DChanAddrType_Abbrev   },
};

// DChan Numering Plan
//
//////////////////////////////////////////////////////////////////////

static VALUEMAP const g_DChanNumPlan[] =
{
   { DCHAN_NUMBERING_PLAN_UNKNOWN,  IDS_DChanNumPlan_Unknown  },
   { DCHAN_NUMBERING_PLAN_ISDN,     IDS_DChanNumPlan_ISDN     },
   { DCHAN_NUMBERING_PLAN_DATA,     IDS_DChanNumPlan_Data     },
   { DCHAN_NUMBERING_PLAN_TELEX,    IDS_DChanNumPlan_Telex    },
   { DCHAN_NUMBERING_PLAN_NATIONAL, IDS_DChanNumPlan_National },
   { DCHAN_NUMBERING_PLAN_PRIVATE,  IDS_DChanNumPlan_Private  },
};

// DChan Subaddress Type
//
//////////////////////////////////////////////////////////////////////

static VALUEMAP const g_DChanSubAddrType[] =
{
   { DCHAN_SUBADDRESS_TYPE_NSAP,  IDS_DChanSubAddrType_NSAP  },
   { DCHAN_SUBADDRESS_TYPE_USER,  IDS_DChanSubAddrType_User  },
};


static BOOL GetValues(VALUEMAP const * const pMap, int const cMapItems, CDWordArray & adwValues)
{
   BOOL fSuccess = FALSE;

   try
   {
      AffirmThrow(pMap != NULL);
      AffirmThrow(cMapItems > 0);
      AffirmThrow(AfxIsValidAddress(pMap, (sizeof(*pMap) * cMapItems), FALSE));

      for (int i = 0; i < cMapItems; i++)
      {
         adwValues.SetAtGrow(i, pMap[i].dwValue);
      }

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

   return fSuccess;
}

static BOOL GetDisplayNames(VALUEMAP const * const pMap, int const cMapItems, CStringArray & astrDisplayNames)
{
   BOOL fSuccess = FALSE;

   try
   {
      AffirmThrow(pMap != NULL);
      AffirmThrow(cMapItems > 0);
      AffirmThrow(AfxIsValidAddress(pMap, (sizeof(*pMap) * cMapItems), FALSE));

      for (int i = 0; i < cMapItems; i++)
      {
         CString strDisplayName;
         AffirmThrow(strDisplayName.LoadString(pMap[i].nDisplayNameId));
         astrDisplayNames.SetAtGrow(i, strDisplayName);
      }

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

   return fSuccess;
}

BOOL SValueMap::Init(int const eValueMap)
{
   BOOL fSuccess = FALSE;

   try
   {
      eMapType = MAP_TYPE_UNKNOWN;
      adwValues.RemoveAll();
      astrDisplayNames.RemoveAll();
      nMin = 0;
      nMax = 0;

      static const struct
      {
         int eMap;
         int eType;
         VALUEMAP const * pMap;
         int cItems;
      }
      aMaps[] =
      {
         // CT1/PRI/E1
         { MAP_CT1_SIGNALING,       MAP_TYPE_STR2DWORD, g_CT1SignalingMap,    ElementCount(g_CT1SignalingMap)     },
         { MAP_CT1_WINKDIGITS,      MAP_TYPE_INTRANGE,  g_CT1WinkDigitsRange, ElementCount(g_CT1WinkDigitsRange)  },
         { MAP_PRI_SWITCH,          MAP_TYPE_STR2DWORD, g_PRISwitchMap,       ElementCount(g_PRISwitchMap)        },
         { MAP_E1_SWITCH,           MAP_TYPE_STR2DWORD, g_E1SwitchMap,        ElementCount(g_E1SwitchMap)         },

		 // E1R2
		 { MAP_E1R2_SWITCH,         MAP_TYPE_STR2DWORD, g_E1R2SwitchMap,      ElementCount(g_E1R2SwitchMap)       },
		 { MAP_E1R2_R2SWITCHTYPE,   MAP_TYPE_STR2DWORD, g_E1R2SwitchTypeMap,  ElementCount(g_E1R2SwitchTypeMap)   },
		 { MAP_E1R2_CD_BITS,        MAP_TYPE_STR2DWORD, g_E1R2CDBitsMap,      ElementCount(g_E1R2CDBitsMap)       },
		 { MAP_E1R2_MAXDNISDIGITS,  MAP_TYPE_STR2DWORD, g_E1R2DNISMap,		  ElementCount(g_E1R2DNISMap)		  },
		 { MAP_E1R2_MINDNISDIGITS,  MAP_TYPE_STR2DWORD, g_E1R2DNISMap,		  ElementCount(g_E1R2DNISMap)		  },
		 { MAP_E1R2_MAXANIDIGITS,   MAP_TYPE_STR2DWORD, g_E1R2ANIMap,		  ElementCount(g_E1R2ANIMap)		  },
		 { MAP_E1R2_MINANIDIGITS,   MAP_TYPE_STR2DWORD, g_E1R2ANIMap,		  ElementCount(g_E1R2ANIMap)		  },
		 { MAP_E1R2_SENDANIDIGITS,  MAP_TYPE_STR2DWORD, g_E1R2ANIMap,		  ElementCount(g_E1R2ANIMap)		  },
		 { MAP_E1R2_ANIDIGITSIGNAL, MAP_TYPE_STR2DWORD, g_E1R2SignalMap,      ElementCount(g_E1R2SignalMap)       },
		 { MAP_E1R2_ANSWERSIGNAL,   MAP_TYPE_STR2DWORD, g_E1R2SignalMap,	  ElementCount(g_E1R2SignalMap)		  },
		 { MAP_E1R2_BUSYSIGNAL,     MAP_TYPE_STR2DWORD, g_E1R2SignalMap,	  ElementCount(g_E1R2SignalMap)		  },
		 { MAP_E1R2_OUTGOINGTYPE,   MAP_TYPE_STR2DWORD, g_E1R2OutgoingMap,    ElementCount(g_E1R2OutgoingMap)     },
		 { MAP_E1R2_ENDDNISSIGNAL,  MAP_TYPE_STR2DWORD, g_E1R2SignalMap,	  ElementCount(g_E1R2SignalMap)       },

         // BRI
         { MAP_BRI_SWITCH,          MAP_TYPE_STR2DWORD, g_BRISwitchMap,       ElementCount(g_BRISwitchMap)        },

         // DChan
         { MAP_DCHAN_ADDRTYPE,      MAP_TYPE_STR2DWORD, g_DChanAddressType,   ElementCount(g_DChanAddressType)    },
         { MAP_DCHAN_NUMPLAN,       MAP_TYPE_STR2DWORD, g_DChanNumPlan,       ElementCount(g_DChanNumPlan)        },
         { MAP_DCHAN_SUBADDRTYPE,   MAP_TYPE_STR2DWORD, g_DChanSubAddrType,   ElementCount(g_DChanSubAddrType)    },
      };

      int eType = MAP_TYPE_UNKNOWN;
      VALUEMAP const * pMap = NULL;
      int cItems = 0;

      for (int i = 0; i < ElementCount(aMaps); i++)
      {
         if (eValueMap == aMaps[i].eMap)
         {
            eType = aMaps[i].eType;
            pMap = aMaps[i].pMap;
            cItems = aMaps[i].cItems;
            break;
         }
      }

      AffirmThrow(eType != MAP_TYPE_UNKNOWN);
      AffirmThrow(pMap != NULL);
      AffirmThrow(cItems > 0);

      eMapType = eType;

      switch (eType)
      {
         case MAP_TYPE_STR2DWORD:
         {
            AffirmThrow(GetValues(pMap, cItems, adwValues));
            AffirmThrow(GetDisplayNames(pMap, cItems, astrDisplayNames));
            break;
         }

         case MAP_TYPE_INTRANGE:
         {
            AffirmThrow(cItems == 1);
            nMin = pMap[0].nMin;
            nMax = pMap[0].nMax;
            break;
         }
         default: AffirmThrow(FALSE); break;
      }

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

   return fSuccess;
}

int SValueMap::ToIndex(DWORD const dwValue, int const iDefault /* = -1 */)
{
   int iIndex = iDefault;

   try
   {
      switch (eMapType)
      {
         case MAP_TYPE_STR2DWORD:
         {
            for (int i = 0; i < adwValues.GetSize(); i++)
            {
               if (dwValue == adwValues[i])
               {
                  iIndex = i;
                  break;
               }
            }
            break;
         }

         case MAP_TYPE_INTRANGE:
         {
            AffirmThrow((int)dwValue >= nMin);
            AffirmThrow((int)dwValue <= nMax);
            iIndex = dwValue;
            break;
         }

         default: AffirmThrow(FALSE); break;
      }
   }
   catch (CAffirmException ae)
   {
   }

   return iIndex;
}

DWORD SValueMap::FromIndex(int const iIndex)
{
   int dwValue = 0;      // not really sure what a good failure value would be

   try
   {
      switch (eMapType)
      {
         case MAP_TYPE_STR2DWORD:
         {
            AffirmThrow(iIndex >= 0);
            AffirmThrow(iIndex < adwValues.GetSize());
            dwValue = adwValues[iIndex];
            break;
         }

         case MAP_TYPE_INTRANGE:
         {
            AffirmThrow(iIndex >= nMin);
            AffirmThrow(iIndex <= nMax);
            dwValue = iIndex;
            break;
         }
         default: AffirmThrow(FALSE); break;
      }
   }
   catch (CAffirmException ae)
   {
   }

   return dwValue;
}

CString SValueMap::DisplayNameFromValue(DWORD const dwValue)
{
   CString strDisplayName = TEXT("");

   try
   {
      switch (eMapType)
      {
         case MAP_TYPE_STR2DWORD:
         {
            int iIndex = ToIndex(dwValue);
            AffirmThrow(iIndex >= 0);
            AffirmThrow(iIndex < astrDisplayNames.GetSize());
            strDisplayName = astrDisplayNames[iIndex];
            break;
         }

         case MAP_TYPE_INTRANGE:
         {
            AffirmThrow((int)dwValue >= nMin);
            AffirmThrow((int)dwValue <= nMax);
            strDisplayName.Format(TEXT("%d"), dwValue);
            break;
         }
         default: AffirmThrow(FALSE); break;
      }
   }
   catch (CAffirmException ae)
   {
   }

   return strDisplayName;
}
