//////////////////////////////////////////////////
//Title    : spLog.c
//Auhtor   : Liu Wei
//Desc     : sccp log implementation  
//Created  : 2007-05-19
//Revision :
//
//Revision :
//
//////////////////////////////////////////////////

#include "./include/sccp.h"
#include "./include/sccp_pub.h"
#include "./include/sccp_func.h"

BYTE sccpDebugFull = 0;
/* by simon at 23/9/26 */
extern SCCP_SegMsgBuf sccp_segmsgbuf[MAX_SEGMSG_BUF];

extern void spWatchDogStatic ( u8 uDebugStaticMask );
extern char sccp_debug_buf[5120];
extern int spLog_fd;
extern unsigned long spLogDebug_mask;

void spLog ( char *info )
{
#ifdef DEBUG_TEST
    if( strlen ( info ) < 2048 )
    {
        printf ( "[SCCP]: %s\n", info );
    }
#else
    if( strlen ( sccp_debug_buf ) + strlen ( info ) > 2048 )
    {
        sccpDebugFull = 1;
        return;
    }
    strncat ( sccp_debug_buf, info, 2048 );
    strcat ( sccp_debug_buf, "\r\n" );

    if( spLog_fd != -1 )
    {
        write ( spLog_fd, info, strlen ( info ) );
        write ( spLog_fd, "\r\n", 2 );
    }

    if( strlen ( sccp_debug_buf ) > 2050 )
    {
        printf ( "sccp debug buffer overflow, len=%d\n", strlen ( sccp_debug_buf ) );
    }
#endif
    return;
}

///////////////////////////////////////////////////////////////////////////
//                                                                      ///
///////////////////////////////////////////////////////////////////////////

void spShowAddr ( SCCP_ADDR * pAddr, const char *sAddrName )
{
    char srcAddr[128], digits[24];

    Digits2Str ( digits, pAddr->GTAI, ( ( pAddr->len + 1 ) / 2 ) % MAX_DIGITS );
    digits[pAddr->len] = 0;
    sprintf ( srcAddr, "%s: SPC=%06X SSN=%d RI=%d GTI=%d NP=%d TT=%d GT=%s", sAddrName, pAddr->DPC, pAddr->SSN, pAddr->RI, pAddr->GTI, pAddr->NP, pAddr->TT, digits );
    spLog ( srcAddr );
}

///////////////////////////////////////////////////////////////////////////
//                                                                      
///////////////////////////////////////////////////////////////////////////
void spLogDebug ( DWORD mask, const char *fmt, ... )
{
    va_list ap;
    char buf[1024];

    if( ( mask & spLogDebug_mask ) == 0 || sccpDebugFull )
    {
        return;
    }

    if( spLogDebug_mask & SCCPDB_TIME )
    {
        struct timeval tv;
        struct timezone tz;
        struct tm *t;
        char timestr[32];

        gettimeofday ( &tv, &tz );
        t = localtime ( &tv.tv_sec );
        if( t == NULL )
        {
        	assert( 0 && "syscall : localtime fail");
        	exit(0);
        }
        sprintf ( timestr, "(%d:%d:%d.%ld):", t->tm_hour, t->tm_min, t->tm_sec, tv.tv_usec );
        spLog ( timestr );
    }

    if( ( mask & SCCPDB_ERR ) && ( strlen ( sccp_debug_buf ) + 5 < 2048 ) )
    {
        strcat ( sccp_debug_buf, "\33[31m" );
    }

    va_start ( ap, fmt );
    vsnprintf ( buf, 1024, fmt, ap );
    va_end ( ap );
    strcat ( buf, "\33[37m" );
    spLog ( buf );
}

///////////////////////////////////////////////////////////////////////////
//                                                                      ///
///////////////////////////////////////////////////////////////////////////

