/****************************************************/
/*Title:    gtt.c                                   */
/*Descr:    GTT Table Management                    */
/*Author:   Liang Hanxi                             */
/*Create:   2002-2-19                               */
/*Modify:   2003-4-30                               */
/****************************************************/
#include "./include/sccp.h"

/*===========export================*/
int BuildRouteIndex (  );
u_short SelectRoute ( BYTE * pDigits, BYTE DigitsLen );
void TranslateGT ( SCCP_ADDR * addr, SCCP_ROUTE * pRoute );

/*===========import================*/
extern void spLog ( char *info );
extern void spShowErr(int checkFlag, char * str);
extern int ParseLine ( char *str, char ( *row )[128], int maxrow );
extern int Digits2Array ( BYTE * pArray, BYTE * pDigits, int DigitsLen );
extern int Bcd2Array ( BYTE * pArray, BYTE * pBcd, int BcdLen );
extern int Array2Digits ( BYTE * pDigits, BYTE * pArray, int ArrayLen );
extern void spLogDebug ( DWORD mask, const char *fmt, ... );

/*===========private================*/
static int AddRoute ( BYTE * pStartDigits, BYTE * pEndDigits, BYTE DigitsLen, u_short index );
static int AddLargerNode ( SCCP_ROUTE_NODE * pNode, BYTE * pDigits, BYTE DigitsLen, u_short index );
static int AddLessNode ( SCCP_ROUTE_NODE * pNode, BYTE * pDigits, BYTE DigitsLen, u_short index );
static SCCP_ROUTE_NODE *NewNode (  );

static SCCP_ROUTE_NODE RouteNode[SCCP_ROUTE_NODE_NUM];
static SCCP_ROUTE_NODE *pHead = &RouteNode[0];
static u_short heap_index = 1, item_index = 0;

int BuildRouteIndex (  )
{
    int i;
    BYTE StartNum[32], EndNum[32], NumLen;
    BYTE TTmod10, TTdiv10, TTdiv100;
    BYTE field = 0;

    TTmod10 = TTdiv10 = TTdiv100 = 0;
    spLog ( "Build GTT Index..." );
    memset ( &RouteNode[0], 0, SCCP_ROUTE_NODE_NUM * sizeof ( SCCP_ROUTE_NODE ) );
    heap_index = 1;
    item_index = 0;

    for ( i = 2; i < 256; i++ )
    {
        field = 0;
        if( LocalSSN[i].status[0] == 0 && LocalSSN[i].status[1] == 0 )
            continue;
        if( LocalSSN[i].msisdn_len < 1 )
            continue;
        //              if (mtp3_ansiFlag(LocalSSN[i].NetID) != 1)/* ITU */
        StartNum[field++] = NP_MSISDN;
        //              else
        {                       //ANSI
            StartNum[field++] = TT_0;
            StartNum[field++] = TT_1;
            //StartNum[field++] = TT_4;
            StartNum[field++] = TT_0;
        }
        NumLen = Bcd2Array ( StartNum + field, LocalSSN[i].msisdn, LocalSSN[i].msisdn_len % MAX_DIGITS ) + field;
        if( NumLen < 2 || NumLen > 26 )
            continue;
        if( StartNum[NumLen - 1] > 9 )
            NumLen--;

        if( AddRoute ( StartNum, StartNum, NumLen, 1024 + i ) == 0 )
            spLog ( "Error: Fail to add local node, resource limit..." );
    }

    field = 0;
    for ( i = 0; i < SCCP_ROUTE_NUM; i++ )
    {
        if( RouteList[i].avail == 0 )
            continue;

        TTmod10 = RouteList[i].TT % 10;
        TTdiv10 = ( RouteList[i].TT / 10 ) % 10;
        TTdiv100 = RouteList[i].TT / 100;

        field = 0;
        if( RouteList[i].NP != 0 )
            StartNum[field++] = RouteList[i].NP;
        else
            StartNum[field++] = NP_MSISDN;
        if( RouteList[i].TT != 0 )
        {
            StartNum[field++] = TTdiv100;
            StartNum[field++] = TTdiv10;
            StartNum[field++] = TTmod10;
        }
        else
        {
            StartNum[field++] = TT_0;
            StartNum[field++] = TT_1;
            //StartNum[field++] = TT_4;
            StartNum[field++] = TT_0;
        }

        field = 0;
        if( RouteList[i].NP != 0 )
            EndNum[field++] = RouteList[i].NP;
        else
            EndNum[field++] = NP_MSISDN;
        if( RouteList[i].TT != 0 )
        {
            EndNum[field++] = TTdiv100;
            EndNum[field++] = TTdiv10;
            EndNum[field++] = TTmod10;
        }
        else
        {
            EndNum[field++] = TT_0;
            EndNum[field++] = TT_1;
            //EndNum[field++] = TT_4;
            EndNum[field++] = TT_0;
        }

        NumLen = Bcd2Array ( StartNum + field, RouteList[i].StartDigits, RouteList[i].len % MAX_DIGITS ) + field;
        if( NumLen < 2 || NumLen > 26 )
            continue;
        if( StartNum[NumLen - 1] > 9 )
            NumLen--;
        Bcd2Array ( EndNum + field, RouteList[i].EndDigits, RouteList[i].len );

		if( AddRoute ( StartNum, EndNum, NumLen, i ) == 0 ){
            spLog ( "Error: Fail to add route, resource limit..." );
			break;
		}
    }
    return 1;
}

