#ifndef __ARRAY_H
#define __ARRAY_H

#ifndef __OBJECT_H
#include <object.h>
#endif

#ifndef NULL
#define NULL 0L
#endif

// @doc EXTERNAL
//
// @type COMPARE_FUNCTION | Prototipo funzione di confronto tra elementi della
//      clsse <c TObject> da passare al metodo sort dei <c TArray>
typedef (*COMPARE_FUNCTION)(const TObject**, const TObject**);

// @doc EXTERNAL
//
// @type CONDITION_FUNCTION | Prototipo funzione di ricerca/filtro
//      per i derivati di <c TObject> da passare ai metodi dei <c TContainer>

typedef bool (*CONDITION_FUNCTION) ( const TObject& );

// @doc EXTERNAL
//
// @type OPERATION_FUNCTION | Prototipo funzione attuatore 
//      da passare ai metodi sort dei <c TContainer>

typedef void (*OPERATION_FUNCTION) ( const TObject& );


// @class TContainer | Generico contenitore ad accesso casuale( con indice )
// @base public | TObject

class TContainer : public TObject
{
  
  // @access Private Member
private:
  
  CONDITION_FUNCTION _last_condition;    
  
  // @access Public Member
public:
  
  // @cmember Ritorna l'indice del primo oggetto
  virtual TObject* first_item( ) pure;
  // @cmember Ritorna l'indice dell'ultimo oggetto
  virtual TObject* last_item( ) pure;
  // @cmember Ritorna l'indice del primo oggetto dopo i
  virtual TObject* succ_item( ) pure;
  // @cmember Ritorna l'indice del primo oggetto che precede i
  virtual TObject* pred_item( ) pure;
  // @cmember Ritorna numero di oggetti nel container
  virtual long objects( ) pure;
  
  virtual void for_each( OPERATION_FUNCTION );    
  virtual void for_each_that( OPERATION_FUNCTION, CONDITION_FUNCTION = NULL );
  
  // @cmember Ritorna il puntatore al primo oggetto che soddisfa la condizione
  virtual TObject* first_that( CONDITION_FUNCTION = NULL );
  // @cmember Ritorna il puntatore all'ultimo oggetto che soddisfa la condizione
  virtual TObject* last_that( CONDITION_FUNCTION = NULL );
  // @cmember Ritorna il prossimo oggetto che soddisfa la condizione. Va usata con first_that per scandire il container
  virtual TObject* succ_that( );
  // @cmember Ritorna il precedente oggetto che soddisfa la condizione. Va usata con last_that per scandire il container all'indietro
  virtual TObject* pred_that( );
  // @cmember Ritorna il numero di elementi che soddisfano la condizione
  virtual long count( CONDITION_FUNCTION = NULL );
  TObject* operator++ (){ return succ_item( ); };
  TObject* operator-- (){ return pred_item( ); };
  
};



// @class TArray | Classe per la definizione degli array
//
// @base public | TObject
class TArray : public TContainer
{

  // @access Private Member

  // @cmember Array di puntatori ad oggetti
  TObject** _data;
  // @cmember Dimensione dell'array
  int _size;
  // @cmember Numero di elementi presenti nell'array
  int _items;
  // @cmember Prossimo elemento libero nell'array
  int _next;
  
  // @cmember Indice per la scansione sequenziale
  int _scanindex;
  
  // @access Protected Member
protected:

  // @cmember Modifica la dimensione dell'array.
  void resize(int newdim);

  // @access Public Member
public:
  // @cmember Costruttore. Crea un array (chiama <mf TArray::resize>)
  TArray(int arraysize);
  // @cmember Costruttore. Crea un array (non chiama <mf TArray::resize>)
  TArray();
  // @cmember Costruttore. Copia tutto l'array e ne duplica gli elementi
  TArray(const TArray&);
  
  // @cmember Distruttore
  virtual ~TArray() ;
  // @cmember Ritorna il nome della classe
  virtual const char* class_name() const ;
  // @cmember Ritorna l'id  della class
  virtual word class_id() const ;
  // @cmember Stampa un array
  virtual void print_on(ostream& out) const ;
  // @cmember Controlla se si tratta di un oggetto valido
  virtual bool ok() const ;

  // @cmember Ritorna la grandezza dell'array
  int size() const
  { return _size; }
  // @cmember Ritorna numero di oggetti nell'array
  virtual long objects( )
  { return _items; }
  
  virtual int items( ) const
  { return _items; }
  
  
  virtual TObject* first_item( );
  
  virtual TObject* last_item( );
  
  virtual TObject* succ_item( );
  
  virtual TObject* pred_item( );
  
