#include "./include/sip_ua_pub.h"
#include "./include/sip.h"
#include "./include/sip_ua_dialog.h"
#include "./include/sip_ua_const.h"
#include "./include/sip_ua_ext.h"
#include "./include/sip_ext.h"
#include "./include/sip_debug.h"

int sip_ua_create_tag(WORD dialogId)
{
    struct timeval  tv;

    if (dialogId >= SIP_UA_MAX_NUM_OF_DIALOG)
        return -1;

    gettimeofday(&tv, NULL);

    sprintf(sipUaDialog[dialogId].localTag, "%X%lX%lX", dialogId, tv.tv_sec, tv.tv_usec);

    return 0;
}

int sip_ua_create_call_id(WORD usrPort, WORD dialogId)
{
    struct timeval  tv;

    if (dialogId >= SIP_UA_MAX_NUM_OF_DIALOG)
        return -1;

    gettimeofday(&tv, NULL);

    sprintf(sipUaDialog[dialogId].callId.value, "%X%lX%lX", usrPort, tv.tv_usec, tv.tv_sec);
    strcpy(sipUaDialog[dialogId].callId.host, sipUaDottedHostIp);

    return 0;
}

void sip_ua_fill_dialog_uri(SIP_UA_URI *sipUaUri, SIP_URI *sipUri)
{
    if ((sipUaUri == NULL) || (sipUri == NULL))
        return;

    sipUaUri->uriType = sipUri->uriType;
    strcpy(sipUaUri->userName, sipUri->userName);
    strcpy(sipUaUri->password, sipUri->password);
    strcpy(sipUaUri->domain, sipUri->host.addr.domain);
}

int sip_ua_set_dialog_state(WORD dialogId, BYTE state)
{
    if ((dialogId>= SIP_UA_MAX_NUM_OF_DIALOG) || (sipUaDialog[dialogId].flag == 0))
    {
        sprintf((char *)sipAsciTempBuf, "sip_ua_set_dialog_state: dialogId wrong\r\n");
        sip_log_err(sipAsciTempBuf);
        return -1;
    }

    sipUaDialog[dialogId].state = state;

    return 0;
}

int sip_ua_update_dialog_with_req(WORD dialogId, SIP_API_STRUCT *sipApiMsg)
{
    SIP_DIALOG  *sipUaDlgPtr;
    BYTE            method;

    if (sipApiMsg == NULL)
    {
        return -1;
    }

    if ((dialogId >= SIP_UA_MAX_NUM_OF_DIALOG) || (sipUaDialog[dialogId].flag == 0))
    {
        sprintf((char *)sipAsciTempBuf, "sip_ua_update_dialog_with_req:dialogId wrong\r\n");
        sip_log_err(sipAsciTempBuf);
        return -1;
    }

    sipUaDlgPtr = &sipUaDialog[dialogId];
    method = sipApiMsg->sipApiMsg.sipMsg.sipStartLine.sipMethod;

/*    if (method == SIP_METHOD_INVITE)
    {
        strcpy(sipUaDlgPtr->invBranch, sipApiMsg->sipApiMsg.sipMsg.sipHdrVias.vias[1].params.para[0].para.paraStr);
    }//for cancel*/
    
    if ((method != SIP_METHOD_ACK) && (method != SIP_METHOD_CANCEL))
    {
        if (sipApiMsg->sipApiMsg.sipMsg.sipHdrCseq.value <= sipUaDlgPtr->remoteCseq.value)
        {
            sprintf((char *)sipAsciTempBuf, "sip_ua_update_dialog_with_req:req seq is less than seq in dialog\r\n");
            sip_log_err(sipAsciTempBuf);
            return -2;
        }

        sipUaDlgPtr->remoteCseq.value = sipApiMsg->sipApiMsg.sipMsg.sipHdrCseq.value;
    }

    if ((method == SIP_METHOD_RE_INVITE) 
         || ((method == SIP_METHOD_ACK) && ((sipUaDlgPtr->paramFlag & SIP_UA_DIALOG_REMOTE_TARGET_FLAG) != SIP_UA_DIALOG_REMOTE_TARGET_FLAG)))
    {
        if ((sipApiMsg->sipApiMsg.sipMsg.sipGenHdrFlag[0] & SIP_HDR_CONTACT_MASK) == SIP_HDR_CONTACT_MASK)
        {
            sip_ua_fill_dialog_uri(&sipUaDlgPtr->remoteTarget, &sipApiMsg->sipApiMsg.sipMsg.sipHdrContacts.contacts[sipApiMsg->sipApiMsg.sipMsg.sipHdrContacts.head].url);
            sipUaDlgPtr->paramFlag |= SIP_UA_DIALOG_REMOTE_TARGET_FLAG;
        }
    }

    return 0;
}

