#ifndef _JSTACK_H
#define _JSTACK_H

#include <cstdlib>
#include <cstring>

using namespace std;

struct stack_exception { 
   const char * message;
   stack_exception(const char * msg) { message = msg; }
};

class Stack {
   char * buffer;
   char * pointer;
   size_t the_size;
   size_t current_size;

public:
   Stack(char * sp, size_t sz) { 
      the_size = sz;
      buffer = sp;
      memset(buffer, 0, the_size);
      pointer = buffer; 
      current_size = 0U;
   }

   virtual ~Stack() {

   }

   void push_int(int i) {
      *((int*)pointer)  = i;
      pointer += sizeof(int);
      current_size += sizeof(int);
   }
   void push_short(short s) {
      *((short*)pointer)  = s;
      pointer += sizeof(short);
      current_size += sizeof(short);
   }
   void push_float(float f) {
      *((float*)pointer)  = f;
      pointer += sizeof(float);
      current_size += sizeof(float);
   }
   void push_long(long long l) {
      *((long long*)pointer)  = l;
      pointer += sizeof(long long);
      current_size += sizeof(long long);
   }
   void push_double(double d) {
      *((double*)pointer)  = d;
      pointer += sizeof(double);
      current_size += sizeof(double);
   }
   void push_pointer(char * p) {
      *((char**)pointer)  = p;
      pointer += sizeof(char*);
      current_size += sizeof(char*);
   }
   void push_byte(char arg) {
      *((char*)pointer)  = arg;
      pointer += sizeof(char);
      current_size += sizeof(char);
   }
   void push_boolean(bool arg) {
      *((bool*)pointer)  = arg;
      pointer += sizeof(bool);
      current_size += sizeof(bool);
   }
   void push_char(char arg) {
      *((char*)pointer)  = arg;
      pointer += sizeof(char);
      current_size += sizeof(char);
   }

   int top_int() {
      if(current_size > 0) {
         char * ptr = pointer - sizeof(int);
         return *(int*)ptr;
      }
      return -1;
   }
   short top_short() {
      if(current_size > 0) {
         char * ptr = pointer - sizeof(short);
         return *(short*)ptr;
      }
      return -1;
   }
   float top_float() {
      if(current_size > 0) {
         char * ptr = pointer - sizeof(float);
         return *(float*)ptr;
      }
      return -1.0F;
   }
   long long top_long() {
      if(current_size > 0) {
         char * ptr = pointer - sizeof(long long);
         return *(long long*)ptr;
      }
      return -1;
   }
   double top_double() {
      if(current_size > 0) {
         char * ptr = pointer - sizeof(double);
         return *(double*)ptr;
      }
      return -1.0;
   }
   char top_char() {
      if(current_size > 0) {
         char * ptr = pointer - sizeof(char);
         return *(char*)ptr;
      }
      return -1;
   }
   char * top_pointer() {
      char * ptr = pointer - sizeof(char*);
      return *(char**)ptr;
   }
   bool top_boolean() {
      if(current_size > 0) {
         char * ptr = pointer - sizeof(bool);
         return *(bool*)ptr;
      }
      return false;
   }


   void pop_int() {
      if(current_size > 0) {
         pointer -= sizeof(int);
         current_size -= sizeof(int);
      }
      else {
         throw stack_exception("pop_int"); 
      }
   }
   void pop_short() {
      if(current_size > 0) {
         pointer -= sizeof(short);
         current_size -= sizeof(short);
      }
      else {
         throw stack_exception("pop_short");
      }
   }
   void pop_float() {
      if(current_size > 0) {
         pointer -= sizeof(float);
         current_size -= sizeof(float);
      }
      else {
         throw stack_exception("pop_float");
      }
   }
   void pop_long() {
      if(current_size > 0) {
         pointer -= sizeof(long long);
         current_size -= sizeof(long long);
      }
      else {
         throw stack_exception("pop_long");
      }
   }
   void pop_double() {
      if(current_size > 0) {
         pointer -= sizeof(double);
         current_size -= sizeof(double);
      }
      else {
         throw stack_exception("pop_double");
      }
   }
   void pop_pointer() {
      if(current_size > 0) {
         pointer -= sizeof(char*);
         current_size -= sizeof(char*);
      }
      else {
         throw stack_exception("pop_pointer");
      }
   }
   void pop_boolean() {
      if(current_size > 0) {
         pointer -= sizeof(bool);
         current_size -= sizeof(bool);
      }
      else {
         throw stack_exception("pop_boolean");
      }
   }
   void pop_char() {
      if(current_size > 0) {
         pointer -= sizeof(char);
         current_size -= sizeof(char);
      }
      else {
         throw stack_exception("pop_char");
      }
   }

   size_t size() {
      return the_size;
   }
};

#endif
