/* vset_query.cc */

#include "vset_query.h"
#include "data_classes.h"
#include <strings.h>
#include "element.h"

bool set_query_block::set_id( const dc_label *Id = nil ) {
  if( id_t == Rect_Matrix_t ) {
    delete( C.rmatrix_c );
  } else if( id_t == Vector_t || id_t == Triple_t ) {
    delete( C.vector_c );
  }

  element = false;
  if( ( id = ( dc_label * )Id ) != nil ) {
    if( !( id->is_data() && ( id_t = id->sub_type() ) != Data_t ) ) {
      if( ( id_t = id->sub_type() ) == Element_t ) {
	element = true;
	id_t = ( ( dc_element * )id )->get_rtype();
      } else {
	id_t = Undef_t;
	id = nil;
      }
    }
  } else {
    id_t = Undef_t;
  }
  direction = Query;
  bzero( &C, sizeof( contents_u ) );
  switch( id_t ) {
  case Undef_t : return true;
  case Rect_Matrix_t : C.rmatrix_c = new Matrix; return false;
  case Triple_t : C.vector_c = new ColumnVector(3); return false;
  case Vector_t : C.vector_c = new ColumnVector;
  default : return false;
  }
}

set_query_block::~set_query_block( void ) {
  if( id_t == Rect_Matrix_t ) {
    delete( C.rmatrix_c );
  } else if( id_t == Vector_t || id_t == Triple_t ) {
    delete( C.vector_c );
  }
}

bool set_query_block::get( bool &b ) {
  if( id_t == Boolean_t ) {
    b = C.boolean_c;
    return false;
  }
  return true;
}

bool set_query_block::get( double &d ) {
  if( id_t == Real_t || id_t == Distrib_t ) {
    d = C.real_c;
  } else if( id_t == Int_t ) {
    d = ( double )C.int_c;
  } else return true;
  return false;
}

bool set_query_block::get( long int &i ) {
  if( id_t == Real_t || id_t == Distrib_t ) {
    i = ( long int )C.real_c;
  } else if( id_t == Int_t ) {
    i = C.int_c;
  } else return true;
  return false;
}

bool set_query_block::get( Matrix &M ) {
  if( id_t == Rect_Matrix_t ) {
    M = *( C.rmatrix_c );
  } else if( id_t == Vector_t || id_t == Triple_t ) {
    M = *( C.vector_c );
  } else return true;
  return false;
}

bool set_query_block::get( ColumnVector &V ) {
  if( id_t == Vector_t || id_t == Triple_t ) {
    V = *( C.vector_c );
    return false;
  } 
  return true;
}

bool set_query_block::get( double &mean, double &min, double &max ) {
  if( id_t == Distrib_t ) {
    mean = C.distrib_c[0];
    min = C.distrib_c[1];
    max = C.distrib_c[2];
    return false;
  }
  return true;
}

bool set_query_block::get( double &mean, double &stddev ) {
  if( id_t == Distrib_t ) {
    mean = C.distrib_c[0];
    stddev = C.distrib_c[3];
    return false;
  }
  return true;
}

bool set_query_block::set( const bool b ) {
  if( id_t == Boolean_t ) { 
    C.boolean_c = b; 
    direction = Set; 
    return false;
  } 
  return true;
}

bool set_query_block::set( const double d ) {
  if( id_t == Real_t || id_t == Distrib_t ) {
    C.real_c = d;
  } else if( id_t == Int_t ) {
    C.int_c = ( long int )d;
  } else return true;
  direction = Set; 
  return false;
}

bool set_query_block::set( const long int i ) {
  if( id_t == Real_t || id_t == Distrib_t ) {
    C.real_c = ( double )i;
  } else if( id_t == Int_t ) {
    C.int_c = i;
  } else return true;
  direction = Set; 
  return false;
}

bool set_query_block::set( const Matrix &M ) {
  if( id_t == Rect_Matrix_t ) {
    *( C.rmatrix_c ) = M;
    direction = Set; 
    return false;
  } 
  return true;
}

