#include "AdvDomain.hh"

const std::string AdvDomain::className=std::string("AdvDomain");

/** 
 *  default constructor
 */
AdvDomain::AdvDomain() {
    this->type=CC;
    this->srcBin.clear();
}

/**
 *  constructor.
 *
 *  @param[in] src an element container as the source
 */
AdvDomain::AdvDomain(ElementContainer &src) {
    set(src, 0, src.PutSize(src.PutYKey())-1);
    this->type=CC;
}

/** 
 *  constructor
 *  
 *  @param[in] src an element container as the source
 *  @param[in] xLower the value of the lower bin bound
 *  @param[in] xUpper the value of the upper bin bound
 */
AdvDomain::AdvDomain(ElementContainer &src, const Double xLower, const Double xUpper) {
    set(src, xLower, xUpper);
    this->type=CC;
}

/** 
 *  constructor
 *  
 *  @param[in] src an element container as the source
 *  @param[in] lower the index of the lower bin bound
 *  @param[in] upper the index of the upper bin bound
 */
AdvDomain::AdvDomain(ElementContainer &src, const UInt4 lower, const UInt4 upper) {
    set(src, lower, upper);
    this->type=CC;
}

/** 
 *  constructor
 *  
 *  @param[in] src an element container as the source
 *  @param[in] xLower the value of the lower bin bound
 *  @param[in] xUpper the value of the upper bin bound
 *  @param[in] type the type of the domain bounds
 */
AdvDomain::AdvDomain(ElementContainer &src, const Double xLower, const Double xUpper, const BoundsType type) {
    set(src, xLower, xUpper, type);
}

/** 
 *  constructor
 *  
 *  @param[in] src an element container as the source
 *  @param[in] lower the index of the lower bin bound
 *  @param[in] upper the index of the upper bin bound
 *  @param[in] type the type of the domain bounds
 */
AdvDomain::AdvDomain(ElementContainer &src, const UInt4 lower, const UInt4 upper, const BoundsType type) {
    set(src, lower, upper, type);
}

/**
 *  copy constructor
 */
AdvDomain::AdvDomain(const AdvDomain &domain) {
    this->srcBin = domain.srcBin;
    this->lowerBound  = domain.lowerBound;
    this->upperBound  = domain.upperBound;
}

/** 
 *  destructor
 */
AdvDomain::~AdvDomain() {
    this->srcBin.clear();
}

/**
 *  operator =
 */
AdvDomain AdvDomain::operator = (const AdvDomain &domain)  {
    this->srcBin = domain.srcBin;
    this->lowerBound = domain.lowerBound;
    this->upperBound = domain.upperBound;
    return *this;
}

/** 
 *  set the source by  bin bounds that an element container contains
 *  
 *  \param[in] src an element container as the source
 *  \throw std::invalid_argument if the size of bin of element container as source is too few
 */
void AdvDomain::setSource(ElementContainer &src) {
    std::string memberName = std::string("setSource(ElementContainer&)");
    std::string separator  = std::string(": ");
    DebugMessage(className, memberName, "enter\n");
    //src.Dump();
    DebugMessage(className, memberName, __FILE__, __LINE__, "size of x=%u\n", src.PutX().size());
    //assert(src.PutSize(src.PutXKey()) >=2 );
     
    if ( src.PutSize(src.PutXKey()) < 2 ) {
        DebugMessage(className, memberName, __FILE__, __LINE__, "size of x=%u\n", src.PutX().size());
        throw std::invalid_argument(className + separator + memberName + separator + std::string("too few bin"));
    }
    //this->srcBin=src.Put(src.PutXKey());
    this->srcBin=src.PutX();
    DebugMessage(className, memberName, "exit\n");
}


