#include "ByteData.hxx"
#include <netinet/in.h>
#include <assert.h>
#include <iostream>

namespace StateFile {

  ByteData::ByteData( void ) { 
    len_ = mask_ = localMem_ = byteLen_ = 0;

    data_ = NULL; 
  }

  ByteData::~ByteData(void) { 
    if (data_) { 
      if (localMem_)
	delete [] data_; 
      data_ = NULL;
    } 
  }

  uint32 ByteData::byteLength( void ) {
    return len_ + byteLen_;
  }

  uint8* ByteData::getData( void ) {
    if (len_ && data_)
      return data_;
    else
      return NULL;
  }

  uint8 ByteData::getData( uint32 index ) {
    if (index < len_)
      return data_[index];
    return 0;
  }

  std::string ByteData::toString( void ) {
    if (data_ && len_)
      return std::string( (char*)data_, len_ );
    return "";
  }

  void ByteData::setData( uint8* data, uint32 size ) {
    setLength(size);
    memcpy( data_, data, len_ );    
  }

  void ByteData::setData( std::string data ) {
    if (localMem_ && data_)
      delete [] data_;

    setSize( data.length() );
    data_ = new uint8[ len_ + 1 ];
    localMem_ = len_ + 1;
    memcpy(data_, data.c_str(), len_);
  }

  void ByteData::setLength( uint32 size ) {
    setSize( size );
    if (!data_ || (localMem_ < len_)) {
      if (data_)
	delete data_;
      data_ = new uint8[ len_ + 1 ];
    } 
    localMem_ = len_ + 1;
    for (uint32 i = 0; i < localMem_; i++)
      data_[i] = 0;
  }
  
  void ByteData::clear( void ) {
    if (localMem_ > 0 && data_) 
      delete [] data_;
    data_ = NULL;
    len_ = localMem_ = 0;
  }


  // return true iff data was read into the buffer
  bool ByteData::fileRead( std::fstream *file, bool skip ) {
    uint32 size = 0;
    
    assert(file != NULL);
    
    if (byteLen_) {
      file->read( (char*)&size, byteLen_ );
      
      if ( byteLen_ > 1 )
	len_ = ntohl( size );
      else
	len_ = size;
    }
    
    if (len_ == 0) {
      if (localMem_ && data_)
	delete [] data_;
      data_ = NULL;
      return false;
    }
    
    assert( (len_ & mask_) == len_ );
    
    if (skip) {
      file->seekg( len_, std::ios::cur );
      clear();
      return false;
    }
    
    if (!data_ || ( localMem_ < len_)) {
      if (data_)
	delete [] data_;
      data_ = new uint8[ len_ + 1 ];
      localMem_ = len_ + 1;
    }
    
    for (uint32 i = 0; i < localMem_; i++) 
      data_[i] = 0;
    
    file->read( (char*)data_, len_ );

    //std::cout << "Data: (" << (int)data_[0] 
    //	      << ")    Len: (" << len_ 
    //	      << ")" << std::endl;
    
    return true;
  }
  
  bool ByteData::fileWrite( std::fstream *file, bool skip) {
    if (!file) return false;
    
    if (skip) {
      uint32 zero = 0;
      file->write( (char*)&zero, byteLen_ );
      return true;
    }
    
    if (byteLen_) {
      uint32 size = len_;
      if (byteLen_ > 1) 
	size = htonl( len_ );
      file->write( (char*)&size, byteLen_ );
    }
    
    if (len_ && data_)
      file->write( (char*)data_, len_ );
    
    return true;
  }

}
