#include <iostream>
#include <fstream>
#include <iomanip>
#include <ctime>
#include <cmath>
#include <sstream>
#include <csignal>
#include <vector>
#include <cstdlib>
#include <cerrno>
#include <climits>
#include <TROOT.h>
#include <TCanvas.h>
#include <TProfile2D.h>
#include <TF1.h>
#include <TH1.h>
#include <TH2.h>
#include "AsciiRoot.h"
#include "utils.h"
#include "Tracer.h"
#include "Hit.h"
#include "ChanList.h"


#ifdef __APPLE__
#define sighandler_t sig_t
#endif

bool _A_do_run = true;
void _A_got_intr(int)
{
    _A_do_run = false;
}

// decodes the header and returns a vector with the integers found
std::vector<int> decode_header(const std::string &h, AsciiRoot::XtraValues &xtra)
{
    std::vector<int> vout;
    std::istringstream istr(h);
    char *endptr, *str;
    char buf[256];
    long val;

    xtra.clear();

    while (istr)
    {
        istr.getline(buf, sizeof(buf), ';');
        if (!istr)
            break;

        errno = 0;
        val = strtol(buf, &endptr, 0);

        if ((errno == ERANGE && (val == LONG_MAX || val == LONG_MIN)) || (errno != 0 && val == 0))
        {
            std::string sval(buf), sout;
            sout = trim_str(sval);
            if (!sout.empty())
                xtra.push_back( sout );
        }
        else if ( endptr == buf || *endptr != '\0' )
        {
            std::string sval(buf), sout;
            sout = trim_str(sval);
            if (!sout.empty())
                xtra.push_back( sout );
        }
        else
        {
            vout.push_back(atoi(buf) );
        }
    }
    return vout;
}

AsciiRoot::AsciiRoot(const char *nam, const char *pedfile, const char *gainfile) :
    _nchan(max_nchan),_seedcut(10.), _neighcut(5.), _average_gain(1.), _version(2), _polarity(1)
{
    int i;
    for (i=0;i<max_nchan;i++)
    {
        _ped[i] = 0.;
        _gain[i] = 1.;
        _noise[i] = 1.;
        _data.data[i] = 0;
        _mask[i] = false;
    }

    if (nam)
        open(nam);

    if (pedfile)
        load_pedestals(pedfile);

    if (gainfile)
        load_gain(gainfile);

    // TODO: this loads a "fixed" name file. Be more general...
    // load_masking();
}
AsciiRoot::~AsciiRoot()
{
    if (ifile)
    {
        ifile->close();
    }
}

void AsciiRoot::open(const char *name)
{
    ifile = new std::ifstream(name);
    if (!(*ifile))
    {
        std::cout << "Could not open data file: " << name << std::endl;
        delete ifile;
        ifile = 0;
		return;
    }
    std::string header;
    unsigned int ic, lheader;
    char c;
    ifile->read((char *)&_t0, sizeof(time_t));
    //std::cout << "64b: " << ctime(&_t0) << std::endl;
    ifile->read((char *)&_type, sizeof(int));
    //std::cout << "type_ " << _type << std::endl;
    if ( _type > 15 )
    {
        ifile->seekg(0, std::ios::beg);
        ifile->read((char *)&_t0, sizeof(int));
        ifile->read((char *)&_type, sizeof(int));
        //std::cout << "32b: " << ctime(&_t0) << std::endl;
    }


    ifile->read((char *)&lheader, sizeof(unsigned int));
    for (ic=0; ic<80; ic++)
    {
        ifile->read(&c, sizeof(char));
    //std::cout << "biplab header ch1 " << c << std::endl; 
        header.append(1, c);
    }
    header = trim_str(header);
    //std::cout << "biplab header ch2 " << header << std::endl; 

    if (header[0]!='V' && header[0]!='v')
    {
        _version = 0;
    }
    else
    {
        _version = int(header[1]-'0');
        header = header.substr(5);
    }

    std::cout << "type: " << _type << " header: " << header << std::endl;
    std::vector<int> param = decode_header(header, _xtra);
    ifile->read((char *)_ped, max_nchan*sizeof(double));
    ifile->read((char *)_noise, max_nchan*sizeof(double));
    switch (_type)
    {
        case 1: // calibration
        case 2: // laser sync
            _npoints = param[0];
            _from = param[1];
            _to = param[2];
            _step = param[3];
            break;
        case 3: // laser run
        case 4: // source run
        case 5: // pedestal run
            if (param.empty())
                _nevts = 100000;
            else
                _nevts = param[0];
            _npoints = _from = _to = _step = 0;
            break;
    }
    data_start = ifile->tellg();
}

