// =====================================================================
//  $Id: St02SinglePixelInterface.cc,v 1.1 2003/07/11 05:34:15 goiwai Exp $
//  $Name: CLDAQ-1-06-02 $
// =====================================================================
#include "St02SinglePixelInterface.hh"
#include "St02SinglePixel.hh"
#include "St02BadChannelMap.hh"
#include "TInputObjectFile.hh"
#include "TDataRecord.hh"
#include "TDataElement.hh"
#include "St02DataRecordConversion.hh"

St02SinglePixelInterface::St02SinglePixelInterface( 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() ) ) {
    St02SinglePixel sp;    
    tifs >> sp;
    if ( tifs.fail() ) {
      break;
    } else {
      theSinglePixelList.push_back( sp );
    }
  }
  tifs.close();
}

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

  St02DataRecordConversion 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 ( isThisSinglePixel( map, row, col ) ) {
	    //if ( isThisOverThreshold( map, row, col ) && isThisSinglePixel( map, row, col ) ) {
	    Tint h = col;
	    Tint v = row;
	    Tdouble dark = ( theBadChannelMap -> GetOfflineDarkRmsMap().GetOfflineDarkAverageMap().GetMap() )[ row ][ col ];
	    Tdouble signal = map[ row ][ col ] - dark;
	    Tdouble rms = ( theBadChannelMap -> GetOfflineDarkRmsMap().GetMap() )[ row ][ col ];
	    St02SinglePixel sp( h, v, signal, dark, rms );
	    theSinglePixelList.push_back( sp );
	  }
	}
      }
    }

#ifdef DEBUG
    if ( theSinglePixelList.size() > 1000 ) {
      Tcout << ifile.GetTotalDataSize() << " read." << Tendl;
      break;
    }
#endif
  }
}

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

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

  Tdouble factor = theBadChannelMap -> GetEnvironmentVariableTable().GetDoubleValue( "ST02_SPIXEL_THRESHOLD_SIGMA" );

  Tdouble threshold = ( rms * factor ) + dark;

  if ( signaldark > threshold ) {

#ifdef DEBUG
    if ( signaldark < 100.0 ) {
      Tcout << "====" << Tendl;
      Tcout << " SMALL VALUE CATCH" << Tendl;
      Tcout << " FACTOR: " << factor << Tendl;
      Tcout << " DARK: " << dark << Tendl;
      Tcout << " RMS: " << rms << Tendl;
      Tcout << " SIGNAL+DARK: " << signaldark << Tendl;
      Tcout << " THRESHOLD: " << threshold << Tendl << Tendl;
    }
#endif

    return( Ttrue );
  } else {
    return( Tfalse );
  }
}

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

Tbool St02SinglePixelInterface::isThereOverThresholdAroundHere( const TDataMultiplicity& map, Tint row, Tint col ) const
{
  Tdouble factor = theBadChannelMap -> GetEnvironmentVariableTable().GetDoubleValue( "ST02_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 -> GetOfflineDarkRmsMap().GetMap() )[ row - 1 ][ col - 1 ];
    dark = ( theBadChannelMap -> GetOfflineDarkRmsMap().GetOfflineDarkAverageMap().GetMap() )[ row - 1 ][ col - 1 ];
    threshold =  ( rms * factor ) + dark;
    if ( signaldark > threshold ) {
      return( Ttrue );
    }
  }
  if ( row > 0 ) {
    signaldark = map[ row - 1 ][ col ];
    rms = ( theBadChannelMap -> GetOfflineDarkRmsMap().GetMap() )[ row - 1 ][ col ];
    dark = ( theBadChannelMap -> GetOfflineDarkRmsMap().GetOfflineDarkAverageMap().GetMap() )[ row - 1 ][ col ];
    threshold = ( rms * factor ) + dark;
    if ( signaldark > threshold ) {
      return( Ttrue );
    }
  }
  if ( row > 0 && col < hpixels - 1 ) {
    signaldark = map[ row - 1 ][ col + 1 ];
    rms = ( theBadChannelMap -> GetOfflineDarkRmsMap().GetMap() )[ row - 1 ][ col + 1 ];
    dark = ( theBadChannelMap -> GetOfflineDarkRmsMap().GetOfflineDarkAverageMap().GetMap() )[ row - 1 ][ col + 1 ];
    threshold = ( rms * factor ) + dark;
    if ( signaldark > threshold ) {
      return( Ttrue );
    }
  }
  if ( col > 0 ) {
    signaldark = map[ row ][ col - 1 ];
    rms = ( theBadChannelMap -> GetOfflineDarkRmsMap().GetMap() )[ row ][ col - 1 ];
    dark = ( theBadChannelMap -> GetOfflineDarkRmsMap().GetOfflineDarkAverageMap().GetMap() )[ row ][ col - 1 ];
    threshold = ( rms * factor ) + dark;
    if ( signaldark > threshold ) {
      return( Ttrue );
    }
  }
  if ( col < hpixels - 1 ) {
    signaldark = map[ row ][ col + 1 ];
    rms = ( theBadChannelMap -> GetOfflineDarkRmsMap().GetMap() )[ row ][ col + 1 ];
    dark = ( theBadChannelMap -> GetOfflineDarkRmsMap().GetOfflineDarkAverageMap().GetMap() )[ row ][ col + 1 ];
    threshold = ( rms * factor ) + dark;
    if ( signaldark > threshold ) {
      return( Ttrue );
    }
  }
  if ( row < vpixels - 1 && col > 0 ) {
    signaldark = map[ row + 1 ][ col - 1 ];
    rms = ( theBadChannelMap -> GetOfflineDarkRmsMap().GetMap() )[ row + 1 ][ col - 1 ];
    dark = ( theBadChannelMap -> GetOfflineDarkRmsMap().GetOfflineDarkAverageMap().GetMap() )[ row + 1 ][ col - 1 ];
    threshold = ( rms * factor ) + dark;
    if ( signaldark > threshold ) {
      return( Ttrue );
    }
  }
  if ( row < vpixels - 1 ) {
    signaldark = map[ row + 1 ][ col ];
    rms = ( theBadChannelMap -> GetOfflineDarkRmsMap().GetMap() )[ row + 1 ][ col ];
    dark = ( theBadChannelMap -> GetOfflineDarkRmsMap().GetOfflineDarkAverageMap().GetMap() )[ row + 1 ][ col ];
    threshold = ( rms * factor ) + dark;
    if ( signaldark > threshold ) {
      return( Ttrue );
    }
  }
  if ( row < vpixels - 1 && col < hpixels - 1 ) {
    signaldark = map[ row + 1 ][ col + 1 ];
    rms = ( theBadChannelMap -> GetOfflineDarkRmsMap().GetMap() )[ row + 1 ][ col + 1 ];
    dark = ( theBadChannelMap -> GetOfflineDarkRmsMap().GetOfflineDarkAverageMap().GetMap() )[ row + 1 ][ col + 1 ];
    threshold = ( rms * factor ) + dark;
    if ( signaldark > threshold ) {
      return( Ttrue );
    }
  }
  return( Tfalse );
}

Tbool St02SinglePixelInterface::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 St02SinglePixelInterface::isThisBadChannel( Tint row, Tint col ) const
{
  if ( theBadChannelMap -> IsBadChannel( row, col ) ) {
    return( Ttrue );
  } else {
    return( Tfalse );
  }
}
