// =====================================================================
//  $Id: st02OFFflatband.cc,v 1.2 2003/10/06 16:28:19 goiwai Exp $
//  $Name: CLDAQ-1-14-06 $
//  $Log: st02OFFflatband.cc,v $
//  Revision 1.2  2003/10/06 16:28:19  goiwai
//  *** empty log message ***
//
//  Revision 1.1  2003/09/09 22:19:49  goiwai
//  これまで,OFFxxx.ccというファイル名だったオフライン解析用のプログラムを
//  st02OFFxxx.ccに変更しました.
//  ファイル名競合の防止が目的です.
//
//  Revision 1.2  2003/07/30 16:16:33  goiwai
//  ファイルにコミットログをつけることにしました.
//
// =====================================================================
#include "TInputObjectFile.hh"
#include "TDataRecord.hh"
#include "TDataElement.hh"
#include "Trootinit.h"

#include "St02DataRecordConversion.hh"

// フィッティングを 中心から fitregion×σ の範囲で行う
static const Tdouble _fitregion = 2.0;
static TstringList _pathlist;
static TintList _runid;
static TstringList _runtype;
static TstringList _devid;
static TdoubleList _temp;
static TdoubleList _atime;
static TdoubleList _vshift;
static TdoubleList _mean;
static TdoubleList _meanerror;
static Tdouble _DC;
static Tdouble _DCe;

static TApplication* _App;
static TCanvas* _CVdark;
static TH1D** _H1Ddark;
static TGraphErrors* _GEdark;

static Tvoid setpathlist( Tint argc, Tchar** argv );
static Tbool existfiles();
static Tvoid setruninfo();
static Tbool isgood();
static Tvoid darkplot();
static Tvoid darkvstime();
static Tvoid writeresult();

int main( int argc, char** argv, char** envv )
{
  if ( argc < 2 ) {
    Tcerr << "usage: " << argv[ 0 ] << " <drec> [<drec2> ...]" << Tendl;
    return -1;
  }
  setpathlist( argc, argv );

  if ( existfiles() ) {
    setruninfo();
  } else {
    Tcerr << "not found." << Tendl;
    return -1;
  }

  if ( ! isgood() ) {
    Tcerr << "bad record." << Tendl;
    return -1;
  }

  _App = rootinit();
  darkplot();
  darkvstime();
  writeresult();
  _App -> Terminate();
  //_App -> Run();

  return 0;
}

Tvoid setpathlist( Tint argc, Tchar** argv )
{
  for ( Tint i = 1; i < argc; i ++ ) {
    _pathlist.push_back( argv[ i ] );
  }
  return;
}

Tbool existfiles()
{
  Tbool retval = Ttrue;
  for ( Tsize_t i = 0; i < _pathlist.size(); i ++ ) {
    retval &= isexist( _pathlist[ i ] );
  }
  return retval;
}

Tvoid setruninfo()
{
  static Tstring runidtag[ 3 ] = { "INFO", "RUN ID", "0" };
  static Tstring runtypetag[ 3 ] = { "INFO", "RUN INFO", "RUN TYPE" };
  static Tstring devidtag[ 3 ] = { "INFO", "RUN INFO", "DEVICE ID" };
  static Tstring temptag[ 3 ] = { "INFO", "RUN INFO", "TEMPERATURE (C)" };
  static Tstring atimetag[ 3 ] = { "INFO", "RUN INFO", "PERIOD (sec)" };
  static Tstring vshifttag[ 3 ] = { "INFO", "RUN INFO", "NEGATIVE VOLTAGE (V)" };

  
  for ( Tsize_t i = 0; i < _pathlist.size(); i ++ ) {
    TInputObjectFile f( _pathlist[i] );
    TDataRecord runbegin;
    TDataElement e;
    f.Read( runbegin );

    Tint runid;
    runbegin.FindDataElement( runidtag, e );
    e.StorePrimitive( runid );
    _runid.push_back( runid );

    Tstring runtype;
    runbegin.FindDataElement( runtypetag, e );
    e.StorePrimitive( runtype );
    _runtype.push_back( runtype );

    Tstring devid;
    runbegin.FindDataElement( devidtag, e );
    e.StorePrimitive( devid );
    _devid.push_back( devid );

    Tdouble temp;
    runbegin.FindDataElement( temptag, e );
    e.StorePrimitive( temp );
    _temp.push_back( temp );
    
    Tdouble atime;
    runbegin.FindDataElement( atimetag, e );
    e.StorePrimitive( atime );
    _atime.push_back( atime );

    Tdouble vshift;
    runbegin.FindDataElement( vshifttag, e );
    e.StorePrimitive( vshift );
    _vshift.push_back( vshift );
  }

  return;
}

