#include "Header.hh"
#include "Domain.hh"
#include "ParamSet.hh"
#include "MovingAverage.hh"
#include "BSpline.hh"
#include "MethodType.hh"
#include <cmath>
#include <cstdlib>
#include <ios>
#include <ctime>

int main(Int4 argc, Char **argv) {

    ElementContainer src;

    vector<Double> x;
    vector<Double> y;
    vector<Double> e;
    vector<Double> r;

    const UInt4 N=1500;
    Double xbegin=0.0;
    Double xend=15.0;

    Double p, q, s, t, a;

    Double xdelta=(xend-xbegin)/N;
    for(UInt4 i=0; i <= N; ++i) {
        //x.push_back(static_cast<Double>(i));
        x.push_back(xbegin + xdelta*i);
    }
    //std::cout << "bin.size()=" <<x.size() << endl;

    for(UInt4 i=0; i < N; ++i) {
        a=(x.at(i) + x.at(i+1))/2.0;
        //p=100000.0*exp(-1.0*pow((a - 7.5)/2.5, 2.0)) + 30000.0*exp(-1.0*pow((a - 3.0)/3.0, 2.0)) + 5000.0*exp(-1.0*pow((a-13.0)/4.0, 2.0)) + 1000.0;
        p=100000.0*exp(-1.0*pow((a - 5.0)/2.5, 2.0)) + 100000.0*exp(-1.0*pow((a-10.0)/2.5, 2.0)) + 1000.0;
        s=static_cast<Double>(rand())/static_cast<Double>(RAND_MAX);
        t=static_cast<Double>(rand())/static_cast<Double>(RAND_MAX) - 0.5;
        q=(t>0.0 ? 1.0 : (t=0.0 ?  0.0 : -1.0))*(p/10.0)*sqrt(-1.0*log(s));
        e.push_back(p/10.0);
        y.push_back(floor(p + q));
    }


    src.AddToHeader("run number", 1);
    src.AddToHeader("level", 1);
    src.AddToHeader("Inst.", "manyo");
    src.Add("TOF", x);
    src.Add("Intensity", y);
    src.Add("Error", e);
    src.SetKeys("TOF", "Intensity", "Error");
    //std::cout << "testDomain.cc::main, PutXKey() = " << src.PutXKey() << '\n';
    r = src.Put("TOF");
    //std::cout << "testDomain.cc::main, " << r.size() << '\n';
    r = src.Put(src.PutXKey());
    //std::cout << "testDomain.cc::main, " << r.size() << '\n';
    r = src.Put(src.PutXKey());
    for (std::vector<Double>::const_iterator cur = r.begin(); cur != r.end(); ++cur) {
        //std::cout << "testDomain.cc::main, r= " << *cur << '\n';
    }
    //std::cout << "testDomain.cc::main, PutXKey=" << src.PutXKey() << ", PutYKey=" << src.PutYKey() << ", PutEKey=" << src.PutEKey() << endl;
    src.Dump();

    ElementContainer *result = new ElementContainer(src.PutHeader());
    //std::cout << "testDomain.cc::main, result CheckKey operation ==> " << result->PutHeaderPointer()->CheckKey("operation") << '\n';
    //std::cout << "testDomain.cc::main, result CheckKey method    ==> " << result->PutHeaderPointer()->CheckKey("method") << '\n';
    //std::cout << "testDomain.cc::main, result CheckKey BinBounds ==> " << result->PutHeaderPointer()->CheckKey("BinBounds") << '\n';
    result->AddToHeader("operation", "smoothing");
    //std::cout << "testDomain.cc::main, result CheckKey operation ==> " << result->PutHeaderPointer()->CheckKey("operation") << '\n';
    result->AddToHeader("method", "moving average");
    //std::cout << "testDomain.cc::main, result CheckKey method    ==> " << result->PutHeaderPointer()->CheckKey("method") << '\n';
    //result->Dump();

    //UInt4 wLower;
    UInt4 wUpper, width;
    Double lamda;
    UInt4 lower, upper;

    std::cout << "input window width, window offset, lamda  ==>" << endl;
    std::cin >> width >> wUpper >> lamda;
    std::cout << width << wUpper << lamda;
    std::cout << "input lower and upper bound od domain  ==>" << endl;
    std::cin >> lower >> upper;
    std::cout << lower << upper;

    //wLower=width-wUpper-1;

    Domain domain;
    domain.setSource(src);
    domain.setType(Domain::CC);

    domain.setRange(width-wUpper-1, src.PutSize(src.PutXKey())-wUpper-1);
    //domain.setRange(max(lower, width-wUpper-1), min(upper, src.PutSize(src.PutXKey())-wUpper-1));
    std::cout << "testDomain.cc::main, result CheckKey BinBounds ==> " << result->PutHeaderPointer()->CheckKey("BinBounds") << endl;
    //std::cout << "testDomain.cc::main, result PutHeaderPointer ==> " << result->PutHeaderPointer() == static_cast<HeaderBase*>(NULL) << endl;
    std::cout << "testDomain.cc::main, result getLower ==> " << domain.getLowerBound() << endl ;
    std::cout << "testDomain.cc::main, result getLower ==> " << domain.getUpperBound() << endl ;
    std::cout << "testDomain.cc::main, result getLower ==> " << domain.getLowerBoundID() << endl ;
    std::cout << "testDomain.cc::main, result getLower ==> " << domain.getUpperBoundID() << endl ;


    std::cout << "testDomain.cc::main, the width of the window              ==> " << width  << endl ;
    //std::cout << "testDomain.cc::main, the lower bound offset of the window ==> " << wLower << endl ;
    std::cout << "testDomain.cc::main, the upper bound offset of the window ==> " << wUpper << endl ;
    std::cout << "testDomain.cc::main, lamda                                ==> " << lamda  << endl ;
    std::cout << "testDomain.cc::main," << endl;

    ParamSet param;
    param.add("window width", width);
    param.add("window upper", wUpper);
    param.add("use strict definition", true);
    param.dump();


    MovingAverage method;
    //method.setDefaultParam(src).dump();
    std::cout << "checkParam=" << method.checkParam(src, domain, param) << endl;
    clock_t start, stop, total;
    total=0;
    for (int i=0; i<100; ++i) {
        start=clock();
        method.toInnerForm(src, domain, param);
        method.eval();
        stop=clock();

        total += (stop-start);
        printf("%5d %10ld %10ld %10ld %10ld\n", i, start, stop, stop-start, total);
    }

    std::cerr << "chi_sq = " << method.getLikehood() << endl;
    std::cout << "average time:" << total/100 << endl;
    
    std::cout << "testDomain.cc::main, methodName=" << method.getMethodName() << endl;
    method.getParamDescription();

//    //std::cout << "testDomain.cc::main, chi_sq=" << chi_sq << endl;
//    //std::cout << "testDomain.cc::main, smoothness=" << smoothness << endl;
//    //Double likehood=chi_sq + lamda*smoothness;
//    //printf("likehood    =%23.15e = %23.15e + %23.15e * %23.15e\n", likehood, chi_sq, lamda, smoothness);
//    printf("%12s %7s %23.15e\n", "chi_sq",     "", chi_sq    );
//    printf("%12s %7s %23.15e\n", "smoothness", "", smoothness);
//    printf("%12s %7s %23.15e\n", "lamda",      "", lamda);
//
//    result->AddToHeader("chi_sq",      chi_sq);
//    result->AddToHeader("smootheness", smoothness);
    result->AddToHeader("lamda",       lamda);

    method.toElementContainer(src, *result);
//
    result->SetKeys(src.PutXKey(), src.PutYKey(), src.PutEKey());
//    result->Dump();

    vector< vector<Double> > trend = method.getTrend();
    std::cerr << "trend.size()   =" << trend.size() << endl;
    for (UInt4 i=0U; i<trend.size(); ++i) {
        fprintf(stderr, "trend[%u].size()=%lu\n", i, trend[i].size());
    }
    UInt4 w  = param.getUInt4("window width");
    UInt4 wu = param.getUInt4("window upper");
    UInt4 wl = w - wu - 1;
    std::cerr << "window width" << "=" << w << endl;
    std::cerr << "window upper" << "=" << wu << endl;
    std::cerr << "window lower" << "=" << wl << endl;
    string xKey=src.PutXKey();
    string yKey=src.PutYKey();

    // forward difference
    /*
    UInt4 lowerBound1=0U,                                     upperBound1=max(lower, wl                  );
    UInt4 lowerBound2=max(lower, wl                  ),       upperBound2=max(lower, wl                  )+wl;
    UInt4 lowerBound3=max(lower, wl                  )+wl   , upperBound3=min(upper, src.PutSize(yKey)-wu)-wu-1U;
    UInt4 lowerBound4=min(upper, src.PutSize(yKey)-wu)-wu-1U, upperBound4=min(upper, src.PutSize(yKey)-wu);
    UInt4 lowerBound5=min(upper, src.PutSize(yKey)-wu),       upperBound5=           src.PutSize(yKey);
    */

    // backword difference
    /*
    UInt4 lowerBound1=0U,                                     upperBound1=max(lower, wl                  );
    UInt4 lowerBound2=max(lower, wl                  ),       upperBound2=max(lower, wl                  )+wl+1U;
    UInt4 lowerBound3=max(lower, wl                  )+wl+1U, upperBound3=min(upper, src.PutSize(yKey)-wu)-wu;
    UInt4 lowerBound4=min(upper, src.PutSize(yKey)-wu)-wu,    upperBound4=min(upper, src.PutSize(yKey)-wu);
    UInt4 lowerBound5=min(upper, src.PutSize(yKey)-wu),       upperBound5=           src.PutSize(yKey);
    */

    // central difference
    //UInt4 lowerBound1=0U,                                     upperBound1=max(lower, wl                  );
    //UInt4 lowerBound2=max(lower, wl                  ),       upperBound2=max(lower, wl                  )+wl+1U;
    //UInt4 lowerBound3=max(lower, wl                  )+wl+1U, upperBound3=min(upper, src.PutSize(yKey)-wu)-wu-1U;
    //UInt4 lowerBound4=min(upper, src.PutSize(yKey)-wu)-wu-1U, upperBound4=min(upper, src.PutSize(yKey)-wu);
    //UInt4 lowerBound5=min(upper, src.PutSize(yKey)-wu),       upperBound5=src.       PutSize(yKey);
    UInt4 lowerBound1, upperBound1;
    UInt4 lowerBound2, upperBound2;
    UInt4 lowerBound3, upperBound3;
    UInt4 lowerBound4, upperBound4;
    UInt4 lowerBound5, upperBound5;
    UInt4 lowerBound6, upperBound6;
    UInt4 lowerBound7, upperBound7;
    lowerBound1=max(lower, 3*wl) - 3*wl,                   upperBound1=max(lower, 3*wl) - 2*wl;
    lowerBound2=max(lower, 3*wl) - 2*wl,                   upperBound2=max(lower, 3*wl) -   wl;
    lowerBound3=max(lower, 3*wl) -   wl,                   upperBound3=max(lower, 3*wl);
    lowerBound4=max(lower, 3*wl),                          upperBound4=min(upper, src.PutSize(yKey)-3*wu);
    lowerBound5=min(upper, src.PutSize(yKey)-3*wu),        upperBound5=min(upper, src.PutSize(yKey)-3*wu) +   wu;
    lowerBound6=min(upper, src.PutSize(yKey)-3*wu) +   wu, upperBound6=min(upper, src.PutSize(yKey)-3*wu) + 2*wu;
    lowerBound7=min(upper, src.PutSize(yKey)-3*wu) + 2*wu, upperBound7=min(upper, src.PutSize(yKey)-3*wu) + 3*wu;
    printf("bound 1 [%5u, %5u) %u\n", lowerBound1, upperBound1, upperBound1-lowerBound1);
    printf("bound 2 [%5u, %5u) %u\n", lowerBound2, upperBound2, upperBound2-lowerBound2);
    printf("bound 3 [%5u, %5u) %u\n", lowerBound3, upperBound3, upperBound3-lowerBound3);
    printf("bound 4 [%5u, %5u) %u\n", lowerBound4, upperBound4, upperBound4-lowerBound4);
    printf("bound 5 [%5u, %5u) %u\n", lowerBound5, upperBound5, upperBound5-lowerBound5);
    printf("bound 6 [%5u, %5u) %u\n", lowerBound6, upperBound6, upperBound6-lowerBound6);
    printf("bound 7 [%5u, %5u) %u\n", lowerBound7, upperBound7, upperBound7-lowerBound7);
    printf("\n");

    lowerBound1=0U,                                         upperBound1=max(lower, wl                  );
    lowerBound2=max(lower, wl                  ),           upperBound2=max(lower, wl                  )+   wl+1U;
    lowerBound3=max(lower, wl                  )+   wl+1U,  upperBound3=max(lower, wl                  )+2*(wl+1U);
    lowerBound4=max(lower, wl                  )+2*(wl+1U), upperBound4=min(upper, src.PutSize(yKey)-wu)-2*(wu+1U);
    lowerBound5=min(upper, src.PutSize(yKey)-wu)-2*(wu+1U), upperBound5=min(upper, src.PutSize(yKey)-wu)-wu-1U;
    lowerBound6=min(upper, src.PutSize(yKey)-wu)-wu-1U,     upperBound6=min(upper, src.PutSize(yKey)-wu);
    lowerBound7=min(upper, src.PutSize(yKey)-wu),           upperBound7=src.       PutSize(yKey);
    printf("bound 1 [%5u, %5u) %u\n", lowerBound1, upperBound1, upperBound1-lowerBound1);
    printf("bound 2 [%5u, %5u) %u\n", lowerBound2, upperBound2, upperBound2-lowerBound2);
    printf("bound 3 [%5u, %5u) %u\n", lowerBound3, upperBound3, upperBound3-lowerBound3);
    printf("bound 4 [%5u, %5u) %u\n", lowerBound4, upperBound4, upperBound4-lowerBound4);
    printf("bound 5 [%5u, %5u) %u\n", lowerBound5, upperBound5, upperBound5-lowerBound5);
    printf("bound 6 [%5u, %5u) %u\n", lowerBound6, upperBound6, upperBound6-lowerBound6);
    printf("bound 7 [%5u, %5u) %u\n", lowerBound7, upperBound7, upperBound7-lowerBound7);
    printf("\n");

    printf("%5s %5s %23s %10s %23s", "", "No.", "range of bin", "mid point", "original");
    printf(" %13s %23s", "range of sum", "moving average");
    printf(" %23s %23s", "1st. diff quot", "2nd. diff quot");
    printf("\n");
    Double binL, binU, xm;
    for (UInt4 i=0U; i<wl; ++i) {
        binL=src.Put(xKey, i  );
        binU=src.Put(xKey, i+1U);
        xm = (binL + binU)/2.0;
        printf("%5s %5u [%10.5f %10.5f) %10.5f %23.15e", "loop1", i, binL, binU, xm, src.Put(yKey, i));
        printf(" [%5u %5u] %23.15e", 0, i+wu, trend[0][i]);
        printf(" %23.15e %23.15e", trend[1][i], trend[2][i]);
        printf("\n");
    }
    /*
    for (UInt4 i=wl; i<2*wl+1U; ++i) {
        binL=src.Put(xKey, i  );
        binU=src.Put(xKey, i+1U);
        xm = (binL + binU)/2.0;
        printf("%5s %5u, [%10.5f %10.5f) %10.5f %23.15e", "loop2", i, binL, binU, xm, src.Put(yKey, i));
        printf(" [%5u %5u] %23.15e", i-wl, i+wu, trend[0][i-wl]);
        printf("\n");
    }
    for (UInt4 i=2*wl+1U; i < 3*wl + 2U; ++i) {
        binL=src.Put(xKey, i);
        binU=src.Put(xKey, i+1U);
        xm = (binL + binU)/2.0;
        printf("%5s %5u, [%10.5f %10.5f) %10.5f %23.15e", "loop3", i, binL, binU, xm, src.Put(yKey, i));
        printf(" [%5u %5u] %23.15e", i-wl, i+wu, trend[0][i-wl]);
        printf(" %23.15e", trend[1][i-2*wl-1U]);
        printf("\n");
    }
    */
    //for (UInt4 i=3*wl+2U; i<src.PutSize(yKey)-3*wu-2U; ++i) {
    for (UInt4 i=wl; i<src.PutSize(yKey)-wu; ++i) {
        binL=src.Put(xKey, i  );
        binU=src.Put(xKey, i+1U);
        xm = (binL + binU)/2.0;
        printf("%5s %5u [%10.5f %10.5f) %10.5f %23.15e", "loop4", i, binL, binU, xm, src.Put(yKey, i));
        printf(" [%5u %5u] %23.15e", i-wl, i+wu, trend[0][i]);
        //printf(" [%5u %5u] %23.15e", i-wl, i+wu, trend[0][i-wl]);
        printf(" %23.15e %23.15e", trend[1][i], trend[2][i]);
        //printf(" %23.15e %23.15e", trend[1][i-2*wl-1U], trend[2][i-3*wl-2U]);
        printf("\n");
    }
    /*
    for (UInt4 i=src.PutSize(yKey)-3*wu-2U; i<src.PutSize(yKey)-2*wu-1U; ++i) {
        binL=src.Put(xKey, i);
        binU=src.Put(xKey, i+1U);
        xm = (binL + binU)/2.0;
        printf("%5s %5u, [%10.5f %10.5f) %10.5f %23.15e", "loop5", i, binL, binU, xm, src.Put(yKey, i));
        printf(" [%5u %5u] %23.15e", i-wl, i+wu, trend[0][i-wl]);
        printf(" %23.15e", trend[1][i-2*wl-1U]);
        printf("\n");
    }
    for (UInt4 i=src.PutSize(yKey)-2*wu-1U; i<src.PutSize(yKey)-wu; ++i) {
        binL=src.Put(xKey, i  );
        binU=src.Put(xKey, i+1U);
        xm = (binL + binU)/2.0;
        printf("%3s %5u, [%10.5f %10.5f) %10.5f %23.15e", "loop6", i, binL, binU, xm, src.Put(yKey, i));
        printf(" [%5u %5u] %23.15e", i-wl, i+wu, trend[0][i-wl]);
        printf("\n");
    }
    */
    for (UInt4 i=src.PutSize(yKey)-wu; i<src.PutSize(yKey); ++i) {
        binL=src.Put(xKey, i  );
        binU=src.Put(xKey, i+1U);
        xm = (binL + binU)/2.0;
        printf("%5s %5u [%10.5f %10.5f) %10.5f %23.15e", "loop7", i, binL, binU, xm, src.Put(yKey, i));
        printf(" [%5u %5u] %23.15e", i-wl, src.PutSize(yKey)-1, trend[0][i]);
        printf(" %23.15e %23.15e", trend[1][i], trend[2][i]);
        printf("\n");
    }

    // found peak
    //UInt4 lowerBound1=0U,                                         upperBound1=max(lower, wl                  );
    /*
    UInt4 offset0=max(lower, wl);
    UInt4 offset1=max(lower, wl)+   wl+1U;
    UInt4 offset2=max(lower, wl)+2*(wl+1U);
    for (UInt4 i=max(lower, wl)+2*(wl+1U); i<min(upper, src.PutSize(yKey)-wu)-2*(wu+1U)-1U; ++i) {
        //printf("searching peak/sholder i=%5u i-offset0=%5u i-offset1=%5u i+1-offset1=%5u i-offset2=%5u i+1-offset2=%5u\n", i, i-offset0, i-offset1, i+1-offset1, i-offset2, i+1-offset2);
        if ( trend[1].at(i-offset1) > 0.0 && 0.0 > trend[1].at(i+1-offset1) ) {
            Double x, h, w, xl, xr;
            x=src.Put(src.PutXKey(), i+1);
            h=(trend[0].at(i-offset0) + trend[0].at(i+1-offset0))/2.0;
            // found the left hald-value width 
            xl=x;
            for (UInt4 j=i; j>max(lower, wl)+2*(wl+1U)+1U; --j) {  // found the half-value point
                //printf("searching half-value point on left side: j=%5u j-offsert0=%5u j-1-offset0=%5u\n", j, j-offset0, j-1-offset0);
                if ( trend[0].at(j-1-offset0) < h/2.0 && h/2.0 < trend[0].at(j-offset0) ) {
                    xl=src.Put(src.PutXKey(), j);
                    printf("found half-value point on left side: j=%5u j-offsert0=%5u j-1-offset0=%5u xl=%23.15e\n", j, j-offset0, j-1-offset0, xl);
                     break;
                } else if ( h/2.0 < trend[0].at(j-1-offset0) && h/2.0 < trend[0].at(j-offset0) &&
                            trend[1].at(j-1-offset1) < 0.0 && 0.0 < trend[1].at(j+1-offset1) &&
                            trend[2].at(j-1-offset2) > 0.0 && trend[2].at(j+1-offset2) > 0.0) { // the truning point of wtich value is larger than the half value of peak height
                    xl=src.Put(src.PutXKey(), j);
                    printf("found turning point on left side: j=%5u j-offsert0=%5u j-1-offset0=%5u xl=%23.15e\n", j, j-offset0, j-1-offset0, xl);
                    break;
                } //else if ( h/2.0 < trend[0].at(j-1-offset0) && trend[0].at(j-1-offset0) < trend[0].at(j-offset0) &&
                //            0.0   < trend[1].at(j-1-offset1) && 0.0 < trend[0].at(j-offset1)
                //    ) {
                //    printf("found end point on left side: j=%5u j-offsert0=%5u j-1-offset0=%5u\n", j, j-offset0, j-1-offset0);
                //    xl=src.Put(src.PutXKey(), j-1);
                //    break;
                //}
            }
            // found the right hald-value width 
            xr=x;
            for (UInt4 j=i+1; j< min(upper, src.PutSize(yKey)-wu)-2*(wu+1U)-1U; ++j) {
                //printf("searching half-value point on right size: j=%5u j-offsert0=%5u j+1-offset0=%5u\n", j, j-offset0, j+1-offset0);
                if ( trend[0].at(j-offset0) > h/2.0 && h/2.0 > trend[0].at(j+1-offset0) ) {
                    xr=src.Put(src.PutXKey(), j+1);
                    printf("found half-value point on right side: j=%5u j-offsert0=%5u j+1-offset0=%5u xr=%23.15e\n", j, j-offset0, j+1-offset0, xr);
                    break;
                } else if ( h/2.0 < trend[0].at(j-offset0) && h/2.0 < trend[0].at(j+1-offset0) &&
                            trend[1].at(j-offset1) < 0.0 && 0.0 < trend[1].at(j+1-offset1) &&
                            trend[2].at(j-offset2) > 0.0 && trend[2].at(j+1-offset2) > 0.0) { // the truning point of wtich value is larger than the half value of peak height
                    xr=src.Put(src.PutXKey(), j+1);
                    printf("found turning point on right side: j=%5u j-offsert0=%5u j+1-offset0=%5u xr=%23.15e\n", j, j-offset0, j+1-offset0, xr);
                    break;
                }
            }
            w = (xr-xl)/2.0;
            printf("found a peak: x=%23.15e h=%23.15e, xl=%23.15e xr=%23.15e w=%23.15e\n", x, h, xl, xr, w);
        } else if ( 0.0 < trend[1].at(i-offset1)       && 0.0 < trend[1].at(i+1-offset1) &&
                          trend[2].at(i-offset2) < 0.0 && 0.0 < trend[2].at(i+1-offset2) ) { // sholder
            Double x, h, w, xl, xr;
            x=src.Put(src.PutXKey(), i+1);
            h=(trend[0].at(i-offset0) + trend[0].at(i+1-offset0))/2.0;

            xl=x;
            for (UInt4 j=i; j>max(lower, wl)+2*(wl+1U); --j) {
                //printf("founding sholder: j=%5u j-offsert0=%5u j-1-offset0=%5u\n", j, j-offset0, j-1-offset0);
                if ( trend[0].at(j-1-offset0) < h/2.0 && h/2.0 < trend[0].at(j-offset0) ) {
                    xl=src.Put(src.PutXKey(), j);
                    break;
                } else if (h/2.0 < trend[0].at(j-1-offset0) && h/2.0 < trend[0].at(j-offset0) &&
                           trend[1].at(j-1-offset1) < 0.0   && 0.0   < trend[1].at(j-offset1) &&
                           trend[2].at(j-1-offset2) > 0.0   && trend[2].at(j-offset2) > 0.0   ) {
                    xl=src.Put(xKey, j);
                    break;
                }
            }
            // found the right hald-value width 
            printf("found sholder: x=%23.15e h=%23.15e, xl=%23.15e w=%23.15e\n", x, h, xl, x-xl);
        } else if ( 0.0 > trend[1].at(i-offset1)       && 0.0 > trend[1].at(i+1-offset1) &&
                          trend[2].at(i-offset2) > 0.0 && 0.0 > trend[2].at(i+1-offset2) ) { // sholder
            Double x, h, w, xl, xr;
            x=src.Put(src.PutXKey(), i+1);
            h=(trend[0].at(i-offset0) + trend[0].at(i+1-offset0))/2.0;

            xr=x;
            for (UInt4 j=i+1; j< min(upper, src.PutSize(yKey)-wu)-2*(wu+1U)-1U; ++j) {
                if ( trend[0].at(j) > h/2.0 && h/2.0 > trend[0].at(j+1) ) {
                    xr=src.Put(src.PutXKey(), j+1);
                    break;
                }
            }
            // found the right hald-value width 
            printf("found sholder: x=%23.15e h=%23.15e, xr=%23.15e w=%23.15e\n", x, h, xr, xr-x);
        }
    }
    */


    for (UInt4 i=0; i<trend[0].size()-1; ++i) {
        //printf("searching peak/sholder i=%5u\n", i);
        if ( trend[1].at(i) > 0.0 && 0.0 > trend[1].at(i+1) ) {
            Double x, h, w, xl, xr;
            x=src.Put(src.PutXKey(), i+1);
            h=(trend[0].at(i) + trend[0].at(i+1))/2.0;
            // found the left hald-value width 
            xl=x;
            for (UInt4 j=i; j>0; --j) {  // found the half-value point
                //printf("searching half-value point on left side: j=%5u j=%5u j-1=%5u\n", j, j, j-1);
                if ( trend[0].at(j-1) < h/2.0 && h/2.0 < trend[0].at(j) ) {
                    xl=src.Put(src.PutXKey(), j);
                    printf("found half-value point on left side: j=%5u j-offsert0=%5u j-1=%5u xl=%23.15e\n", j, j, j-1, xl);
                     break;
                } else if ( h/2.0 < trend[0].at(j-1) && h/2.0 < trend[0].at(j) &&
                            trend[1].at(j-1) < 0.0 && 0.0 < trend[1].at(j+1) &&
                            trend[2].at(j-1) > 0.0 && trend[2].at(j+1) > 0.0) { // the truning point of wtich value is larger than the half value of peak height
                    xl=src.Put(src.PutXKey(), j);
                    printf("found turning point on left side: j=%5u j-offsert0=%5u j-1=%5u xl=%23.15e\n", j, j, j-1, xl);
                    break;
                } //else if ( h/2.0 < trend[0].at(j-1) && trend[0].at(j-1) < trend[0].at(j) &&
                //            0.0   < trend[1].at(j-1) && 0.0 < trend[0].at(j)
                //    ) {
                //    printf("found end point on left side: j=%5u j-offsert0=%5u j-1=%5u\n", j, j, j-1);
                //    xl=src.Put(src.PutXKey(), j-1);
                //    break;
                //}
            }
            // found the right hald-value width 
            xr=x;
            for (UInt4 j=i+1; j< min(upper, src.PutSize(yKey)-wu)-2*(wu+1U)-1U; ++j) {
                //printf("searching half-value point on right size: j=%5u j-offsert0=%5u j+1=%5u\n", j, j, j+1);
                if ( trend[0].at(j) > h/2.0 && h/2.0 > trend[0].at(j+1) ) {
                    xr=src.Put(src.PutXKey(), j+1);
                    printf("found half-value point on right side: j=%5u j-offsert0=%5u j+1=%5u xr=%23.15e\n", j, j, j+1, xr);
                    break;
                } else if ( h/2.0 < trend[0].at(j) && h/2.0 < trend[0].at(j+1) &&
                            trend[1].at(j) < 0.0 && 0.0 < trend[1].at(j+1) &&
                            trend[2].at(j) > 0.0 && trend[2].at(j+1) > 0.0) { // the truning point of wtich value is larger than the half value of peak height
                    xr=src.Put(src.PutXKey(), j+1);
                    printf("found turning point on right side: j=%5u j-offsert0=%5u j+1=%5u xr=%23.15e\n", j, j, j+1, xr);
                    break;
                }
            }
            w = (xr-xl)/2.0;
            printf("found a peak: x=%23.15e h=%23.15e, xl=%23.15e xr=%23.15e w=%23.15e\n", x, h, xl, xr, w);
        } else if ( 0.0 < trend[1].at(i)       && 0.0 < trend[1].at(i+1) &&
                          trend[2].at(i) < 0.0 && 0.0 < trend[2].at(i+1) ) { // sholder
            Double x, h, w, xl;
            x=src.Put(src.PutXKey(), i+1);
            h=(trend[0].at(i) + trend[0].at(i+1))/2.0;

            xl=x;
            for (UInt4 j=i; j>max(lower, wl)+2*(wl+1U); --j) {
                //printf("founding sholder: j=%5u j-offsert0=%5u j-1=%5u\n", j, j, j-1);
                if ( trend[0].at(j-1) < h/2.0 && h/2.0 < trend[0].at(j) ) {
                    xl=src.Put(src.PutXKey(), j);
                    break;
                } else if (h/2.0 < trend[0].at(j-1) && h/2.0 < trend[0].at(j) &&
                           trend[1].at(j-1) < 0.0   && 0.0   < trend[1].at(j) &&
                           trend[2].at(j-1) > 0.0   && trend[2].at(j) > 0.0   ) {
                    xl=src.Put(xKey, j);
                    break;
                }
            }
            w=x-xl;
            // found the right hald-value width 
            printf("found sholder: x=%23.15e h=%23.15e, xl=%23.15e w=%23.15e\n", x, h, xl, w);
        } else if ( 0.0 > trend[1].at(i)       && 0.0 > trend[1].at(i+1) &&
                          trend[2].at(i) > 0.0 && 0.0 > trend[2].at(i+1) ) { // sholder
            Double x, h, w, xr;
            x=src.Put(src.PutXKey(), i+1);
            h=(trend[0].at(i) + trend[0].at(i+1))/2.0;

            xr=x;
            for (UInt4 j=i+1; j< min(upper, src.PutSize(yKey)-wu)-2*(wu+1U)-1U; ++j) {
                if ( trend[0].at(j) > h/2.0 && h/2.0 > trend[0].at(j+1) ) {
                    xr=src.Put(src.PutXKey(), j+1);
                    break;
                }
            }
            w=xr-x;
            // found the right hald-value width 
            printf("found sholder: x=%23.15e h=%23.15e, xr=%23.15e w=%23.15e\n", x, h, xr, xr-x);
        }
    }


}
