/***************************************************************************
           LabelItem.cpp -  label item within a SignalView
                             -------------------
    begin                : Sat Mar 26 2011
    copyright            : (C) 2011 by Thomas Eschenbacher
    email                : 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 <QAction>
#include <QIcon>
#include <QMenu>

#include <KLocalizedString>

#include "libkwave/Label.h"
#include "libkwave/SignalManager.h"
#include "libkwave/String.h"
#include "libkwave/Utils.h"
#include "libkwave/undo/UndoModifyMetaDataAction.h"
#include "libkwave/undo/UndoTransactionGuard.h"

#include "libgui/LabelItem.h"
#include "libgui/SignalView.h"

//***************************************************************************
Kwave::LabelItem::LabelItem(Kwave::SignalView &view,
                            Kwave::SignalManager &signal_manager,
                            unsigned int index,
                            const Kwave::Label &label)
    :Kwave::ViewItem(view, signal_manager),
     m_index(index),
     m_initial_pos(label.pos()),
     m_current_pos(label.pos()),
     m_description(label.name()),
     m_undo_transaction(nullptr)
{
}

//***************************************************************************
Kwave::LabelItem::~LabelItem()
{
    if (m_undo_transaction) {
        // restore the previous data
        qDebug("Kwave::LabelItem::~LabelItem() -> aborted -> reverting!");
        m_undo_transaction->abort();
        delete m_undo_transaction;
        m_undo_transaction = nullptr;
    }
}

//***************************************************************************
Kwave::ViewItem::Flags Kwave::LabelItem::flags() const
{
    return Kwave::ViewItem::CanGrabAndMove;
}

//***************************************************************************
QString Kwave::LabelItem::toolTip(sample_index_t &ofs)
{
    Q_UNUSED(ofs)

    QString description = (m_description.length()) ?
        i18nc("tooltip of a label, %1=index, %2=description/name",
                "Label #%1 (%2)", m_index, m_description) :
        i18nc("tooltip of a label, without description, %1=index",
                "Label #%1", m_index);

    QString hms = Kwave::ms2hms(m_view.samples2ms(m_current_pos));
    QString tip = _("%1\n%2\n%3").arg(description).arg(m_current_pos).arg(hms);

    return tip;
}

//***************************************************************************
void Kwave::LabelItem::appendContextMenu(QMenu *parent)
{
    Q_ASSERT(parent);
    if (!parent) return;

    // locate the "label" menu
    QMenu *label_menu = nullptr;
    foreach (const QAction *action, parent->actions()) {
        if (action->text() == i18n("Label")) {
            label_menu = action->menu();
            break;
        }
    }

    // the context menu of a label has been activated
    if (label_menu) {

        // find the "New" action and disable it
        foreach (QAction *action, label_menu->actions()) {
            if (action->text() == i18n("New")) {
                action->setEnabled(false);
                break;
            }
        }

        QAction *action_label_delete = label_menu->addAction(
            QIcon::fromTheme(_("list-remove")),
            i18n("&Delete"), this, SLOT(contextMenuLabelDelete()));
        Q_ASSERT(action_label_delete);
        if (!action_label_delete) return;

        QAction *action_label_properties = label_menu->addAction(
            QIcon::fromTheme(_("configure")),
            i18n("&Properties..."), this, SLOT(contextMenuLabelProperties()));
        Q_ASSERT(action_label_properties);
        if (!action_label_properties) return;
    }

}

//***************************************************************************
void Kwave::LabelItem::contextMenuLabelDelete()
{
    emit sigCommand(_("label:delete(%1)").arg(m_index));
}

//***************************************************************************
void Kwave::LabelItem::contextMenuLabelProperties()
{
    emit sigCommand(_("nomacro:label:edit(%1)").arg(m_index));
}

//***************************************************************************
QCursor Kwave::LabelItem::mouseCursor() const
{
    return Qt::SizeHorCursor;
}

//***************************************************************************
void Kwave::LabelItem::moveTo(const QPoint &mouse_pos)
{
    const sample_index_t new_pos = m_view.offset() +
                                   m_view.pixels2samples(mouse_pos.x());

    Kwave::Label label = m_signal_manager.findLabel(new_pos);
    if (label.isNull()) {

        // this is the first move ?
        if (!m_undo_transaction) {
            // there probably will be something to undo later
            // create an undo transaction guard
            m_undo_transaction = new(std::nothrow)
                Kwave::UndoTransactionGuard(
                    m_signal_manager, i18n("Move Label"));
            Q_ASSERT(m_undo_transaction);
            if (!m_undo_transaction) return;

            // save the previous label data for undo
            Kwave::Label lbl = m_signal_manager.findLabel(m_initial_pos);
            if (!m_undo_transaction->registerUndoAction(new(std::nothrow)
                UndoModifyMetaDataAction(Kwave::MetaDataList(lbl)))) {
                qWarning("Kwave::LabelItem::done(): saving undo data failed!");
                return;
            }
        }

        if (m_signal_manager.modifyLabel(m_index, new_pos,
                                         m_description, false)) {
            Kwave::Label lbl = m_signal_manager.findLabel(new_pos);
            if (!lbl.isNull()) {
                m_index       = m_signal_manager.labelIndex(lbl);
                m_current_pos = lbl.pos();
            }
        }
    }
}

//***************************************************************************
void Kwave::LabelItem::done()
{
    if (m_undo_transaction) {
        // close the undo transaction (regularly, with undo action)
        if (m_current_pos == m_initial_pos)
            m_undo_transaction->abort();
        delete m_undo_transaction;
        m_undo_transaction = nullptr;
    }
}

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

#include "moc_LabelItem.cpp"