void AsciiRoot::rewind()
{
    if (ifile)
    {
        ifile->clear();
        ifile->seekg(data_start, std::ios::beg);
    }
}

void AsciiRoot::close()
{
    if (ifile)
    {
        ifile->close();
        delete ifile;
        ifile = 0;
    }
}

void AsciiRoot::reset_data()
{
    memset(&_data, 0, sizeof(_data));
}

int AsciiRoot::read_event()
{
    if (ifile)
    {
        unsigned int header, size, user=0, code=0;
        char *block_data=0;
        if (_version)
        {
            do
            {
                do
                {
                    ifile->read((char *)&header, sizeof(unsigned int));
                    if (ifile->bad() || ifile->eof())
                        return -1;

                    code = (header>>16) & 0xFFFF;
                } while ( code != 0xcafe );

                code = header & 0x0fff;
                user = header & 0x1000;
                switch (code)
                {
                    case NewFile:
                        ifile->read((char *)&size, sizeof(unsigned int));
                        block_data = new char[size];
                        ifile->read(block_data, size);
                        new_file(size, block_data);
                        break;
                    case StartOfRun:
                        ifile->read((char *)&size, sizeof(unsigned int));
                        block_data = new char[size];
                        ifile->read(block_data, size);
                        start_of_run(size, block_data);
                        break;
                    case DataBlock:
                        ifile->read((char *)&size, sizeof(unsigned int));
                        if (user)
                        {
                            reset_data();
                            block_data = new char[size];
                            ifile->read(block_data, size);
                            new_data_block(size, block_data);
                        }
                        else
                        {
                            if ( _version == 1 )
                            {
                                ifile->read((char *)&_data, sizeof(EventData));
                                for (int ii=0; ii<2; ii++)
                                    memset(_header[ii], 0, 16*sizeof(unsigned short));

                            }
                            else
                            {
                                ifile->read((char *)&_data.value, sizeof(double));
                                ifile->read((char *)&_data.time, sizeof(unsigned int));
                                ifile->read((char *)&_data.temp, sizeof(unsigned short));
                                for (int ii=0; ii<2; ii++)
                                {
                                    ifile->read((char *)_header[ii], 16*sizeof(unsigned short));
                                    ifile->read((char *)&_data.data[ii*128], 128*sizeof(unsigned short));
                                }
                            }
                        }

                        break;
                    case CheckPoint:
                        ifile->read((char *)&size, sizeof(unsigned int));
                        block_data = new char[size];
                        ifile->read(block_data, size);
                        check_point(size, block_data);
                        break;
                    case EndOfRun:
                        ifile->read((char *)&size, sizeof(unsigned int));
                        block_data = new char[size];
                        ifile->read(block_data, size);
                        end_of_run(size, block_data);
                        break;
                    default:
                        std::cout << "Unknown block data type: " << std::hex << header << " - " << code << std::dec << std::endl;
                }
                if (block_data)
                {
                    delete [] block_data;
                    block_data = 0;
                }

            } while ( code != DataBlock && !(ifile->bad() || ifile->eof()) );
        }
        else
        {
            ifile->read((char *)&_data, sizeof(EventData));
            for (int ii=0; ii<2; ii++)
                memset(_header[ii], 0, 16*sizeof(unsigned short));
        }

        if (ifile->eof())
        {
            std::cout << "End of file" << std::endl;
            return -1;
        }
        else if (ifile->bad())
        {
            std::cout << "Problems with data file" << std::endl;
            return -1;
        }
        else
        {
            //process_event();
            return 0;
        }
    }
    else
        return -1;
}

void AsciiRoot::set_data(int nchan, const unsigned short int *data)
{
    int i;
    _nchan = nchan;
    for (i=0;i<_nchan;i++)
        _data.data[i] = data[i];
}