Tbool isgood()
{
  Tsize_t ninfo = _pathlist.size();

  for ( Tsize_t i = 0; i < ninfo - 1; i ++ ) {
    for ( Tsize_t j = i + 1; j < ninfo; j ++ ) {
      // 全てランIDが異なるかどうか
      if ( _runid[ i ] == _runid[ j ] ) {
        Tcerr << "run ID duplication." << Tendl;
        return Tfalse;
      }

      // ランタイプが全てダークランかどうか
      if ( _runtype[ i ] != _runtype[ j ] && _runtype[ i ] != "DARK RUN" ) {
        Tcerr << "not DARK RUN." << Tendl;
        return Tfalse;
      }

      // デバイスIDが全て同じかどうか
      if ( _devid[ i ] != _devid[ j ] ) {
        Tcerr << "diffrent device ID." << Tendl;
        return Tfalse;
      }

      // 温度が全て同じかどうか
      if ( _temp[ i ] != _temp[ j ] ) {
        Tcerr << "diffrent temperature." << Tendl;
        return Tfalse;
      }

      // 蓄積時間が全て異なるかどうか
      if ( _atime[ i ] == _atime[ j ] ) {
        Tcerr << "accumulation time duplication." << Tendl;
        return Tfalse;
      }

      // シフトレジスタの電圧が全て同じかどうか
      if ( _vshift[ i ] != _vshift[ j ] ) {
        Tcerr << "different vertical shift register." << Tendl;
        return Tfalse;
      }

    }
  }


  return Ttrue;
}


Tvoid darkplot()
{
  Tint cvx = 320;
  Tint cvy = 240;
  Tsize_t ndark = _pathlist.size();

  _CVdark = new TCanvas( "CVdark", "D.C. by Accumulation Time", cvx*2, cvy*4 );
  _CVdark -> ToggleEventStatus();
  _CVdark->Divide(1,2);
  _CVdark->GetPad(1)->Divide(2,2);
  // こんな感じでいきます
  // ---------
  // |   |   |
  // ---------
  // |   |   |
  // ---------
  // |       |
  // |       |
  // ---------

  // ヒストグラムを作ります
  _H1Ddark = new TH1D*[ ndark ];
  for ( Tsize_t i = 0; i < ndark; i ++ ) {
    Tint runid = _runid[ i ];
    Tstring devid = _devid[ i ];
    Tdouble temp = _temp[ i ];
    Tdouble vshift = _vshift[ i ];
    Tdouble atime = _atime[ i ];

    // タイトルとオブジェクト名
    Tstring title = devid + ": " + itostr( runid ) + ", ";
    title = title + dtostr(temp) + "{}^{#circ}C, ";
    title = title + dtostr(atime) + "sec, ";
    title = title + dtostr(vshift) + "V";
    Tstring name = "H1Ddark" + itostr( i );

    // ヒストグラムの見た目
    _H1Ddark[ i ] = new TH1D( name.c_str(), title.c_str(), 500, -1000.0, 4096.0 );
    TGaxis::SetMaxDigits( 2 );
    _H1Ddark[ i ] -> GetXaxis()->SetTitle("Pulseheight (ADU)");
    _H1Ddark[ i ] -> GetXaxis()->CenterTitle();
    _H1Ddark[ i ] -> GetXaxis()->SetNoExponent();
    _H1Ddark[ i ] -> GetYaxis()->SetTitle("Counts");
    _H1Ddark[ i ] -> GetYaxis()->CenterTitle();
    _CVdark -> GetPad(1) -> cd( i + 1 );
    _H1Ddark[ i ] -> Draw();


    // データレコードから有感領域をフィル
    St02DataRecordConversion conversion;
    TDataRecord record;
    TInputObjectFile f( _pathlist[ i ] );
    Tint noverflow = 0;

    while ( f.Read( record ) != 0 ) {
      TDataMultiplicity& darkmap = conversion.Convert( record );
      if ( conversion.IsSuccess() ) {
        for ( Tint y = 0; y < darkmap.num_row(); y ++ ) {
          for ( Tint x = 0; x < darkmap.num_col(); x ++ ) {
            if ( darkmap[ y ][ x ] > 4096.0 ) {
              noverflow ++;
            }
            _H1Ddark[ i ] -> Fill( darkmap[ y ][ x ] );
          }
        }
      }
    }


    Tdouble ent = _H1Ddark[ i ]->GetEntries();
    // オーバーフローの割合が5%を越えたら警告
    if ( noverflow > (Tint)ent*0.05 ) {
      Tcout << "*********************************************" << Tendl;
      Tcout << "* " << _pathlist[ i ] << ": overflow event too much." << Tendl;
      Tcout << "* Temperature: " << _temp[i] << Tendl;
      Tcout << "* Accumulation: " << _atime[i] << Tendl;
      Tcout << "* Vertical Shift Register Voltage: " << _vshift[i] << Tendl;
      Tcout << "*********************************************" << Tendl;
    }


    // まずは全体をフィッティング
    _H1Ddark[ i ] -> Fit("gaus", "q0");
    TF1* g0 = _H1Ddark[ i ] -> GetFunction( "gaus" );
    Tdouble m = g0->GetParameter(1);
    Tdouble s = g0->GetParameter(2);
    Tdouble xmin = m - _fitregion * s;
    Tdouble xmax = m + _fitregion * s;

    // 範囲を指定したガウシアンでフィット
    TF1* g = new TF1("g","gaus",xmin,xmax);
    g->SetParameters(g0->GetParameters());
    g->SetLineWidth(1);
    _H1Ddark[ i ] -> Fit("g","qr");


    // フィッティング情報をプッシュ
    _mean.push_back( g-> GetParameter(1) );
    _meanerror.push_back( g-> GetParError(1) );


    // アップデート
    _CVdark -> Modified();
    _CVdark -> Update();
  }

  _CVdark -> cd( 0 );
  return;
}

