/* distrib.cc */

#include "distrib.h"
#include <ctype.h>

dc_distrib::dc_distrib( void ) {
  set( 0, 0, 0 );
}

dc_distrib::dc_distrib( const double nMean, const double nMin, 
			const double nMax ) {
  set( nMean, nMin, nMax );
}

dc_distrib::dc_distrib( const double nMean, const double nStdDev ) {
  set( nMean, nStdDev );
}

dc_distrib &dc_distrib::operator=( dc_data &D ) {
  if( D.sub_type() == Distrib_t ) {
    val = ( ( dc_distrib * )&D )->val;
    Min = ( ( dc_distrib * )&D )->Min;
    Max = ( ( dc_distrib * )&D )->Max;
    bounds_absolute = ( ( dc_distrib * )&D )->bounds_absolute;
    StdDev = ( ( dc_distrib * )&D )->StdDev;
  } else {
    dc_trace( TRACE_ERROR ) {
      cerr << "dc_distrib::operator= -- cannot assign " << D.type_string()
	   << " to " << type_string() << "\n";
    }
  }
  return *this;
}

ostream &dc_distrib::display_c( ostream &stream = cout ) const {
  if( bounds_absolute ) {
    return stream << "( Mean " << val << ", Min " << Min << ", Max " << Max 
		  << " )" << units;
  } else {
    return stream << "( Mean " << val << ", StdDev " << StdDev << " )" 
		  << units;
  }
}

istream &operator>>( istream &stream, dc_distrib &D ) {
  double v1, v2;
  stream >> v1;
  /* eat whitespace */
  while( isspace( stream.peek() ) ) stream.get();
  if( stream.peek() != ',' ) {
    D.val = v1;
    D.bounds_absolute = false;
    return stream;
  }
  stream >> v2;
  while( isspace( stream.peek() ) ) stream.get();
  if( stream.peek() != ',' ) {
    D.val = v1;
    D.StdDev = v2;
    D.bounds_absolute = false;
    return stream;  
  }
  D.val = v1;
  D.Min = v2;
  stream >> D.Max;
  D.bounds_absolute = true;
  return stream;
}

void dc_distrib::set( const double nMean, const double nStdDev ) {
  val = nMean; StdDev = nStdDev; 
  Min = val - 3 * StdDev;
  Max = val + 3 * StdDev;
  bounds_absolute = false;
}

void dc_distrib::set( double nMean, double nMin, double nMax ) {
  if( nMin > nMax ) {
    dc_trace( TRACE_WARNING ) {
      cerr << "dc_distrib::set -- Max " << nMin << " < Min " << nMax 
	   << ".  swapping\n";
    }
    double t = nMin;
    nMin = nMax;
    nMax = t;
  }

  if( nMean < nMin ) { 
    dc_trace( TRACE_WARNING ) {
      cerr << "dc_distrib::set -- Mean " << nMean << " < Min " << nMin 
	   << ". setting Mean = Min\n";
    }
    nMean = nMin;
  } else if( nMean > nMax ) {
    dc_trace( TRACE_WARNING ) {
      cerr << "dc_distrib::set -- Mean " << nMean << " > Max " << nMax
	   << ". setting Mean = Max\n";
    }
    nMean = nMax;
  }

  val = nMean; Min = nMin; Max = nMax;
  StdDev = ( Max - Min ) / 6;
  bounds_absolute = true;
}

double dc_distrib::get_sample( void ) const {
  return ( drand48() * ( Max - Min ) ) + Min;
}

dc_data *dc_distrib::duplicate( void ) const {
  dc_distrib *dupe;
  if( bounds_absolute ) {
    dupe = new dc_distrib( val, Min, Max );
  } else {
    dupe = new dc_distrib( val, StdDev );
  }
  dupe->set_units( get_units_c() );

  return ( dc_data * )dupe;
}