double AsciiRoot::time() const
{
    unsigned short fpart = _data.time & 0xffff;
    short ipart = (_data.time & 0xffff0000)>>16;
    if (ipart<0)
        fpart *= -1;
//    double tt = 100.*(1. -(ipart + (fpart/65535.)));
    double tt = 100.0*(ipart + (fpart/65535.));
    return tt;
}

double AsciiRoot::temp() const
{
    return 0.12*_data.temp - 39.8;
}


TH1 *AsciiRoot::show_pedestals()
{
    int ic;
    TH1 *hst = create_h1("hPed","Pedestals",nchan(),-0.5, nchan()-0.5);
    hst->SetYTitle("ADCs");
    hst->SetXTitle("Channel no.");
    for (ic=0; ic<nchan(); ic++)
        hst->SetBinContent(ic+1, _ped[ic]);

    return hst;
}

TH1 *AsciiRoot::show_noise()
{
    int ic;
    TH1 *hst = create_h1("hNoise","Noise",nchan(),-0.5, nchan()-0.5);
    if (gain()==1)
    {
        hst->SetYTitle("ADCs");
    }
    else
    {
        hst->SetYTitle("e^{-} ENC");
    }
    hst->SetXTitle("Channel no.");
    for (ic=0; ic<nchan(); ic++)
        hst->SetBinContent(ic+1, noise(ic));

    return hst;
}



// Save ADC values in "ADCs" 2D-array of type unsigned short and size "evts x N".
//void AsciiRoot::get_ADC_values(unsigned short *ADCs, const Int_t N, const Int_t evts)
void AsciiRoot::get_ADC_time_temp_values(unsigned short *ADCs, double *_time, double *_temp, const Int_t N, const Int_t evts)
{
  int i = -1;
  int ievt = -1;

  if (!ifile)
    return;

  std::ifstream::pos_type here = ifile->tellg();
  std::cout << "==================================================" << std::endl;
  std::cout << "Saving ADC values..." << std::endl;
  std::cout << "==================================================" << std::endl; 
 // int evt_count(0);
 // for (ievt=0; read_event()==0 ; ievt++){ evt_count++; }
 // std::cout << "biplabd count events: "  << evt_count << std::endl; 
 // rewind();

  for (ievt=0; read_event()==0 && ievt<evts; ievt++){
    //  std::cout << "evt num: " << ievt << " temp: " << temp() << " time " << time() << std::endl;
    _time[ievt] = time();
    _temp[ievt] = temp();
    for (i=0; i<N; i++){
      *(ADCs+N*ievt+i) = _data.data[i];
    }
  }

  rewind();

  return;
}


// Added by BD on 9th June 2014, modified by FL on 7th October 2014
int AsciiRoot::get_nevents(){
  int evt_count(0);
  if (!ifile) return evt_count;
  while (read_event()==0) evt_count++; 
  rewind();
  return evt_count-1;
}


void AsciiRoot::compute_pedestals_fast(int mxevts, double wped, double wnoise)
{
    int i, ievt;

    if (!ifile)
        return;

    if (mxevts<0)
        mxevts = 100000000;

    for (i=0;i<max_nchan;i++)
        _ped[i] = _noise[i] = 0.;

    std::ifstream::pos_type here = ifile->tellg();
    std::cout << "Computing fast pedestas..." << std::endl;
    for (ievt=0; read_event()==0 && ievt<mxevts; ievt++)
    {
        if (!(ievt%100))
        {
            std::cout << "\revent " << std::setw(10) << ievt << std::flush;
        }
        common_mode();
        for (i=0; i<nchan(); i++)
        {
            // TODO: figure out how to determine the chip number when
            //       Plugin::filter_event has been called
            int ichip = i/128;
            // IF noise is 0, set it arbitrarily to 1.
            if (_noise[i]==0.)
                _noise[i] = 1.;

            if (_ped[i]==0.)
            {
                // If pedestal is not yet computed we assume the current
                // channel value should not be too far
                _ped[i] = _data.data[i];
            }
            else
            {
                // Do the pedestal and noise correction
                double corr;
                double xs;

                _signal[i] = _data.data[i] - _ped[i];
                corr = _signal[i] * wped;

                xs = (_signal[i]-_cmmd[ichip])/_noise[i];
                if (corr > 1.)
                    corr = 1.;

                if (corr < -1)
                    corr = -1.;

                _ped[i] += corr;

                if (fabs(xs) < 3.)
                {
                    _noise[i] = _noise[i]*(1.0-wnoise) + xs*xs*wnoise;
                }
            }
        }
    }
    std::cout << "\nDone" << std::endl;
    rewind();
}


