// =====================================================================
//  $Id: St00SinglePixelInterface.cc,v 1.3 2003/10/06 16:28:17 goiwai Exp $
//  $Name: CLDAQ-1-14-03 $
//  $Log: St00SinglePixelInterface.cc,v $
//  Revision 1.3  2003/10/06 16:28:17  goiwai
//  *** empty log message ***
//
//  Revision 1.2  2003/07/30 16:15:52  goiwai
//  ファイルにコミットログをつけることにしました.
//
// =====================================================================
#include "St00SinglePixelInterface.hh"
#include "St00SinglePixel.hh"
#include "St00BadChannelMap.hh"
#include "TInputObjectFile.hh"
#include "TDataRecord.hh"
#include "TDataElement.hh"
#include "St00DataRecordConversion.hh"

St00SinglePixelInterface::St00SinglePixelInterface( const Tstring& filename )
  : theSinglePixelList(), theBadChannelMap( 0 )
{
  Tifstream tifs;
  tifs.open( filename.c_str() );
  if ( !( tifs.good() ) || !( tifs.is_open() ) ) {
    Tcerr << "fail to open a file " << filename << "." << Tendl;
    exit( -1 );
  }

  theSinglePixelList.clear();
  while ( !( tifs.eof() ) ) {
    St00SinglePixel sp;    
    tifs >> sp;
    if ( tifs.fail() ) {
      break;
    } else {
      theSinglePixelList.push_back( sp );
    }
  }
  tifs.close();
}

St00SinglePixelInterface::St00SinglePixelInterface( const Tstring& dark, const Tstring& source )
  : theSinglePixelList(), theBadChannelMap( 0 )
{
  theBadChannelMap = new St00BadChannelMap( dark );

  St00DataRecordConversion conversion;
  TDataRecord r;
  TInputObjectFile ifile( source );
  while ( ( ifile >> r ) != 0 ) {
    const TDataMultiplicity& map = conversion.Convert( r );
    if ( conversion.IsSuccess() ) {
      for ( Tint row = 0; row < map.num_row(); row ++ ) {
	for ( Tint col = 0; col < map.num_col(); col ++ ) {
	  if ( isThisOverThreshold( map, row, col ) && isThisSinglePixel( map, row, col ) ) {
	    Tint h = col;
	    Tint v = row;
	    Tdouble dark = ( theBadChannelMap -> GetOfflineRmsMap().GetOfflineDarkAverageMap().GetMap() )[ row ][ col ];
	    Tdouble signal = map[ row ][ col ] - dark;
	    Tdouble rms = ( theBadChannelMap -> GetOfflineRmsMap().GetMap() )[ row ][ col ];
	    St00SinglePixel sp( h, v, signal, dark, rms );
	    theSinglePixelList.push_back( sp );
	  }
	}
      }
    }
  }
}

St00SinglePixelInterface::~St00SinglePixelInterface()
{
  if ( theBadChannelMap ) {
    delete theBadChannelMap;
  }
}

Tbool St00SinglePixelInterface::isThisOverThreshold( const TDataMultiplicity& map, Tint row, Tint col ) const
{
  Tdouble signaldark = map[ row ][ col ];
  Tdouble dark = ( theBadChannelMap -> GetOfflineRmsMap().GetOfflineDarkAverageMap().GetMap() )[ row ][ col ];
  Tdouble rms = ( theBadChannelMap -> GetOfflineRmsMap().GetMap() )[ row ][ col ];

  Tdouble factor = theBadChannelMap -> GetEnvironmentVariableTable().GetDoubleValue( "ST00_SPIXEL_THRESHOLD_SIGMA" );
  Tdouble threshold = dark + ( rms * factor );

  if ( signaldark > threshold ) {
    //Tcout << "DEBUG: " << __FILE__ << " " << __LINE__ << " " << dark << "+" << factor << "*" << rms <<  "=" << threshold << " " << signaldark << Tendl;
    return Ttrue;
  } else {
    return Tfalse;
  }
}

Tbool St00SinglePixelInterface::isThisSinglePixel( const TDataMultiplicity& map, Tint row, Tint col ) const
{
  if ( isThereOverThresholdAroundHere( map, row, col ) ) {
    return Tfalse;
  }
  if ( isThereBadChannelAroundHere( row, col ) ) {
    return Tfalse;
  }
  if ( isThisBadChannel( row, col ) ) {
    return Tfalse;
  }
  return Ttrue;
}

