//
// Copyright (C) 2006-2012 SIPez LLC.  All rights reserved.
//
// Copyright (C) 2004-2006 SIPfoundry Inc.
// Licensed by SIPfoundry under the LGPL license.
//
// Copyright (C) 2004-2006 Pingtel Corp.  All rights reserved.
// Licensed to SIPfoundry under a Contributor Agreement.
//
// $$
///////////////////////////////////////////////////////////////////////////////

// SYSTEM INCLUDES

#ifdef TEST
#include <assert.h>
#include "utl/UtlMemCheck.h"
#endif //TEST

#ifdef __pingtel_on_posix__
#include <stdlib.h>
#endif

// APPLICATION INCLUDES
#include <siptest/CommandMsgProcessor.h>
#include <net/SipUserAgent.h>
#include <os/OsServerTask.h>
#include <os/OsTask.h>

// EXTERNAL FUNCTIONS
// EXTERNAL VARIABLES
// CONSTANTS
// STATIC VARIABLE INITIALIZATIONS

/* //////////////////////////// PUBLIC //////////////////////////////////// */

/* ============================ CREATORS ================================== */

// Constructor
CommandMsgProcessor::CommandMsgProcessor(SipUserAgent* sipUserAgent)
{
#ifdef TEST
   if (!sIsTested)
   {
      sIsTested = true;
      test();
   }
#endif //TEST

   userAgent = sipUserAgent;
   numRespondToMessages = 0;
   userAgent->addMessageConsumer(this);
   mpResponseMessage = NULL;
   mpLastResponseMessage = NULL;
}

// Copy constructor
CommandMsgProcessor::CommandMsgProcessor(const CommandMsgProcessor& rCommandMsgProcessor)
{
}

// Destructor
CommandMsgProcessor::~CommandMsgProcessor()
{
}

/* ============================ MANIPULATORS ============================== */

// Assignment operator
CommandMsgProcessor&
CommandMsgProcessor::operator=(const CommandMsgProcessor& rhs)
{
   if (this == &rhs)            // handle the assignment to self case
      return *this;

   return *this;
}

UtlBoolean CommandMsgProcessor::handleMessage(OsMsg& eventMessage)
{
    int msgType = eventMessage.getMsgType();
    // int msgSubType = eventMessage.getMsgSubType();

    if(msgType == OsMsg::PHONE_APP)
    // && msgSubType == CP_SIP_MESSAGE)
    {
        osPrintf("CommandMsgProcessor::handleMessage Got a message\n");
        int messageType = ((SipMessageEvent&)eventMessage).getMessageStatus();

        const SipMessage* sipMsg = ((SipMessageEvent&)eventMessage).getMessage();
        UtlString callId;
        if(sipMsg)
        {
            osPrintf("numRespondToMessages: %d isResponse: %d messageType: %d TransErro: %d\n",
                     numRespondToMessages, sipMsg->isResponse(), messageType,
                     SipMessageEvent::TRANSPORT_ERROR);
            if((numRespondToMessages == -1 || numRespondToMessages > 0) &&
               !sipMsg->isResponse() && messageType != SipMessageEvent::TRANSPORT_ERROR)
            {
                osPrintf("valid message\n");
                if(numRespondToMessages > 0)
                {
                    numRespondToMessages--;
                }

                SipMessage response;
                if(mpResponseMessage)
                {
                    response = *mpResponseMessage;
                }

                // Copy To, From, CallId, Via(s), CSeq from request
                response.setResponseData(sipMsg, responseStatusCode, responseStatusText.data());

                // If this is an INVITE 200 response, we need to set the Route headers
                UtlString method;
                sipMsg->getRequestMethod(&method);
                if(method.compareTo(SIP_INVITE_METHOD) == 0 && responseStatusCode >= 200 && responseStatusCode < 300)
                {
                    response.setInviteOkRoutes(*sipMsg);
                }

                UtlString address;
                int port;
                UtlString protocol;
                UtlString tag;

                sipMsg->getToAddress(&address,
                   &port,
                   &protocol,
                   NULL,
                   NULL,
                   &tag);

                if( tag.isNull())
                {
                    int tagNum = rand();
                    char tag[100];
                    sprintf(tag, "%d", tagNum);
                    UtlString tagWithDot(tag);
                    tagWithDot.append(".34756498567498567");
                                      response.setToFieldTag(tagWithDot);
                }
 
                UtlString msgBytes;
                int msgLen;
                response.getBytes(&msgBytes, &msgLen);
                osPrintf("%s",msgBytes.data());

                if(mpLastResponseMessage)
                {
                    delete mpLastResponseMessage;
                    mpLastResponseMessage = NULL;
                }
                // Keep a copy of the last response sent
                mpLastResponseMessage = new SipMessage(response);

                if(userAgent->send(response))
                {
                    osPrintf("Sent response\n");
                }
                else
                {
                    osPrintf("Send failed\n");
                }
            }
        }
    }
    return(TRUE);
}