void spShowBCD ( DWORD mask, BYTE * buf, int len )
{
//    int i = 0, j = 0, linemax = 24;
    char info[1024];

    if( ( spLogDebug_mask & SCCPDB_MSG ) == 0 || ( spLogDebug_mask & mask ) == 0 || sccpDebugFull )
    {
        return;
    }

    if( len >= 256 )
    {
        len = 256;
    }

    MsgToFmtLog ( buf, len, info, 1024 );
    spLog ( info );
}

void spLogSeg ( SCCP_SegMsgBuf * pSegMsgbuf )
{
    char digits[24], info[256];

    spShowAddr ( &pSegMsgbuf->SegID.CGA, "spShowAddr" );

    BcdToAscii ( digits, pSegMsgbuf->SegID.SegLR, 6 );
    digits[6] = 0;
    sprintf ( info, "Seginfo: Total=%d RSE=%d DPC=%06X SLS=%d Class=%d SegLR=0x%s", pSegMsgbuf->MsgTotal, pSegMsgbuf->RSE, pSegMsgbuf->SegID.DPC, pSegMsgbuf->SegID.SLS, pSegMsgbuf->MsgClass, digits );
    spLog ( info );

}

///////////////////////////////////////////////////////////////////////////
//                                                                      ///
///////////////////////////////////////////////////////////////////////////

void spShowMsg ( DWORD mask, const char *pDesc, Intra_Msg * pIntraMsg )
{
//    int i = 0, j = 0, linemax = 24;
	int len;
//    char srcAddr[128], dstAddr[128];
	char digits[24], info[1024];
    char *pStr;

    if( ( mask & spLogDebug_mask ) == 0 && ( sccp_filter_msg ( &pIntraMsg->CGA, &pIntraMsg->CDA ) == 0 || mask >= SCCPDB_STP ) )
    {
        return;
    }
    if( sccpDebugFull )
    {
        return;
    }
    if( strlen ( sccp_debug_buf ) + 2 < 2048 )
    {
        strcat ( sccp_debug_buf, "\r\n" );
    }
    if( spLogDebug_mask & SCCPDB_TIME )
    {
        struct timeval tv;
        struct timezone tz;
        struct tm *t;
        char timestr[32];

        gettimeofday ( &tv, &tz );
        t = localtime ( &tv.tv_sec );
        if( t == NULL )
        {
        	assert( 0 && "syscall : localtime fail");
        	exit(0);
        }
        sprintf ( timestr, "(%d:%d:%d.%ld):", t->tm_hour, t->tm_min, t->tm_sec, tv.tv_usec );
        spLog ( timestr );
    }

    if( mask & SCCPDB_ERR && ( strlen ( sccp_debug_buf ) + 5 < 2048 ) )
    {
        strcat ( sccp_debug_buf, "\33[31m" );
    }

    spGetMsgStr ( pIntraMsg->msgtype, pStr );
    sprintf ( info, "%s %s[%d->%d], SLS=%02x, NetID=%d, msglen=%d\33[37m", pDesc, pStr, pIntraMsg->CGA.SSN, pIntraMsg->CDA.SSN, pIntraMsg->SLS, pIntraMsg->NetID, pIntraMsg->msglen );

    spLog ( info );

    if( ( spLogDebug_mask & SCCPDB_ADDR ) || ( mask & SCCPDB_ERR ) )
    {
        spShowAddr ( &pIntraMsg->CGA, "SrcAddr" );
        spShowAddr ( &pIntraMsg->CDA, "DstAddr" );
    }

    if( mask & SCCPDB_AIF )
    {
        char digits1[24], digits2[24];

        BcdToAscii ( digits1, pIntraMsg->aSLR, 6 );
        digits1[6] = 0;
        BcdToAscii ( digits2, pIntraMsg->aDLR, 6 );
        digits2[6] = 0;
        sprintf ( info, "SLR = %s DLR = %s ", digits1, digits2 );
        spLog ( info );
    }

    if( mask & SCCPDB_XUDT )
    {
        BcdToAscii ( digits, pIntraMsg->Segmnt.SegLR, 6 );
        digits[6] = 0;
        sprintf ( info, "Seginfo: RS=%d SegLR=0x%s", pIntraMsg->Segmnt.RSBits, digits );
        spLog ( info );
    }

    if( ( spLogDebug_mask & SCCPDB_MSG ) == 0 )
    {
        return;
    }

    len = pIntraMsg->msglen % 256;
    MsgToFmtLog ( pIntraMsg->data, len, info, 1024 );
    spLog ( info );
}

