/* ga_input.h */

#ifndef GA_INPUT__H
#define GA_INPUT__H

#include <iostream.h>
#include "common.h"
#include <LEDA/list.h>
#include "types.h"
#include "display.h"

class StdBitString;
class dc_label;
class dc_element;
//class dc_arg;

class ga_input { /* virtual class */
protected:
  /* input path label */
  string path;
  //  dc_arg arg;
public:
  /* will set [off...off+nBits()-1] of bitstring. 
     returns true for error iff bitstring too short */
  virtual bool get( StdBitString &, int off ) const = 0;
  /* will get from [off..off+nBits-1] of bitstring.
     returns true for error if bitstring too short or unable to set input. */
  virtual bool set( const StdBitString &, int off ) = 0;
  /* number of bits that this input needs */
  virtual int nBits( void ) = 0;

  /* type of object this links to */
  virtual dc_type type( void ) = 0;

  void set_path( cstring p ) { path = p; }
  cstring get_path( void ) const { return path; }

  virtual ostream &display( ostream & = cout ) const = 0;

  /* true if failure to find legal match */
  virtual bool find_input( dc_label *origin ) = 0;
};

/* virtual class -- links to element with rtype == type() */
class ga_el_input : public ga_input {
protected:
  dc_element *input;
public:
  ga_el_input( void ) { input = nil; }
  /* finds a visible element matching path with rtype == type() */
  bool find_input( dc_label *origin );
};

class ga_bool_input : public ga_el_input {
private:
  bool val;
public:
  ga_bool_input( void ) { val = false; }

  bool get( StdBitString &, int ) const;
  bool set( const StdBitString &, int );
  int nBits( void ) { return 1; }
  dc_type type( void ) { return Boolean_t; }

  void set( bool b ) { val = b; }

  ostream &display( ostream &s = cout ) const {
    return s << path << " = " << (val ? "true" : "false" );
  }
};

class ga_int_input : public ga_el_input {
private:
  long int min;
  int nbits; /* log2( range ) */
  long int range; /* ( 2^nbits - 1 ) >= ( max - min ) */

  long val; /* in range 0...range-1 */

public:
  ga_int_input( void ) { min = 0; nbits = 0; range = 0; val = 0; }
  
  bool get( StdBitString &, int ) const;
  bool set( const StdBitString &, int );
  int nBits( void ) { return nbits; }
  dc_type type( void ) { return Int_t; }

  void set_int( long int i );
  long get_int( void ) const { return ( ( long )val ) + min; }

  bool set_range( long int n, long int x );

  ostream &display( ostream &s = cout ) const;
};

class ga_real_input : public ga_el_input {
private:
  double min;
  int nbits;
  long range; /* 2^nbits - 1 */
  double div; /* ( max - min ) / range */
  
  long val; /* 0...range. form = ( real - min ) / div */

public:
  ga_real_input( void ) { min = 0; nbits = 0; range = 0; div = 1; val = 0; }
  
  bool get( StdBitString &, int ) const;
  bool set( const StdBitString &, int );
  int nBits( void ) { return nbits; }
  dc_type type( void ) { return Real_t; }

  void set_real( double );
  void set_real_normalized( double ); /* expects input in range [0..1] */
  double get_real( void ) const;

  bool set_range( double n, double x, int nbits );
  bool set_range( double n, double x, double resolution );

  ostream &display( ostream &s = cout ) const;

  /* gets value from input */
  bool refresh( void );
};



class ga_input_list {
private:
  list<ga_input *> inputs;
  //  list<dc_arg *  > args;
  int nbits;
  
public:
  ga_input_list() { nbits = 0; }
  ~ga_input_list() { clear(); }

  void add_input( ga_input & );
  void clear( void );

  void get( StdBitString & ) const; /* will resize bitstring */
  bool set( const StdBitString & ); /* return true iff bitstring missized */

  void forall_inputs( void fn( const ga_input & ) ) const;
  void forall_inputs( void fn( const ga_input &, void * ), void * ) const;

  int nBits( void ) { return nbits; }
  ostream &display( ostream & = cout ) const;

  bool find_inputs( dc_label *origin );

  //  const lis<dc_arg *> &get_arg_list( void ) { return args; }
};

inline ostream &operator<<( ostream &s, const ga_input &i )
  { return i.display( s ); }
inline ostream &operator<<( ostream &s, const ga_input_list &i )
  { return i.display( s ); }

#endif
