/* 
This sample decodes a message and demonstrates how a user-defined callback
can be used to intercept output that would otherwise go to stdout.  To
achieve this functionality the objects must be generated with the
-prttostrm qualfiier to the asn1c command.  

In this particular sample the message is a CSTA answer call request
message, but the callback mechanisms work for any object generated
with the -prttostrm qualifier.
*/

#include <stdio.h>
#include <stdlib.h>
#include "CSTA-ROSE-PDU-types.h"
#include "CSTA-answer-call.h"

#define MAXMSGLEN 1024

/* User callback function to intercept output.  Note that the first
   argument can be anything (see the callback registration below).  */

void writeToFile(void* pPrntStrmInfo, const char* fmtspec, 
                 va_list arglist);

int main (int argc, char** argv)
{
   OSOCTET msgbuf[MAXMSGLEN];
   OSBOOL trace = TRUE;
   FILE *fp, *fpLog;
   const char* filename = "message.dat";
   int i, len, stat;

   /* Process command line arguments */

   if (argc > 1) {
      for (i = 1; i < argc; i++) {
         if (!strcmp (argv[i], "-v")) trace = TRUE;
         else if (!strcmp (argv[i], "-i")) filename = argv[++i];
         else if (!strcmp (argv[i], "-notrace")) trace = FALSE;
         else {
            printf ("usage: reader [ -v ] [ -i <filename>\n");
            printf ("   -v  verbose mode: print trace info\n");
            printf ("   -i <filename>  read encoded msg from <filename>\n");
            printf ("   -notrace  do not display trace info\n");
            return 0;
         }
      }
   }

   /* Read input file into a memory buffer */

   /* Note that g++ on Linux suggests the inner parentheses around the
      "assignment used as truth value".  I disagree, but here they are to
      eliminate the warning message.  */
   if ((fp = fopen (filename, "rb"))) {
      len = fread (msgbuf, 1, sizeof(msgbuf), fp);
   }
   else {
      printf ("Error opening %s for read access\n", filename);
      return -1;
   }

   /* Set up logging */
   if((fpLog = fopen("reader.log", "w")))
   {
      /* Here the callback function is registered as a global
         print handler. This means all print/debug streams
         will be passed to this handler.
      */
      rtxSetGlobalPrintStream(&writeToFile, (void *) fpLog);
   }
   else
   {
      printf("Failed to setup logging\n");
      return -1;
   }
   
   /* Set up a decode buffer. */

   ASN1BERDecodeBuffer decodeBuffer (msgbuf, len);

   /* Decode ROSE header */

   ASN1T_CSTA_ROSE_PDU rosepdu;
   ASN1C_CSTA_ROSE_PDU rosepduC (decodeBuffer, rosepdu);

   stat = rosepduC.Decode ();

   if (trace) {
      decodeBuffer.binDump ();
   }

   if (stat == 0) {
      if (trace) {
         printf ("Decoding was successful. See reader.log for details.\n");
         rosepduC.toStream ("RoseHeader_AnswerCallArgument");
      }
   }
   else {
       decodeBuffer.printErrorInfo ();
       return -1;
   }

   /*
     Decode the CSTA message contained within the ROSE header.  For the purposes
     of this sample, we will assume that the message file we're reading was
     created by the writer program that corresponds to this reader program.  So
     we will expect the ROSE header to contain an invoke object as opposed to
     a return result object.  If it's not an invoke object, we'll just exit.
   */

   if (rosepdu.t != T_CSTA_ROSE_PDU_invoke) {
      printf("ROSE header of decoded message does not contain an invoke object.\n");
      exit(0);
   }

   /*
     Similarly we will assume that the opcode in the ROSE header is a local opcode
     and is the opcode for Answer Call.  If it isn't, we'll just exit.
   */

   if (rosepdu.u.invoke->opcode.t != T_Code_local) {
      printf("Opcode in ROSE header of decoded message is not a local opcode.\n");
      exit(0);
   }
   if (rosepdu.u.invoke->opcode.u.local != 2) { // AnswerCall opcode
      printf("Opcode in ROSE header of decoded message is not an AnswerCall opcode.\n");
      exit(0);
   }

   /* Now decode the actual CSTA message.  */

   ASN1BERDecodeBuffer decodeBuffer2(rosepdu.u.invoke->argument.data, 
      rosepdu.u.invoke->argument.numocts);
   ASN1T_AnswerCallArgument cstapdu;
   ASN1C_AnswerCallArgument cstapduC(decodeBuffer2, cstapdu);
   stat = cstapduC.Decode();
   if (trace) {
      decodeBuffer2.binDump ();
   }

   if (stat == 0) {
      if (trace) {
         printf ("Decoding was successful. See reader.log for details.\n");
         cstapduC.toStream ("AnswerCallArgument");
      }
   }
   else {
       decodeBuffer2.printErrorInfo ();
       return -1;
   }

   return 0;
}

