#ifndef __OBJECT_H
#define __OBJECT_H

#ifndef __IOSTREAM_H
#include <iostream.h>
#endif

#ifndef __CLASSES_H
#include "classes.h"
#endif

#ifndef __STDTYPES_H
#include "stdtypes.h"
#endif

#ifndef __CHECKS_H
#include "checks.h"
#endif

//////////////////////////////////////////////////////////////////////////////
// Object
//////////////////////////////////////////////////////////////////////////////

// @doc EXTERNAL

// @class TObject | Classe base per la definizione della gerarchia degli oggetti
class TObject
// @author:(INTERNAL) Guido
{
  // @access Public Member
public:
  // @cmember Distruttore
  virtual ~TObject()
  {}
  // @cmember Ritorna il nome della classe
  virtual const char* class_name() const;
  // @cmember Ritorna l'id della classe
  virtual word class_id() const;
  // @cmember Controlla se si tratta di un oggetto derivato dalla classe <p cid>
  virtual bool is_kind_of(word cid) const;
  // @cmember Controlla se si tratta di un oggetto valido (sempre TRUE)
  virtual bool ok() const;
  // @cmember Duplica un'oggetto
  virtual TObject* dup() const;
  // @cmember Permette di stampare l'oggetto
  virtual void print_on(ostream& out) const;
  // @cmember Permette di leggere l'oggetto da istream
  virtual void read_from(istream&)
  {}
  // @cmember Ritorna il codice hash dell'oggetto
  virtual word hash() const 
  { return 0; }  
};


//////////////////////////////////////////////////////////////////////////////
// Error Object
//////////////////////////////////////////////////////////////////////////////

// @doc EXTERNAL

// @class TError_Object | Classe per poter ritornare un oggetto sempre errato (ok() == false)
//
// @base public | TObject
class TError_Object : public TObject
// @author:(INTERNAL) Guido
{
  // @access Public Member
public:
  // @cmember Ritorna il nome dell'oggetto
  virtual const char* class_name() const;
  // @cmember Ritorna l'id della classe
  virtual word class_id() const;
  // @cmember Controlla se si tratta di un oggetto derivato dalla classe <p cid>
  virtual bool is_kind_of(word cid) const;  
  // @cmember Controlla se si tratta di un oggetto valido (sempre FALSE)
  virtual bool ok() const;
  
  // @xref <c TObject>  
};


//////////////////////////////////////////////////////////////////////////////
// Error Object
//////////////////////////////////////////////////////////////////////////////


// @class TSortable | Classe per la comparazione degli oggetti
//
// @base public | TObject
class TSortable : public TObject
// @author:(INTERNAL) Guido
{
  // @access Public Memebr
public:
  // @cmember Permette la comparazione degli oggetti
  //          <nl>Ritorna: <gt>0 se <p this> <gt> <p s>
  //          <nl>         0  se <p this> == <p s>
  //          <nl>         <lt>0 se <p this> <lt> <p s>
  //          <nl>         UNDEFINED se l'ordine non e' definito  
  virtual int compare(const TSortable& s) const pure;
  // @cmember Ritorna il nome della classe
  virtual const char* class_name() const;
  // @cmember Ritorna l'id della classe
  virtual word class_id() const;
  // @cmember Controlla se si tratta di un oggetto derivato dalla classe <p cid>
  virtual bool is_kind_of(word cid) const;  
  // @cmember Distruttore
  virtual ~TSortable() 
  {}
};


//////////////////////////////////////////////////////////////////////////////
// inline functions
//////////////////////////////////////////////////////////////////////////////

// @doc EXTERNAL

// @func inline ostream& | operator <lt><lt> | Permette di reindirizzare l'oggeto per la stampa

// @rdesc Ritorna l'output sul quale e' stata reindirizzata la stampa
inline ostream& operator <<(
  ostream& out,       // @parm Indica l'output sul quale stampare l'oggetto
  const TObject& obj) // @parm Oggetto da stampare
{
  obj.print_on(out);
  return out;
}


// @doc EXTERNAL

// @func inline istream& | operator <gt><gt> | Permette di leggere l'oggetto
//
// @rdesc Ritorna l'input dal quale e' stato letto l'oggetto
inline istream& operator >>(
  istream& in,  // @parm Input da cui leggere l'oggetto
  TObject& obj) // @parm Indirizzo in cui posizionare l'oggetto letto

  // @comm Legge dall'input passato come parametro l'oggetto, nel caso si tratti
  //       di un oggetto on valido viene dato un messaggio di errore.
{
  obj.read_from(in);
  CHECK(obj.ok(), "Can't read an Object from a stream");
  return in;
}

