/*
 * BadPixelProtocol.cpp  --  Part of the CinePaint plug-in "Bracketing_to_HDR"
 *
 * Copyright (c) 2005-2006  Hartmut Sbosny  <hartmut.sbosny@gmx.de>
 *
 * LICENSE:
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 */
/**
  BadPixelProtocol.cpp
*/

#include <iostream>
#include <fstream>
#include "BadPixelProtocol.hpp"
#include "Rgb_utils.hpp"        // <<-Op for Rgb<>


using std::cout;



/**  Output the bit pattern (Muster) of `arg´ (debug helper) */
template <typename T>
void bitout (T arg)
{
    for (int i=sizeof(T)*8-1; i>=0; i--)
      std::cout << bool(arg & (1 << i));
}



/**  Local used bitmasks (used in BadPixelProtocol::out())  */
enum WhichBits {
    SET_NONE   =  0,
    SET_MIN_R  =  1,          ///< R set to min
    SET_MIN_G  =  2,          ///< G set to min
    SET_MIN_B  =  4,          ///< B set to min
    SET_MAX_R  =  8,          ///< R set to max
    SET_MAX_G  = 16,          ///< G set to max
    SET_MAX_B  = 32           ///< B set to max
};
const unsigned  ALL_MIN_BITS = SET_MIN_R | SET_MIN_G | SET_MIN_B;
const unsigned  ALL_MAX_BITS = SET_MAX_R | SET_MAX_G | SET_MAX_B;


/**  Maximal number of bad pixel lines to output to file or stdout */
unsigned  bad_pixel_protocol_max_lines_ = 1000;



/*=========================
//    BadPixelProtocol
//========================*/

/**+*************************************************************************\n
  Ctor
  @param fname: Name of bad pixel file. fname==0 or "" means: no file output.
  @param to_stdout: Output to stdout? (true/false)
  
  @internal Default Ctor von \c std::ofstream gibt etwas != 0, ein file.open()
   danach einen Null-Stream (doppelt geoeffnet?). Um einen Null-Stream zu erzeugen,
   muss mit file(0) oder file("") konstruiert werden!
******************************************************************************/
BadPixelProtocol::BadPixelProtocol (const char* fname, bool to_stdout)
  : file_       (0),
    to_stdout_  (to_stdout),
    lines_      (0)
{ 
    if (fname && *fname) {      // fname==0 or fname=="" means: no file output
      file_.open (fname);
      if (file_)
        file_ << "# List of bad HDR pixel. Generated by CinePaint plug-in 'bracketing_to_hdr'.\n"; 
      else
        std::cerr << "Br2Hdr-WARNING **: Could not open bad pixel protocol file \""<< fname <<"\".\n";
    }        
}

/**+*************************************************************************\n
  out()  -  output a info line to `file_' and/or to stdout for a "bad pixel".
             
  @param x,y: pixel coordinates
  @param sum_w: weight of that pixel. sum_w==0 is criteron for a "bad pixel"
  @param h: the HDR value
  @param val_min,val_max: minimal and maximal HDR value in that image series, 
     as they are used in the merge_HDR() function.
******************************************************************************/
void BadPixelProtocol::out (int x, int y, const Rgb<double>& sum_w, 
                            const Rgb<float>& h, 
                            const Rgb<float>& val_min, 
                            const Rgb<float>& val_max)
{
    if (lines_ > bad_pixel_protocol_max_lines_)     // recording limit reached
      return;
    
    unsigned  which = 0;
      
    if (sum_w.r == 0) 
      if (h.r == val_min.r)  which |= SET_MIN_R;
      else                   which |= SET_MAX_R;
    
    if (sum_w.g == 0) 
      if (h.g == val_min.g)  which |= SET_MIN_G;
      else                   which |= SET_MAX_G;
    
    if (sum_w.b == 0) 
      if (h.b == val_min.b)  which |= SET_MIN_B;
      else                   which |= SET_MAX_B;
        
    if (!which) return;         // no bad pixel
      
    if (lines_ == bad_pixel_protocol_max_lines_) {
      file_ << "More than " << lines_ << " bad pixels. Recording abborted.\n";
      if (to_stdout_) cout << "More than " << lines_ << " bad pixels. Recording abborted.\n";
      ++ lines_;
      return;
    }
    
    if (which & ALL_MIN_BITS)
      if (which == ALL_MIN_BITS) 
      {   file_  << "pure MIN ["<<x<<", "<<y<<"] = " << h << "   sum_w="<<sum_w<<'\n';
          if (to_stdout_)
            cout << "pure MIN ["<<x<<", "<<y<<"] = " << h << "   sum_w="<<sum_w<<'\n';
      }  
      else 
      {   file_  << "part MIN ["<<x<<", "<<y<<"] = " << h << "   sum_w="<<sum_w<<'\n';           
          if (to_stdout_) 
            cout << "part MIN ["<<x<<", "<<y<<"] = " << h << "   sum_w="<<sum_w<<'\n';           
      }      
        
    if (which & ALL_MAX_BITS)
      if (which == ALL_MAX_BITS) 
      {   file_  << "pure MIN ["<<x<<", "<<y<<"] = " << h << "   sum_w="<<sum_w<<'\n';
          if (to_stdout_)
            cout << "pure MIN ["<<x<<", "<<y<<"] = " << h << "   sum_w="<<sum_w<<'\n';
      }
      else 
      {   file_  << "part MAX ["<<x<<", "<<y<<"] = " << h << "   sum_w="<<sum_w<<'\n';           
          if (to_stdout_)
            cout << "part MAX ["<<x<<", "<<y<<"] = " << h << "   sum_w="<<sum_w<<'\n';           
      }
      
    ++ lines_;
}


/** static elements: */

/**  Default name of the bad pixel protocol file */
const char* BadPixelProtocol::default_fname_ = "bad_hdr_pixel.txt";