void AdvDomain::setBinRange(const UInt4 lower, const UInt4 upper) {
    std::string memberName = std::string("setBinRange(cons UInt4, const UInt4)");
    std::string separator = std::string(": ");
    DebugMessage(className, memberName, "enter\n");

    DebugMessage(className, memberName, "%u <= lower==%u < %u: %s\n", 0, lower, srcBin.size()-1, (0 <= lower && lower < srcBin.size()-1 ? "true" : "false" ));
    if ( ! (0 <= lower && lower < this->srcBin.size()-1) ) {
        throw std::out_of_range(className + separator + memberName + separator + std::string("the lower bound is out of range."));
    }
    DebugMessage(className, memberName, "%u <= upper==%u < %u: %s\n", 0, upper, srcBin.size()-1, (0 <= upper && upper < srcBin.size()-1 ? "true" : "false" ));
    if ( ! (0 <= upper && upper < this->srcBin.size()-1) ) {
        throw std::out_of_range(className + separator + memberName + separator + std::string("the upper bound is out of range."));
    }
    if ( lower > upper ) {
        throw std::invalid_argument(className + separator + memberName + separator + std::string("argument error"));
    }

    this->lowerBound=lower;
    this->upperBound=upper+1;
    DebugMessage(className, memberName, __FILE__, __LINE__, "LowerID==>xLower: %10u ==> %23.15e\n", this->lowerBound, this->srcBin.at(this->lowerBound));    
    DebugMessage(className, memberName, __FILE__, __LINE__, "UpperID==>xUpper: %10u ==> %23.15e\n", this->upperBound, this->srcBin.at(this->upperBound));
    DebugMessage(className, memberName, "exit\n");
}

void AdvDomain::setBinBoundRange(const UInt4 lower, const UInt4 upper) {
    std::string memberName = std::string("setBinBoundRange(cons UInt4, const UInt4)");
    std::string separator = std::string(": ");
    DebugMessage(className, memberName, "enter\n");

    DebugMessage(className, memberName, "%u <= lower==%u < %u: %s\n", 0, lower, srcBin.size(), (0 <= lower && lower < srcBin.size() ? "true" : "false" ));
    if ( ! (0 <= lower && lower < this->srcBin.size()) ) {
        throw std::out_of_range(className + separator + memberName + separator + std::string("the lower bound is out of range."));
    }
    DebugMessage(className, memberName, "%u <= upper==%u < %u: %s\n", 0, upper, srcBin.size(), (0 <= upper && upper < srcBin.size() ? "true" : "false" ));
    if ( ! (0 <= upper && upper < this->srcBin.size()) ) {
        throw std::out_of_range(className + separator + memberName + separator + std::string("the upper bound is out of range."));
    }
    if ( lower > upper ) {
        throw std::invalid_argument(className + separator + memberName + separator + std::string("argument error"));
    }

    this->lowerBound=lower;
    this->upperBound=upper;
    DebugMessage(className, memberName, __FILE__, __LINE__, "LowerID==>xLower: %10u ==> %23.15e\n", this->lowerBound, this->srcBin.at(this->lowerBound));    
    DebugMessage(className, memberName, __FILE__, __LINE__, "UpperID==>xUpper: %10u ==> %23.15e\n", this->upperBound, this->srcBin.at(this->upperBound));
    DebugMessage(className, memberName, "exit\n");
}

/** 
 *  set the range by two indices of bin bounds
 *  
 *  @param[in] lower the index of the lower bin bound
 *  @param[in] upper the index of the upper bin bound
 *
 *  @deprecated
 */
void AdvDomain::setRange(const UInt4 lower, const UInt4 upper) {
    std::string memberName = std::string("setRange(cons UInt4, const UInt4)");
    std::string separator = std::string(": ");
    DebugMessage(className, memberName, "enter\n");

    this->setBinRange(lower, upper);
    //assert(this->srcBin.size() >= 2);
    //assert(0 <= lower && lower <= this->srcBin.size()-1);
    //assert(0 <= upper && upper <= this->srcBin.size()-1);
    //assert(lower < upper);

    //DebugMessage(className, memberName, "%u <= lower==%u < %u: %s\n", 0, lower, srcBin.size(), (0 <= lower && lower < srcBin.size() ? "true" : "false" ));
    //if ( ! (0 <= lower && lower < this->srcBin.size())) {
    //    throw std::out_of_range(className + separator + memberName + separator + std::string("the lower bound is out of range."));
    //}
    //DebugMessage(className, memberName, "%u <= upper==%u < %u: %s\n", 0, upper, srcBin.size(), (0 <= upper && upper < srcBin.size() ? "true" : "false" ));
    //if ( ! (0 <= upper && upper < this->srcBin.size())) {
    //    throw std::out_of_range(className + separator + memberName + separator + std::string("the upper bound is out of range."));
   // }
    //DebugMessage(className, memberName, "lower == %u < upper == %u: %s\n", lower, upper, (lower < upper ? "true" : "false"));
    //if ( lower > upper ) {
    //    throw std::invalid_argument(className + separator + memberName + separator + std::string("argument error"));
    //}

    //this->lowerBound=lower;
    //this->upperBound=upper;
    //DebugMessage(className, memberName, __FILE__, __LINE__, "LowerID==>xLower: %10u ==> %23.15e\n", this->lowerBound, this->srcBin.at(this->lowerBound));    
    //DebugMessage(className, memberName, __FILE__, __LINE__, "UpperID==>xUpper: %10u ==> %23.15e\n", this->upperBound, this->srcBin.at(this->upperBound));
    DebugMessage(className, memberName, "exit\n");
}