  // @cmember Ritorna l'indice del primo oggetto
  int first() const;
  // @cmember Ritorna l'indice dell'ultimo oggetto
  int last() const;
  // @cmember Ritorna l'indice del primo oggetto dopo i
  int succ(int i) const;
  // @cmember Ritorna l'indice del primo oggetto che precede i
  int pred(int i) const;
  
  // @cmember Ritorna l'oggetto puntato da index
  TObject& operator[] (int index) const ;
  // @cmember Ritorna l'oggetto di posto index
  TObject* objptr(int index) const ;
  // @cmember Assegna all'array l'oggetto passato
  TArray& operator= (const TArray& a);

  // @cmember Rimuove uno o tutti (default) gli elementi
  virtual bool destroy(int index = -1, bool pack = FALSE);
  // @cmember Aggiunge un oggetto ad un array.
  virtual int add(TObject* obj, int index = -1) ;
  // @cmember Inserisce un elemento dell'array nella posizione index
  virtual int insert(TObject* obj, int index = 0);

  // @cmember Aggiunge un oggetto all'array. L'oggetto viene duplicato
  int add(const TObject& object, int index = -1) ;
  // @cmember Inserisce un oggetto alla posizione index
  int insert(const TObject& object, int index = 0);
  // @cmember Elimina l'elemento nella posizione index dell'array
  TObject* remove(int index, bool pack = FALSE);
  // @cmember Scambia di posto due elementi dell'array
  void swap(int i1, int i2);
  // @cmember Rende contigui tutti gli elementi non nulli
  void pack();
  // @cmember Ordina i TObject secondo il criterio definito in <t COMPARE_FUNCTION>
  void sort(COMPARE_FUNCTION = NULL);
};

inline TObject* TArray::objptr(int index) const
{
  return (index < _size && index >= 0) ? _data[index] : NULL;
}

inline TObject& TArray::operator[] (int index) const
{
  TObject* o = objptr(index);
#ifdef DBG
  if (o == NULL)
    fatal_box("Can't access NULL array item: %d of %d", index, size());
#endif
  return *o;
}
// @class TBit_array | Come la classe <c TArray> ma i suoi elementi sono bit;
//                      questo permette di costruire array piu' piccoli rispetto
//                      alla classe TArray.
//
// @base public | TObject
class TBit_array : public TObject
{

  // @access Private Member

  // @cmember dimensione dell'array
  word _size;
  // @cmember bit in cui sono contenuti i dati
  byte* _bit;

  // @access Protected Member
protected:
  // @cmember Controlla se si tratta di un oggetto valido
  virtual bool ok() const;
  // @cmember Stampa un array
  virtual void print_on(ostream& out) const;

  // @cmember Modifica la dimensione dell'array.
  void resize(word size);
  // @cmember Copia nell'array l'elemento passato come parametro
  void copy(const TBit_array& ba);
  // @cmember Ritorna il numero del byte contenente il bit n
  word index(long n) const { return word(n >> 3); }
  // @cmember Ritorna la posizione del bit n all'interno del byte
  byte mask(long n) const { return 1 << (n & 0x7); }

  // @access Public Member
public:
  // @cmember Costruttore. Crea un array di (chiama <mf TBit_array::resize>)
  TBit_array(long size = 0);
  // @cmember Costruttore. Crea un array di (chiama <mf TBit_array::copy>)
  TBit_array(const TBit_array& ba);
  // @cmember Distruttore
  virtual ~TBit_array();

  // @cmember Assegna all'array l'oggetto passato
  TBit_array& operator=(const TBit_array& ba);
  // @cmember Ritorna l'oggetto puntato da n
  bool operator[] (long n) const;
  // @cmember Ritorna l'or logico tra due Bit_array modificando l'oggetto corrente
  TBit_array& operator |=(const TBit_array& b); 

  // @cmember Ritorna la posizione del primo 1 nell'array (-1 se non lo trova)
  long first_one() const;
  // @cmember Ritorna la posizione dell'ultimo 1 nell'array (-1 se non lo trova)
  long last_one() const;
  // @cmember Ritorna il numero di 1 presenti nell'array
  long ones() const;

  // @cmember Setta ad 1 il bit n-esimo dell'array
  void set(long n);
  // @cmember Setta a 0 il bit n-esimo dell'array
  void reset(long n);
  // @cmember Not logico del bit n-esimo dell'array
  void not(long n);

  // @cmember Setta il bit n-esimo a seconda del valore passato come secondo elemento
  void set(long n, bool on) { on ? set(n) : reset(n); }
  // @cmember Setta ad 1 tutti i bit dell'array
  void set();
  // @cmember Setta a 0 tutti i bit dell'array
  void reset();
  // @cmember Data una stringa setta ad 1 gli elementi indicati della stringa
  void set(const char* numbers);
};


#endif