Tvoid darkvstime()
{
  Tstring title = _devid[0] + ", ";
  title = title + dtostr(_temp[0]) + "{}^{#circ}C, ";
  title = title + dtostr(_vshift[0]) + "V";

  _CVdark -> GetPad(2) -> cd();
  _GEdark = new TGraphErrors();
  _GEdark -> SetName( "GEdark" );
  _GEdark -> SetTitle( title.c_str() );
  _GEdark -> SetMarkerStyle(1);
  _GEdark -> SetMarkerSize(0.3);

  for ( Tsize_t i = 0; i < _pathlist.size(); i ++ ) {
    _GEdark -> SetPoint( i, _atime[i], _mean[i] );
    _GEdark -> SetPointError( i, 0.0, _meanerror[i] );
  }

  _GEdark->Draw( "ap" );
  _GEdark->Fit( "pol1","q" );
  TF1* p1 = _GEdark->GetFunction("pol1");
  p1->SetLineWidth(1);
  p1->SetParName(1,"Dark Current");
  _DC = p1->GetParameter(1);
  _DCe = p1->GetParError(1);

  TGaxis::SetMaxDigits( 2 );
  _GEdark->GetXaxis()->SetTitle( "Accumulation Time (sec)" );
  _GEdark->GetXaxis()->SetNoExponent();
  _GEdark->GetXaxis()->CenterTitle();
  _GEdark->GetYaxis()->SetTitle( "Pulseheight Average (ADU/pixel)" );
  _GEdark->GetYaxis()->CenterTitle();



  // アップデート
  _CVdark -> Modified();
  _CVdark -> Update();
  _CVdark -> cd( 0 );
  return;
}


Tvoid writeresult()
{
  Tstring fbody = "FB" + dtostr(_vshift[0]) + "V";

  Tstring fname = fbody + "canvas.ps";
  _CVdark->Print( fname.c_str() );

  fname = fbody + "canvas.gif";
  _CVdark->Print( fname.c_str() );

  fname = fbody + "canvas.C";
  _CVdark->Print( fname.c_str() );

  fname = fbody + "objects.root";
  TFile f( fname.c_str(), "RECREATE", "OFFLINE FB" );
  for ( Tsize_t i = 0; i < _pathlist.size(); i ++ ) {
    _H1Ddark[i]->Write();
  }
  _GEdark->Write();
  _CVdark->Write();
  f.Close();


  Tofstream olog("LOGFB",Tapp);
  olog << "TEMP: " << _temp[0] << Tendl;
  olog << "VSHIFT: " << _vshift[0] << Tendl;
  olog << "DARK: " << _DC << " " << _DCe << Tendl;
  olog << "----" << Tendl;
  olog.close();


  return;
}