/** 
 *  set the range by the values of lower and upper bounds
 *  
 *  @param[in] xLower the value of the lower bin bound
 *  @param[in] xUpper the value of the upper bin bound
 */
void AdvDomain::setRange(const Double xLower, const Double xUpper) {
    std::string memberName=std::string("setRange(const Double, const Double)");
    std::string separator  = std::string(": ");
    DebugMessage(className, memberName, "enter\n");

    //assert( this->srcBin.size() >= 2);
    //assert( *(this->srcBin.begin()) <= xLower && xLower <= *(this->srcBin.end()) );
    //assert( *(this->srcBin.begin()) <= xUpper && xUpper <= *(this->srcBin.end()) );
    //assert( xLower < xUpper);
    DebugMessage(className, memberName, "%e <= xLower==%e <=%e: %s\n", srcBin.front(), xLower, srcBin.back(), (srcBin.front() <= xLower && xLower <= srcBin.back() ? "true" : "false" ));
    if ( !(srcBin.front() <= xLower && xLower <= srcBin.back()) ) {
        throw std::out_of_range(className + separator + memberName + separator + std::string("the lower bound is out of range."));
    }
    DebugMessage(className, memberName, "%e <= xUpper==%e <=%e: %s\n", srcBin.front(), xUpper, srcBin.back(), (srcBin.front() <= xUpper && xUpper <= srcBin.back() ? "true" : "false"));
    if ( !(srcBin.front() <= xUpper && xUpper <= srcBin.back()) ) {
        throw std::out_of_range(className + separator + memberName + separator + std::string("the upper bound is out of range."));
    }
    DebugMessage(className, memberName, "xLower == %e < xUpper == %e: %s\n", xLower, xUpper, (xLower < xUpper ? "true" : "false"));
    if ( xLower >= xUpper ) {
        throw std::invalid_argument(className + separator + memberName + separator + std::string("the lower bound is not small the upper boud."));
    }

    // assersion : x coodinates lb <= xl      <  xu        <= ub
    // assersion : bin bound id  0 <=  l      <=  u        <= srcBin.size()-1
    // assetsion : bin No.       0 <=  l'(=l) <   u'=(u-1) <= srcBin.size()-2
    DebugMessage(className, memberName, "xLower ==> nearest id(%u), bin bound x(%e)\n", nearest(xLower), srcBin.at(nearest(xLower)));
    this->lowerBound=nearest(xLower);
    DebugMessage(className, memberName, "xUpper ==> nearest id(%u), bin bound x(%e)\n", nearest(xUpper), srcBin.at(nearest(xUpper)));
    this->upperBound=nearest(xUpper);

    if (this->lowerBound < this->upperBound ) {
        ;
    } else if (this->lowerBound == this->upperBound ) {
        warningMessage(className, memberName, __FILE__, __LINE__, "the lower and upper bounds are too near.\n");
        warningMessage(className, memberName, __FILE__, __LINE__, "lower=%f, upper=%f\n", xLower, xUpper);
        if (this->lowerBound == 0) {
            ++(this->upperBound);
        } else if (this->lowerBound == this->srcBin.size()-1 ) {
            --(this->lowerBound);
        } else {
            --(this->lowerBound);
            ++(this->upperBound);
        }
        warningMessage(className, memberName, __FILE__, __LINE__, "reset the lower and upper bound.\n");
        warningMessage(className, memberName, __FILE__, __LINE__, "lowerBound=%u\n", this->lowerBound);
        warningMessage(className, memberName, __FILE__, __LINE__, "upperBound=%u\n", this->upperBound);
    } else {
        errorMessage(className, memberName, __FILE__, __LINE__, "the upper bounds is smaller than the lower bound\n");
        errorMessage(className, memberName, __FILE__, __LINE__, "lower=%f", this->srcBin.at(this->lowerBound));
        errorMessage(className, memberName, __FILE__, __LINE__, ", upper=%f\n", this->srcBin.at(this->upperBound));
        errorMessage(className, memberName, __FILE__, __LINE__, "lower index = %u", this->lowerBound);;
        errorMessage(className, memberName, __FILE__, __LINE__, ", upper index =%u\n", this->upperBound);
    }

    DebugMessage(className, memberName, "exit\n");
}

