/*
 * This file is part of the FORS Data Reduction Pipeline
 * Copyright (C) 2002-2010 European Southern Observatory
 *
 * 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., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 */

#ifdef HAVE_CONFIG_H
#include <config.h>
#endif

#include <stdexcept>
#include <sstream>

#include <cpl_frameset.h>
#include "fors_ccd_config.h"
#include "fiera_config.h"

namespace fors 
{

fiera_config::fiera_config(const cpl_propertylist * header) :
mosca::fiera_config(header)
{
    
    //Fix the prescan regions in order to avoid too many bad rows
    if(m_chip_id == "CCID20-14-5-3")
    {
        if(m_binning_factor_x == 1 && m_binning_factor_y == 1)
        {
            m_port_configs[0].prescan_region.set_lly(2067);
            m_port_configs[0].prescan_region.set_ury(2067);
        }
        else if(m_binning_factor_x == 2 && m_binning_factor_y == 2)
        {
            m_port_configs[0].prescan_region.set_lly(1033);
            m_port_configs[0].prescan_region.set_ury(1033);
        }
    }
    else if(m_chip_id == "CCID20-14-5-6")
    {
        m_port_configs[0].prescan_region.set_lly(0);
        m_port_configs[0].prescan_region.set_ury(0);
    }
    else if(m_chip_id == "Norma III")
    {
        if(m_binning_factor_x == 1 && m_binning_factor_y == 1)
        {
            m_port_configs[0].prescan_region.set_lly(2067);
            m_port_configs[0].prescan_region.set_ury(2067);
        }
        else if(m_binning_factor_x == 2 && m_binning_factor_y == 2)
        {
            m_port_configs[0].prescan_region.set_lly(1033);
            m_port_configs[0].prescan_region.set_ury(1033);
        }
    }
    else if(m_chip_id == "Marlene")
    {
        m_port_configs[0].prescan_region.set_lly(0);
        m_port_configs[0].prescan_region.set_ury(0);
    }
}

fiera_config::fiera_config()
{
}

fiera_config::~fiera_config()
{
}

std::auto_ptr<fors::fiera_config>  ccd_config_read
(const cpl_frame * source, const cpl_frame * bias_frame)
{
    cpl_errorstate   error_prevstate = cpl_errorstate_get();
    /* Getting overscan regions */ 
    cpl_propertylist *header      = NULL;
    header = cpl_propertylist_load(cpl_frame_get_filename(source), 0);
    if (header == NULL) 
        return std::auto_ptr<fors::fiera_config>(0);

    std::auto_ptr<fors::fiera_config> 
        ccd_config(new fors::fiera_config(header));
    cpl_propertylist_delete(header);
    if(!cpl_errorstate_is_equal(error_prevstate))
        return std::auto_ptr<fors::fiera_config>(0);
    
    /* Update RON estimation from bias */
    cpl_propertylist * master_bias_header =
       cpl_propertylist_load(cpl_frame_get_filename(bias_frame), 0);
    fors::update_ccd_ron(*ccd_config, master_bias_header);
    cpl_propertylist_delete(master_bias_header);
    if(!cpl_errorstate_is_equal(error_prevstate))
        return std::auto_ptr<fors::fiera_config>(0);
    
    return ccd_config;
}

/**
 * It returns an empty pointer if the frameset is empty or 
 * the CCD configurations are different for all the
 * frames. If there is just one frame, it returns the
 * CCD configuration of that frame.
 * TODO: Documentation
 */
std::auto_ptr<fors::fiera_config> ccd_settings_equal
(const cpl_frameset * fset)
{
    int iframe;
    std::auto_ptr<fors::fiera_config> reference_config;
    if(cpl_frameset_get_size(fset) < 1)
        return reference_config;
    cpl_propertylist * ref_header =
       cpl_propertylist_load(cpl_frame_get_filename(
              cpl_frameset_get_position_const(fset, 0)), 0);
    reference_config.reset(new fors::fiera_config(ref_header));

    for(iframe = 1; iframe < cpl_frameset_get_size(fset); ++iframe)
    {
        cpl_propertylist * other_header = 
            cpl_propertylist_load(cpl_frame_get_filename(
                  cpl_frameset_get_position_const(fset, iframe)), 0);
        fors::fiera_config other_config = fors::fiera_config(other_header);

        cpl_propertylist_delete(other_header);
        if(*reference_config != other_config)
            return reference_config;
    }

    cpl_propertylist_delete(ref_header);
    return reference_config;
}

void update_ccd_ron(mosca::ccd_config ccd_config, 
                    cpl_propertylist * master_bias_header)
{
    if(master_bias_header == NULL)
        std::invalid_argument("empty header");

    //Get number of ports
    size_t nports = ccd_config.nports();

    //Loop on the ports
    for(size_t iport = 0; iport < nports; iport++)
    {
        std::ostringstream key_stream;
        key_stream<<"ESO QC DET OUT"<<iport+1<<" RON";
        double computed_ron = 
                cpl_propertylist_get_double(master_bias_header,
                                            key_stream.str().c_str());
        ccd_config.set_computed_ron(iport, computed_ron);
    }
}

} /* namespace fors */