int sip_ua_update_dialog_with_rsp(WORD dialogId, SIP_API_STRUCT * sipApiMsg, BYTE flag)
{
     SIP_DIALOG *sipUaDlgPtr;
     BYTE           head;
     BYTE           num;
     int            i;
     BYTE           method;
     BYTE           endHead;

     if (sipApiMsg == NULL)
     {
         return -1;
     }

     if ((dialogId >= SIP_UA_MAX_NUM_OF_DIALOG) || (sipUaDialog[dialogId].flag == 0))
     {
         sprintf((char *)sipAsciTempBuf, "sip_ua_update_dialog_with_rsp: dialogId wrong\r\n");
         sip_log_err(sipAsciTempBuf);
         return -1;
     }

     method = sipApiMsg->sipApiMsg.sipMsg.sipHdrCseq.method;
     sipUaDlgPtr = &sipUaDialog[dialogId];

     if (sipApiMsg->sipApiMsg.sipMsg.sipHdrCseq.value != sipUaDlgPtr->localCseq.value)
     {
         sprintf((char *)sipAsciTempBuf, "sip_ua_update_dialog_with_rsp: rsp seq is not equal to seq in dialog\r\n");
         sip_log_err(sipAsciTempBuf);
         return -2;
     }

     if ((method != SIP_METHOD_INVITE) && (method != SIP_METHOD_RE_INVITE))
     {
         return -1;
     }

     if (flag == 1)
         strcpy(sipUaDlgPtr->remoteTag, sipApiMsg->sipApiMsg.sipMsg.sipHdrTo.params.para[0].para.paraStr);

     if ((method == SIP_METHOD_INVITE) && ((sipApiMsg->sipApiMsg.sipMsg.sipGenHdrFlag[0] & SIP_HDR_RECORD_ROUTE_MASK) == SIP_HDR_RECORD_ROUTE_MASK))
     {
         head = sipApiMsg->sipApiMsg.sipMsg.sipHdrRecordRoutes.head;
         sipUaDlgPtr->routeSets.num = endHead = num = sipApiMsg->sipApiMsg.sipMsg.sipHdrRecordRoutes.num;

         for (i = 0; i < num; i++)
         {
             --endHead;

             memcpy(&sipUaDlgPtr->routeSets.recRoutes[endHead], &sipApiMsg->sipApiMsg.sipMsg.sipHdrRecordRoutes.recRoutes[head], sizeof(SIP_HDR_RECORD_ROUTE));

             if (++head >= SIP_MAX_NUM_OF_RECORD_ROUTES)
                 head = 0;
         }

         sipUaDlgPtr->routeSets.head = 0;
     }

     if ((sipApiMsg->sipApiMsg.sipMsg.sipGenHdrFlag[0] & SIP_HDR_CONTACT_MASK) == SIP_HDR_CONTACT_MASK)
     {
         sip_ua_fill_dialog_uri(&sipUaDlgPtr->remoteTarget, &sipApiMsg->sipApiMsg.sipMsg.sipHdrContacts.contacts[sipApiMsg->sipApiMsg.sipMsg.sipHdrContacts.head].url);
         sipUaDlgPtr->paramFlag |= SIP_UA_DIALOG_REMOTE_TARGET_FLAG;
     }

     return 0;
}

int sip_ua_init_dialog_as_client_with_inv(BYTE cgId, WORD usrPort, SIP_MSG *sipMsg)//sapIndex
{
    WORD    dialogId = sipUaDialogSelect;
    int     i;

   if (sipMsg == NULL)//if ((sapIndex >= SIP_UA_MAX_NUM_OF_SAP) || (sipMsg == NULL))
   {
       return -1;
   }

   if (dialogId >= SIP_UA_MAX_NUM_OF_DIALOG)
   {
       dialogId = 0;
   }

   for (i = 0; i < SIP_UA_MAX_NUM_OF_DIALOG; i++)
   {
       if (sipUaDialog[dialogId].flag == 1)
       {
           if (++dialogId >= SIP_UA_MAX_NUM_OF_DIALOG)
               dialogId = 0;

           continue;
       }

       sip_ua_init_dialog(dialogId);
       sipUaDialog[dialogId].flag = 1;
       sipUaDialog[dialogId].type = SIP_CALLER;
       sipUaDialog[dialogId].cgId = cgId;//sipUaDialog[dialogId].userIndex = sapIndex;
       sipUaDialog[dialogId].usrPort = usrPort;
       sipUaDialog[dialogId].state = SIP_UA_DIALOG_IDLE;

       sip_ua_create_tag(dialogId);
       sip_ua_create_call_id(usrPort, dialogId);
       sipUaDialog[dialogId].invCSeq = sipUaDialog[dialogId].localCseq.value= 0;
       sipUaDialog[dialogId].remoteCseq.value = 0;

       sip_ua_fill_dialog_uri(&sipUaDialog[dialogId].localURI, &sipMsg->sipHdrFrom.url);
       sip_ua_fill_dialog_uri(&sipUaDialog[dialogId].remoteURI, &sipMsg->sipHdrTo.url);

       sipUaDialogSelect = (dialogId + 1) % SIP_UA_MAX_NUM_OF_DIALOG;

       return dialogId;
   }

   sprintf((char *)sipAsciTempBuf, "client initial dialog with inv failed\r\n");
   sip_log_err(sipAsciTempBuf);
   return -1;
}