/** 
 *  set the type of the domain
 *  
 *  @param[in] type the type of the domain bounds, one of CLOSE_CLOSE, CLOSE_OPEN, OPEN_CLOSE, OPEN_OPEN
 */
void AdvDomain::setType(const BoundsType type) {
   this->type=type;
}

/** 
 *  set the domain
 *  
 *  @param[in] src an element container as the source
 *  @param[in] xLower the value of the lower bin bound
 *  @param[in] xUpper the value of the upper bin bound
 */
void AdvDomain::set(ElementContainer &src, const Double xLower, const Double xUpper) {
    setSource(src);
    setRange(xLower, xUpper);
    this->type=CC;
}

/** 
 *  set the domain
 *  
 *  @param[in] src an element container as the source
 *  @param[in] lower the index of the lower bin bound
 *  @param[in] upper the index of the upper bin bound
 */
void AdvDomain::set(ElementContainer &src, const UInt4 lower, const UInt4 upper) {
    setSource(src);
    setRange(lower, upper);
    this->type=CC;
}

/** 
 *  set the domain
 *  
 *  @param[in] src an element container as the source
 *  @param[in] xLower the value of the lower bin bound
 *  @param[in] xUpper the value of the upper bin bound
 *  @param[in] type the type of the domain bounds
 */
void AdvDomain::set(ElementContainer &src, const Double xLower, const Double xUpper, const BoundsType type) {
    setSource(src);
    setRange(xLower, xUpper);
    this->type=type;
}

/** 
 *  set the domain
 *  
 *  @param[in] src an element container as the source
 *  @param[in] lower the index of the lower bin bound
 *  @param[in] upper the index of the upper bin bound
 *  @param[in] type the type of the domain bounds
 */
void AdvDomain::set(ElementContainer &src, const UInt4 lower, const UInt4 upper, const BoundsType type) {
    setSource(src);
    setRange(lower, upper);
    this->type=type;
}

/** 
 *  set lower bound by the index of  the bin
 */
void AdvDomain::setLowerBoundID(const UInt4 lower) {
    assert(this->srcBin.size() >= 2);
    assert(0 <= lower && lower <= this->srcBin.size()-1);

    this->lowerBound=lower;
}

/** 
 *  set the upper bound of the index of the bin
 */
void AdvDomain::setUpperBoundID(const UInt4 upper) {
    assert(this->srcBin.size() >= 2);
    assert(0 <= upper && upper <= this->srcBin.size()-1);

    this->upperBound=upper;
}

/** 
 *  set the lower bound of the domain
 *  
 *  @param[in] xLower the value of the lower bound
 */
void AdvDomain::setLowerBound(const Double xLower) {
    std::string memberName=std::string("setLowerBound(const Double)");
    //assert(this->srcBin.size() >= 2);

    UInt4 l=nearest(xLower);
    if ( l < this->upperBound) {
        this->lowerBound=l;
    } else {
        warningMessage(className, memberName, __FILE__, __LINE__, "the lower bound is eqaul to or larger than the upper Bound.\n");
        warningMessage(className, memberName, __FILE__, __LINE__, "the lower bound is not changed.\n");
        warningMessage(className, memberName, __FILE__, __LINE__, "given the lower bound=%f", xLower);
        warningMessage(className, memberName, __FILE__, __LINE__, ", the upper bound = %f\n", this->srcBin.at(this->upperBound));
    }
}

/** 
 *  set the upper bound of the domain
 *  
 *  @param[in] xLower the value of the upper bound
 */