u_short SelectRoute ( BYTE * pDigits, BYTE DigitsLen )
{
    SCCP_ROUTE_NODE *pNode = pHead;
    int i;
    u_short result = 0xFFFF;
    BYTE num;

    for ( i = 0; i < DigitsLen; i++ )
    {
        num = pDigits[i];
        if( pNode->psub[num] >= &RouteNode[0] && pNode->psub[num] <= &RouteNode[SCCP_ROUTE_NODE_NUM-1] )
        {
            pNode = pNode->psub[num];
            if( pNode->nItem != 0xFFFF )
                result = pNode->nItem;
        }
        else
        {
            return result;
        }
    }
    return result;
}

int GetACNInfo ( SCCP_ADDR * pAddr, BYTE ** pAcnInfo )
{
    u_long spc;
    u_short nRoute = 0xFFFF;
    BYTE Num[MAX_DIGITS * 2], NumLen;
    BYTE NetID;
    BYTE field = 0;
    u16 acn_index=0;
    char str[128]={0};

    if( pAddr->NP > 0 )
        Num[field++] = pAddr->NP;
    else
        Num[field++] = NP_MSISDN;
    if( pAddr->TT > 0 )
    {
        Num[field++] = pAddr->TT / 100;
        Num[field++] = ( pAddr->TT / 10 ) % 10;
        Num[field++] = pAddr->TT % 10;
    }
    else
    {
        Num[field++] = TT_0;
        Num[field++] = TT_1;
        //Num[field++] = TT_4;
        Num[field++] = TT_0;
    }
    NumLen = pAddr->len % ( MAX_DIGITS * 2 );
    Digits2Array ( Num + field, pAddr->GTAI, ( NumLen + 1 ) / 2 );
    if( pAddr->GTI )
    {
        nRoute = SelectRoute ( Num, NumLen + field );
        if( nRoute < SCCP_ROUTE_NUM )
        {
            if( pAddr->NetID > 3 )
                NetID = RouteList[nRoute].NetID;
            else
                NetID = pAddr->NetID;

            spc = RouteList[nRoute].DPC[0] * 0x10000 + RouteList[nRoute].DPC[1] * 0x100 + RouteList[nRoute].DPC[2];
	    acn_index = RouteList[nRoute].	acn_index;
        }
        else if( nRoute >= 1024 && nRoute < 1024 + 256 )
        {
            if( pAddr->NetID > 3 )
                NetID = LocalSSN[nRoute - 1024].NetID % 4;
            else
                NetID = pAddr->NetID;

	    acn_index = LocalSSN[nRoute - 1024].acn_index;
            spc = SCCP_Param.spc[NetID];
        }
        else
            return 0;
    }
    else
    {
        NetID = pAddr->NetID;
        spc = pAddr->DPC;
    }

	if(acn_index >=SCCP_ROUTE_NUM)
		return 0;
	*pAcnInfo = &acn_ver_table[acn_index].LocationUpdating;
	Bcd2Str ( str, &acn_ver_table[acn_index].LocationUpdating, sizeof(SCCP_ACN_VER_TABLE)-1);
	spLogDebug(SCCPDB_MSG, "GetACNInfo (gtt)route num=%d, acn index=%d\r\n %s \r\n", nRoute, acn_index, str);
/*
    *pAcnInfo = spc_to_acn ( NetID, spc );
    if( *pAcnInfo == NULL )
        return 0;
*/        
    return 37;
}

