/* vset_query.h */

#ifndef VSET_QUERY__H
#define VSET_QUERY__H

#include "root.h"
#include "id.h"
#include "data.h"
#include <matrix/newmatio.h>
#include <matrix/newmatnl.h>
#include <iostream.h>
#include "id_lookup.h"

/* VSET_QUERY
   vset_query( int num_blocks, set_query_block & ) is used to do a series of
   sets and queries on the label hierarchy.
   
   the block array may be allocated either dynamically or statically, and
   cleanup is left to the user.
   
   the id that a block refers to may be set or gotten using a known dc_label *,
   a string pathname or an internal tag.  pathnames and tags are checked for
   correctness, but an invalid dc_label * will cause a segfault 


   SET/GET MEMBER FUNCTIONS
   the get block member function is used to get a queried value after vset_query
   has been called.

   the set block member function is used to set the value that will be passed to
   id on the next vall to vset_query.

   if set or get are called with an illegal argument ( ex. set( Matrix ) on a 
   block of type Real_t ) true is returned.  false is returned on success.


   MULTIPLE VSET_QUERY CALLS USING UNCHANGED BLOCKS
   after a call to vset_query, every blocks direction will be changed to Query.
   subsequent calls using a block that has not been set will return the updated
   value rather than continually setting the value to whatever that blocks 
   contents is and overwriting changes due to advancing time
   */

enum set_query_dir { Query = 0, Set = 1 };

union contents_u {
  bool boolean_c;
  double distrib_c[4];
  double real_c;
  long int int_c;
  Matrix *rmatrix_c;
  ColumnVector *vector_c;
};

struct set_query_block {
private:
  dc_label *id;
  set_query_dir direction; /* may not be set or queried directly by user */
  contents_u C; /* may be queried using get( ... ) */
  dc_type id_t; /* set internally.  may be queried using ::get_type()
		   defined in "types.h".  valid types are:
		   Boolean_t, Distrib_t, Int_t, Real_t, Rect_Matrix_t, 
		   String_t, Symbol_t, Triple_t, and Vector_t.  
		   If id is invalid type will be Undef_t */
  bool element;
  
public:
  set_query_block( const dc_label *Id = nil ) { id_t = Undef_t; set_id( Id ); }
  ~set_query_block();
  
  /* true on error */
  bool set_id( const dc_label * );
  bool set_path( const string &path, dc_label *origin = nil ) 
    { return set_id( search( path, origin ) ); }
  bool set_tag( const tag T ) { return set_id( lookup( T ) ); }

  dc_label *get_id( void ) { return id; } /* nil on error */
  string get_path( void ) { return ( id ) ? id->label() : string( "<nil>" ); }
  tag get_tag( void ) { if( id ) return id->get_tag(); else return tag_error; }

  dc_type get_type( void ) { return id_t; }

  /* true on failure.  queries or gets will not take effect until vset query
     called on array including this block */
  bool get( bool & );
  bool get( double & );
  bool get( long int & );
  bool get( Matrix & );
  bool get( ColumnVector & );
  bool get( double &mean, double &min, double &max );
  bool get( double &mean, double &stddev );

  bool set( const bool );
  bool set( const double );
  bool set( const long int );
  bool set( const Matrix & );
  bool set( const ColumnVector & );
  bool set( const double mean, const double min, const double max );
  bool set( const double mean, const double stddev );

  friend int vset_query( const int, set_query_block [] );
  friend int vset_query_complex( const int, set_query_block [] );
  friend ostream &operator<<( ostream &, const set_query_block & );
};

/* both return number of successful sets and queries */

/* sets performed before queries */
int vset_query( const int, set_query_block [] ); 
/* performs sets and queries inorder from left to right */
int vset_query_complex( const int, set_query_block[] );
#endif
