/***************************************************************************
    UndoModifyMetaDataAction.cpp  -  Undo action for modifying meta data
                             -------------------
    begin                : Sun Apr 03 2011
    copyright            : (C) 2011 by Thomas Eschenbacher
    email                : Thomas Eschenbacher <Thomas.Eschenbacher@gmx.de>

 ***************************************************************************/

/***************************************************************************
 *                                                                         *
 *   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.                                   *
 *                                                                         *
 ***************************************************************************/

#include "config.h"
#include <KLocalizedString>

#include "libkwave/SignalManager.h"
#include "libkwave/String.h"
#include "libkwave/undo/UndoModifyMetaDataAction.h"

//***************************************************************************
Kwave::UndoModifyMetaDataAction::UndoModifyMetaDataAction(
    const Kwave::MetaDataList &meta_data)
    :UndoAction(), m_saved_data(meta_data)
{
}

//***************************************************************************
Kwave::UndoModifyMetaDataAction::~UndoModifyMetaDataAction()
{
}

//***************************************************************************
QString Kwave::UndoModifyMetaDataAction::description()
{
    // sanity check: list should not be empty
    Q_ASSERT(!m_saved_data.isEmpty());
    if (m_saved_data.isEmpty()) return _("");

    QString name;
    {
        const Kwave::MetaData &m = m_saved_data.first();
        if (m.hasProperty(Kwave::MetaData::STDPROP_TYPE))
            name = m[Kwave::MetaData::STDPROP_TYPE].toString();
    }

    // if the meta data list contains only one object: try to find
    // out the object's name
    if ((m_saved_data.count() == 1) && name.length()) {
        return i18nc(
            "name of the undo action for modifying a meta data object",
            "Modify %1",
            name
        );
    }

    // check if the list contains only objects of the same type
    bool all_same_type = true;
    foreach (const Kwave::MetaData &m, m_saved_data) {
        QString n = m[Kwave::MetaData::STDPROP_TYPE].toString();
        if (!n.length() || (n != name)) {
            all_same_type = false;
            break;
        }
    }
    if (all_same_type) {
        return i18nc(
            "name of the undo action for modifying multiple "
            "meta data objects of the same type: "
            "%1=number of elements, %2=name of one element in singular",
            "Modify %1 %2 objects",
            m_saved_data.count(), name
        );
    }

    return i18n("Modify Meta Data");
}

//***************************************************************************
qint64 Kwave::UndoModifyMetaDataAction::undoSize()
{
    return sizeof(*this) + sizeof(m_saved_data);
}

//***************************************************************************
qint64 Kwave::UndoModifyMetaDataAction::redoSize()
{
    return undoSize();
}

//***************************************************************************
bool Kwave::UndoModifyMetaDataAction::store(Kwave::SignalManager &)
{
    // nothing to do, all data has already
    // been stored in the constructor
    return true;
}

//***************************************************************************
Kwave::UndoAction *Kwave::UndoModifyMetaDataAction::undo(
    Kwave::SignalManager &manager, bool with_redo)
{
    if (m_saved_data.isEmpty()) return nullptr;

    // store data for redo
    if (with_redo) {
        Kwave::MetaDataList old_data;
        const Kwave::MetaDataList &current_data = manager.metaData();

        foreach (const Kwave::MetaData &meta, m_saved_data) {
            if (current_data.contains(meta)) {
                // add a new entry that will replace the old one
                old_data.add(current_data[meta.id()]);
            } else {
                // add an empty entry that will delete the old one when added
                Kwave::MetaData empty_element(meta);
                old_data.add(empty_element);
                old_data[empty_element.id()].clear();
            }
        }

        // restore the saved meta data
        manager.mergeMetaData(m_saved_data);

        // take the previous values as new undo data
        m_saved_data = old_data;

        return this;
    } else {
        // restore the saved meta data
        manager.mergeMetaData(m_saved_data);
        return nullptr;
    }
}

//***************************************************************************
void Kwave::UndoModifyMetaDataAction::dump(const QString &indent)
{
   foreach (const Kwave::MetaData &m, m_saved_data) {
        qDebug("%sundo modify meta data object '%s'",
               DBG(indent), DBG(m.id()));

        // dump all properties of the object
        foreach (const QString &key, m.keys()) {
            QVariant v = m[key];
            QString value;
            if (v.typeId() == QMetaType::QVariantList) {
                foreach (const QVariant &v1, v.toList())
                    value += _("'") + v1.toString() + _("' ");
            } else {
                value = v.toString();
            }
            qDebug("%s    '%s' = '%s",
                   DBG(indent), DBG(key), DBG(value));
        }
    }
}

//***************************************************************************
//***************************************************************************