void AdvDomain::setUpperBound(const Double xUpper) {
    std::string memberName=std::string("setUpperBound(const Double)");
    //assert(this->srcBin.size() >= 2);

    UInt4 u=nearest(xUpper);
    if ( u > this->lowerBound) {
        this->upperBound=u;
    } else {
        warningMessage(className, memberName, __FILE__, __LINE__, "the upper bound is eqaul to or smaller than the lower Bound.\n");
        warningMessage(className, memberName, __FILE__, __LINE__, "the upper bound is not changed.\n");
        warningMessage(className, memberName, __FILE__, __LINE__, "given the upper bound=%f", xUpper);
        warningMessage(className, memberName, __FILE__, __LINE__, ", the lower bound = ", this->srcBin.at(this->lowerBound));
    }

}

/**
 *  get all bounds of bins that are included in the specified range
 */
std::vector<Double> *AdvDomain::getBin() {
    std::string memberName = std::string("getBin()");

    std::vector<Double>::const_iterator l=this->srcBin.begin();
    std::vector<Double>::const_iterator u=this->srcBin.begin();
    DebugMessage(className, memberName, __FILE__, __LINE__, "size of bin; %u\n", srcBin.size());
    DebugMessage(className, memberName, __FILE__, __LINE__, "LowerID==>xLower: %10u ==> %23.15e\n", this->lowerBound, this->srcBin.at(this->lowerBound));    
    DebugMessage(className, memberName, __FILE__, __LINE__, "UpperID==>xUpper: %10u ==> %23.15e\n", this->upperBound, this->srcBin.at(this->upperBound));    
    for (UInt4 i=0; i<this->lowerBound; ++i) {
        ++l;
    }
    for (UInt4 i=0; i<=this->upperBound; ++i) {
        ++u;
    }
    DebugMessage(className, memberName, __FILE__, __LINE__, "lowerBound; %u\n", *l);
    DebugMessage(className, memberName, __FILE__, __LINE__, "upperBound; %u\n", *u);
    return (new std::vector<Double>(l, u));
}


/** create middle (center) points of bins that are included in the the specified range.
 */
std::vector<Double> *AdvDomain::createXC() {
    std::vector<Double> *retval = new std::vector<Double>((this->upperBound-1) - this->lowerBound +1);
    for (UInt4 i=this->lowerBound; i<this->upperBound; ++i) {
        //retval->push_back( (this->srcBin.at(i) + this->srcBin.at(i+1))/2.0 );
        retval->at(i - this->lowerBound) = (this->srcBin.at(i) + this->srcBin.at(i+1))/2.0;
    }
    return retval;
}

/** get a list of the lower bounds of bins that are included in the specified range.
 */
std::vector<Double>* AdvDomain::getXL() {
    std::vector<Double>* retval = new std::vector<Double>((this->upperBound-1) - this->lowerBound +1);
    for (UInt4 i=this->lowerBound; i<this->upperBound; ++i) {
       retval->at(i - this->lowerBound) = srcBin.at(i);
    }
    return retval;
}

/** get a list of the lower bounds of bins that included in the specified range.
 */
std::vector<Double>* AdvDomain::getXU() {
    std::vector<Double>* retval = new std::vector<Double>((this->upperBound) - (this->lowerBound +1) + 1);
    for (UInt4 i=this->lowerBound+1; i<=this->upperBound; ++i) {
       retval->at(i - (this->lowerBound+1)) = srcBin.at(i);
    }
    return retval;
}

/**
 *  create a list of the dividing points of bins, Dp[i-l] = (1-c)*X[i] + c*[i+1]  (l &le; i &lt; u).
 *  @param[in] c division ratio
 *  @return internally dividing points, if 0 &le; c &le 1.0
 *  @return externally dividing pointe, otherwise
 *
 *  Dp[i-l] = (1-c)*X[i] + c*[i+1] = X[i] + c*(X[i+1] - X[i])
 *
 *  when c = 0.5, the method is equivalent to AdvDomain::createXC(), @see{AdvDomain::createXC}
 *  when c = 0.0, the method is equivalent to AdvDomain::getXL(),    @see{AdvDomain::getXL}
 *  when c = 1.0, the method is equivalent to AdvDomain::getXU(),    @see{AdvDomain::getXU}
 */