bool set_query_block::set( const ColumnVector &V ) {
  if( id_t == Vector_t ) {
    *( C.vector_c ) = V;
  } else if( id_t == Triple_t ) {
    if( V.Nrows() != 3 ) return 3;
    *( C.vector_c ) = V;
  } else if( id_t == Rect_Matrix_t ) {
    *( C.rmatrix_c ) = V;
  } else return true;
  direction = Set; 
  return false;
}

bool set_query_block::set( const double mean, const double min, 
			   const double max ) {
  if( id_t == Distrib_t ) {
    C.distrib_c[0] = mean;
    C.distrib_c[1] = min;
    C.distrib_c[2] = max;
    direction = Set; 
    return false;
  }
  return true;
}

bool set_query_block::set( const double mean, const double stddev ) {
  if( id_t == Distrib_t ) {
    C.distrib_c[0] = mean;
    C.distrib_c[3] = stddev;
    direction = Set; 
    return false;
  }
  return true;
}

int vset_query( const int nblocks, set_query_block blk[] ) {
  int errors = 0;
  for( int i = 0 ; i < nblocks ; i++ ) {
    if( blk[i].direction == Set ) {
      if( blk[i].element ) {
	dc_data *D = ( ( dc_element * )blk[i].id )->get();
	if( !D ) { errors++; } else {
	  switch( D->sub_type() ) {
	  case Boolean_t :
	    ( ( dc_boolean * )D )->set( blk[i].C.boolean_c ); break;
	  case Distrib_t :
	    if( ( ( dc_distrib * )D )->get_bounds_abs() ) {
	      ( ( dc_distrib * )D )->set( blk[i].C.distrib_c[0], 
					  blk[i].C.distrib_c[1], 
					  blk[i].C.distrib_c[2] );
	    } else {
	      ( ( dc_distrib * )D )->set( blk[i].C.distrib_c[0], 
					  blk[i].C.distrib_c[3] );
	    } break;
	  case Int_t :
	    ( ( dc_int * )D )->set( blk[i].C.int_c ); break;
	  case Real_t :
	    ( ( dc_real * )D )->set( blk[i].C.real_c ); break;
	  case Rect_Matrix_t :
	    ( ( dc_rect_matrix * )D )->set( *( blk[i].C.rmatrix_c ) );
	    break;
	  case Triple_t :
	    ( ( dc_triple * )D )->set( *( blk[i].C.vector_c ) ); break;
	  case Vector_t :
	    ( ( dc_vector * )D )->set( *( blk[i].C.vector_c ) ); break;
	  default : errors++;
	  }
	}
      } else {
	switch( blk[i].id_t ) {
	case Boolean_t :
	  ( ( dc_boolean * )blk[i].id )->set( blk[i].C.boolean_c ); break;
	case Distrib_t :
	  if( ( ( dc_distrib * )blk[i].id )->get_bounds_abs() ) {
	    ( ( dc_distrib * )blk[i].id )->set( blk[i].C.distrib_c[0], 
						blk[i].C.distrib_c[1], 
						blk[i].C.distrib_c[2] );
	  } else {
	    ( ( dc_distrib * )blk[i].id )->set( blk[i].C.distrib_c[0], 
						blk[i].C.distrib_c[3] );
	  } break;
	case Int_t :
	  ( ( dc_int * )blk[i].id )->set( blk[i].C.int_c ); break;
	case Real_t :
	  ( ( dc_real * )blk[i].id )->set( blk[i].C.real_c ); break;
	case Rect_Matrix_t :
	  ( ( dc_rect_matrix * )blk[i].id )->set( *( blk[i].C.rmatrix_c ) );
	  break;
	case Triple_t :
	  ( ( dc_triple * )blk[i].id )->set( *( blk[i].C.vector_c ) ); break;
	case Vector_t :
	  ( ( dc_vector * )blk[i].id )->set( *( blk[i].C.vector_c ) ); break;
	default : errors++;
	}
      }
    }
  }

  for( int i = 0 ; i < nblocks ; i++ ) {
    if( blk[i].direction == Query ) {
      if( blk[i].element ) {
	dc_data *D = ( ( dc_element * )blk[i].id )->get();
	if( !D ) { errors++; } else {
	  switch( D->sub_type() ) {
	  case Boolean_t :
	    blk[i].C.boolean_c = ( ( dc_boolean * )D )->get(); break;
	  case Distrib_t :
	    blk[i].C.distrib_c[0] = ( ( dc_distrib * )D )->get_mean();
	    blk[i].C.distrib_c[1] = ( ( dc_distrib * )D )->get_min();
	    blk[i].C.distrib_c[2] = ( ( dc_distrib * )D )->get_max();
	    blk[i].C.distrib_c[3] = ( ( dc_distrib * )D )->get_stddev();
	    break;
	  case Int_t :
	    blk[i].C.int_c = ( ( dc_int * )D )->get(); break;
	  case Real_t :
	    blk[i].C.real_c = ( ( dc_real * )D )->get(); break;
	  case Rect_Matrix_t :
	    *( blk[i].C.rmatrix_c ) = ( ( dc_rect_matrix * )D )->get();
	    break;
	  case Triple_t :
	    *( blk[i].C.vector_c ) = ( ( dc_triple * )D )->get(); break;
	  case Vector_t :
	    *( blk[i].C.vector_c ) = ( ( dc_vector * )D )->get(); break;
	  default : errors++;
	  }
	}
      } else {
	switch( blk[i].id_t ) {
	case Boolean_t :
	  blk[i].C.boolean_c = ( ( dc_boolean * )blk[i].id )->get(); break;
	case Distrib_t :
	  blk[i].C.distrib_c[0] = ( ( dc_distrib * )blk[i].id )->get_mean();
	  blk[i].C.distrib_c[1] = ( ( dc_distrib * )blk[i].id )->get_min();
	  blk[i].C.distrib_c[2] = ( ( dc_distrib * )blk[i].id )->get_max();
	  blk[i].C.distrib_c[3] = ( ( dc_distrib * )blk[i].id )->get_stddev();
	  break;
	case Int_t :
	  blk[i].C.int_c = ( ( dc_int * )blk[i].id )->get(); break;
	case Real_t :
	  blk[i].C.real_c = ( ( dc_real * )blk[i].id )->get(); break;
	case Rect_Matrix_t :
	  *( blk[i].C.rmatrix_c ) = ( ( dc_rect_matrix * )blk[i].id )->get();
	  break;
	case Triple_t :
	  *( blk[i].C.vector_c ) = ( ( dc_triple * )blk[i].id )->get(); break;
	case Vector_t :
	  *( blk[i].C.vector_c ) = ( ( dc_vector * )blk[i].id )->get(); break;
	default : errors++;
	}
      }
    } else {
      blk[i].direction = Query;
    }
  }
  return errors;
}

