/*
  The oSIP library implements the Session Initiation Protocol (SIP -rfc3261-)
  Copyright (C) 2001,2002,2003,2004,2005,2006,2007 Aymeric MOIZARD jack@atosc.org
  
  This library is free software; you can redistribute it and/or
  modify it under the terms of the GNU Lesser General Public
  License as published by the Free Software Foundation; either
  version 2.1 of the License, or (at your option) any later version.
  
  This library is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  Lesser General Public License for more details.
  
  You should have received a copy of the GNU Lesser General Public
  License along with this library; if not, write to the Free Software
  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
*/

#include <osip2/internal.h>
#include <osip2/osip.h>

#include "fsm.h"

/* Create a sipevent according to the SIP message buf. */
/* INPUT : char *buf | message as a string.            */
/* return NULL  if message cannot be parsed            */
osip_event_t *
osip_parse (const char *buf, size_t length)
{
  int i;
  osip_event_t *se = __osip_event_new (UNKNOWN_EVT, 0);

  if (se == NULL)
    return NULL;

#ifdef TEST_PARSER_SPEED
  {
    int kk;
    int pstime1, pstime;
    struct timespec tv1;

    clock_get_time (CLOCK_REALTIME, &tv1);
    pstime = ((tv1.tv_sec * 1000) + (tv1.tv_nsec / 1000000));
    for (kk = 0; kk < 10000; kk++)
      {

        i = osip_message_init (&(se->sip));

        if (osip_message_parse (se->sip, buf, length) == -1)
          {
            fprintf (stdout, "osip_message_parse retrun -1\n");
            osip_message_free (se->sip);
        } else
          {                     /* msg is parsed */
            osip_message_free (se->sip);
          }
      }
    clock_get_time (CLOCK_REALTIME, &tv1);
    pstime1 = ((tv1.tv_sec * 1000) + (tv1.tv_nsec / 1000000));
    fprintf (stdout, "CPU clock ticks for 10000 messages - T1: %i - T2: %i\n",
             pstime1, pstime);
    fprintf (stdout, "CPU time for 10000 messages - %d\n", (pstime1 - pstime));
  }
  osip_free (se);
  return NULL;
#endif
  /* parse message and set up an event */
  i = osip_message_init (&(se->sip));
  if (i != 0)
    {
      osip_free (se);
      return NULL;
    }
  if (osip_message_parse (se->sip, buf, length) == -1)
    {
      OSIP_TRACE (osip_trace
                  (__FILE__, __LINE__, OSIP_ERROR, NULL,
                   "could not parse message\n"));
      osip_message_free (se->sip);
      osip_free (se);
      return NULL;
  } else
    {
      if (se->sip->call_id != NULL && se->sip->call_id->number != NULL)
        {
          OSIP_TRACE (osip_trace
                      (__FILE__, __LINE__, OSIP_INFO3, NULL,
                       "MESSAGE REC. CALLID:%s\n", se->sip->call_id->number));
        }

      if (MSG_IS_REQUEST (se->sip))
        {
          if (se->sip->sip_method == NULL || se->sip->req_uri == NULL)
            {
              osip_message_free (se->sip);
              osip_free (se);
              return NULL;
            }
        }

      se->type = evt_set_type_incoming_sipmessage (se->sip);
      return se;
    }
}


/* allocates an event from retransmitter.             */
/* USED ONLY BY THE STACK.                            */
/* INPUT : int transactionid | id of the transaction. */
/* INPUT : type_t type | type of event.               */
/* returns null on error. */
osip_event_t *
__osip_event_new (type_t type, int transactionid)
{
  osip_event_t *sipevent;

  sipevent = (osip_event_t *) osip_malloc (sizeof (osip_event_t));
  if (sipevent == NULL)
    return NULL;
  sipevent->type = type;
  sipevent->sip = NULL;
  sipevent->transactionid = transactionid;
  return sipevent;
}

/* allocates an event from user.                      */
/* USED ONLY BY THE USER.                             */
/* INPUT : osip_message_t *sip | sip message for transaction.  */
/* returns null on error. */
osip_event_t *
osip_new_outgoing_sipmessage (osip_message_t * sip)
{
  osip_event_t *sipevent;

  if (sip == NULL)
    return NULL;
  if (MSG_IS_REQUEST (sip))
    {
      if (sip->sip_method == NULL)
        return NULL;
      if (sip->req_uri == NULL)
        return NULL;
    }
  sipevent = (osip_event_t *) osip_malloc (sizeof (osip_event_t));
  if (sipevent == NULL)
    return NULL;

  sipevent->sip = sip;
  sipevent->type = evt_set_type_outgoing_sipmessage (sip);
  sipevent->transactionid = 0;
  return sipevent;
}

type_t
evt_set_type_incoming_sipmessage (osip_message_t * sip)
{
  if (MSG_IS_REQUEST (sip))
    {
      if (MSG_IS_INVITE (sip))
        return RCV_REQINVITE;
      else if (MSG_IS_ACK (sip))
        return RCV_REQACK;
      return RCV_REQUEST;
  } else
    {
      if (MSG_IS_STATUS_1XX (sip))
        return RCV_STATUS_1XX;
      else if (MSG_IS_STATUS_2XX (sip))
        return RCV_STATUS_2XX;
      return RCV_STATUS_3456XX;
    }
}

type_t
evt_set_type_outgoing_sipmessage (osip_message_t * sip)
{

  if (MSG_IS_REQUEST (sip))
    {
      if (MSG_IS_INVITE (sip))
        return SND_REQINVITE;
      if (MSG_IS_ACK (sip))
        return SND_REQACK;
      return SND_REQUEST;
  } else
    {
      if (MSG_IS_STATUS_1XX (sip))
        return SND_STATUS_1XX;
      else if (MSG_IS_STATUS_2XX (sip))
        return SND_STATUS_2XX;
      return SND_STATUS_3456XX;
    }
}

void
osip_event_free (osip_event_t * event)
{
  if (event != NULL)
    {
      osip_message_free (event->sip);
      osip_free (event);
    }
}
