/* This test driver program encodes a data record and writes the        */
/* encoded result to an output file..                                   */

#include <stdio.h>
#include <stdlib.h>
#include "CSTA-ROSE-PDU-types.h"
#include "CSTA-event-report-definitions.h"

#define MAXMSGLEN 1024

static int encodeEventReportRequest (ASN1BEREncodeBuffer& encodeBuffer);

static int encodeROSEInvokeHeader (ASN1BEREncodeBuffer& encodeBuffer, 
                                   int msglen);

int main (int argc, char** argv)
{
   /* Run-time support variables */

   const OSOCTET* msgptr;
   OSOCTET	msgbuf[MAXMSGLEN];
   int		i, len;
   FILE*        fp;
   const char*        filename = "message.dat";
   OSBOOL     trace = TRUE;

   /* 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], "-o")) filename = argv[++i];
         else if (!strcmp (argv[i], "-notrace")) trace = FALSE;
         else {
            printf ("usage: writer [ -v ] [ -o <filename>\n");
            printf ("   -v  verbose mode: print trace info\n");
            printf ("   -o <filename>  write encoded msg to <filename>\n");
            printf ("   -notrace  do not display trace info\n");
            return 0;
         }
      }
   }


      /* Initialize the encoding context */

      ASN1BEREncodeBuffer encodeBuffer (msgbuf, sizeof(msgbuf));

      /* Encode operation argument */

      if ((len = encodeEventReportRequest (encodeBuffer)) < 0) return len;

      /* Encode ROSE header on top of encoded argument */

      if ((len = encodeROSEInvokeHeader (encodeBuffer, len)) < 0) return len;

      msgptr = encodeBuffer.getMsgPtr();

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

      /* Write the encoded message out to the output file */

      /* 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, "wb"))) {
         fwrite (msgptr, 1, len, fp);
         fclose (fp);
      }
      else {
         printf ("Error opening %s for write access\n", filename);
         return -1;
      }

   return 0;

}

/* Encode "Established" event for "cSTAEventReport" operation */

static int encodeEventReportRequest (ASN1BEREncodeBuffer& encodeBuffer)
{
   ASN1T_cerd_CSTAEventReportArgument eventReportArg;
   ASN1C_cerd_CSTAEventReportArgument eventReportArgC(encodeBuffer, eventReportArg);
   int len;

   /* To make it simple, we will omit all of the optional fields */
   ASN1T_EstablishedEvent established;

   /* EstablishedEvent.establishedConnection */
   ASN1T_ConnectionID_both both;
   both.callID.numocts = 1;
   OSOCTET data1 = 0x10;
   both.callID.data = &data1;
   ASN1T_DeviceID staticID;
   staticID.deviceIdentifier.t = T_DeviceID_deviceIdentifier_dialingNumber;
   staticID.deviceIdentifier.u.dialingNumber = "22343";
   both.deviceID.t = T_LocalDeviceID_staticID;
   both.deviceID.u.staticID = &staticID;
   established.establishedConnection.t = T_ConnectionID_both;
   established.establishedConnection.u.both = &both;

   /* EstablishedEvent.answeringDevice */
   ASN1T_DeviceID deviceId2;
   deviceId2.deviceIdentifier.t = T_DeviceID_deviceIdentifier_dialingNumber;
   deviceId2.deviceIdentifier.u.dialingNumber = "22343";
   established.answeringDevice.t = T_SubjectDeviceID_deviceIdentifier;
   established.answeringDevice.u.deviceIdentifier = &deviceId2; 

   /* EstablishedEvent.callingDevice */
   ASN1T_DeviceID deviceId3;
   deviceId3.deviceIdentifier.t = T_DeviceID_deviceIdentifier_dialingNumber;
   deviceId3.deviceIdentifier.u.dialingNumber = "14085551212";
   established.callingDevice.t = T_CallingDeviceID_deviceIdentifier;
   established.callingDevice.u.deviceIdentifier = &deviceId3; 

   /* EstablishedEvent.calledDevice */
   ASN1T_DeviceID deviceId4;
   deviceId4.deviceIdentifier.t = T_DeviceID_deviceIdentifier_dialingNumber;
   deviceId4.deviceIdentifier.u.dialingNumber = "22343";
   established.calledDevice.t = T_CalledDeviceID_deviceIdentifier;
   established.calledDevice.u.deviceIdentifier = &deviceId4; 

   /* EstablishedEvent.lastRedirectionDevice */
   ASN1T_DeviceID deviceId9;
   deviceId9.deviceIdentifier.t = T_DeviceID_deviceIdentifier_dialingNumber;
   deviceId9.deviceIdentifier.u.dialingNumber = "22343";
   established.lastRedirectionDevice.t = T_RedirectionDeviceID_numberdialed;
   established.lastRedirectionDevice.u.numberdialed = &deviceId9;

   established.m.localConnectionInfoPresent = 1;
   established.localConnectionInfo = LocalConnectionState::connected;
   established.cause = EventCause::normal;

   /* EstablishedEvent.networkCallingDevice */
   ASN1T_DeviceID deviceId5;
   deviceId5.deviceIdentifier.t = T_DeviceID_deviceIdentifier_dialingNumber;
   deviceId5.deviceIdentifier.u.dialingNumber = "14085551212";
   established.m.networkCallingDevicePresent = 1;
   established.networkCallingDevice.t = T_NetworkCallingDeviceID_deviceIdentifier;
   established.networkCallingDevice.u.deviceIdentifier = &deviceId5; 

   /* EstablishedEvent.networkCalledDevice */
   ASN1T_DeviceID deviceId6;
   deviceId6.deviceIdentifier.t = T_DeviceID_deviceIdentifier_dialingNumber;
   deviceId6.deviceIdentifier.u.dialingNumber = "18001234567";
   established.m.networkCalledDevicePresent = 1;
   established.networkCalledDevice.t = T_NetworkCalledDeviceID_deviceIdentifier;
   established.networkCalledDevice.u.deviceIdentifier = &deviceId6; 

   /* EstablishedEvent.associatedCallingDevice */
   ASN1T_DeviceID deviceId7;
   deviceId7.deviceIdentifier.t = T_DeviceID_deviceIdentifier_dialingNumber;
   deviceId7.deviceIdentifier.u.dialingNumber = "023";
   established.m.associatedCallingDevicePresent = 1;
   established.associatedCallingDevice.t = T_AssociatedCallingDeviceID_deviceIdentifier;
   established.associatedCallingDevice.u.deviceIdentifier = &deviceId7; 

   /* CallControlEvents.EstablishedEvent */
   ASN1T_cerd_CallControlEvents callControlEvents;
   callControlEvents.t = T_cerd_CallControlEvents_established;
   callControlEvents.u.established = &established;

   /* CSTAEventReportArgument */
   eventReportArg.crossRefIdentifier.numocts = 1;
   OSOCTET data2 = 0x99;
   eventReportArg.crossRefIdentifier.data = &data2;
   eventReportArg.eventSpecificInfo.t = T_cerd_EventSpecificInfo_callControlEvents;
   eventReportArg.eventSpecificInfo.u.callControlEvents = &callControlEvents;

   /* Encode */

   len = eventReportArgC.Encode();

   if (len < 0) {
      printf ("Encode of CSTAEventReportArgument failed.\n");
      encodeBuffer.printErrorInfo();
   }

   return len;
}

/* Encode ROSE header */

static int encodeROSEInvokeHeader (ASN1BEREncodeBuffer& encodeBuffer, 
                                   int msglen)
{
   ASN1T_CSTA_ROSE_PDU pdu;
   ASN1C_CSTA_ROSE_PDU pduC (encodeBuffer, pdu);
   ASN1T_CSTA_ROSE_PDU_invoke invoke;
   int len;

   /* Populate header structure */

   invoke.m.argumentPresent = 1;
   invoke.invokeId.t = T_InvokeId_present;
   invoke.invokeId.u.present = 1; /* arbitrary number: should be unique */
   invoke.opcode.t = T_Code_local;
   invoke.opcode.u.local = 21;   /* opeartion code for "cSTAEventReport" operation from Table 1 */

   /* This is where we get the previously encoded message component..   */
   invoke.argument.numocts = msglen;
   invoke.argument.data = (OSOCTET*) encodeBuffer.getMsgPtr();

   pdu.t = T_CSTA_ROSE_PDU_invoke;
   pdu.u.invoke = &invoke;

   /* Encode */

   len = pduC.Encode();

   if (len < 0) {
      printf ("Encode ROSE PDU failed.\n");
      encodeBuffer.printErrorInfo();
   }

   return len;
}
