#include "AdvEqualSpacing.hh"

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

const std::string AdvEqualSpacing::BIN_WIDTH=std::string("bin width");

AdvParamSet AdvEqualSpacing::setDefaultParam(ElementContainerArray& src) {
    std::string memberName=std::string("setDefaultParam(ElementContainerArray&)");
    DebugMessage(className, memberName, __FILE__, __LINE__, "enter\n");

    AdvParamSet *paramSet=new AdvParamSet();

    paramSet->add(AdvConvolutionConsts::RES_INDEX,    AdvConvolutionConsts::DEFAULT_RES_INDEX);

    ElementContainer *ec = src.PutPointer(AdvConvolutionConsts::DEFAULT_RES_INDEX);
    std::vector<Double> bin = ec->PutX();
    /* bin width */
    paramSet->add(AdvEqualSpacing::BIN_WIDTH, (bin.back() - bin.front())/(bin.size()-1));
    /* width check threshold */
    paramSet->add(AdvConvolutionConsts::WIDTH_THRESHOLD,     AdvConvolutionConsts::DEFAULT_WIDTH_THRESHOLD);

    DebugMessage(className, memberName, __FILE__, __LINE__, "exit\n");
    return *paramSet;
}

Bool AdvEqualSpacing::checkAllBinWidth(const std::vector<Double>& bin, const Double widthThreshold) {
    std::string memberName=std::string("checkAllBinWidth(std::vector<Double>&, Double)");
    DebugMessage(className, memberName, __FILE__, __LINE__, "enter\n");

    Double width=abs(bin.back() - bin.front())/(bin.size()-1);

    Bool retval=true;
    for (UInt4 i=0; i<bin.size()-1; ++i) {
//#ifdef DEBUG
//        DebugMessage(className, memberName, __FILE__, __LINE__,
//            "i=%d, relative error of width=%e, result=%s\n",
//             i,
//             abs(abs(bin.at(i+1) - bin.at(i))/width - 1.0),
//             (abs(abs(bin.at(i+1) - bin.at(i))/width - 1.0) < widthThreshold ? "true" : "false")
//        );
//#endif // DEBUG
        retval = retval && (abs(abs(bin.at(i+1) - bin.at(i))/width - 1.0) < widthThreshold);
    }

    DebugMessage(className, memberName, __FILE__, __LINE__, "exit\n");
    return retval;
}

Bool AdvEqualSpacing::checkParam(ElementContainerArray& src, std::vector<AdvDomain>& domains, AdvParamSet& paramSet) {
    std::string memberName=std::string("checkParam(ElementContainerArray&, std::vector<AdvDomain>&, AdvParamSet&)");
    DebugMessage(className, memberName, __FILE__, __LINE__, "enter\n");

    Bool retval=true;

    if (src.PutSize() == 1) {
        retval=false;
        errorMessage(className, memberName, __FILE__, __LINE__, "too few data.\n");
    }

    if (src.PutSize() != domains.size()) {
        retval=false;
        errorMessage(className, memberName, __FILE__, __LINE__,
            "the number of element conainers in the given array is not equal to the number of domains.\n");
    }

    //UInt4 id = paramSet.getUInt4(AdvEqualSpacing::RES_INDEX);
    UInt4 id = paramSet.getUInt4(AdvConvolutionConsts::RES_INDEX);
    if (! (0 <= id && id < src.PutSize()) ) {
        retval=false;
        errorMessage(className, memberName, __FILE__, __LINE__, "the index for the  resolution in src is out of range.\n");
        errorMessage(className, memberName, __FILE__, __LINE__, "it must be  0 <= index < %d \n", src.PutSize());
    }

    //Double widthThreshold = paramSet.getDouble(AdvEqualSpacing::WIDTH_THRESHOLD);
    Double widthThreshold = paramSet.getDouble(AdvConvolutionConsts::WIDTH_THRESHOLD);
    std::vector<Double> bin;
    for (UInt4 i=0; i<domains.size(); ++i) {
        bin=*(domains.at(i).getBin());
        if (!  this->checkAllBinWidth(bin, widthThreshold)) {
            if (i==id) {
                warningMessage(className, memberName, __FILE__, __LINE__, "the all bin's width of resolution data ate not constant.\n");
            } else {
                warningMessage(className, memberName, __FILE__, __LINE__, "the all bin's width of source data ate not constant.\n");
            }
            warningMessage(className, memberName, __FILE__, __LINE__, "the bins are rebinning so that all bis width are const.\n");
        }
    }

    DebugMessage(className, memberName, __FILE__, __LINE__, "exit\n");
    return retval;
}