Tbool St00SinglePixelInterface::isThereOverThresholdAroundHere( const TDataMultiplicity& map, Tint row, Tint col ) const
{
  Tdouble factor = theBadChannelMap -> GetEnvironmentVariableTable().GetDoubleValue( "ST00_SPIXEL_NO_AROUND_SIGMA" );
  Tint hpixels = theBadChannelMap -> GetNumberOfHorizontalPixels();
  Tint vpixels = theBadChannelMap -> GetNumberOfVerticalPixels();

  Tdouble signaldark;
  Tdouble rms;
  Tdouble dark;
  Tdouble threshold;
  if ( row > 0 && col > 0 ) {
    signaldark = map[ row - 1 ][ col - 1 ];
    rms = ( theBadChannelMap -> GetOfflineRmsMap().GetMap() )[ row - 1 ][ col - 1 ];
    dark = ( theBadChannelMap -> GetOfflineRmsMap().GetOfflineDarkAverageMap().GetMap() )[ row - 1 ][ col - 1 ];
    threshold = dark + ( rms * factor );
    if ( signaldark > threshold ) {
      return Ttrue;
    }
  }
  if ( row > 0 ) {
    signaldark = map[ row - 1 ][ col ];
    rms = ( theBadChannelMap -> GetOfflineRmsMap().GetMap() )[ row - 1 ][ col ];
    dark = ( theBadChannelMap -> GetOfflineRmsMap().GetOfflineDarkAverageMap().GetMap() )[ row - 1 ][ col ];
    threshold = dark + ( rms * factor );
    if ( signaldark > threshold ) {
      return Ttrue;
    }
  }
  if ( row > 0 && col < hpixels - 1 ) {
    signaldark = map[ row - 1 ][ col + 1 ];
    rms = ( theBadChannelMap -> GetOfflineRmsMap().GetMap() )[ row - 1 ][ col + 1 ];
    dark = ( theBadChannelMap -> GetOfflineRmsMap().GetOfflineDarkAverageMap().GetMap() )[ row - 1 ][ col + 1 ];
    threshold = dark + ( rms * factor );
    if ( signaldark > threshold ) {
      return Ttrue;
    }
  }
  if ( col > 0 ) {
    signaldark = map[ row ][ col - 1 ];
    rms = ( theBadChannelMap -> GetOfflineRmsMap().GetMap() )[ row ][ col - 1 ];
    dark = ( theBadChannelMap -> GetOfflineRmsMap().GetOfflineDarkAverageMap().GetMap() )[ row ][ col - 1 ];
    threshold = dark + ( rms * factor );
    if ( signaldark > threshold ) {
      return Ttrue;
    }
  }
  if ( col < hpixels - 1 ) {
    signaldark = map[ row ][ col + 1 ];
    rms = ( theBadChannelMap -> GetOfflineRmsMap().GetMap() )[ row ][ col + 1 ];
    dark = ( theBadChannelMap -> GetOfflineRmsMap().GetOfflineDarkAverageMap().GetMap() )[ row ][ col + 1 ];
    threshold = dark + ( rms * factor );
    if ( signaldark > threshold ) {
      return Ttrue;
    }
  }
  if ( row < vpixels - 1 && col > 0 ) {
    signaldark = map[ row + 1 ][ col - 1 ];
    rms = ( theBadChannelMap -> GetOfflineRmsMap().GetMap() )[ row + 1 ][ col - 1 ];
    dark = ( theBadChannelMap -> GetOfflineRmsMap().GetOfflineDarkAverageMap().GetMap() )[ row + 1 ][ col - 1 ];
    threshold = dark + ( rms * factor );
    if ( signaldark > threshold ) {
      return Ttrue;
    }
  }
  if ( row < vpixels - 1 ) {
    signaldark = map[ row + 1 ][ col ];
    rms = ( theBadChannelMap -> GetOfflineRmsMap().GetMap() )[ row + 1 ][ col ];
    dark = ( theBadChannelMap -> GetOfflineRmsMap().GetOfflineDarkAverageMap().GetMap() )[ row + 1 ][ col ];
    threshold = dark + ( rms * factor );
    if ( signaldark > threshold ) {
      return Ttrue;
    }
  }
  if ( row < vpixels - 1 && col < hpixels - 1 ) {
    signaldark = map[ row + 1 ][ col + 1 ];
    rms = ( theBadChannelMap -> GetOfflineRmsMap().GetMap() )[ row + 1 ][ col + 1 ];
    dark = ( theBadChannelMap -> GetOfflineRmsMap().GetOfflineDarkAverageMap().GetMap() )[ row + 1 ][ col + 1 ];
    threshold = dark + ( rms * factor );
    if ( signaldark > threshold ) {
      return Ttrue;
    }
  }
  return Tfalse;
}

Tbool St00SinglePixelInterface::isThereBadChannelAroundHere( Tint row, Tint col ) const
{
  Tint colmax = theBadChannelMap -> GetNumberOfHorizontalPixels() - 1;
  Tint rowmax = theBadChannelMap -> GetNumberOfVerticalPixels() - 1;

  // 0 1 2
  // 3 Q 4
  // 5 6 7
  if ( row > 0 && col > 0 && theBadChannelMap -> IsBadChannel( row - 1, col - 1 ) ) {
    return Ttrue;
  }
  if ( row > 0 && theBadChannelMap -> IsBadChannel( row - 1, col ) ) {
    return Ttrue;
  }

  if ( row > 0 && col < colmax && theBadChannelMap -> IsBadChannel( row - 1, col + 1 ) ) {
    return Ttrue;
  }
  if ( col > 0 && theBadChannelMap -> IsBadChannel( row, col - 1 ) ) {
    return Ttrue;
  }
  if ( col < colmax && theBadChannelMap -> IsBadChannel( row, col + 1 ) ) {
    return Ttrue;
  }
  if ( row < rowmax && col > 0 && theBadChannelMap -> IsBadChannel( row + 1, col - 1 ) ) {
    return Ttrue;
  }
  if ( row < rowmax && theBadChannelMap -> IsBadChannel( row + 1, col ) ) {
    return Ttrue;
  }
  if ( row < rowmax && col < colmax && theBadChannelMap -> IsBadChannel( row + 1, col + 1 ) ) {
    return Ttrue;
  }
  return Tfalse;
}

Tbool St00SinglePixelInterface::isThisBadChannel( Tint row, Tint col ) const
{
  if ( theBadChannelMap -> IsBadChannel( row, col ) ) {
    return Ttrue;
  } else {
    return Tfalse;
  }
}