std::vector<Double>* AdvDomain::createDividingPoints(const Double c) {
    std::vector<Double>* retval = new std::vector<Double>((this->upperBound-1) - this->lowerBound +1);
    for (UInt4 i=this->lowerBound; i<this->upperBound; ++i) {
        //retval->pushback((1.0-c)*(this->srcBin.at(i)) + c*(this->srcBin.at(i+1)));
        retval->at(i - this->lowerBound)=(1.0-c)*(this->srcBin.at(i)) + c*(this->srcBin.at(i+1));
    }
    return retval;
}

/**
 *  get all bin bounds that are included in the specifined range.
 *  gsl_vector version of getBin()
 *  @see AdvDomain::getBin()
 */
gsl_vector *AdvDomain::getBinAsGslVector() {

    gsl_vector *retval = gsl_vector_alloc((this->upperBound + 1)-(this->lowerBound)+1);
    for (UInt4 i=this->lowerBound; i<=this->upperBound+1; ++i) {
        gsl_vector_set(retval, i-(this->lowerBound), this->srcBin.at(i));
    }
    return retval;
}

/**
 *  create middle (center) point of bins that are inluceded in the specified range.
 *  gsl_vector version of createXC()
 *  @see AdvDomain::createXC()
 */
gsl_vector *AdvDomain::createXCAsGslVector() {
    std::string memberName = std::string("createXCAsGslVector()");
    DebugMessage(className, memberName, "enter\n");

    gsl_vector *retval = gsl_vector_alloc((this->upperBound-1) - this->lowerBound +1);
    DebugMessage(className, memberName, "%u<=i<%u\n", this->lowerBound, this->upperBound);
    for (UInt4 i=this->lowerBound; i<this->upperBound; ++i) {
        gsl_vector_set(retval, i - this->lowerBound, (this->srcBin.at(i) + this->srcBin.at(i+1))/2.0 );
        //DebugMessage(className, memberName, "i=%u, xc=%e\n", i, gsl_vector_get(retval, i-this->lowerBound));
    }
    DebugMessage(className, memberName, "the number of xc : %u\n", retval->size);
    DebugMessage(className, memberName, "exit\n");
    return retval;
}

/** get a list of the lower bounds of bins.
 *  gsl_vector version of getXL()
 *  @see AdvDomain::geXL()
 */
gsl_vector* AdvDomain::getXLAsGslVector() {
    gsl_vector* retval = gsl_vector_alloc((this->upperBound-1) - this->lowerBound + 1);
    for (UInt4 i=this->lowerBound; i<this->upperBound; ++i) {
        gsl_vector_set(retval, i - this->lowerBound, srcBin.at(i));
    }
    return retval;
}

/** get a list of the lower bounds of bins.
 *  gsl_vector version of getXU()
 *  @see AdvDomain::geXU()
 */
gsl_vector* AdvDomain::getXUAsGslVector() {
    gsl_vector* retval = gsl_vector_alloc(this->upperBound - (this->lowerBound+1) + 1);
    for (UInt4 i=this->lowerBound+1; i<=this->upperBound; ++i) {
        gsl_vector_set(retval, i - (this->lowerBound+1), srcBin.at(i));
    }
    return retval;
}

/**  create a list of the dividing points of bins Dp[i-l] = (1-c)*X[i] + c*[i+1]  (l &le; i &lt; u).
 *  gsl_vector version of createDividingPoints(const Double c)
 *  @see AdvDomain::createDividingPoints(const Double c)
 */
gsl_vector* AdvDomain::createDividingPointsAsGslVector(const Double c) {
    gsl_vector *retval = gsl_vector_alloc((this->upperBound-1) - this->lowerBound +1);
    //DebugMessage(className, memberName, "%u<=i<%u\n", this->lowerBound, this->upperBound);
    for (UInt4 i=this->lowerBound; i<this->upperBound; ++i) {
        gsl_vector_set(retval, i - this->lowerBound, (1.0-c)*(this->srcBin.at(i)) + c*(this->srcBin.at(i+1)) );
        //DebugMessage(className, memberName, "i=%u, xc=%e\n", i, gsl_vector_get(retval, i-this->lowerBound));
    }
    return retval;
}

/**
 *  get the number of bins included in the range that user specified.
 */
UInt4 AdvDomain::getNumberOfBin() const {
    return ((this->upperBound-1) - this->lowerBound + 1);
}