int vset_query_complex( const int nblocks, set_query_block blk[] ) {
  int errors = 0;
  for( int i = 0 ; i < nblocks ; i++ ) {
    if( blk[i].direction == Query ) {
      if( blk[i].element ) {
        dc_data *D = ( ( dc_element * )blk[i].id )->get();
        if( !D ) { errors++; } else {
          switch( D->sub_type() ) {
          case Boolean_t :
            blk[i].C.boolean_c = ( ( dc_boolean * )D )->get(); break;
          case Distrib_t :
            blk[i].C.distrib_c[0] = ( ( dc_distrib * )D )->get_mean();
            blk[i].C.distrib_c[1] = ( ( dc_distrib * )D )->get_min();
            blk[i].C.distrib_c[2] = ( ( dc_distrib * )D )->get_max();
            blk[i].C.distrib_c[3] = ( ( dc_distrib * )D )->get_stddev();
            break;
          case Int_t :
            blk[i].C.int_c = ( ( dc_int * )D )->get(); break;
          case Real_t :
            blk[i].C.real_c = ( ( dc_real * )D )->get(); break;
          case Rect_Matrix_t :
            *( blk[i].C.rmatrix_c ) = ( ( dc_rect_matrix * )D )->get();
            break;
          case Triple_t :
            *( blk[i].C.vector_c ) = ( ( dc_triple * )D )->get(); break;
          case Vector_t :
            *( blk[i].C.vector_c ) = ( ( dc_vector * )D )->get(); break;
          default : errors++;
          }
        }
      } else {
        switch( blk[i].id_t ) {
        case Boolean_t :
          blk[i].C.boolean_c = ( ( dc_boolean * )blk[i].id )->get(); break;
        case Distrib_t :
          blk[i].C.distrib_c[0] = ( ( dc_distrib * )blk[i].id )->get_mean();
          blk[i].C.distrib_c[1] = ( ( dc_distrib * )blk[i].id )->get_min();
          blk[i].C.distrib_c[2] = ( ( dc_distrib * )blk[i].id )->get_max();
          blk[i].C.distrib_c[3] = ( ( dc_distrib * )blk[i].id )->get_stddev();
          break;
        case Int_t :
          blk[i].C.int_c = ( ( dc_int * )blk[i].id )->get(); break;
        case Real_t :
          blk[i].C.real_c = ( ( dc_real * )blk[i].id )->get(); break;
        case Rect_Matrix_t :
          *( blk[i].C.rmatrix_c ) = ( ( dc_rect_matrix * )blk[i].id )->get();
          break;
        case Triple_t :
          *( blk[i].C.vector_c ) = ( ( dc_triple * )blk[i].id )->get(); break;
        case Vector_t :
          *( blk[i].C.vector_c ) = ( ( dc_vector * )blk[i].id )->get(); break;
        default : errors++;
        }
      }
    } else {
      if( blk[i].element ) {
        dc_data *D = ( ( dc_element * )blk[i].id )->get();
        if( !D ) { errors++; } else {
          switch( D->sub_type() ) {
          case Boolean_t :
            ( ( dc_boolean * )D )->set( blk[i].C.boolean_c ); break;
          case Distrib_t :
            if( ( ( dc_distrib * )D )->get_bounds_abs() ) {
              ( ( dc_distrib * )D )->set( blk[i].C.distrib_c[0], 
                                          blk[i].C.distrib_c[1], 
                                          blk[i].C.distrib_c[2] );
            } else {
              ( ( dc_distrib * )D )->set( blk[i].C.distrib_c[0], 
                                          blk[i].C.distrib_c[3] );
            } break;
          case Int_t :
            ( ( dc_int * )D )->set( blk[i].C.int_c ); break;
          case Real_t :
            ( ( dc_real * )D )->set( blk[i].C.real_c ); break;
          case Rect_Matrix_t :
            ( ( dc_rect_matrix * )D )->set( *( blk[i].C.rmatrix_c ) );
            break;
          case Triple_t :
            ( ( dc_triple * )D )->set( *( blk[i].C.vector_c ) ); break;
          case Vector_t :
            ( ( dc_vector * )D )->set( *( blk[i].C.vector_c ) ); break;
          default : errors++;
          }
        }
      } else {
        switch( blk[i].id_t ) {
        case Boolean_t :
          ( ( dc_boolean * )blk[i].id )->set( blk[i].C.boolean_c ); break;
        case Distrib_t :
          if( ( ( dc_distrib * )blk[i].id )->get_bounds_abs() ) {
            ( ( dc_distrib * )blk[i].id )->set( blk[i].C.distrib_c[0], 
                                                blk[i].C.distrib_c[1], 
                                                blk[i].C.distrib_c[2] );
          } else {
            ( ( dc_distrib * )blk[i].id )->set( blk[i].C.distrib_c[0], 
                                                blk[i].C.distrib_c[3] );
          } break;
        case Int_t :
          ( ( dc_int * )blk[i].id )->set( blk[i].C.int_c ); break;
        case Real_t :
          ( ( dc_real * )blk[i].id )->set( blk[i].C.real_c ); break;
        case Rect_Matrix_t :
          ( ( dc_rect_matrix * )blk[i].id )->set( *( blk[i].C.rmatrix_c ) );
          break;
        case Triple_t :
          ( ( dc_triple * )blk[i].id )->set( *( blk[i].C.vector_c ) ); break;
        case Vector_t :
          ( ( dc_vector * )blk[i].id )->set( *( blk[i].C.vector_c ) ); break;
        default : errors++;
        }
      }
      blk[i].direction = Query;
    }
  }
  return errors;
}

ostream &operator<<( ostream &stream, const set_query_block &blk ) {
  if( blk.direction == Query ) stream << "Read  "; else stream << "Write ";
  return stream << dc_type_string[ blk.id_t ] << " "
		<< ( ( blk.id != nil ) ? blk.id->label() : string( "<nil>" ) );
}
