//===--------------- PrintBuffer.h - Printing objects ----------------------===//
//
//                     The Micro Virtual Machine
//
// This file is distributed under the University of Illinois Open Source 
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//

#ifndef MVM_PRINTBUFFER_H
#define MVM_PRINTBUFFER_H

#include <cstdio> // sprintf
#include <cstring> // memcpy

#include "types.h"
#include "mvm/Object.h"
#include "mvm/UTF8.h"

namespace mvm {

/// PrintBuffer - This class is a buffered string.
///
class PrintBuffer {
public:
 
  /// contents - The buffer.
  ///
  char* contents;

  /// capacity - The capacity of the current buffer.
  ///
  uint32  capacity;

  /// writePosition - The position in the buffer where the next write will
  /// happen.
  ///
  uint32  writePosition;

	void init() {
		capacity = 256;
		contents = new char[capacity];
		writePosition = 0;
	}

public:
	PrintBuffer() {
		init();
	}

	template <class T>
	PrintBuffer(const T *obj) {
		init();
		writeObj(obj);
	}

	PrintBuffer(const Object *obj) {
		llvm_gcroot(obj, 0);
		init();
		writeObj(obj);
	}

	virtual ~PrintBuffer() {
		delete[] contents;
	}
	
	char *cString() {
		return contents;
	}

	void ensureCapacity(uint32 len) {
		uint32 size = writePosition + len + 1;
    if (size >= capacity) {
      while (size >= capacity)
        capacity*= 4;
			char *newContents = new char[capacity];
			memcpy(newContents, contents, writePosition);
			delete[] contents;
			contents = newContents;
    }
	}

  /// write - Writes to this PrintBuffer.
  ///
  virtual PrintBuffer *write(const char *string) {
    uint32 len= strlen(string);
		ensureCapacity(len);
    strcpy(cString() + writePosition, string);
    writePosition+= len;
    return this;
  }

  /// writeChar - Writes a char.
  inline PrintBuffer *writeUTF8(const UTF8 *utf8) {
		uint32 len = utf8->size;
		ensureCapacity(len);
		for(uint32 i=0; i<len; i++) {
			//			printf("%d/%d: '%c (%d)'\n", i, len, utf8->elements[i], utf8->elements[i]);
			contents[writePosition + i] = utf8->elements[i];
		}
		contents[writePosition += len] = 0;
		return this;
  }

  /// writeChar - Writes a char.
  inline PrintBuffer *writeBool(bool v) {
		return write(v ? "true" : "false");
  }

  /// writeChar - Writes a char.
  inline PrintBuffer *writeChar(char v) {
    char buf[32];
    sprintf(buf, "%c", v);
    return write(buf);
  }

  /// writeChar - Writes a int32.
  inline PrintBuffer *writeS4(int v) {
    char buf[32];
    sprintf(buf, "%d", v);
    return write(buf);
  }
  
  /// writes8 - Writes a int64.
  inline PrintBuffer *writeS8(sint64 v) {
    char buf[32];
    sprintf(buf, "%lld", (long long int)v);
    return write(buf);
  }
  
  /// writeFP - Writes a double.
  inline PrintBuffer *writeFP(double v) {
    char buf[32];
    sprintf(buf, "%f", v);
    return write(buf);
  }

  /// writePtr - Writes a pointer.
  inline PrintBuffer *writePtr(void *p) {
    char buf[32];
    sprintf(buf, "%p", p);
    return write(buf);
  }

  /// writeBytes - Writes len bytes in the buffer bytes.
  inline PrintBuffer *writeBytes(unsigned char *bytes, size_t len) {
    write("[");
    for (size_t idx= 0; idx < len; ++idx) {
      if (idx > 0)
        write(" ");
      char buf[32];
      sprintf(buf, "%d", bytes[idx]);
      write(buf);
    }
    write("]");
    return this;
  }

  /// writeObj - Writes anything (except an object) to the buffer.
  ///
	template <class T>
  inline PrintBuffer *writeObj(const T *obj) {
		obj->print(this);
		return this;
	}

  /// writeObj - Writes a gc Object to the buffer.
  ///
  inline PrintBuffer *writeObj(const Object *obj) {
		llvm_gcroot(obj, 0);
		obj->print(this);
		return this;
	}


  /// replaceWith - replace the content of the buffer and free the old buffer
  ///
	void replaceWith(char *buffer) {
		delete[] this->contents;
		this->contents = buffer;
	}
};

} // end namespace mvm

#endif // MVM_PRINTBUFFER_H
