/* ============================================================
 *
 * This file is a part of digiKam project
 * http://www.digikam.org
 *
 * Date        : 2004-09-19
 * Description : a options group to set renaming files
 *               operations during camera downloading
 *
 * Copyright (C) 2004-2005 by Renchi Raju <renchi@pooh.tam.uiuc.edu>
 * 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.
 * 
 * ============================================================ */

// TQt includes.

#include <tqdatetime.h>
#include <tqlayout.h>
#include <tqradiobutton.h>
#include <tqcheckbox.h>
#include <tqcombobox.h>
#include <tqhbox.h>
#include <tqlabel.h>
#include <tqpushbutton.h>
#include <tqtimer.h>
#include <tqwhatsthis.h>

// KDE includes.

#include <tdelocale.h>
#include <tdeconfig.h>
#include <tdeapplication.h>
#include <kiconloader.h>
#include <klineedit.h>
#include <knuminput.h>
#include <kdialogbase.h>
#if KDE_IS_VERSION(3,2,0)
#include <kinputdialog.h>
#else
#include <klineeditdlg.h>
#endif

// Local includes.

#include "renamecustomizer.h"
#include "renamecustomizer.moc"

namespace Digikam
{

class RenameCustomizerPriv
{
public:

    enum DateFormatOptions
    {
        DigikamStandard = 0,
        IsoDateFormat,
        TextDateFormat,
        LocalDateFormat,
        Advanced
    };

    RenameCustomizerPriv()
    {
        renameDefault         = 0;
        renameCustom          = 0;
        renameDefaultBox      = 0;
        renameCustomBox       = 0;
        renameDefaultCase     = 0;
        renameDefaultCaseType = 0;
        addDateTimeBox        = 0;
        addCameraNameBox      = 0;
        addSeqNumberBox       = 0;
        changedTimer          = 0;
        renameCustomPrefix    = 0;
        renameCustomSuffix    = 0;
        startIndexLabel       = 0;
        startIndexInput       = 0;
        focusedWidget         = 0;
        dateTimeButton        = 0;
        dateTimeLabel         = 0;
        dateTimeFormat        = 0;
}

    TQWidget      *focusedWidget;

    TQString       cameraTitle;

    TQRadioButton *renameDefault;
    TQRadioButton *renameCustom;

    TQGroupBox    *renameDefaultBox;
    TQGroupBox    *renameCustomBox;
    
    TQLabel       *renameDefaultCase;
    TQLabel       *startIndexLabel;
    TQLabel       *dateTimeLabel;

    TQComboBox    *renameDefaultCaseType;
    TQComboBox    *dateTimeFormat;

    TQCheckBox    *addDateTimeBox;
    TQCheckBox    *addCameraNameBox;
    TQCheckBox    *addSeqNumberBox;

    TQPushButton  *dateTimeButton;
    TQString       dateTimeFormatString;

    TQTimer       *changedTimer;

    KLineEdit    *renameCustomPrefix;
    KLineEdit    *renameCustomSuffix;

