/*
 * writemarc.c,v 1.1 1994/01/28 17:06:43 franktor Exp
 */

#include <string.h>
#include <stdio.h>
#include <malloc.h>
#include <memory.h>
#include <sr-general.h>
#include <marc.h>
#ifndef __CEXTRACT__
#include <marcproto.h>
#endif
#ifdef __sun__
#include <sunos.h>
#endif

/*
 * writemarc(): Allocates a big enough octetstring, writes a
 * marcpost to it according to ISO-2709 and returns the octetstring.
 */

octetString *
WriteMarcData(Marcrecord *rec)
{
  Marcdata *entry;
  octetString *os, lbl;
  char format[MAX_BUF];
  char buf[MAX_BUF];
  unsigned long pos;	/* Just to keep track of current position */

  /*
   * Add label to length of data:
   */

  os = (octetString *) malloc(sizeof(octetString));
  os->len = Pos_directory;
  
  /*
   * Add length of all directories to length of data:
   */
  for (entry = rec->entries; entry != (Marcdata *) NULL; entry = entry->next)
    os->len += TAG_LENGTH + DATAFIELD_LENGTH;

  os->len += 1; /* FIELD_SEPARATOR after Directory */

  /*
   * Add length of all records to length of data:
   * (And also initialize the record positions in the record structure)
   */
  for (entry = rec->entries; entry != (Marcdata *) NULL; entry = entry->next)
  {
    entry->starting_character_position = os->len;
    os->len += entry->length_of_datafield + 1; /* 1 for FIELD_SEPARATOR */
    if (entry->indicators == True) /* If the indicators are separated */
      os->len += 2;
  }

  os->len += 1; /* 1 for RECORD_SEPPARATOR */
  os->value = (char *) malloc(os->len * sizeof(char));

  lbl = WriteMarcData_Label(&rec->label);
  (void) memcpy(os->value, lbl.value, lbl.len);
  free (lbl.value);

  *(os->value + Pos_directory) = '\0';	/* I want to use strcat() */

  if (rec->label.directory_map_length + rec->label.directory_map_start !=
      DATAFIELD_LENGTH)
    fprintf(stderr, "Warning: Nonstandard (!= %d) length of directory!\n",
            DATAFIELD_LENGTH);
  
  sprintf(format, "%%0%dlu%%0%lulu%%0%lulu", TAG_LENGTH,
          rec->label.directory_map_length, rec->label.directory_map_start);
  
  /*
   * Copy all directory entries into the buffer.
   */
  for (entry = rec->entries; entry != (Marcdata *) NULL; entry = entry->next)
  {
    sprintf(buf, format, entry->tag, entry->length_of_datafield +
            ((entry->indicators == True) ? (unsigned)2 : (unsigned)0),
            entry->starting_character_position);
#ifdef DEBUG
    fprintf(stderr, "Length/Start: %d/%d\n",
            entry->length_of_datafield, entry->starting_character_position);
#endif
    strcat(os->value,buf);
  }
  pos = strlen(os->value);
#ifdef DEBUG
  fprintf(stderr, "End of directory at %d\n", pos);
#endif
  *(os->value + pos++) = FIELD_SEPARATOR;

  /*
   * Copy all the data into the buffer.
   */
  for (entry = rec->entries; entry != (Marcdata *) NULL; entry = entry->next)
  {
    pos = entry->starting_character_position + entry->length_of_datafield;
    if (entry->indicators == True)
    {
      *(os->value + entry->starting_character_position) = entry->indicator1;
      *(os->value + entry->starting_character_position + 1) = entry->indicator2;
      pos += 2;
    }
    (void) memcpy(os->value + entry->starting_character_position +
                  ((entry->indicators == True) ? 2 : 0), entry->data,
                  entry->length_of_datafield);
    *(os->value + pos++) = FIELD_SEPARATOR;
  }
  *(os->value + pos++) = RECORD_SEPARATOR;
  os->len = pos;
  /*
   * Now I know for certain the length of the record, so update the first
   * five bytes to reflect that.
   */
  sprintf(format, "%%0%dd", Len_record_length);
  sprintf(buf, format, os->len);
  (void) memcpy(os->value, buf, Len_record_length);
#ifdef DEBUG
  if (os->len != rec->label.record_length)
    fprintf(stderr, "Warning, mismatch in length: %d != %d\n",
            rec->label.record_length, os->len);
#endif
  return os;
}

/*
 * WriteMarcData_Label copies the information in the label-structure
 * into an allocated char array, and returns the pointer to a static
 * octetString containing a pointer to that array.
 */

octetString
WriteMarcData_Label(Record_label *label)
{
  static octetString os;
  char format[MAX_BUF];

  os.len = Len_label + 1; /* +1 since sprintf adds \0 */
  os.value = (char *) malloc(os.len * sizeof(char));

  if (label->directory_map_length + label->directory_map_start != DATAFIELD_LENGTH)
  {
    fprintf(stderr, "Error, label seems uninitialized.\n");
    return os;
  }

  /*
   * Now I just write the whole Record_label with one huge sprintf()
   */
  
  sprintf(format, "%%0%dd%%c%%%ds%%0%dd%%0%dd%%0%dd%%%ds%%0%dd%%0%dd%%%ds",
          Len_record_length,
/*
          Len_record_status,
*/
          Len_implementation_codes,
          Len_indicator_length,
          Len_identifier_length,
          Len_base_address_of_data,
          Len_reserved_user_systems,
          Len_directory_map_length,
          Len_directory_map_start,
          Len_reserved_future);
  sprintf(os.value, format,
          label->record_length,
          label->record_status,
          label->implementation_codes,
          label->indicator_length,
          label->identifier_length,
          label->base_address_of_data,
          label->reserved_user_systems,
          label->directory_map_length,
          label->directory_map_start,
          label->reserved_future);
  return os;
}
