
#include "preact/range.h"


// ----------------------- Range ---------------------------
Range::Range(string s) : label(s), rscale(LOG), minimum(1.), maximum(10.), minimum_policy(IGNORE),
			 maximum_policy(IGNORE), clear_minimum(0.), clear_maximum(0.),
			 clear_scale_minmax(1.) { } ;

void Range::tryswap() {
  if (maximum<minimum) {
    fp_64 m = minimum ;
    minimum = maximum ;
    maximum = m ;

    m = clear_minimum ;
    clear_minimum = clear_maximum ;
    clear_maximum = m ;

    policy p = minimum_policy ;
    minimum_policy = maximum_policy ;
    maximum_policy = p ;
  } ;
} ;

void Range::set_scale(scaling s) {
  rscale = s ;
  if (rscale == LOG) {
    if (minimum<0.) set_min(1.0) ; // will force maximum>0. also
  } ;
} ;

void Range::set_min(fp_64 min) {
  minimum = min ;
  if (rscale == LOG) minimum=fabs(minimum) ;
  if (minimum>maximum) maximum=minimum ;
} ;

void Range::set_max(fp_64 max) { 
  maximum = max ;
  if (rscale == LOG) maximum=fabs(maximum) ;
  if (minimum>maximum) minimum=maximum ;
} ;

void Range::set_min_policy(policy pmin, fp_64 clear_value, fp_64 clear_scale) {
  if (clear_scale>0.) clear_scale_minmax = clear_scale ;
  minimum_policy = pmin ;
  clear_minimum  = clear_value ;
} ;

void Range::set_max_policy(policy pmax, fp_64 clear_value, fp_64 clear_scale) {
  if (clear_scale>0.) clear_scale_minmax = clear_scale ;
  maximum_policy = pmax ;
  clear_maximum  = clear_value ;
} ;

int  Range::query(const fp_64& x) const {
  if (x<minimum) {
    if (minimum_policy == HALT) return -1 ;
    return 1 ;
  }
  else if (x>maximum) {
    if (maximum_policy == HALT) return -1 ;
    return 1 ;
  } ;
  return 0 ;
} ;       
    
state Range::current() const {
  state s ;

  s.vs.resize(1) ;
  s.vs[0] = label ;
  
  s.vi.resize(3) ;
  s.vi[0] = rscale ;
  s.vi[1] = minimum_policy ;
  s.vi[2] = maximum_policy ;

  fp_64 m = (minimum+maximum)/2. ;      // scaling for LINEAR
  s.vd.resize(4) ;

  m = ((rscale == LOG) ? minimum : m) ; // use value if LOG scale
  s.vd[0] = doublescale(minimum,m) ;

  m = ((rscale == LOG) ? maximum : m) ; // use value if LOG scale
  s.vd[1] = doublescale(maximum,m) ;

  s.vd[2] = doublescale(clear_minimum, clear_scale_minmax) ;
  s.vd[3] = doublescale(clear_maximum, clear_scale_minmax) ;

  return s ;
} ;

// 
// template instatiations
//
template bool Range::check(const fwrap<fp_64>& x, fwrap<fp_64>& f) const ;
template bool Range::check(const fwrap<fp_32>& x, fwrap<fp_32>& f) const ;
template bool Range::check(const fp_64& x,        fwrap<fp_64>& f) const ;
template bool Range::check(const fp_32& x,        fwrap<fp_32>& f) const ;
template bool Range::check(const fp_64& x, fp_64& f) const ;
template bool Range::check(const fp_32& x, fp_32& f) const ;
 
// --------------- other ----------------
ostream& operator<<(ostream& s, Range::scaling p) {
  switch(p) {
  case Range::LOG:
    s<<"LOG" ; break ;
  case Range::LINEAR:
    s<<"LINEAR" ; break ;
  default:
    s<<"UNKNOWN_SCALE" ; break ;
  } ;
  return s ;
} ;

ostream& operator<<(ostream& s, Range::policy p) {
  switch(p) {
  case Range::IGNORE:
    s<<"IGNORE" ; break ;
  case Range::WARN:
    s<<"WARN"   ; break ;
  case Range::HALT:
    s<<"HALT"   ; break ;
  case Range::IGNORE_CLEAR:
    s<<"IGNORE_CLEAR" ; break ;
  case Range::WARN_CLEAR:
    s<<"WARN_CLEAR"   ; break ;
  default:
    s<<"UNKNOWN_POLICY" ;
  } ;
  return s ;
} ;

ostream& operator<<(ostream& s, const Range& r) {
  s << " -- Range --"   << endl ;
  s << "  label:       " << r.name()        << endl ;
  s << "  scaling:     " << r.scale()       << endl ;
  s << "  clear_scale: " << r.clear_scale() << endl ;
  s << "  ---\n" ;
  s << "  minimum:     " << r.min()         << endl ;
  s << "  min policy:  " << r.min_policy()  << endl ;
  s << "  min clear:   " << r.min_clear()   << endl ;
  s << "  ---\n" ;
  s << "  maximum:     " << r.max()         << endl ;
  s << "  max policy:  " << r.max_policy()  << endl ;
  s << "  max clear:   " << r.max_clear()   << endl ;  
  s << " -- End Range --"   << endl ;
  return s ;
} ;