    KIntNumInput *startIndexInput;
};

RenameCustomizer::RenameCustomizer(TQWidget* parent, const TQString& cameraTitle)
                : TQButtonGroup(parent)
{
    d = new RenameCustomizerPriv;
    d->changedTimer = new TQTimer(this);
    d->cameraTitle  = cameraTitle;

    setFrameStyle( TQFrame::NoFrame );
    setRadioButtonExclusive(true);
    setColumnLayout(0, TQt::Vertical);
    TQGridLayout* mainLayout = new TQGridLayout(layout(), 4, 1);

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

    d->renameDefault = new TQRadioButton(i18n("Camera filenames"), this);
    TQWhatsThis::add( d->renameDefault, i18n("<p>Turn on this option to use camera "
                                            "provided image filenames without modifications."));
    mainLayout->addMultiCellWidget(d->renameDefault, 0, 0, 0, 1);

    d->renameDefaultBox = new TQGroupBox( this );
    d->renameDefaultBox->setFrameStyle(TQFrame::NoFrame|TQFrame::Plain);
    d->renameDefaultBox->setInsideMargin(0);
    d->renameDefaultBox->setColumnLayout(0, TQt::Vertical);

    d->renameDefaultCase = new TQLabel( i18n("Change case to:"), d->renameDefaultBox );
    d->renameDefaultCase->setSizePolicy( TQSizePolicy::Minimum, TQSizePolicy::Preferred );

    d->renameDefaultCaseType = new TQComboBox( d->renameDefaultBox );
    d->renameDefaultCaseType->insertItem(i18n("Leave as Is"), 0);
    d->renameDefaultCaseType->insertItem(i18n("Upper"), 1);
    d->renameDefaultCaseType->insertItem(i18n("Lower"), 2);
    d->renameDefaultCaseType->setSizePolicy(TQSizePolicy::Minimum, TQSizePolicy::Preferred);
    TQWhatsThis::add( d->renameDefaultCaseType, i18n("<p>Set the method to use to change the case "
                                                    "of image filenames."));
                                           
    TQHBoxLayout* boxLayout1 = new TQHBoxLayout( d->renameDefaultBox->layout() );
    boxLayout1->addSpacing( 10 );
    boxLayout1->addWidget( d->renameDefaultCase );
    boxLayout1->addWidget( d->renameDefaultCaseType );

    mainLayout->addMultiCellWidget(d->renameDefaultBox, 1, 1, 0, 1);

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

    d->renameCustom = new TQRadioButton(i18n("Customize"), this);
    mainLayout->addMultiCellWidget(d->renameCustom, 2, 2, 0, 1);
    TQWhatsThis::add( d->renameCustom, i18n("<p>Turn on this option to customize image filenames "
                                           "during download."));

    d->renameCustomBox = new TQGroupBox(this);
    d->renameCustomBox->setFrameStyle(TQFrame::NoFrame|TQFrame::Plain);
    d->renameCustomBox->setInsideMargin(0);
    d->renameCustomBox->setColumnLayout(0, TQt::Vertical);

    TQGridLayout* renameCustomBoxLayout = new TQGridLayout(d->renameCustomBox->layout(), 
                                                         6, 2, KDialogBase::spacingHint());
    renameCustomBoxLayout->setColSpacing( 0, 10 );

    TQLabel* prefixLabel = new TQLabel(i18n("Prefix:"), d->renameCustomBox);
    renameCustomBoxLayout->addMultiCellWidget(prefixLabel, 0, 0, 1, 1);
    d->renameCustomPrefix = new KLineEdit(d->renameCustomBox);
    d->focusedWidget = d->renameCustomPrefix;
    renameCustomBoxLayout->addMultiCellWidget(d->renameCustomPrefix, 0, 0, 2, 2);
    TQWhatsThis::add( d->renameCustomPrefix, i18n("<p>Set the prefix which will be added to "
                                                 "image filenames."));

    TQLabel* suffixLabel = new TQLabel(i18n("Suffix:"), d->renameCustomBox);
    renameCustomBoxLayout->addMultiCellWidget(suffixLabel, 1, 1, 1, 1);
    d->renameCustomSuffix = new KLineEdit(d->renameCustomBox);
    renameCustomBoxLayout->addMultiCellWidget(d->renameCustomSuffix, 1, 1, 2, 2);
    TQWhatsThis::add( d->renameCustomSuffix, i18n("<p>Set the suffix which will be added to "
                                                  "image filenames."));

    d->addDateTimeBox = new TQCheckBox( i18n("Add Date && Time"), d->renameCustomBox );
    renameCustomBoxLayout->addMultiCellWidget(d->addDateTimeBox, 2, 2, 1, 2);
    TQWhatsThis::add( d->addDateTimeBox, i18n("<p>Set this option to add the camera provided date and time."));

    TQWidget *dateTimeWidget = new TQWidget(d->renameCustomBox);
    d->dateTimeLabel    = new TQLabel(i18n("Date format:"), dateTimeWidget);
    d->dateTimeFormat   = new TQComboBox(dateTimeWidget);
    d->dateTimeFormat->insertItem(i18n("Standard"),       RenameCustomizerPriv::DigikamStandard);
    d->dateTimeFormat->insertItem(i18n("ISO"),            RenameCustomizerPriv::IsoDateFormat);
    d->dateTimeFormat->insertItem(i18n("Full Text"),      RenameCustomizerPriv::TextDateFormat);
    d->dateTimeFormat->insertItem(i18n("Local Settings"), RenameCustomizerPriv::LocalDateFormat);
    d->dateTimeFormat->insertItem(i18n("Advanced..."),    RenameCustomizerPriv::Advanced);
    TQWhatsThis::add( d->dateTimeFormat, i18n("<p>Select your preferred date format for "
                    "creating new albums. The options available are:</p>"
                    "<p><b>Standard</b>: the date format that has been used as a standard by digiKam. "
                    "E.g.: <i>20060824T142618</i></p>"
                    "<p/><b>ISO</b>: the date format according to ISO 8601 "
                    "(YYYY-MM-DD). E.g.: <i>2006-08-24T14:26:18</i></p>"
                    "<p><b>Full Text</b>: the date format is a user-readable string. "
                    "E.g.: <i>Thu Aug 24 14:26:18 2006</i></p>"
                    "<p><b>Local Settings</b>: the date format depending on TDE control panel settings.</p>"
                    "<p><b>Advanced:</b> allows the user to specify a custom date format.</p>"));
    d->dateTimeButton = new TQPushButton(SmallIcon("configure"), TQString(), dateTimeWidget);
    TQSizePolicy policy = d->dateTimeButton->sizePolicy();
    policy.setHorData(TQSizePolicy::Maximum);
    d->dateTimeButton->setSizePolicy(policy);
    TQHBoxLayout *boxLayout2 = new TQHBoxLayout(dateTimeWidget);
    boxLayout2->addWidget(d->dateTimeLabel);
    boxLayout2->addWidget(d->dateTimeFormat);
    boxLayout2->addWidget(d->dateTimeButton);
    renameCustomBoxLayout->addMultiCellWidget(dateTimeWidget, 3, 3, 1, 2);

    d->addCameraNameBox = new TQCheckBox( i18n("Add Camera Name"), d->renameCustomBox );
    renameCustomBoxLayout->addMultiCellWidget(d->addCameraNameBox, 4, 4, 1, 2);
    TQWhatsThis::add( d->addCameraNameBox, i18n("<p>Set this option to add the camera name."));

    d->addSeqNumberBox = new TQCheckBox( i18n("Add Sequence Number"), d->renameCustomBox );
    renameCustomBoxLayout->addMultiCellWidget(d->addSeqNumberBox, 5, 5, 1, 2);
    TQWhatsThis::add( d->addSeqNumberBox, i18n("<p>Set this option to add a sequence number "
                                              "starting with the index set below."));

    d->startIndexLabel = new TQLabel( i18n("Start Index:"), d->renameCustomBox );
    d->startIndexInput = new KIntNumInput(1, d->renameCustomBox);
    d->startIndexInput->setRange(1, 900000, 1, false);
    TQWhatsThis::add( d->startIndexInput, i18n("<p>Set the starting index value used to rename "
                                              "files with a sequence number."));

    renameCustomBoxLayout->addMultiCellWidget(d->startIndexLabel, 6, 6, 1, 1);
    renameCustomBoxLayout->addMultiCellWidget(d->startIndexInput, 6, 6, 2, 2);

    mainLayout->addMultiCellWidget(d->renameCustomBox, 3, 3, 0, 1);
    mainLayout->setRowStretch(4, 10);

    // -- setup connections -------------------------------------------------

    connect(this, TQ_SIGNAL(clicked(int)),
            this, TQ_SLOT(slotRadioButtonClicked(int)));
            
    connect(d->renameCustomPrefix, TQ_SIGNAL(textChanged(const TQString&)),
            this, TQ_SLOT(slotRenameOptionsChanged()));

    connect(d->renameCustomSuffix, TQ_SIGNAL(textChanged(const TQString&)),
            this, TQ_SLOT(slotRenameOptionsChanged()));

    connect(d->addDateTimeBox, TQ_SIGNAL(toggled(bool)),
            this, TQ_SLOT(slotRenameOptionsChanged()));

    connect(d->addCameraNameBox, TQ_SIGNAL(toggled(bool)),
            this, TQ_SLOT(slotRenameOptionsChanged()));

    connect(d->addSeqNumberBox, TQ_SIGNAL(toggled(bool)),
            this, TQ_SLOT(slotRenameOptionsChanged()));

    connect(d->renameDefaultCaseType, TQ_SIGNAL(activated(const TQString&)),
            this, TQ_SLOT(slotRenameOptionsChanged()));

    connect(d->startIndexInput, TQ_SIGNAL(valueChanged (int)),
            this, TQ_SLOT(slotRenameOptionsChanged()));

    connect(d->changedTimer, TQ_SIGNAL(timeout()),
            this, TQ_SIGNAL(signalChanged()));

    connect(d->dateTimeButton, TQ_SIGNAL(clicked()),
            this, TQ_SLOT(slotDateTimeButtonClicked()));

    connect(d->dateTimeFormat, TQ_SIGNAL(activated(int)),
            this, TQ_SLOT(slotDateTimeFormatChanged(int)));

    connect(d->addDateTimeBox, TQ_SIGNAL(toggled(bool)),
            this, TQ_SLOT(slotDateTimeBoxToggled(bool)));

    // -- initial values ---------------------------------------------------

    readSettings();

    // signal to this not yet connected when readSettings is called? Don't know
    slotDateTimeBoxToggled(d->addDateTimeBox->isChecked());
}

RenameCustomizer::~RenameCustomizer()
{
    delete d->changedTimer;
    saveSettings();
    delete d;
}

bool RenameCustomizer::useDefault() const
{
    return d->renameDefault->isChecked();
}

int RenameCustomizer::startIndex() const
{
    return d->startIndexInput->value();
}

TQString RenameCustomizer::newName(const TQDateTime &dateTime, int index, const TQString &extension) const
{
    if (d->renameDefault->isChecked())
        return TQString();
    else
    {
        TQString name(d->renameCustomPrefix->text());

        // use the "T" as a delimiter between date and time
        TQString date;
        switch (d->dateTimeFormat->currentItem())
        {
            case RenameCustomizerPriv::DigikamStandard:
                date = dateTime.toString("yyyyMMddThhmmss");
                break;
            case RenameCustomizerPriv::TextDateFormat:
                date = dateTime.toString(TQt::TextDate);
                break;
            case RenameCustomizerPriv::LocalDateFormat:
                date = dateTime.toString(TQt::LocalDate);
                break;
            case RenameCustomizerPriv::IsoDateFormat:
                date = dateTime.toString(TQt::ISODate);
                break;
            case RenameCustomizerPriv::Advanced:
                date = dateTime.toString(d->dateTimeFormatString);
                break;
         }

        // it seems that TQString::number does not support padding with zeros
        TQString seq;
        seq.sprintf("-%06d", index);

        if (d->addDateTimeBox->isChecked())
            name += date;

        if (d->addSeqNumberBox->isChecked())
            name += seq;

        if (d->addCameraNameBox->isChecked())
            name += TQString("-%1").arg(d->cameraTitle.simplifyWhiteSpace().replace(" ", ""));

        name += d->renameCustomSuffix->text();
        name += extension;

        return name;
    }
}

RenameCustomizer::Case RenameCustomizer::changeCase() const
{
    RenameCustomizer::Case type = NONE;

    if (d->renameDefaultCaseType->currentItem() == 1)
        type=UPPER;
    if (d->renameDefaultCaseType->currentItem() == 2)
        type=LOWER;

    return type;
}

void RenameCustomizer::slotRadioButtonClicked(int)
{
    TQRadioButton* btn = dynamic_cast<TQRadioButton*>(selected());
    if (!btn)
        return;

    d->renameCustomBox->setEnabled( btn != d->renameDefault );
    d->renameDefaultBox->setEnabled( btn == d->renameDefault );
    slotRenameOptionsChanged();
}

void RenameCustomizer::slotRenameOptionsChanged()
{
    d->focusedWidget = focusWidget();

    if (d->addSeqNumberBox->isChecked())
    {
        d->startIndexInput->setEnabled(true);
        d->startIndexLabel->setEnabled(true);
    }
    else
    {
        d->startIndexInput->setEnabled(false);
        d->startIndexLabel->setEnabled(false);
    }

    d->changedTimer->start(500, true);
}

void RenameCustomizer::slotDateTimeBoxToggled(bool on)
{
    d->dateTimeLabel->setEnabled(on);
    d->dateTimeFormat->setEnabled(on);
    d->dateTimeButton->setEnabled(on
            && d->dateTimeFormat->currentItem() == RenameCustomizerPriv::Advanced);
    slotRenameOptionsChanged();
}

void RenameCustomizer::slotDateTimeFormatChanged(int index)
{
    if (index == RenameCustomizerPriv::Advanced)
    {
        d->dateTimeButton->setEnabled(true);
        //d->dateTimeButton->show();
        //slotDateTimeButtonClicked();
    }
    else
    {
        d->dateTimeButton->setEnabled(false);
        //d->dateTimeButton->hide();
    }
    slotRenameOptionsChanged();
}

void RenameCustomizer::slotDateTimeButtonClicked()
{
    bool ok;
    TQString message = i18n("<qt><p>Enter the format for date and time.</p>"
                           "<p>Use <i>dd</i> for the day, "
                           "<i>MM</i> for the month, "
                           "<i>yyyy</i> for the year, "
                           "<i>hh</i> for the hour, "
                           "<i>mm</i> for the minute, "
                           "<i>ss</i> for the second.</p>"
                           "<p>Examples: <i>yyyyMMddThhmmss</i> "
                           "for 20060824T142418,<br>"
                           "<i>yyyy-MM-dd hh:mm:ss</i> "
                           "for 2006-08-24 14:24:18.</p></qt>");

#if KDE_IS_VERSION(3,2,0)
    TQString newFormat = KInputDialog::getText(i18n("Change Date and Time Format"),
                                              message,
                                              d->dateTimeFormatString, &ok, this);
#else
    TQString newFormat = KLineEditDlg::getText(i18n("Change Date and Time Format"),
                                              message,
                                              d->dateTimeFormatString, &ok, this);
#endif

    if (!ok)
        return;

    d->dateTimeFormatString = newFormat;
    slotRenameOptionsChanged();
}

void RenameCustomizer::readSettings()
{
    TDEConfig* config = kapp->config();
    
    config->setGroup("Camera Settings");
    bool def         = config->readBoolEntry("Rename Use Default", true);
    bool addSeqNumb  = config->readBoolEntry("Add Sequence Number", true);
    bool adddateTime = config->readBoolEntry("Add Date Time", false);
    bool addCamName  = config->readBoolEntry("Add Camera Name", false);
    int chcaseT      = config->readNumEntry("Case Type", NONE);
    TQString prefix   = config->readEntry("Rename Prefix", i18n("photo"));
    TQString suffix   = config->readEntry("Rename Postfix", TQString());
    int startIndex   = config->readNumEntry("Rename Start Index", 1);
    int dateTime     = config->readNumEntry("Date Time Format", RenameCustomizerPriv::IsoDateFormat);
    TQString format   = config->readEntry("Date Time Format String", "yyyyMMddThhmmss");

    if (def)
    {
        d->renameDefault->setChecked(true);
        d->renameCustom->setChecked(false);
        d->renameCustomBox->setEnabled(false);
        d->renameDefaultBox->setEnabled(true);
    }
    else
    {
        d->renameDefault->setChecked(false);
        d->renameCustom->setChecked(true);
        d->renameCustomBox->setEnabled(true);
        d->renameDefaultBox->setEnabled(false);
    }

    d->addDateTimeBox->setChecked(adddateTime);
    d->addCameraNameBox->setChecked(addCamName);
    d->addSeqNumberBox->setChecked(addSeqNumb);
    d->renameDefaultCaseType->setCurrentItem(chcaseT);
    d->renameCustomPrefix->setText(prefix);
    d->renameCustomSuffix->setText(suffix);
    d->startIndexInput->setValue(startIndex);
    d->dateTimeFormat->setCurrentItem(dateTime);
    d->dateTimeFormatString = format;
    slotRenameOptionsChanged();
}

void RenameCustomizer::saveSettings()
{
    TDEConfig* config = kapp->config();

    config->setGroup("Camera Settings");
    config->writeEntry("Rename Use Default", d->renameDefault->isChecked());
    config->writeEntry("Add Camera Name", d->addCameraNameBox->isChecked());
    config->writeEntry("Add Date Time", d->addDateTimeBox->isChecked());
    config->writeEntry("Add Sequence Number", d->addSeqNumberBox->isChecked());
    config->writeEntry("Case Type", d->renameDefaultCaseType->currentItem());
    config->writeEntry("Rename Prefix", d->renameCustomPrefix->text());
    config->writeEntry("Rename Suffix", d->renameCustomSuffix->text());
    config->writeEntry("Rename Start Index", d->startIndexInput->value());
    config->writeEntry("Date Time Format", d->dateTimeFormat->currentItem());
    config->writeEntry("Date Time Format String", d->dateTimeFormatString);
    config->sync();
}

void RenameCustomizer::restoreFocus()
{
    d->focusedWidget->setFocus();
}

}  // namespace Digikam