/** 
 *  the index of the lower bin bound
 *  
 *  @return the index of the lower bin bound
 *
 *  @deprecated
 */
UInt4 AdvDomain::getLowerBoundID() const {
    //return this->lowerBound;
    return this->getLowerBinID();
}

/** 
 *  the index of the upper bin bound
 *  
 *  @return the index of the upper bin bound
 *
 *  @deprecated
 */
UInt4 AdvDomain::getUpperBoundID() const {
    //return this->upperBound;
    return this->getUpperBinID();
}


/**
 *  the bin bound index of the lower bound of the domain
 */
UInt4 AdvDomain::getLowerBinBoundID() const {
    return this->lowerBound;
}


/**
 *  get the indecies of the lower and upper bin bounds for the domain
 */
std::vector<Int4> *AdvDomain::getBinBoundIDs() const {
    std::vector<Int4> *v=new std::vector<Int4>(2);
    v->at(0)=static_cast<Int4>(this->lowerBound);
    v->at(1)=static_cast<Int4>(this->upperBound);
    return v;
}

/**
 *  the bin bound index of the upper bound of the domain
 */
UInt4 AdvDomain::getUpperBinBoundID() const {
    return this->upperBound;
}

/**
 *  the No. of the lowerest bin in the domain
 */
UInt4 AdvDomain::getLowerBinID() const {
    return this->lowerBound;
}

/**
 *  the bin No. of the upper bound in the domain
 */
UInt4 AdvDomain::getUpperBinID() const {
    return this->upperBound-1;
}

/**
 * get indecies of the lower and upper Bins
 */
std::vector<Int4> *AdvDomain::getBinIDs() const {
    std::vector<Int4> *v=new std::vector<Int4>(2);
    v->at(0)=static_cast<Int4>(this->lowerBound);
    v->at(1)=static_cast<Int4>(this->upperBound-1);
    return v;
}

/** 
 *  the value of the lower bin bound
 *  
 *  @return the value of the lower bin bound
 */
Double AdvDomain::getLowerBound() const {
    return this->srcBin.at(this->lowerBound);
}

/** 
 *  the value of the upper bin bound
 *  
 *  @return the value of the upper bin bound
 */
Double AdvDomain::getUpperBound() const {
    return this->srcBin.at(this->upperBound);
}

/**
 */
Double AdvDomain::getWidth() const {
    return (this->srcBin.at(this->upperBound) - this->srcBin.at(this->lowerBound));
}

/**
 *  the lower and the upper bounds of the domain
 *
 *  @return the both bounds as std::vector<Double>.
 *          0-th. element is the lower bound
 *          1st.  element is the upper bound
 */
std::vector<Double> AdvDomain::getBinBounds() const {
    std::vector<Double> *v = new std::vector<Double>(2);
    v->at(0)= srcBin.at(this->lowerBound);
    v->at(1)= srcBin.at(this->upperBound);
    return *v;
}

/**
 *  @return the type of the domain
 */
AdvDomain::BoundsType AdvDomain::getType() const {
    return this->type;
}

/** 
 *  add the infomation of the domain to the destination
 */
void AdvDomain::addToHeaderOfResult(const std::string &Key, ElementContainer &dest) {
    std::vector<Int4> *bound = new std::vector<Int4>();
    bound->push_back(static_cast<Int4>(this->lowerBound));
    bound->push_back(static_cast<Int4>(this->upperBound));
    dest.AddToHeader(Key, *bound);
}

