/* ============================================================
 *
 * This file is a part of kipi-plugins project
 * http://www.kipi-plugins.org
 *
 * Date        : 2006-10-18
 * Description : EXIF light settings page.
 *
 * Copyright (C) 2006-2007 by Gilles Caulier <caulier dot gilles at gmail dot com>
 *
 * 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, 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.
 * 
 * ============================================================ */

// C++ includes.

#include <cmath>

// QT includes.

#include <tqlayout.h>
#include <tqlabel.h>
#include <tqwhatsthis.h>
#include <tqcombobox.h>
#include <tqmap.h>

// KDE includes.

#include <klocale.h>
#include <kdialog.h>
#include <knuminput.h>

// LibKExiv2 includes. 

#include <libkexiv2/kexiv2.h>

// Local includes.

#include "metadatacheckbox.h"
#include "exiflight.h"
#include "exiflight.moc"

namespace KIPIMetadataEditPlugin
{

    class FlashMode
    {
    public:

        FlashMode() {}
        FlashMode(int id, const TQString& desc) : m_id(id), m_desc(desc) {}

        int     id()   const { return m_id;   }
        TQString desc() const { return m_desc; }

    private:

        int     m_id;
        TQString m_desc;
    };

class EXIFLightPriv
{
public:

    EXIFLightPriv()
    {
        lightSourceCheck     = 0;
        flashModeCheck       = 0;
        flashEnergyCheck     = 0;
        whiteBalanceCheck    = 0;
        lightSourceCB        = 0;
        flashEnergyEdit      = 0;
        flashModeCB          = 0;
        whiteBalanceCB       = 0;

        flashModeMap.insert(0,  FlashMode( 0x00, i18n("No flash") ));
        flashModeMap.insert(1,  FlashMode( 0x01, i18n("Fired") ));
        flashModeMap.insert(2,  FlashMode( 0x05, i18n("Fired, no strobe return light") ));
        flashModeMap.insert(3,  FlashMode( 0x07, i18n("Fired, strobe return light") ));
        flashModeMap.insert(4,  FlashMode( 0x09, i18n("Yes, compulsory") ));
        flashModeMap.insert(5,  FlashMode( 0x0d, i18n("Yes, compulsory, no return light") ));
        flashModeMap.insert(6,  FlashMode( 0x0f, i18n("Yes, compulsory, return light") ));
        flashModeMap.insert(7,  FlashMode( 0x10, i18n("No, compulsory") ));
        flashModeMap.insert(8,  FlashMode( 0x18, i18n("No, auto") ));
        flashModeMap.insert(9,  FlashMode( 0x19, i18n("Yes, auto") ));
        flashModeMap.insert(10, FlashMode( 0x1d, i18n("Yes, auto, no return light") ));
        flashModeMap.insert(11, FlashMode( 0x1f, i18n("Yes, auto, return light") ));
        flashModeMap.insert(12, FlashMode( 0x20, i18n("No flash function") ));
        flashModeMap.insert(13, FlashMode( 0x41, i18n("Yes, red-eye") ));
        flashModeMap.insert(14, FlashMode( 0x45, i18n("Yes, red-eye, no return light") ));
        flashModeMap.insert(15, FlashMode( 0x47, i18n("Yes, red-eye, return light") ));
        flashModeMap.insert(16, FlashMode( 0x49, i18n("Yes, compulsory, red-eye") ));
        flashModeMap.insert(17, FlashMode( 0x4d, i18n("Yes, compulsory, red-eye, no return light") ));
        flashModeMap.insert(18, FlashMode( 0x4f, i18n("Yes, compulsory, red-eye, return light") ));
        flashModeMap.insert(19, FlashMode( 0x59, i18n("Yes, auto, red-eye") ));
        flashModeMap.insert(20, FlashMode( 0x5d, i18n("Yes, auto, red-eye, no return light") ));
        flashModeMap.insert(21, FlashMode( 0x5f, i18n("Yes, auto, red-eye, return light") ));
    }

