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

StringMessage::StringMessage(int maxStringBytes, char tokenDelimiter)
{
  _maxStringBytes = maxStringBytes;
  _tokenDelimiter = tokenDelimiter;

  if ((_buffer = (char *)malloc(_maxStringBytes+1)) == 0) {
    throw Exception("StringMessage::StringMessage() - malloc() #1 failed");
  }
  if ((_token = (char *)malloc(_maxStringBytes+1)) == 0) {
    throw Exception("StringMessage::StringMessage() - malloc() #2 failed");
  }

  _bufferEnd = _buffer + _maxStringBytes;

  reset();
}


StringMessage::~StringMessage()
{
  free((void *)_buffer);
  free((void *)_token);
}


int StringMessage::maxStringBytes()
{
  return _maxStringBytes;
}


void StringMessage::reset()
{
  _bufferPtr = _buffer;
}


void StringMessage::set(CharData *charData)
{
  addToken(charData->ascii());
}


void StringMessage::set(ShortData *shortData)
{
  addToken(shortData->ascii());
}


void StringMessage::set(IntegerData *integerData)
{
  addToken(integerData->ascii());
}


void StringMessage::set(FloatData *floatData)
{
  addToken(floatData->ascii());
}


void StringMessage::set(DoubleData *doubleData)
{
  addToken(doubleData->ascii());
}

void StringMessage::set(StringData *stringData)
{
  char errorBuf[100];

  if (strchr(stringData->ascii(), _tokenDelimiter) != 0) {
    
    sprintf(errorBuf,
	    "StringMessage::set(string) - string \"%s\" contains delimiter",
	    stringData->ascii());
    throw Exception(errorBuf);
  }

  addToken(stringData->ascii());
}


void StringMessage::set(char *string)
{
  addToken(string);
}


void StringMessage::get(CharData *charData)
{
  charData->parseValue(nextToken());
}


void StringMessage::get(ShortData *shortData)
{
  shortData->parseValue(nextToken());
}


void StringMessage::get(IntegerData *integerData)
{
  integerData->parseValue(nextToken());
}


void StringMessage::get(FloatData *floatData)
{
  floatData->parseValue(nextToken());
}


void StringMessage::get(DoubleData *doubleData)
{
  doubleData->parseValue(nextToken());
}


void StringMessage::get(StringData *stringData)
{
  stringData->parseValue(nextToken());
}


void StringMessage::get(char *string, int stringSize)
{
  strncpy(string, nextToken(), stringSize-1);
  string[stringSize-1] = '\0';
}


void StringMessage::setBuffer(char *buffer)
{
  strncpy(_buffer, buffer, _maxStringBytes);
  _buffer[_maxStringBytes] = '\0';
  reset();
}


void StringMessage::pad(char padChar)
{
  for (char *ptr = _bufferPtr; ptr < _bufferEnd; ptr++) {
    *ptr = padChar;
  }
}


char *StringMessage::buffer()
{
  return _buffer;
}


void StringMessage::addToken(const char *newToken)
{
  if (_bufferPtr + strlen(newToken) > _bufferEnd) {
    throw Exception("StringMessage::addToken() - overflow");
  }

  // Insert token delimiter, if this one's not the first
  if (_bufferPtr > _buffer) {
    *_bufferPtr = _tokenDelimiter;
    _bufferPtr++;
  }

  strcpy(_bufferPtr, newToken);
  _bufferPtr += strlen(_bufferPtr);
}



char *StringMessage::nextToken()
{
  if (_bufferPtr >= _buffer + _maxStringBytes) {
    // Already at end; no more tokens
    throw Exception("StringMessage::nextToken() - no more tokens");
  }

  char *endOfToken;
  // Look for token delimiter
  if ((endOfToken = strchr(_bufferPtr, _tokenDelimiter)) == 0) {
    // Last token, so "end of token" is last byte in string
    endOfToken = _bufferEnd;
  }

  // Copy token from buffer into _token
  strncpy(_token, _bufferPtr, endOfToken - _bufferPtr);

  // Append null terminator to token
  _token[endOfToken - _bufferPtr] = '\0';

  // Advance ptr past delimiter
  _bufferPtr = endOfToken + 1;

  return _token;
}