///////////////////////////////////////////////////////////////////////////
//                                                                      ///
///////////////////////////////////////////////////////////////////////////

void spShowPrimitive ( SP_UiPriPara * pUiPriParam, u8 uDirection )
{
    u8 *pStr;

    spGetUlPrimitiveStr ( pUiPriParam->uUiPri, pStr );
    if( uDirection )
    {
        spLogDebug ( SCCPDB_TIME, "AIF ==> SCCP : %s", pStr );
    }
    else
    {
        spLogDebug ( SCCPDB_TIME, "SCCP ==> AIF : %s", pStr );
    }

    spShowUserData ( pUiPriParam );
}

///////////////////////////////////////////////////////////////////////////
//                                                                      ///
///////////////////////////////////////////////////////////////////////////

void spLogStateError ( u16 wConnId, u8 uErrCode )
{
    CO_ConnSection *pCS;
    u8 *pStateStr;
    u8 *pPriStr;
    u8 *pSideStr;

    WxcAssert ( wConnId < CO_CS_MPORT, "SCCP spLogStateError unexpected connection id" );

    pCS = &pSp->tCo.tCSInst[wConnId];

    spGetCoStateStr ( pCS->uCState, pStateStr );
    spGetUlPrimitiveStr ( pCS->uPri, pPriStr );
    spGetCoInstanceSide ( pCS->uSide, pSideStr );

    switch ( uErrCode )
    {
    case ERR_NONE:
        {
#ifdef _WXC_FSM_TEST
            char str[512];

            sprintf ( str, "]coFsm[: call back state %s , side :%s  \n", pStateStr, pSideStr );
            spLog ( str );
#endif
        }
        break;
    case ERR_FSM_UNEXPECT_SIDE:
        spLogDebug ( SCCPDB_ERR, "Recieve unexpected side: %s ", pSideStr );
        spWatchDogStatic ( ERR_FSM_UNEXPECT_SIDE );
        break;
    case ERR_FSM_UNEXPECT_PRI:
        spLogDebug ( SCCPDB_ERR, "Recieve unexpected primitive in the state machine ," "Discard the primtive . \nstate: %s primtive :%s side :%s\n", pStateStr, pPriStr, pSideStr );
        spWatchDogStatic ( ERR_FSM_UNEXPECT_PRI );
        break;
    case ERR_FSM_DISCARD:
        spLogDebug ( SCCPDB_ERR, "Unexpected state machine ,Discard the state : %s side :%s", pStateStr, pSideStr );
        spWatchDogStatic ( ERR_FSM_DISCARD );
        break;
    case ERR_FSM_ERROR:
        spLogDebug ( SCCPDB_ERR, "Unexpected state machine ,error state : %s side :%s", pStateStr, pSideStr );
        spWatchDogStatic ( ERR_FSM_ERROR );
        break;
    case ERR_FSM_FATAL:
        spLogDebug ( SCCPDB_ERR, "Unexpected state machine ,fatal error : %s side :%s", pStateStr, pSideStr );
        spWatchDogStatic ( ERR_FSM_FATAL );
    case ERR_FSM_RESERVED:
        spLogDebug ( SCCPDB_ERR, "Unexpected reserved state machine, unsupported now state : %s side :%s", pStateStr, pSideStr );
        spWatchDogStatic ( ERR_FSM_RESERVED );
        break;
    default:
        spLogDebug ( SCCPDB_ERR, "SCCP log state error , but unkonw eror code" );
        spWatchDogStatic ( ERR_FSM_UNKOWN_ERROR_CODE );
        break;
    }
}

///////////////////////////////////////////////////////////////////////////
//                                                                      ///
///////////////////////////////////////////////////////////////////////////