// @doc EXTERNAL

// @func inline bool | operator == | Controlla se 2 oggetti sono uguali
//
// @rdesc Ritorna i seguenti valori
//
// @flag TRUE | Se i due oggetti sono uguali
// @flag FALSE | Se i due oggetti sono diversi
inline bool operator ==(
  const TSortable& a, // @parm Primo oggetto da confrontare
  const TSortable& b) // @parm Secondo oggetto da confrontare
  // @comm Controlla se i due oggetti passati come parametro sono uguali
  //       utilizzando il criterio di comparazione previsto per l'oggetto.
{
  int res = a.compare(b);
  return res == 0 || res == UNDEFINED;
}

// @doc EXTERNAL

// @func inline bool | operator <gt> | Controlla se un oggetto e' maggiore dell'altro
//
// @rdesc Ritorna i seguenti valori:
//
// @flag TRUE | Se <p a> e' maggiore di <p b>
// @flag FALSE | Se <p b> e' maggiore o uguale a <p a>
inline bool operator >(
  const TSortable& a, // @parm Primo oggetto da confrontare
  const TSortable& b) // @parm Secondo oggetto da confrontare

  // @comm Controlla se l'oggetti passato come primo parametro e' maggiore del
  //       secondo utilizzando il criterio di comparazione previsto per l'oggetto.
{
  int res = a.compare(b);
  return res > 0 || res == UNDEFINED;
}

// @doc EXTERNAL

// @func inline bool | operator <lt> | Controlla se un oggetto e' minore dell'altro
  // @rdesc Ritorna i seguenti valori
  //
  // @flag TRUE | Se <p a> e' minore di <p b>
  // @flag FALSE | Se <p b> e' minore o uguale a <p a>
inline bool operator <(
  const TSortable& a, // @parm Primo oggetto da confrontare
  const TSortable& b) // @parm Secondo oggetto da confrontare

  // @comm Controlla se l'oggetti passato come primo parametro e' minore del
  //       secondo utilizzando il criterio di comparazione previsto per l'oggetto.
{
  int res = a.compare(b);
  return res < 0 || res == UNDEFINED;
}

// @doc EXTERNAL

// @func inline bool | operator <gt>= | Controlla se un oggetto e' maggiore o uguale all'altro
// @rdesc Ritorna i seguenti valori
//
// @flag TRUE | Se <p a> e' maggiore o uguale a <p b>
// @flag FALSE | Se <p b> e' maggiore <p a>
inline bool operator >=(
  const TSortable& a, // @parm Primo oggetto da confrontare
  const TSortable& b) // @parm Secondo oggetto da confrontare

  //
  // @comm Controlla se l'oggetti passato come primo parametro e' maggiore o uguale al
  //       secondo utilizzando il criterio di comparazione previsto per l'oggetto.
{
  int res = a.compare(b);
  return res >= 0 || res == UNDEFINED;
}

// @doc EXTERNAL

// @func inline bool | operator <lt>= | Controlla se un oggetto e' minore o uguale all'altro
  // @rdesc Ritorna i seguenti valori
  //
  // @flag TRUE | Se <p a> e' minore o uguale a <p b>
  // @flag FALSE | Se <p b> e' minore <p a>
inline bool operator <=(
  const TSortable& a, // @parm Primo oggetto da confrontare
  const TSortable& b) // @parm Secondo oggetto da confrontare

  // @comm Controlla se l'oggetti passato come primo parametro e' minore o uguale al
  //       secondo utilizzando il criterio di comparazione previsto per l'oggetto.
{
  int res = a.compare(b);
  return res <= 0 || res == UNDEFINED;
}

// @doc EXTERNAL

// @func inline bool | operator != | Controlla se 2 oggetti sono diversi
//
// @rdesc Ritorna i seguenti valori
//
// @flag TRUE | Se i due oggetti sono diversi
// @flag FALSE | Se i due oggetti sono uguali
inline bool operator !=(
  const TSortable& a, // @parm Primo oggetto da confrontare
  const TSortable& b) // @parm Secondo oggetto da confrontare

  // @comm Controlla se i due oggetti passati come parametro sono diversi
  //       utilizzando il criterio di comparazione previsto per l'oggetto.
{
  int res = a.compare(b);
  return res != 0 && res != UNDEFINED;
}

#ifdef __OBJECT_CPP
#define extern
#endif

extern TError_Object error_object;

#undef extern

#endif // __OBJECT_H