void TranslateGT ( SCCP_ADDR * pAddr, SCCP_ROUTE * pRoute )
{
    BYTE swap[MAX_DIGITS * 2], temp[MAX_DIGITS * 2];
    BYTE ReplaceNum[MAX_DIGITS * 2], len;
    BYTE ReplaceEnd;

    len = Bcd2Array ( ReplaceNum, pRoute->ReplaceDigits, pRoute->replace_len % MAX_DIGITS );

    Digits2Array ( temp, pAddr->GTAI, ( ( pAddr->len + 1 ) / 2 ) % MAX_DIGITS );

    pAddr->NP = NP_GT;
    if( pRoute->ReplaceStart > 1 )
    {
        memcpy ( swap, temp, pRoute->ReplaceStart - 1 );
    }

    memcpy ( swap + pRoute->ReplaceStart - 1, ReplaceNum, len );

    ReplaceEnd = pRoute->ReplaceEnd;
    if( pAddr->len < ReplaceEnd )
        ReplaceEnd = pAddr->len;

    memcpy ( swap + pRoute->ReplaceStart - 1 + len, temp + ReplaceEnd, ( pAddr->len - ReplaceEnd ) % 16 );

    pAddr->len = pRoute->ReplaceStart - 1 + len + pAddr->len - ReplaceEnd;
    if(pAddr->len>15) pAddr->len = 15;
    pAddr->NP = pRoute->OutNP;
    Array2Digits ( pAddr->GTAI, swap, pAddr->len );
}

int AddRoute ( BYTE * pStartDigits, BYTE * pEndDigits, BYTE DigitsLen, u_short index )
{
    SCCP_ROUTE_NODE *pNode = pHead;
    int i, j;
    BYTE startNum, endNum;

    for ( i = 0; i < DigitsLen; i++ )
    {
        startNum = pStartDigits[i] % 10;
        endNum = pEndDigits[i] % 10;
        if( startNum < endNum )
        {
            for ( j = startNum + 1; j < endNum; j++ )
            {
                if( pNode->psub[j] == NULL && ( pNode->psub[j] = NewNode (  ) ) == NULL )
                    return 0;

                /* add by daniel on 2006-5-15 */
                if( pNode->psub[j]->nItem == 0xFFFF )   //if this node has empty index then mark it with the new index, else do nothing
                    /* add by daniel on 2006-5-15 */
                    pNode->psub[j]->nItem = index;
            }
            if( pNode->psub[startNum] == NULL && ( pNode->psub[startNum] = NewNode (  ) ) == NULL )
                return 0;
            if( pNode->psub[endNum] == NULL && ( pNode->psub[endNum] = NewNode (  ) ) == NULL )
                return 0;
            if( AddLargerNode ( pNode->psub[startNum], pStartDigits + i + 1, DigitsLen - i - 1, index ) == 0 )
                return 0;

            if( AddLessNode ( pNode->psub[endNum], pEndDigits + i + 1, DigitsLen - i - 1, index ) == 0 )
                return 0;
            return 1;
        }
        else if( startNum == endNum )
        {
            if( pNode->psub[startNum] == NULL && ( pNode->psub[startNum] = NewNode (  ) ) == NULL )
            {
                //send alarm here
                pNode = NULL;
                return 0;
            }
            pNode = pNode->psub[startNum];

            if( i >= DigitsLen - 1 )
            {
                pNode->nItem = index;
                return 1;
            }
            continue;
        }
        else if( startNum > endNum )
            return 0;
    }
    return 1;
}

