#include <malloc.h>
#include "Exception.h"
#include "FixedFieldStringMessage.h"
#include "CharData.h"
#include "ShortData.h"
#include "IntegerData.h"
#include "FloatData.h"
#include "DoubleData.h"

FixedFieldStringMessage::FixedFieldStringMessage(int maxStringBytes,
						 char padChar) 
  : StringMessage(maxStringBytes, padChar)
{
  _padChar = padChar;
  reset();
}


FixedFieldStringMessage::~FixedFieldStringMessage()
{
}


void FixedFieldStringMessage::addField(int width)
{
  // Check that there is room for another field of specified width in buffer
  int totalWidth = 0;
  for (int i = 0; i < _fieldWidths.size(); i++) {
    int w;
    _fieldWidths.get(i, &w);
    totalWidth += w;
  }

  if (totalWidth + width > maxStringBytes()) {
    throw Exception("FixedFieldStringMessage::addField() - no more space");
  }

  _fieldWidths.add(&width);
  reset();
}


void FixedFieldStringMessage::reset()
{
  StringMessage::reset();
  _field = 0;
  _fieldWidths.get(0, &_fieldWidth);
}


void FixedFieldStringMessage::addToken(const char *newToken)
{
  if (strlen(newToken) > _fieldWidth) {
    char errorBuf[100];

    // Throw exception
    sprintf(errorBuf, "FixedFieldStringMessage::addToken() - "
	    "token \"%s\" exceeds field width (%d)",
	    newToken, _fieldWidth);

    throw Exception(errorBuf);
  }
  strcpy(_bufferPtr, newToken);
  padField();

  advanceField();
}



char *FixedFieldStringMessage::nextToken()
{
  strncpy(_token, _bufferPtr, _fieldWidth);
  // Append null
  _token[_fieldWidth] = '\0';
  advanceField();
  return _token;
}


void FixedFieldStringMessage::padField()
{
  Boolean pad = False;

  // Find terminating null in this field; pad after that
  for (int i = 0; i < _fieldWidth; i++) {
    if (_bufferPtr[i] == '\0') {
      // Pad rest of field
      pad = True;
    }

    if (pad)
      _bufferPtr[i] = _padChar;
  }
}


void FixedFieldStringMessage::advanceField()
{
  if (_field >= _fieldWidths.size()) {
    // Already at end
    return;
  }

  // Advance buffer pointer to next field
  _bufferPtr += _fieldWidth;

  // Get width of next field
  _fieldWidths.get(++_field, &_fieldWidth);
}