/* ============================ ACCESSORS ================================= */
void CommandMsgProcessor::stopResponding()
{
        numRespondToMessages = 0;
}

void CommandMsgProcessor::startResponding(int responseCode, const char* responseText,
                                         int numMessagesToRespondTo)
{
        numRespondToMessages = numMessagesToRespondTo;
        responseStatusCode = responseCode;
        responseStatusText.remove(0);
        if(responseText)
        {
                responseStatusText.append(responseText);
        }
    if(mpResponseMessage) delete mpResponseMessage;
    mpResponseMessage = NULL;
}

void CommandMsgProcessor::startResponding(const char* filename, int numMessagesToRespondTo )
{
        UtlString messageBuffer;
        char buffer[1025];
        int bufferSize = 1024;
        int charsRead;
        UtlString file = filename;

        numRespondToMessages = numMessagesToRespondTo;

        if (!file.isNull())
        {
                //get header parameters from files
                FILE* sipMessageFile = fopen(filename, "r");
                if(sipMessageFile)
                {
                        //printf("opened file: \"%s\"\n", argv[1]);
                        do
                        {
                                charsRead = fread(buffer, 1, bufferSize, sipMessageFile);
                                if(charsRead > 0)
                                {
                                        messageBuffer.append(buffer, charsRead);
                                }
                        }
                        while(charsRead);
                        fclose(sipMessageFile);
                        //messageBuffer.strip(UtlString::trailing, '\n');
                        //messageBuffer.strip(UtlString::trailing, '\r');

                        // Make sure there is a NULL at the end
                        messageBuffer.append("\0");
            if(mpResponseMessage) delete mpResponseMessage;
            mpResponseMessage = new SipMessage(messageBuffer);
            responseStatusCode = mpResponseMessage->getResponseStatusCode();
            mpResponseMessage->getResponseStatusText(&responseStatusText);

                }
        }
        //responseStatusText.append(messageBuffer);
}

void CommandMsgProcessor::resendLastResponse()
{
    if(mpLastResponseMessage)
    {
        if(userAgent->send(*mpLastResponseMessage))
        {
            osPrintf("Sent response\n");
        }
        else
        {
            osPrintf("Send failed\n");
        }
    }
    else
    {
        osPrintf("No previous response\n");
    }

}
/* ============================ INQUIRY =================================== */

/* //////////////////////////// PROTECTED ///////////////////////////////// */

/* //////////////////////////// PRIVATE /////////////////////////////////// */

/* ============================ TESTING =================================== */

#ifdef TEST

// Set to true after the tests have been executed once
bool CommandMsgProcessor::sIsTested = false;

// Test this class by running all of its assertion tests
void CommandMsgProcessor::test()
{

   UtlMemCheck* pUtlMemCheck = 0;
   pUtlMemCheck = new UtlMemCheck();         // checkpoint for memory leak check

   testCreators();
   testManipulators();
   testAccessors();
   testInquiry();

   assert(pUtlMemCheck->delta() == 0);    // check for memory leak
   delete pUtlMemCheck;
}

// Test the creators (and destructor) methods for the class
void CommandMsgProcessor::testCreators()
{
   UtlMemCheck* pUtlMemCheck  = 0;


   pUtlMemCheck = new UtlMemCheck();         // checkpoint for memory leak check

   // test the default constructor (if implemented)
   // test the copy constructor (if implemented)
   // test other constructors (if implemented)
   //    if a constructor parameter is used to set information in an ancestor
   //       class, then verify it gets set correctly (i.e., via ancestor
   //       class accessor method.
   // test the destructor
   //    if the class contains member pointer variables, verify that the
   //    pointers are getting scrubbed.

   assert(pUtlMemCheck->delta() == 0);    // check for memory leak
   delete pUtlMemCheck;
}

// Test the manipulator methods
void CommandMsgProcessor::testManipulators()
{
   UtlMemCheck* pUtlMemCheck  = 0;

   pUtlMemCheck = new UtlMemCheck();         // checkpoint for memory leak check

   // test the assignment method (if implemented)
   // test the other manipulator methods for the class

   assert(pUtlMemCheck->delta() == 0);    // check for memory leak
   delete pUtlMemCheck;
}

// Test the accessor methods for the class
void CommandMsgProcessor::testAccessors()
{
   UtlMemCheck* pUtlMemCheck  = 0;

   pUtlMemCheck = new UtlMemCheck();         // checkpoint for memory leak check

   // body of the test goes here

   assert(pUtlMemCheck->delta() == 0);    // check for memory leak
   delete pUtlMemCheck;
}

// Test the inquiry methods for the class
void CommandMsgProcessor::testInquiry()
{
   UtlMemCheck* pUtlMemCheck  = 0;


   pUtlMemCheck = new UtlMemCheck();         // checkpoint for memory leak check

   // body of the test goes here

   assert(pUtlMemCheck->delta() == 0);    // check for memory leak
   delete pUtlMemCheck;
}

#endif //TEST

/* ============================ FUNCTIONS ================================= */
