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

#include <stdio.h>
#include <stdlib.h>
#include "ACSE-1.h"

#define MAXMSGLEN 1024

static int encodeACSEConnectionRequest (ASN1BEREncodeBuffer& encodeBuffer);

/* These two function declarations are blocked out to avoid a compiler warning,
   but they're here for reference.  */
   
#if 0
static int encodeACSEReleaseRequest (ASN1BEREncodeBuffer& encodeBuffer);
static int encodeACSEAbort (ASN1BEREncodeBuffer& encodeBuffer);
#endif

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 ACSE */
      /* 
         To make connection call encodeACSEConnectionRequest()
         To release connection call encodeACSEReleaseRequest()
         To abort connection call encodeACSEAbort()
      */
      
      if ((len = encodeACSEConnectionRequest (encodeBuffer)) < 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 ACSE Connection Request 

The ACSE_apdu.aarq(request) is transmitted and the CSTA Application waits for 
for an ACSE_apdu.aare(response). If a response is 
received then the connection is available for CSTA Applications to use.

Avaliable connection can be relased in 2 way: 1) Release request 2) Abort connection
*/

static int encodeACSEConnectionRequest (ASN1BEREncodeBuffer& encodeBuffer)
{
   ASN1T_AARQ_apdu aarq_apdu;
   int len;
  
   /*
   set CSTA 3 OID value, for CSTA 3 communication 
   { iso( 1) identified-organization( 3) icd-ecma( 12)
	standard( 0) csta3( 285) application-context-information( 200) }
   */
   ASN1OBJID csta3oid = { 6, {1, 3, 12, 0, 285, 200 } };
   aarq_apdu.aSO_context_name = csta3oid;

   /*
   For simplicity, following data is ignored

   It is necessary for the requesting and responding systems to specify
   the CSTA services that they support. As with the protocol version information, 
   this is also achieved by carrying additional information in the 
   AARQ_apdu.user-information field of the request and response PDUs. The
   application association requestor shall:
   • list the services required from the serving application;
   • list the services it can supply.
   */

   /* All other optional fields are ignored for simplicity */

   /* Encode */
   ASN1T_ACSE_apdu acse_apdu;
   acse_apdu.t = T_ACSE_apdu_aarq;
   acse_apdu.u.aarq = &aarq_apdu;

   ASN1C_ACSE_apdu pdu(encodeBuffer, acse_apdu);

   len = pdu.Encode();

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

   return len;
}

/* Encode ACSE connection Release Request 

The ACSE_apdu.rlrq(request) is transmitted and the CSTA Application 
waits for an ACSE_apdu.rlre(response). If a response is 
received then the connection is released for CSTA Applications.

*/

/* This function is blocked out to prevent a compiler warning, but it's here
   for reference.  */

#if 0
static int encodeACSEReleaseRequest (ASN1BEREncodeBuffer& encodeBuffer)
{
   ASN1T_RLRQ_apdu rlrq_apdu;
   int len;

   rlrq_apdu.m.reasonPresent = 1;
   rlrq_apdu.reason = Release_request_reason::normal;

   /* All other optional fields are ignored for simplicity. */

   /* Encode */
   ASN1T_ACSE_apdu acse_apdu;
   acse_apdu.t = T_ACSE_apdu_rlrq;
   acse_apdu.u.rlrq = &rlrq_apdu;

   ASN1C_ACSE_apdu pdu(encodeBuffer, acse_apdu);

   len = pdu.Encode();

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

   return len;
}
#endif

/* Encode ACSE connection abort, this is not a Request */

/* This function is blocked out to prevent a compiler warning, but it's here
   for reference.  */

#if 0
static int encodeACSEAbort (ASN1BEREncodeBuffer& encodeBuffer)
{
   ASN1T_ABRT_apdu abrt_apdu;
   int len;

   abrt_apdu.abort_source = ABRT_source::acse_service_user;

   /* All other optional fields are ignored for simplicity. */

   /* Encode */
   ASN1T_ACSE_apdu acse_apdu;
   acse_apdu.t = T_ACSE_apdu_abrt;
   acse_apdu.u.abrt = &abrt_apdu;

   ASN1C_ACSE_apdu pdu(encodeBuffer, acse_apdu);

   len = pdu.Encode();

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

   return len;
}
#endif