TH2 *AsciiRoot::compute_pedestals(int mxevts, bool do_cmmd)
{
    if (!ifile)
        return 0;

    if (mxevts<0)
        mxevts = 100000000;

    int ievt, ichan;
    TH2 *hst = create_h2("hRaw","Raw data",nchan(), -0.5,nchan()-0.5, 256, -0.5,1023.5);
    TH2 *hsts = create_h2("hSig","Signal",nchan(), -0.5,nchan()-0.5,256, -127.5,127.5);


    std::ifstream::pos_type here = ifile->tellg();
    std::cout << "Computing pedestas..." << std::endl;
    for (ievt=0; read_event()==0 && ievt<mxevts; ievt++)
    {
        process_event(do_cmmd);
        for (ichan=0; ichan<nchan(); ichan++)
            // TODO: get right chip number in all situations (after calling set_data)
            hst->Fill(ichan, data(ichan)-get_cmmd(ichan/128));

        if (!(ievt%100))
        {
            std::cout << "\revent " << std::setw(10) << ievt << std::flush;
        }
    }
    std::cout << "\nDone" << std::endl;
    rewind();

    // TODO: _nchan can be updated in an event by event basis
    //       while here we are assuming that it is the same
    //       for all the events
    for (ichan=0; ichan<nchan(); ichan++)
    {
        TF1 *g = new TF1("g1", "gaus");
        TH1 *h1 = hst->ProjectionY("__hx__", ichan+1, ichan+1);
        g->SetParameters(h1->GetSumOfWeights(), h1->GetMean(), h1->GetRMS());
        g->SetRange(h1->GetMean()-2.5*h1->GetRMS(), h1->GetMean()+2.5*h1->GetRMS());
        h1->Fit("g1", "q0wr");
        _ped[ichan] = h1->GetFunction("g1")->GetParameter(1);
        _noise[ichan] = h1->GetFunction("g1")->GetParameter(2);
        delete h1;
        delete g;
    }

    rewind();
    for (ievt=0; read_event()==0 && ievt<mxevts; ievt++)
    {
        process_event(do_cmmd);
        for (ichan=0; ichan<nchan(); ichan++)
            hsts->Fill(ichan, signal(ichan));

        if (!(ievt%100))
        {
            std::cout << "\revent " << std::setw(10) << ievt << std::flush;
        }
    }
    std::cout << "\nDone" << std::endl;
    rewind();

    return hst;
}




void AsciiRoot::find_clusters(int ichip)
{
    int chan0=0;
    int chan1=255;
    if (ichip>=0 && ichip<2)
        {
            chan0 = ichip*128;
            chan1 = (ichip+1)*128 -1;
        }

    std::ostringstream ostr;
    ostr << chan0 << '-' << chan1;
    ChanList C(ostr.str().c_str());

    clear();
    find_clusters(C);
    _hits = C.hit_list();
}