/** 
 *  the index of the nearest bin bound in the source from the given value
 *  
 *  @param[in] x searching value
 *  @return the index of the nearest bin bound to the given value
 *
 *  definition of sections (bins) and their No.
 *  ------------------+--------------------------------------------------------------------------------
 *  i-th. bin center  | bc(i)=( b(i) + b(i+1))/2 ( 0 <= i <= b.size()-2 )
 *  ------------------+--------------------------------------------------------------------------------
 *  i-th. section/bin | I(i)= [b(-1),       b(0)   )  ( i = -1              )
 *                    |       [b(i),        b(i+1) )  ( 0 <= i < b.size()-2 )
 *                    |       [b(size()-1), inf.   )  ( i =  b.size()-1     )
 *  ------------------+--------------------------------------------------------------------------------
 *  nearest           | x < (-Inf.,         bc(0)   ) ==> b(0)
 *                    | x < [ bc(i),        bc(i+1) ) ==> b(i)          ( 0 <= i <= b.size()-3 )
 *                    | x < [ bc(size()-2), Inf.    ) ==> b(b.size()-1)
 *  ------------------+--------------------------------------------------------------------------------
 *
 *  nearest bound No. |   |       0       1       2       ...                b.size()-2          b.size()-1
 *                    |-----------+-------+-------+-----------------+-----------------+-----------------------
 *  bin center        |           bc(0)   bc(1)   bc(2)             bc(b.size()-3)    bc(b.size()-2)
 *                    |           |       |       |                 |                 |
 *                    |-------+---+---+---+---+---+--------+--------+--------+--------+--------+--------------> X
 *                    |       |       |       |            |                 |                 |
 *  bin bound         |       b(0)    b(1)    b(2)  ...    b(b.size()-3)     b(b.size()-2)     b(b.size()-1)
 *                    |-------+-------+-------+------------+-----------------+-----------------+--------------
 *  section/bin No.   |   -1      0        1        ...         b.size()-3         b.size()-2      b.size()-1
 */
UInt4 AdvDomain::nearest(const Double x) const {
    assert(this->srcBin.size() >= 2);

    UInt4 retval;
    Int4 i=this->section_search(x);
    //std::cerr << "Debug:  AdvDomain::nearest(Double); x=" << x << ", i=" << i << std::endl;
    if ( i==-1 ) {
        retval=0;
    } else {
        if ( static_cast<UInt4>(i) == this->srcBin.size()-1) {
            retval=this->srcBin.size()-1;
        } else {
            Double xm=(this->srcBin.at(i) + this->srcBin.at(i+1))/2.0;
            //std::cerr << "Debug:  AdvDomain::nearest(Double); x=" << x << ", xm=" << xm << std::endl;
            if ( x < xm ) {
               retval=i;
            } else {
               retval=i+1;
            }
        }
    }
    return retval;

}

/** 
 *  the index of the bin that contains the given value
 *  
 *  @param[in] x searching value
 *  @return the index of the bin that contains the given value
 *
 * definition of sections (bins) and their No.
 * No.     |      -1          0         1      ...         size()-3                       size()-2                  size()-1
 * --------+-------------+---------+---------+-----+----------------------------+-----------------------------+--------------------
 * section |  (-inf., x0)  [x0, x1)  [x1, x2)  ...  [ x(size()-3), x(size()-2) )  [ x(size()-2), x(size()-1) )  [x(size()-1), inf.)
 *
 */
UInt4 AdvDomain::section_search(const Double x) const {
    assert(this->srcBin.size() >= 2);

    Int4 retval;
    if ( x < this->srcBin.at(0)) {
        //std::cerr << "Debug:  AdvDomain::section_search(Double); x=" << x << ", srcBin.at(0)" << this->srcBin.at(0) << std::endl;
        retval=-1;
    } else if ( this->srcBin.at(srcBin.size()-1) < x ) {
        //std::cerr << "Debug:  AdvDomain::section_search(Double); x=" << x ;
        //std::cerr << ", srcBin.at(" << this->srcBin.size()-1 << ")" << this->srcBin.at(this->srcBin.size()-1) << std::endl;
        retval=this->srcBin.size()-1;
    } else {
        UInt4 l, u, m;
        l=0;
        u=this->srcBin.size()-1;
        while ( l+1 < u ) {
            m=(l+u)/2;
            if ( x < this->srcBin.at(m) ) {
               //std::cerr << "Debug  AdvDomain::section_search(Double); l=" << l << ", m=" << m << ", u=" << u;
               //std::cerr << "  AdvDomain::section_search(Double); x=" << x << " < srcBin.at(" << m << ")=" << this->srcBin.at(m) << std::endl;
               u=m;
            } else {
               //std::cerr << "Debug  AdvDomain::section_search(Double); l=" << l << ", m=" << m << ", u=" << u;
               //std::cerr << "  AdvDomain::section_search(Double); x=" << x << " >= srcBin.at(" << m << ")=" << this->srcBin.at(m) << std::endl;
               l=m;
            }
        }
        retval=static_cast<Int4>(l);
    }
    return retval;
}