int AddLargerNode ( SCCP_ROUTE_NODE * pNode, BYTE * pDigits, BYTE DigitsLen, u_short index )
{
    int i, j;
    BYTE startNum;

    for ( i = 0; i < DigitsLen; i++ )
    {
        startNum = pDigits[i] % 10;
        for ( j = startNum + 1; j <= 9; j++ )
        {
            if( pNode->psub[j] == NULL && ( pNode->psub[j] = NewNode (  ) ) == NULL )
                return 0;
            /* add by daniel on 2006-5-15 */
            if( pNode->psub[j]->nItem == 0xFFFF )       //if this node has empty index then mark it with the new index, else do nothing
                /* add by daniel on 2006-5-15 */
                pNode->psub[j]->nItem = index;
        }
        if( pNode->psub[startNum] == NULL && ( pNode->psub[startNum] = NewNode (  ) ) == NULL )
            return 0;
        pNode = pNode->psub[startNum];
    }

    pNode->nItem = index;
    return 1;
}

int AddLessNode ( SCCP_ROUTE_NODE * pNode, BYTE * pDigits, BYTE DigitsLen, u_short index )
{
    int i, j;
    BYTE endNum;

    for ( i = 0; i < DigitsLen; i++ )
    {
        endNum = pDigits[i] % 10;
        for ( j = 0; j < endNum; j++ )
        {
            if( pNode->psub[j] == NULL && ( pNode->psub[j] = NewNode (  ) ) == NULL )
                return 0;
            /* add by daniel on 2006-5-15 */
            if( pNode->psub[j]->nItem == 0xFFFF )       //if this node has empty index then mark it with the new index, else do nothing
                /* add by daniel on 2006-5-15 */
                pNode->psub[j]->nItem = index;
        }
        if( pNode->psub[endNum] == NULL && ( pNode->psub[endNum] = NewNode (  ) ) == NULL )
            return 0;

        pNode = pNode->psub[endNum];
    }
    pNode->nItem = index;
    return 1;
}

SCCP_ROUTE_NODE *NewNode (  )
{
	if( heap_index >= SCCP_ROUTE_NODE_NUM ){
		spLog ( "Fatal Error: Fail to add GT node, no resource" );
        return NULL;
	}

    RouteNode[heap_index].nItem = 0xFFFF;
    return &RouteNode[heap_index++];
}

/*
*Purpose: check whether a GT is in the SCCP GT table
*Param:             np: Number Plan (0x01 MSISDN)
*                         tt: Translation Type(0x00 ITU)
*                         gt: Global title (Digits )
*                         gt_len: length of gt(number of GT Digits)
*Return:    0 - the GT is not in SCCP GTT
*                         Others ¨C the length of the GT in SCCP GTT
*/

int CheckGT(BYTE np, BYTE tt, BYTE *gt, BYTE gt_len)
{
	BYTE Num[32], NumLen;
	BYTE field = 0;
	int nRoute;

//	assert(gt_len < 32);
	if(gt_len >= 32)
	{
		spShowErr(1, "gt_len >= 32");
		return 0;
	}
//	assert(gt != NULL);
	if(gt == NULL)
	{
		spShowErr(1, "gt == NULL");
		return 0;
	}	

	if( np > 0 )
		Num[field++] = np;
	else
		Num[field++] = NP_MSISDN;

	if( tt > 0 )
	{
		Num[field++] = tt / 100;
		Num[field++] = ( tt / 10 ) % 10;
		Num[field++] = tt % 10;
	}
	else
	{
		Num[field++] = TT_0;
		Num[field++] = TT_1;
		//Num[field++] = TT_4;
		Num[field++] = TT_0;
	}
	NumLen = gt_len % ( MAX_DIGITS * 2 );
	Digits2Array ( Num + field, gt, ( NumLen + 1 ) / 2 );

	nRoute = SelectRoute ( Num, NumLen + field );	
	if( nRoute < SCCP_ROUTE_NUM )
	{
		NumLen = Bcd2Array( Num, RouteList[nRoute].EndDigits, RouteList[nRoute].len);
		return NumLen;
	}
	else
		return 0;
}