int sip_ua_init_dialog_as_server_with_inv(BYTE cgId, WORD hdlPort, WORD usrPort, SIP_MSG *sipMsg)//BYTE sapIndex
{
    WORD    dialogId = sipUaDialogSelect;
    int     i;
       int      j;
       BYTE head;

       if (sipMsg == NULL)//if ((sapIndex >= SIP_UA_MAX_NUM_OF_SAP) || (sipMsg == NULL))
       {
           return -1;
       }

       if (dialogId >= SIP_UA_MAX_NUM_OF_DIALOG)
       {
           dialogId = 0;
       }

       for (i = 0; i < SIP_UA_MAX_NUM_OF_DIALOG; i++)
       {
           if (sipUaDialog[dialogId].flag == 1)
           {
               if (++dialogId >= SIP_UA_MAX_NUM_OF_DIALOG)
                   dialogId = 0;

               continue;
           }

           sip_ua_init_dialog(dialogId);
           sipUaDialog[dialogId].flag = 1;
           sipUaDialog[dialogId].type = SIP_CALLEE;
           sipUaDialog[dialogId].cgId = cgId;//sipUaDialog[dialogId].userIndex = sapIndex;
           sipUaDialog[dialogId].usrPort = usrPort;
           sipUaDialog[dialogId].sipUaPort = hdlPort;
           sipUaDialog[dialogId].invUaPort.rvInvUaPort = hdlPort;
           sipUaDialog[dialogId].state = SIP_UA_DIALOG_IDLE;

           if (sipMsg->sipHdrTo.params.para[0].paraName == SIP_API_PNAME_TAG)
           {
               strcpy(sipUaDialog[dialogId].localTag, sipMsg->sipHdrTo.params.para[0].para.paraStr);
           }
           else
           {
               sip_ua_create_tag(dialogId);
           }

           strcpy(sipUaDialog[dialogId].invBranch, sipMsg->sipHdrVias.vias[1].params.para[0].para.paraStr);
           sipUaDialog[dialogId].invCSeq = sipUaDialog[dialogId].localCseq.value = 0;
           sipUaDialog[dialogId].remoteCseq.value = sipUaDialog[dialogId].remoteInvCseq = sipMsg->sipHdrCseq.value;
           memcpy(&sipUaDialog[dialogId].callId, &sipMsg->sipHdrCallId, sizeof(SIP_HDR_CALL_ID));
           sip_ua_fill_dialog_uri(&sipUaDialog[dialogId].localURI, &sipMsg->sipHdrTo.url);
           sip_ua_fill_dialog_uri(&sipUaDialog[dialogId].remoteURI, &sipMsg->sipHdrFrom.url);

           if ((sipMsg->sipGenHdrFlag[0] & SIP_HDR_CONTACT_MASK) == SIP_HDR_CONTACT_MASK)
           {
               sip_ua_fill_dialog_uri(&sipUaDialog[dialogId].remoteTarget, &sipMsg->sipHdrContacts.contacts[sipMsg->sipHdrContacts.head].url);
               sipUaDialog[dialogId].paramFlag |= SIP_UA_DIALOG_REMOTE_TARGET_FLAG;
           }

           strcpy(sipUaDialog[dialogId].remoteTag, sipMsg->sipHdrFrom.params.para[0].para.paraStr);

           if ((sipMsg->sipGenHdrFlag[0] & SIP_HDR_RECORD_ROUTE_MASK) == SIP_HDR_RECORD_ROUTE_MASK)
           {
               sipUaDialog[dialogId].routeSets.num = sipMsg->sipHdrRecordRoutes.num;
               sipUaDialog[dialogId].routeSets.head = 0;
               head = sipMsg->sipHdrRecordRoutes.head;

               for (j = 0; j < sipMsg->sipHdrRecordRoutes.num; j++)
               {
                   memcpy(&sipUaDialog[dialogId].routeSets.recRoutes[j], &sipMsg->sipHdrRecordRoutes.recRoutes[head], sizeof(SIP_HDR_RECORD_ROUTES));

                   if (++head >= SIP_MAX_NUM_OF_RECORD_ROUTES)
                       head = 0;
               }
           }

           sipUaDialogSelect = (dialogId + 1) % SIP_UA_MAX_NUM_OF_DIALOG;

           return dialogId;
       }

       sprintf((char *)sipAsciTempBuf, "server initial dialog with inv failed\r\n");
       sip_log_err(sipAsciTempBuf);
       return -1;
}

int sip_ua_free_dialog(DWORD usrPort, WORD dialogId)
{
    if (dialogId >= SIP_UA_MAX_NUM_OF_DIALOG)
    {
        return -1;
    }

    if (sipUaDialog[dialogId].flag != 1)
    {
        return -1;
    }

    if (sipUaDialog[dialogId].usrPort != usrPort)
    {
        return -1;
    }

    memset(&sipUaDialog[dialogId], 0, sizeof(SIP_DIALOG));
    sipUaDialog[dialogId].uaPort = 0xFFFF;
    sipUaDialog[dialogId].uaAckPort = 0xFFFF;

    return 0;
}