void AdvEqualSpacing::importResolution(ElementContainer& ec, AdvDomain& domain) {
    std::string memberName=std::string("importResolution(ElementContainery&, AdvDomain&)");
    DebugMessage(className, memberName, __FILE__, __LINE__, "enter\n");

    UInt4 lowerBinBoundID = domain.getLowerBinBoundID();
    UInt4 upperBinBoundID = domain.getUpperBinBoundID();

    std::vector<Double> y = ec.PutY();
    std::vector<Double> e = ec.PutE();
    this->resBin=*(domain.getBin());
    for (UInt4 i=lowerBinBoundID; i<upperBinBoundID; ++i) {
        this->resY.push_back(y.at(i));
        this->resYErr.push_back(e.at(i));
    }
//    this->eraseZeroSequenceAtFront(this->resBin, this->resY, this->resYErr);
//    this->eraseZeroSequenceAtBack(this->resBin, this->resY, this->resYErr);
//#ifdef DEBUG
//    for (UInt4 i=0; i<this->resY.size(); ++i) {
//        DebugMessage(className, memberName, __FILE__, __LINE__, "i=%5d [%e, %e) v=%e e=%e\n", i, this->resBin.at(i), this->resBin.at(i+1), this->resY.at(i), this->resYErr.at(i));
//    }
//#endif // DEBUG

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

void AdvEqualSpacing::importSource(ElementContainer& ec, AdvDomain& domain) {
    std::string memberName=std::string("importSource(ElementContainer&, AdvDomain&)");
    DebugMessage(className, memberName, __FILE__, __LINE__, "enter\n");

    UInt4 lowerBinBoundID = domain.getLowerBinBoundID();
    UInt4 upperBinBoundID = domain.getUpperBinBoundID();

    std::vector<Double> y=ec.PutY();
    std::vector<Double> e=ec.PutE();
    std::vector<Double> *tmpY = new std::vector<Double>();
    std::vector<Double> *tmpE = new std::vector<Double>();

    for (UInt4 i=lowerBinBoundID; i<upperBinBoundID; ++i) {
        tmpY->push_back(y.at(i));
        tmpE->push_back(e.at(i));
    }
    this->srcBin.push_back(*(domain.getBin()));
    this->srcY.push_back(*tmpY);
    this->srcYErr.push_back(*tmpE);

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

void AdvEqualSpacing::toInnerForm(ElementContainerArray& src, std::vector<AdvDomain>& domains, AdvParamSet& paramSet) {
    std::string memberName=std::string("toInnerForm(ElementContainerArray&, std::vector<AdvDomain>&, AdvParamSet&)");
    DebugMessage(className, memberName, __FILE__, __LINE__, "enter\n");

    ElementContainer ec;

    //this->width = paramSet.getDouble(AdvEqualSpacing::BIN_WIDTH);
    //this->widthThreshold=paramSet.getDouble(AdvEqualSpacing::WIDTH_THRESHOLD);
    this->width = paramSet.getDouble(AdvEqualSpacing::BIN_WIDTH);
    this->widthThreshold=paramSet.getDouble(AdvConvolutionConsts::WIDTH_THRESHOLD);

    /* import resolution data */
    //this->resID = paramSet.getUInt4(AdvEqualSpacing::RES_INDEX);
    this->resID = paramSet.getUInt4(AdvConvolutionConsts::RES_INDEX);
    ec = src.Put(this->resID);
    this->importResolution(ec, domains.at(this->resID));

    /* import source data */
    for (UInt4 i=0; i<src.PutSize(); ++i) {
        if ( i == this->resID ) continue;
        ec = src.Put(i);
        importSource(ec, domains.at(i));
    }
    DebugMessage(className, memberName, __FILE__, __LINE__, "%d source data imported \n", this->srcBin.size());

    /* allocate new data area */
    this->newSrcBin  = std::vector< std::vector<Double> >(src.PutSize()-1);
    this->newSrcY    = std::vector< std::vector<Double> >(src.PutSize()-1);
    this->newSrcYErr = std::vector< std::vector<Double> >(src.PutSize()-1);
    DebugMessage(className, memberName, __FILE__, __LINE__, "%d new bin area of source data allocated \n", this->newSrcBin.size());
    DebugMessage(className, memberName, __FILE__, __LINE__, "%d new value area of source data allocated \n", this->newSrcY.size());
    DebugMessage(className, memberName, __FILE__, __LINE__, "%d new value error area data allocated \n", this->newSrcYErr.size());

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

void AdvEqualSpacing::eraseZeroSequenceAtFront(std::vector<Double>& b, std::vector<Double>& y, std::vector<Double>& e) {
    std::string memberName=std::string("eraseZeroSequenceAtFront(std::vector<Double>&, std::vector<Double>&, std::vector<Double>&)");
    DebugMessage(className, memberName, __FILE__, __LINE__, "enter\n");

    while (y.size() > 0 && y.front() == 0.0) {
        b.erase(b.begin());
        y.erase(y.begin());
        e.erase(e.begin());
    }
    DebugMessage(className, memberName, __FILE__, __LINE__, "size of b = %d\n", b.size());
    DebugMessage(className, memberName, __FILE__, __LINE__, "size of y = %d\n", y.size());
    DebugMessage(className, memberName, __FILE__, __LINE__, "size of e = %d\n", e.size());

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

void AdvEqualSpacing::eraseZeroSequenceAtBack(std::vector<Double>& b, std::vector<Double>& y, std::vector<Double>& e) {
    std::string memberName=std::string("eraseZeroSequenceAtBack(std::vector<Double>&, std::vector<Double>&, std::vector<Double>&)");
    DebugMessage(className, memberName, __FILE__, __LINE__, "enter\n");

    while (y.size() > 1 && y.back() == 0.0) {
        b.erase(--b.end());
        y.erase(--y.end());
        e.erase(--e.end());
    }
    DebugMessage(className, memberName, __FILE__, __LINE__, "size of b = %d\n", b.size());
    DebugMessage(className, memberName, __FILE__, __LINE__, "size of y = %d\n", y.size());
    DebugMessage(className, memberName, __FILE__, __LINE__, "size of e = %d\n", e.size());

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

void AdvEqualSpacing::addZeroSequenceAtFront(const Double w, const UInt4 n, std::vector<Double>& b, std::vector<Double>& y, std::vector<Double>& e) {
    std::string memberName=std::string("addZeroSequenceAtFront(std::vector<Double>&, std::vector<Double>&, std::vector<Double>&)");
    DebugMessage(className, memberName, __FILE__, __LINE__, "enter\n");

    Double l = b.front();
    for (UInt4 i=0; i<n; ++i) {
        b.insert(b.begin(), l - w*i);
        y.insert(y.begin(), 0.0);
        e.insert(y.begin(), 0.0);
    }

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

void AdvEqualSpacing::addZeroSequenceAtBack(const Double w, const UInt4 n, std::vector<Double>& b, std::vector<Double>& y, std::vector<Double>& e) {
    std::string memberName=std::string("addZeroSequenceAtBack(std::vector<Double>&, std::vector<Double>&, std::vector<Double>&)");
    DebugMessage(className, memberName, __FILE__, __LINE__, "enter\n");

    Double l = b.back();
    for (UInt4 i=0; i<n; ++i) {
        b.push_back(l + w*i);
        y.push_back(0.0);
        e.push_back(0.0);
    }

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

std::vector<Double> AdvEqualSpacing::mergeBin(const std::vector<Double>& bin1, const std::vector<Double>& bin2) {
    std::string memberName=std::string("mergeBin(const std::vector<Double>&, cosnt std::vector<Double>&");
    DebugMessage(className, memberName, __FILE__, __LINE__, "enter\n");

    DebugMessage(className, memberName, __FILE__, __LINE__, "size of bin1 = %d\n", bin1.size());
    DebugMessage(className, memberName, __FILE__, __LINE__, "size of bin2 = %d\n", bin2.size());

    std::vector<Double> *retval = new std::vector<Double>();
    std::vector<Double>::const_iterator it1 = bin1.begin();
    std::vector<Double>::const_iterator it2 = bin2.begin();
    while (it1 != bin1.end() && it2 !=bin2.end()) {
        if (*it1 < *it2) {
            retval->push_back(*it1);
            ++it1;
        } else if (*it2 < *it1) {
            retval->push_back(*it2);
            ++it2;
        } else {
            retval->push_back(*it1);
            ++it1;
            ++it2;
        }
    }
    //DebugMessage(className, memberName, __FILE__, __LINE__, "[%13.6e, %13.6e)\n", retval->front(), retval->back());
    if (it1 == bin1.end() && it2 != bin2.end()) {
        //DebugMessage(className, memberName, __FILE__, __LINE__, "left of bin2 = [%13.6e, %13.6e)\n", *it2, bin2.back());
        for (; it2 != bin2.end(); ++it2) {
            retval->push_back(*it2);
        }
    } else if (it2 == bin2.end() && it1 != bin1.end()) {
        //DebugMessage(className, memberName, __FILE__, __LINE__, "left of bin1 = [%13.6e, %13.6e)\n", *it1, bin1.back());
        for (; it1 != bin1.end(); ++it1) {
            retval->push_back(*it1);
        }
    }
    DebugMessage(className, memberName, __FILE__, __LINE__, "result [%13.6e, %13.6e)\n", retval->front(), retval->back());
    DebugMessage(className, memberName, __FILE__, __LINE__, "result bin size=%d\n", retval->size());

    DebugMessage(className, memberName, __FILE__, __LINE__, "exit\n");
    return *retval;
}

Int4 AdvEqualSpacing::indexOfBin(const std::vector<Double>& bin, const Double v) {
    std::string memberName=std::string("indexOfBin(std::vector<Double>&, Double)");
    //DebugMessage(className, memberName, __FILE__, __LINE__, "enter\n");
    Int4 retval;

    if (v < bin.at(0)) {
        retval=-1;
        //DebugMessage(className, memberName, __FILE__, __LINE__, "v=%e < bin.at(0)=%e\n", v, bin.at(0));
    } else if ( bin.at(bin.size()-1) <= v) {
        retval=bin.size()-1;
        //DebugMessage(className, memberName, __FILE__, __LINE__, "v=%e >= bin.at(%d)=%e\n", v, bin.size()-1, bin.at(bin.size()-1));
    } else {
        Int4 l=0;
        Int4 u=bin.size()-1;
        Int4 m;
        while ( l+1 < u) {
            m = (l+u)/2;
            //DebugMessage(className, memberName, __FILE__, __LINE__, "(l, m, u)=(%d, %d, %d)\n", l, m, u);
            if ( v < bin.at(m) ) {
                u=m;
            } else {
                l=m;
            }
        }
        retval=l;
    }

    //DebugMessage(className, memberName, __FILE__, __LINE__, "exit\n");
    return retval;
}

Int4 AdvEqualSpacing::indexOfBinBound(const std::vector<Double>& bin, const Double v) {
    std::string memberName=std::string("indexOfBinBound(std::vector<Double>&, Double)");
    //DebugMessage(className, memberName, __FILE__, __LINE__, "enter\n");

    Int4 retval;
    if (v < bin.front() || bin.back() < v) {
        retval=-1;
        //DebugMessage(className, memberName, __FILE__, __LINE__, "[%e, %e) does not include %e\n", bin.front(), bin.back(), v);
    } else {
        Int4 l=0;
        Int4 u=bin.size()-1;
        Int4 m;
        while ( u > l+1) {
            m=(l+u)/2;
            //DebugMessage(className, memberName, __FILE__, __LINE__, "(l, m, u)=(%d, %d, %d)\n", l, m, u);
            if ( v < bin.at(m) ) {
                u=m;
            } else {
                l=m;
            }
        }
        if (v == bin.at(l)) {
            retval=l;
        } else if ( v == bin.at(u)) {
            retval=u;
        } else {
            retval=-1;
        }
    }

    //DebugMessage(className, memberName, __FILE__, __LINE__, "exit\n");
    return retval;
}

void AdvEqualSpacing::assignValueAndErr(const std::vector<Double>& oldBin, const std::vector<Double>& oldY, const std::vector<Double>& oldErr,
                  const std::vector<Double>& newBin, std::vector<Double>& newY, std::vector<Double>& newErr) {
    std::string memberName=std::string("assignValueAndErr(std::vector<Double>&, std::vector<Double>&, std::vector<Double>&, std::vector<Double>&, vecctor<Double>&, std::vector<Double>&)");
    DebugMessage(className, memberName, __FILE__, __LINE__, "enter\n");

    DebugMessage(className, memberName, __FILE__, __LINE__, "size of oldBin = %d\n", oldBin.size());
    DebugMessage(className, memberName, __FILE__, __LINE__, "size of oldY   = %d\n", oldY.size());
    DebugMessage(className, memberName, __FILE__, __LINE__, "size of oldErr = %d\n", oldErr.size());
    DebugMessage(className, memberName, __FILE__, __LINE__, "size of newBin = %d\n", newBin.size());

    newY.clear();
    newErr.clear();
    for (UInt4 i=0; i<newBin.size()-1; ++i) {
        Int4 j=indexOfBin(oldBin, newBin.at(i));
        if ( j<0 || static_cast<Int4>(oldY.size()) <= j) {
            //DebugMessage(className, memberName, __FILE__, __LINE__, "oldBin[%d]=%e, newBin[%d]=%e e\n", j, oldBin[j], i, newBin[i]);
            //DebugMessage(className, memberName, __FILE__, __LINE__, "out of range\n");
            newY.push_back(  0.0);
            newErr.push_back(0.0);
        } else {
            //DebugMessage(className, memberName, __FILE__, __LINE__, "oldBin[%d]=%e, newBin[%d]=%e oldBin[%d]=%e\n", j, oldBin[j], i, newBin[i], j+1, oldBin.at(j+1));
            newY.push_back(  oldY.at(j));
            newErr.push_back(oldErr.at(j));
        }
        //DebugMessage(className, memberName, __FILE__, __LINE__, "newY[%d]=%e, newErr[%d]=%e\n", i, newY[i], i, newErr[i]);
    }

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

void AdvEqualSpacing::binning(const std::vector<Double>& tmpBin, const std::vector<Double>& tmpY, const std::vector<Double>& tmpErr,
                    const std::vector<Double>& newBin, std::vector<Double>& newY, std::vector<Double>& newErr) {
    std::string memberName=std::string("binning(std::vector<Double>&, std::vector<Double>&, std::vector<Double>&, std::vector<Double>&, vecctor<Double>&, std::vector<Double>&)");
    DebugMessage(className, memberName, __FILE__, __LINE__, "enter\n");
    DebugMessage(className, memberName, __FILE__, __LINE__, "size of newBin: %d\n", newBin.size());

    Double w = (newBin.back() - newBin.front())/(newBin.size()-1);
    newY.clear();
    newErr.clear();
    DebugMessage(className, memberName, __FILE__, __LINE__, "newY and newErr are cleaned\n");
    for (UInt4 i=0; i<newBin.size()-1; ++i) {
        Int4 j=indexOfBinBound(tmpBin, newBin.at(i  ));
        Int4 k=indexOfBinBound(tmpBin, newBin.at(i+1));
        //DebugMessage(className, memberName, __FILE__, __LINE__, "newBin[%5d]=%e, tmpBin[%5d]=%e\n", i,   newBin.at(i  ), j, tmpBin.at(j));
        //DebugMessage(className, memberName, __FILE__, __LINE__, "newBin[%5d]=%e, tmpBin[%5d]=%e\n", i+1, newBin.at(i+1), k, tmpBin.at(k));
        Double sumY=0.0;
        Double sumErr=0.0;
        for (Int4 l=j; l<k; ++l) {
            sumY   += tmpY.at(  l)*(tmpBin.at(l+1) - tmpBin.at(l))/w;
            sumErr += tmpErr.at(l)*(tmpBin.at(l+1) - tmpBin.at(l))/w;
        }
        newY.push_back(sumY); 
        newErr.push_back(sumErr); 
    }

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

void AdvEqualSpacing::extRebin(const std::vector<Double>& oldB, const std::vector<Double>& oldY, const std::vector<Double>& oldE,
                     const std::vector<Double>& newB,       std::vector<Double>& newY,       std::vector<Double>& newE) {
    std::string memberName=std::string("extRebin(const std::vector<Double>&, const std::vector<Double>&, const std::vector<Double>&, const std::vector<Double>&, std::vector<Double>&, const std::vector<Double>&)");

    DebugMessage(className, memberName, __FILE__, __LINE__, "enter\n");

    std::vector<Double> tmpBin = this->mergeBin(oldB, newB);
    std::vector<Double> tmpY, tmpErr;
    this->assignValueAndErr(oldB, oldY, oldE, tmpBin, tmpY, tmpErr);
#ifdef DEBUG
//    for (UInt4 i=0; i<tmpBin.size()-1; ++i) {
//        DebugMessage(className, memberName, __FILE__, __LINE__, "i=%5d [%23.15e, %23.15e) %23.15e %23.15e\n", i, tmpBin.at(i), tmpBin.at(i+1), tmpY.at(i), tmpErr.at(i));
//    }
#endif // DEBUG

    this->binning(tmpBin, tmpY, tmpErr, newB, newY, newE);
#ifdef DEBUG
//    for (UInt4 i=0; i<newB.size()-1; ++i) {
//        DebugMessage(className, memberName, __FILE__, __LINE__, "i=%5d [%23.15e, %23.15e) %23.15e %23.15e\n", i, newB.at(i), newB.at(i+1), newY.at(i), newE.at(i));
//    }
#endif // DEBUG
    
    DebugMessage(className, memberName, __FILE__, __LINE__, "exit\n");
}

class BinGen {
    private:
        Double origin;
        Double width;
        Int4 i;
    public:
        BinGen(const Double origin_, const Double width_, const Int4 startIndex) : origin(origin_), width(width_), i(startIndex) {};
        ~BinGen() {};
        Double operator() () { Double retval = origin + width*i; ++i; return retval; };
};


void AdvEqualSpacing::eval() {
    std::string memberName=std::string("eval()");
    DebugMessage(className, memberName, __FILE__, __LINE__, "enter\n");

    /** erase zero squence at the front and the back */
    this->eraseZeroSequenceAtFront(this->resBin, this->resY, this->resYErr);
    this->eraseZeroSequenceAtBack(this->resBin, this->resY, this->resYErr);
#ifdef DEBUG
    for (UInt4 i=0; i<this->resY.size(); ++i) {
        DebugMessage(className, memberName, __FILE__, __LINE__, "i=%5d [%e, %e) v=%e e=%e\n", i, this->resBin.at(i), this->resBin.at(i+1), this->resY.at(i), this->resYErr.at(i));
    }
#endif // DEBUG

    DebugMessage(className, memberName, __FILE__, __LINE__, "size of new src bin: %d\n", this->newSrcBin.size());
    DebugMessage(className, memberName, __FILE__, __LINE__, "size of new src y  : %d\n", this->newSrcY.size());
    DebugMessage(className, memberName, __FILE__, __LINE__, "size of new src e  : %d\n", this->newSrcYErr.size());
    DebugMessage(className, memberName, __FILE__, __LINE__, "size of new src bin.at(0): %d\n", this->newSrcBin.at(0).size());
    DebugMessage(className, memberName, __FILE__, __LINE__, "size of new src y.at(0)  : %d\n", this->newSrcY.at(0).size());
    DebugMessage(className, memberName, __FILE__, __LINE__, "size of new src e.at(0)  : %d\n", this->newSrcYErr.at(0).size());
    /* check wheter the data is equally spaced or not */
    if (! this->checkAllBinWidth(this->resBin, this->widthThreshold)) {
        infoMessage(className, memberName, __FILE__, __LINE__, "all bin width of the resolution or the responce are not constant.\n");
        infoMessage(className, memberName, __FILE__, __LINE__, "the data will be rebined.\n");
        infoMessage(className, memberName, __FILE__, __LINE__, "new bin's width for all data: %23.15e\n", this->width);

        UInt4 n = static_cast<UInt4>(ceil(abs((this->resBin.back() - this->resBin.front())/this->width))); // the number of bins
        infoMessage(className, memberName, __FILE__, __LINE__, "the range of new bin: [%e, %e)\n", this->resBin.front(), this->resBin.back());
        infoMessage(className, memberName, __FILE__, __LINE__, "size of new bins: %d\n", n);
       
        /* create new bin */
        this->newResBin=std::vector<Double>(n+1);
        std::generate(newResBin.begin(), newResBin.end(), BinGen(this->resBin.front(), this->width, 0));
        /* rebinning resolution data */
        this->extRebin(this->resBin, this->resY, this->resYErr, this->newResBin, this->newResY, this->newResYErr);
        std::cerr << "done rebining of the resolution data" << std::endl;
        std::cerr << "size of bin  : " << this->newResBin.size() << std::endl;
        std::cerr << "size of value: " << this->newResY.size() << std::endl;
        std::cerr << "size of err  : " << this->newResYErr.size() << std::endl;
    } else {
        this->newResBin =this->resBin;
        this->newResY   =this->resY;
        this->newResYErr=this->resYErr;
    }

    //Double width=abs((this->resBin.back() - this->resBin.front()))/(this->resBin.size()-1);
    DebugMessage(className, memberName, __FILE__, __LINE__, "width = %e\n", this->width);
    for (UInt4 i=0; i<srcBin.size(); ++i) {
        Int4 n = static_cast<Int4>(ceil(abs(this->srcBin.at(i).back() - this->srcBin.at(i).front())/this->width));
        DebugMessage(classname, memberName, __FILE__, __LINE__, "n = %d\n", n);
        
        this->newSrcBin.at(i) = std::vector<Double>(n+1);
        std::generate(this->newSrcBin.at(i).begin(), this->newSrcBin.at(i).end(), BinGen(this->srcBin.at(i).front(), width, 0));
        DebugMessage(className, memberName, __FILE__, __LINE__, "generate new bins\n");
        DebugMessage(className, memberName, __FILE__, __LINE__, "size of new bins:%d\n", this->newSrcBin.at(i).size());
        DebugMessage(className, memberName, __FILE__, __LINE__, "value at front of new bins:%e\n", this->newSrcBin.at(i).front());
        DebugMessage(className, memberName, __FILE__, __LINE__, "value at back  of new bins:%e\n", this->newSrcBin.at(i).back());

        this->newSrcY.at(i)    = std::vector<Double>(n-1);
        this->newSrcYErr.at(i) = std::vector<Double>(n-1);
        this->extRebin(this->srcBin.at(i), this->srcY.at(i), this->srcYErr.at(i), this->newSrcBin.at(i), this->newSrcY.at(i), this->newSrcYErr.at(i));
        std::cerr << "done rebining of the " << i << "-th. data" << std::endl;
        std::cerr << "size of bin  : " << this->newSrcBin.at(i).size() << std::endl;
        std::cerr << "size of value: " << this->newSrcY.at(i).size() << std::endl;
        std::cerr << "size of err  : " << this->newSrcYErr.at(i).size() << std::endl;
    }

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

ElementContainer* AdvEqualSpacing::exportAsElementContainer(ElementContainer* src, const std::vector<Double>& bin, const std::vector<Double>& y, const std::vector<Double>& e) const {
    std::string xkey  = src->PutXKey();
    std::string ykey  = src->PutYKey();
    std::string ekey  = src->PutEKey();
    std::string xunit = src->PutUnit(xkey);
    std::string yunit = src->PutUnit(ykey);
    std::string eunit = src->PutUnit(ekey);

    ElementContainer *dest=new ElementContainer(src->PutHeader());
    dest->Add(xkey, bin, xunit);
    dest->Add(ykey, y,   yunit);
    dest->Add(ekey, e,   eunit);
    dest->SetKeys(xkey, ykey, ekey);

    return dest;
}
/*
*/
void AdvEqualSpacing::toElementContainerArray(ElementContainerArray& src, ElementContainerArray& dest) const {

    std::cerr << "index resolution data  : " << this->resID << std::endl;
    std::cerr << "size of bin  : " << this->newResBin.size() << std::endl;
    std::cerr << "size of value: " << this->newResY.size() << std::endl;
    std::cerr << "size of err  : " << this->newResYErr.size() << std::endl;
    Int4 offset=0;

    for (UInt4 i=0; i<src.PutSize(); ++i) {
        ElementContainer *srcEc = src.PutPointer(i);
       
        std::cerr << "current index  : " << i << std::endl;
        ElementContainer *destEc;
        if (i == this->resID) {
            destEc = exportAsElementContainer(srcEc, this->newResBin, this->newResY, this->newResYErr);
            offset=-1;
        } else {
            destEc = exportAsElementContainer(srcEc, this->newSrcBin.at(i+offset), this->newSrcY.at(i+offset), this->newSrcYErr.at(i+offset));
        }

        dest.AddPointer(destEc);
    }
}