void AsciiRoot::find_clusters(ChanList &C)
{
    // TODO: figure out how to determine the chip number in
    //       all the situations
    int i, j, imax=-1, left, right;
    double mxsig=-1.e20, sg, val;
    bool used[C.Nch()];

    for (i=0;i<C.Nch();i++)
    {
        used[i]= _mask[C[i]] ? true : false;
    }



    while (true)
    {
        /*
         * Find the highest
         */
        imax = -1;
        for (j=0; j<C.Nch(); j++)
        {
            i = C[j];
            if (used[j] || _signal[i]*polarity()<0.)
                continue;

            if ( polarity()*sn(i) > _seedcut)
            {
                val = fabs(signal(i));
                if (mxsig<val)
                {
                    mxsig = val;
                    imax = j;
                }
            }
        }

        if (imax<0 || imax >= C.Nch() )
            break;

        sg = signal(C[imax]);
        used[imax]=true;
        // Now look at neighbors
        // first to the left
        left = imax;
        for (j=imax-1;j>=0;j--)
        {
            i = C[j];
            if ( used[j] || _signal[i]*polarity()<0.)
                break;

            if ( fabs(sn(i)) > _neighcut )
            {
                used[j] = true;
                sg += signal(i);
                left = j;
            }
            else
                // TODO: this needs to be removed
                // The idea is to merge to clusters that have only one strip in between
                // In the laser runs this is a consequences of reflections...
            {
                int jx = j-1;
                if (jx>=0  )
                {
                    if ( fabs(sn(C[jx])) > _neighcut )
                        continue;
                }
                break;
            }
        }

        // now to the right
        right = imax;
        for (j=imax+1;j<C.Nch();j++)
        {
            i = C[j];
            if ( used[j] || _signal[i]*polarity()<0.)
                break;
            if ( fabs(sn(i))>_neighcut )
            {
                used[j] = true;
                sg += signal(i);
                right = j;
            }
            else
                // TODO: this needs to be removed
                // The idea is to merge to clusters that hanve only one strip in between
                // In the laser runs this is a consequences of reflections...
            {
                int jx = i+1;
                if (jx<C.Nch())
                {
                    if ( fabs(sn(C[jx])) > _neighcut )
                        continue;
                }
                break;
            }
        }
        C.add_hit(Hit(imax, left, right, sg));
    }
}

void AsciiRoot::save_pedestals(const char *fnam)
{
    std::ofstream ofile(fnam);
    if (!ofile)
    {
        std::cout << "Could not open " << fnam << " to save pedestals." << std::endl;
        return;
    }

    // TODO: _nchan can be updated in an event by event basis
    //       while here we are assuming that it is the same
    //       for all the events
    int i;
    for (i=0; i<nchan(); i++)
    {
        ofile << _ped[i] << "\t" << _noise[i] << "\n";
    }
    ofile.close();
}

void AsciiRoot::load_pedestals(const char *fnam)
{
    std::ifstream ifile(fnam);
    if (!ifile)
    {
        std::cout << "Could not open " << fnam << " to load pedestals." << std::endl;
        return;
    }
    int i;
    for (i=0; i<max_nchan; i++)
    {
        if (ifile.eof())
            break;

        ifile >> _ped[i] >> std::ws >> _noise[i] >> std::ws;
        _mask[i] = (_noise[i]>20. || _noise[i]<=0.);
    }
    ifile.close();
    TCanvas *pedcanvas = create_canvas("Pedcanvas", "Pedestal Values", 600, 400);
    TH1 *pedestalhisto = create_h1("pedestalhisto", "Pedestal Values", 256, -0.5, 255.5);
    for (i=0; i<256; i++)
    {
        pedestalhisto->Fill(i, _ped[i]);
    }
    pedcanvas->cd(1);
    pedestalhisto->Draw();
}

void AsciiRoot::load_masking(const char *fnam)
{
    std::ifstream ifile(fnam);
    if (!ifile)
    {
        std::cout << "Could not open masked.txt. " << std::endl;
        return;
    }
    int val;
    for (int i=0; i<500; i++)
    {
        ifile >> val >> std::ws;
        if (ifile.eof())
            break;
        if (val>255)
        {
            std::cout << "A value is greater than 255, causing an overflow crash. Please check the text file again. It has been set to 1 for continuation purposes. " << std::endl;
            val = 1;
        }
        _mask[val] = true;
    }
}

void AsciiRoot::load_gain(const char *fnam)
{
    std::ifstream ifile(fnam);
    if (!ifile)
    {
        std::cout << "Could not open " << fnam << " to load the gain." << std::endl;
        return;
    }
    int i;
    int ichan;
    double val, xn, xm;
    xn=xm=0.;
    for (i=0; i<max_nchan; i++)
    {
        ifile >> ichan >> std::ws;
        if (ifile.eof())
            break;
        ifile >> val;
        if (ifile.eof())
            break;

        xn++;

        xm += val;
        _gain[ichan] = val;

        ifile >> std::ws;
        if (ifile.eof())
            break;
    }
    if (xn>0)
    {
        _average_gain = xm/xn;
    }
    ifile.close();
}