    typedef TQMap<int, FlashMode> FlashModeMap; 

    FlashModeMap      flashModeMap;

    TQCheckBox        *flashEnergyCheck;
   
    TQComboBox        *lightSourceCB;
    TQComboBox        *flashModeCB;
    TQComboBox        *whiteBalanceCB;

    KDoubleSpinBox   *flashEnergyEdit;

    MetadataCheckBox *lightSourceCheck;
    MetadataCheckBox *flashModeCheck;
    MetadataCheckBox *whiteBalanceCheck;
};

EXIFLight::EXIFLight(TQWidget* parent)
         : TQWidget(parent)
{
    d = new EXIFLightPriv;

    TQGridLayout* grid = new TQGridLayout(parent, 4, 3, KDialog::spacingHint());

    // --------------------------------------------------------

    d->lightSourceCheck = new MetadataCheckBox(i18n("Light source:"), parent);
    d->lightSourceCB    = new TQComboBox(false, parent);
    d->lightSourceCB->insertItem(i18n("Unknown"),                                 0);
    d->lightSourceCB->insertItem(i18n("Daylight"),                                1);
    d->lightSourceCB->insertItem(i18n("Fluorescent"),                             2);
    d->lightSourceCB->insertItem(i18n("Tungsten (incandescent light)"),           3);
    d->lightSourceCB->insertItem(i18n("Flash"),                                   4);
    d->lightSourceCB->insertItem(i18n("Fine weather"),                            5);
    d->lightSourceCB->insertItem(i18n("Cloudy weather"),                          6);
    d->lightSourceCB->insertItem(i18n("Shade"),                                   7);
    d->lightSourceCB->insertItem(i18n("Daylight fluorescent (D 5700 - 7100K)"),   8);
    d->lightSourceCB->insertItem(i18n("Day white fluorescent (N 4600 - 5400K)"),  9);
    d->lightSourceCB->insertItem(i18n("Cool white fluorescent (W 3900 - 4500K)"), 10);
    d->lightSourceCB->insertItem(i18n("White fluorescent (WW 3200 - 3700K)"),     11);
    d->lightSourceCB->insertItem(i18n("Standard light A"),                        12);
    d->lightSourceCB->insertItem(i18n("Standard light B"),                        13);
    d->lightSourceCB->insertItem(i18n("Standard light C"),                        14);
    d->lightSourceCB->insertItem(i18n("D55"),                                     15);
    d->lightSourceCB->insertItem(i18n("D65"),                                     16);
    d->lightSourceCB->insertItem(i18n("D75"),                                     17);
    d->lightSourceCB->insertItem(i18n("D50"),                                     18);
    d->lightSourceCB->insertItem(i18n("ISO studio tungsten"),                     19);
    d->lightSourceCB->insertItem(i18n("Other light source"),                      20);
    grid->addMultiCellWidget(d->lightSourceCheck, 0, 0, 0, 0);
    grid->addMultiCellWidget(d->lightSourceCB, 0, 0, 2, 3);
    TQWhatsThis::add(d->lightSourceCB, i18n("<p>Select here the kind of light source used "
                                           "to take the picture."));

    // --------------------------------------------------------

    d->flashModeCheck = new MetadataCheckBox(i18n("Flash mode:"), parent);
    d->flashModeCB    = new TQComboBox(false, parent);

    for (EXIFLightPriv::FlashModeMap::Iterator it = d->flashModeMap.begin();
        it != d->flashModeMap.end(); ++it )
       d->flashModeCB->insertItem(it.data().desc());

    grid->addMultiCellWidget(d->flashModeCheck, 1, 1, 0, 0);
    grid->addMultiCellWidget(d->flashModeCB, 1, 1, 2, 3);
    TQWhatsThis::add(d->flashModeCB, i18n("<p>Select here the flash program mode used by camera "
                                         "to take the picture."));

    // --------------------------------------------------------

    d->flashEnergyCheck = new TQCheckBox(i18n("Flash energy (BCPS):"), parent);
    d->flashEnergyEdit  = new KDoubleSpinBox(1.0, 10000.0, 1.0, 1.0, 1, parent);
    grid->addMultiCellWidget(d->flashEnergyCheck, 2, 2, 0, 0);
    grid->addMultiCellWidget(d->flashEnergyEdit, 2, 2, 2, 2);
    TQWhatsThis::add(d->flashEnergyEdit, i18n("<p>Set here the flash energy used to take the picture "
                                             "in BCPS unit. Beam Candle Power Seconds is the measure "
                                             "of effective intensity of a light source when it is "
                                             "focused into a beam by a reflector or lens. This value "
                                             "is the effective intensity for a period of one second."));

    // --------------------------------------------------------

    d->whiteBalanceCheck = new MetadataCheckBox(i18n("White balance:"), parent);
    d->whiteBalanceCB    = new TQComboBox(false, parent);
    d->whiteBalanceCB->insertItem(i18n("Auto"),   0);
    d->whiteBalanceCB->insertItem(i18n("Manual"), 1);
    grid->addMultiCellWidget(d->whiteBalanceCheck, 3, 3, 0, 0);
    grid->addMultiCellWidget(d->whiteBalanceCB, 3, 3, 2, 2);
    TQWhatsThis::add(d->whiteBalanceCB, i18n("<p>Select here the white balance mode set by camera when "
                                           "the picture have been shot."));


    grid->setColStretch(1, 10);                     
    grid->setRowStretch(4, 10);                     

    // --------------------------------------------------------

    connect(d->lightSourceCheck, TQT_SIGNAL(toggled(bool)),
            d->lightSourceCB, TQT_SLOT(setEnabled(bool)));

    connect(d->flashModeCheck, TQT_SIGNAL(toggled(bool)),
            d->flashModeCB, TQT_SLOT(setEnabled(bool)));

    connect(d->flashEnergyCheck, TQT_SIGNAL(toggled(bool)),
            d->flashEnergyEdit, TQT_SLOT(setEnabled(bool)));

    connect(d->whiteBalanceCheck, TQT_SIGNAL(toggled(bool)),
            d->whiteBalanceCB, TQT_SLOT(setEnabled(bool)));

    // --------------------------------------------------------

    connect(d->flashEnergyCheck, TQT_SIGNAL(toggled(bool)),
            this, TQT_SIGNAL(signalModified()));

    connect(d->lightSourceCheck, TQT_SIGNAL(toggled(bool)),
            this, TQT_SIGNAL(signalModified()));

    connect(d->flashModeCheck, TQT_SIGNAL(toggled(bool)),
            this, TQT_SIGNAL(signalModified()));

    connect(d->whiteBalanceCheck, TQT_SIGNAL(toggled(bool)),
            this, TQT_SIGNAL(signalModified()));

    // --------------------------------------------------------

    connect(d->lightSourceCB, TQT_SIGNAL(activated(int)),
            this, TQT_SIGNAL(signalModified()));

    connect(d->flashModeCB, TQT_SIGNAL(activated(int)),
            this, TQT_SIGNAL(signalModified()));

    connect(d->whiteBalanceCB, TQT_SIGNAL(activated(int)),
            this, TQT_SIGNAL(signalModified()));

    connect(d->flashEnergyEdit, TQT_SIGNAL(valueChanged(double)),
            this, TQT_SIGNAL(signalModified()));
}

EXIFLight::~EXIFLight()
{
    delete d;
}

void EXIFLight::readMetadata(TQByteArray& exifData)
{
    blockSignals(true);
    KExiv2Iface::KExiv2 exiv2Iface;
    exiv2Iface.setExif(exifData);
    long int num=1, den=1;
    long     val=0;

    d->lightSourceCB->setCurrentItem(0);
    d->lightSourceCheck->setChecked(false);
    if (exiv2Iface.getExifTagLong("Exif.Photo.LightSource", val))
    {
        if ((val>=0 && val <=4) || (val> 8 && val <16) || (val> 16 && val <25) || val == 255) 
        {    
            if (val > 8 && val < 16)
                val = val - 4;
            else if (val > 16 && val < 25)
                val = val - 5;
            else if (val == 255)    
                val = 20;
    
            d->lightSourceCB->setCurrentItem(val);
            d->lightSourceCheck->setChecked(true);
        }
        else 
            d->lightSourceCheck->setValid(false);
    }
    d->lightSourceCB->setEnabled(d->lightSourceCheck->isChecked());

    d->flashModeCB->setCurrentItem(0);
    d->flashModeCheck->setChecked(false);
    if (exiv2Iface.getExifTagLong("Exif.Photo.Flash", val))
    {
        int item = -1;    
        for (EXIFLightPriv::FlashModeMap::Iterator it = d->flashModeMap.begin();
            it != d->flashModeMap.end(); ++it )
        {
            if (it.data().id() == val)
                item = it.key();
        }
        
        if (item != -1)
        {
            d->flashModeCB->setCurrentItem(item);
            d->flashModeCheck->setChecked(true);
        }
        else
            d->flashModeCheck->setValid(false);
    }
    d->flashModeCB->setEnabled(d->flashModeCheck->isChecked());

    d->flashEnergyEdit->setValue(1.0);
    d->flashEnergyCheck->setChecked(false);
    if (exiv2Iface.getExifTagRational("Exif.Photo.FlashEnergy", num, den))
    {
        d->flashEnergyEdit->setValue((double)(num) / (double)(den));
        d->flashEnergyCheck->setChecked(true);
    }
    d->flashEnergyEdit->setEnabled(d->flashEnergyCheck->isChecked());

    d->whiteBalanceCB->setCurrentItem(0);
    d->whiteBalanceCheck->setChecked(false);
    if (exiv2Iface.getExifTagLong("Exif.Photo.WhiteBalance", val))
    {
        if (val>=0 && val<=1)
        {
            d->whiteBalanceCB->setCurrentItem(val);
            d->whiteBalanceCheck->setChecked(true);
        }
        else
            d->whiteBalanceCheck->setValid(false);
    }
    d->whiteBalanceCB->setEnabled(d->whiteBalanceCheck->isChecked());

    blockSignals(false);
}

void EXIFLight::applyMetadata(TQByteArray& exifData)
{
    KExiv2Iface::KExiv2 exiv2Iface;
    exiv2Iface.setExif(exifData);
    long int num=1, den=1;

    if (d->lightSourceCheck->isChecked())
    {
        long val = d->lightSourceCB->currentItem();
        if (val > 4 && val < 12)
            val = val + 4;
        else if (val > 11 && val < 20)
            val = val + 5;
        else if (val == 20)    
            val = 255;

        exiv2Iface.setExifTagLong("Exif.Photo.LightSource", val);
    }
    else if (d->lightSourceCheck->isValid())
        exiv2Iface.removeExifTag("Exif.Photo.LightSource");

    if (d->flashModeCheck->isChecked())
    {
        long val = d->flashModeCB->currentItem();
        exiv2Iface.setExifTagLong("Exif.Photo.Flash", d->flashModeMap[val].id());
    }
    else if (d->flashModeCheck->isValid())
        exiv2Iface.removeExifTag("Exif.Photo.Flash");

    if (d->flashEnergyCheck->isChecked())
    {
        exiv2Iface.convertToRational(d->flashEnergyEdit->value(), &num, &den, 1);
        exiv2Iface.setExifTagRational("Exif.Photo.FlashEnergy", num, den);
    }
    else
        exiv2Iface.removeExifTag("Exif.Photo.FlashEnergy");

    if (d->whiteBalanceCheck->isChecked())
        exiv2Iface.setExifTagLong("Exif.Photo.WhiteBalance", d->whiteBalanceCB->currentItem());
    else if (d->whiteBalanceCheck->isValid())
        exiv2Iface.removeExifTag("Exif.Photo.WhiteBalance");

    exifData = exiv2Iface.getExif();
}

}  // namespace KIPIMetadataEditPlugin

