#include "oop.h"

#include <stdio.h>
#include <stdarg.h>
#include <ctype.h>


#define method(type, name, args, value)									\
  type Object::name args										\
  {													\
    if (!this)												\
      fprintf(stderr, "send to nil\n");									\
    else												\
      fprintf(stderr, "'%s' does not understand '%s %s%s'\n", _debugName(), #type, #name, #args);	\
    abort();												\
    return value;											\
  }
#include "oop-methods.h"
#undef method

#undef className
#define className(name)				\
  int Object::is##name(void)			\
  {						\
    return 0;					\
  }
#include "oop-classes.h"
#undef className


oop Object::error(char *fmt, ...)
{
  va_list ap;
  va_start(ap, fmt);
  vfprintf(stderr, fmt, ap);
  va_end(ap);
  fprintf(stderr, "\n");
  abort();
  return this;
}

unsigned Object::hash(void)
{
  return identityHash();
}

unsigned Object::identityHash(void)
{
  return (unsigned)this >> 4;
}

int Object::operator ==(oop other)
{
  return this == other;
}

int Object::operator !=(oop other)
{
  return !(*this == other);
}

oop Object::speciesNew(int n)
{
  return classNew(n);
}

oop Object::printString(void)
{
  oop aStream= (new String)->writeStream();
  printOn(aStream);
  return aStream->contents();
}

char *Object::printCString(void)
{
  return printString()->cString();
}

oop Object::printOn(oop aStream)
{
  char *name= _debugName();
  aStream->nextPut(Character::value('a'));
  switch (toupper(name[0]))
    {
    case 'A': case 'E': case 'I': case 'O': case 'U':
      aStream->nextPut(Character::value('n'));
    }
  aStream->nextPutAll(new String(name));
  return this;
}