void AsciiRoot::process_event(bool do_cmmd)
{
    int i;
    for (i=0; i<nchan(); i++)
    {
        _signal[i] = _data.data[i]-_ped[i];
        _sn[i] = _noise[i]>1. && !_mask[i] ? _signal[i]/_noise[i] : 0.;
    }
    if (do_cmmd)
    {
        int ichip=-1;
        common_mode();

        for (i=0; i<nchan(); i++)
        {
            // TODO: figure out the right chip number
            if (!(i%128))
                ichip ++;

            _signal[i] = _data.data[i]-_ped[i] - _cmmd[ichip];
            _sn[i] = (_noise[i] >1. && !_mask[i] ? _signal[i]/_noise[i] : 0.);
        }
    }
}

void AsciiRoot::add_channel_list(const ChanList &C)
{
    chan_list.push_back(C);
}


void AsciiRoot::common_mode()
{
    ChanList C("0-127");
    common_mode(C);

    _cmmd[0] = C.CommonMode();
    _cnoise[0] = C.Noise();


    C.Set("128-255");
    common_mode(C);

    _cmmd[1] = C.CommonMode();
    _cnoise[1] = C.Noise();
}

void AsciiRoot::common_mode(ChanList &C, bool correct)
{
    int ip, i, j;

    double mean, sm, xn, xx, xs, xm, tmp;
    bool use_it;
    mean = sm = 0.;
    for (ip=0;ip<3;ip++)
    {
        xn = xs = xm = 0.;
        for (j=0; j<C.Nch(); j++)
        {
            i = C[j];
            if (_mask[i])
                continue;

            use_it = true;
            xx = data(i) - _ped[i];
            if (ip)
            {
                tmp = fabs((xx-mean)/sm);
                use_it = (tmp<2.5);
            }
            if (use_it)
            {
                xn++;
                xm += xx;
                xs += xx * xx;
            }
        }
        if (xn>0.)
        {
            mean = xm / xn;
            sm = sqrt( xs/xn - mean*mean);
        }
        //  std::cout << "...iter " << ip << ": xm " << mean << " xs: " << sm << std::endl;
    }
    C.CommonMode(mean);
    C.Noise(sm);

    if (correct)
    {
        for ( j=0; j<C.Nch(); j++ )
        {
            i = C[j];
            _signal[i] = _data.data[i]-_ped[i] - C.CommonMode();
            _sn[i] = (_noise[i] >1. && !_mask[i] ? _signal[i]/_noise[i] : 0.);
        }
    }
}