void spLogTimerOut ( u16 wConnId, u8 uTimerID )
{
    u8 *pTimerStr;

    spGetTimerOutStr ( uTimerID, pTimerStr );
    spLogDebug ( SCCPDB_ERR, "SCCP Timer Out Timer ID : %s  ConnID : %d ", pTimerStr, wConnId );
    spWatchDogStatic ( SP_TIMER_OUT );
}

///////////////////////////////////////////////////////////////////////////
//                                                                      ///
///////////////////////////////////////////////////////////////////////////

void spShowUserData ( SP_UiPriPara * pPri )
{
    SP_UD *pUd;
    SP_UiPriUnion *pPriUn;

    pPriUn = &pPri->tPriUnion;

    switch ( pPri->uUiPri )
    {
    case N_CONNECT_REQ:
        if( !( pPriUn->tPriNConnReq.uOptFlag & 0x08 ) )
        {
            return;
        }
        spLogDebug ( SCCPDB_AIF, "Connect Req primitive Flag :0x%X ", pPriUn->tPriNConnReq.uOptFlag );
        pUd = &pPriUn->tPriNConnReq.tUD;
        break;
    case N_CONNECT_IND:
        if( !( pPriUn->tPriNConnInd.uOptFlag & 0x04 ) )
        {
            return;
        }
        spLogDebug ( SCCPDB_AIF, "Connect Ind primitive Flag :0x%X NetID : %d "
                     "RI : %d SSN : %d" , pPriUn->tPriNConnInd.uOptFlag
                     ,pPriUn->tPriNConnInd.tCDA.NetID 
                     ,pPriUn->tPriNConnInd.tCDA.RI  
                     ,pPriUn->tPriNConnInd.tCDA.SSN );
        pUd = &pPriUn->tPriNConnInd.tUD;
        break;
    case N_CONNECT_CFM:
        if( !( pPriUn->tPriNConnCfm.uOptFlag & 0x04 ) )
        {
            return;
        }
        spLogDebug ( SCCPDB_AIF, "Connect Cfm primitive Flag :0x%X ", pPriUn->tPriNConnCfm.uOptFlag );
        pUd = &pPriUn->tPriNConnCfm.tUD;
        break;
    case N_CONNECT_RSP:
        if( !( pPriUn->tPriNConnRsp.uOptFlag & 0x04 ) )
        {
            return;
        }
        spLogDebug ( SCCPDB_AIF, "Connect Rsp primitive Flag :0x%X ", pPriUn->tPriNConnRsp.uOptFlag );
        pUd = &pPriUn->tPriNConnRsp.tUD;
        break;
    case N_DISCONNECT_REQ:
        if( !( pPriUn->tPriNDisconnReq.uOptFlag & 0x04 ) )
        {
            return;
        }
        spLogDebug ( SCCPDB_AIF, "Disconnect Req primitive Flag :0x%X ", pPriUn->tPriNDisconnReq.uOptFlag );
        pUd = &pPriUn->tPriNDisconnReq.tUD;
        break;
    case N_DISCONNECT_IND:
        if( !( pPriUn->tPriNDisconnInd.uOptFlag & 0x04 ) )
        {
            return;
        }
        spLogDebug ( SCCPDB_AIF, "Disconnect Ind primitive Flag :0x%X ", pPriUn->tPriNDisconnInd.uOptFlag );
        pUd = &pPriUn->tPriNDisconnInd.tUD;
        break;
    case N_DATA_REQ:
        pUd = &pPriUn->tPriNDataReq.tUD;
        break;
    case N_DATA_IND:
        pUd = &pPriUn->tPriNDataInd.tUD;
        break;
    case N_DATAAK_REQ:
    case N_EDATA_REQ:
    case N_RESET_REQ:
    case N_RESET_RSP:
    case N_INFORM_REQ:
        return;
    default:
        return;
    }
    if( pUd->uDataLen > 0 )
    {
        spShowBCD ( SCCPDB_AIF, pUd->aUserData, ( pUd->uDataLen ) % 256 );
    }
}