void AsciiRoot::spy_data(bool with_signal, int nevt)
{
    TVirtualPad *pad;
    if (!ifile)
        return;

    sighandler_t old_handler = ::signal(SIGINT, _A_got_intr);
    _A_do_run = true;

    TCanvas *cnvs = (TCanvas *)gROOT->FindObject("cnvs");
    if (cnvs)
    {
        cnvs->Clear();
    }
    else
       cnvs = new TCanvas("cnvs","cnvs", 700, 800);

    cnvs->Divide(2,3);


    TH1 *hsignal = create_h1("hsignal","signal (ADC)",256, -0.5, 255.0);
    hsignal->SetXTitle("Channel");
    hsignal->SetYTitle("ADC");
    hsignal->SetMinimum(-300);
    hsignal->SetMaximum(300);

    TH1 *helec = create_h1("helec","signal (elec)", 256, -0.5, 255.5);
    helec->SetXTitle("Channel");
    helec->SetYTitle("electrons");
    helec->SetMinimum(-300/gain());
    helec->SetMaximum(300/gain());

    TH1 *hraw = create_h1("hraw","Raw Data (around 512.)",256, 0., 256.);
    hraw->SetXTitle("Channel");
    hraw->SetYTitle("ADC");
    hraw->SetMinimum(-300);
    hraw->SetMaximum(+300);

    TH1 *hrawc = create_h1("hrawc","Raw Data (no commd)",256, 0., 256.);
    hrawc->SetXTitle("Channel");
    hrawc->SetYTitle("ADC");
    hrawc->SetMinimum(-300);
    hrawc->SetMaximum(+300);


    TH1 *hcmmd[2];
    hcmmd[0] = create_h1("hcmmd0","Common mode (Chip 0)",50,-100.,100.);
    hcmmd[0]->SetXTitle("Common mode");
    hcmmd[1] = create_h1("hcmmd1","Common mode (Chip 1)",50,-100.,100.);
    hcmmd[1]->SetXTitle("Common mode");

    int ievt,jevt;
    for (ievt=jevt=0; read_event()==0 && _A_do_run && ievt<nevt;jevt++)
    {
        process_event();
        find_clusters();
        if ( with_signal && empty())
            continue;

        int i,ichip=-1;
        for (i=0; i<nchan(); i++)
        {
            // TODO: figure out chip number
            if (!(i%128))
                ichip++;

            hsignal->SetBinContent(i+1, _signal[i]);
            helec->SetBinContent(i+1, signal(i));
            hraw->SetBinContent(i+1,data(i)-512.);
            hrawc->SetBinContent(i+1, data(i)-_ped[i]);
            // TODO: why we draw the signal + common mode ?
            //       May be cause signal should be ~0...
            hcmmd[ichip]->Fill(_signal[i]+get_cmmd(ichip));
        }
        pad = cnvs->cd(1);
        pad->SetGrid(1,1);
        hsignal->Draw();
        pad = cnvs->cd(2);
        pad->SetGrid(1,1);
        helec->Draw();

        pad = cnvs->cd(3);
        pad->SetGrid(1,1);
        hraw->Draw();

        pad = cnvs->cd(4);
        pad->SetGrid(1,1);
        hrawc->Draw();

        pad = cnvs->cd(5);
        pad->SetGrid(1,1);
        hcmmd[0]->Draw();

        pad = cnvs->cd(6);
        pad->SetGrid(1,1);
        hcmmd[1]->Draw();

        std::cout << std::setiosflags(std::ios::fixed);
        std::cout << "*** Event " << jevt << " *****" << std::endl;
        std::cout << "Common Mode:" << std::endl
                  << "   Chip 0 " << std::setw(6) << std::setprecision(1) << get_cmmd(0) << " noise: " << get_cnoise(0)
                  << std::endl
                  << "   Chip 1 " << std::setw(6) << std::setprecision(1) << get_cmmd(1) << " noise: " << get_cnoise(1)
                  << std::endl;

        std::cout << "Time: " << time() << " ns" << std::endl;
        std::cout << "Signal chan(0) << " << signal(0) << " chan(1) " << signal(1) << std::endl;
        std::cout << "Clusters: " << std::endl;

        HitList::iterator ip;
        for (ip=begin(); ip!=end(); ++ip)
        {
            std::cout << "   chan: " << ip->center()
                      << " sig: "
                      << std::setw(6) << std::setprecision(1) << ip->signal()
                      << " left: " << ip->left() << " right: " << ip->right()
                      << std::endl;
            std::cout << '\t' << "channels: " << std::endl;
            int j;
            for (j=ip->left();j<=ip->right();j++)
                std::cout << "\t   " << j << " sn: " << _sn[j] << " signal: " << _signal[j] << " noise: " << _noise[j] << '\n';
            std::cout << std::endl;
        }

        cnvs->Update();
        ievt++;
    }
    std::cout << std::endl;
    _A_do_run= true;
    ::signal(SIGINT, old_handler);
}

bool is_text(const char *fnam)
{
    int nc;
    char buffer[1024];
    std::ifstream ifile(fnam);
    if (!fnam)
        return false;

    ifile.read(buffer, sizeof(buffer));
    nc = ifile.gcount();
    ifile.close();
    if (!nc) // empty files are text
    {
        return true;
    }

    std::string ss(buffer, nc);
    ifile.close();

    if ( ss.find('\0') != ss.npos )
        return false;

    double nontext = 0.;
    double ntotal = 0.;
    std::string::iterator ip;
    for (ip=ss.begin(); ip!=ss.end(); ++ip)
    {
        ntotal++;
        char c = *ip;
        if ( (c<' ' || c >'~') && !strchr("\n\t\r\b", c) )
            nontext++;
    }
    if ( nontext/ntotal > 0.3 )
        return false;

    return true;
}

