//  ************************************************************************************************
//
//  BornAgain: simulate and fit reflection and scattering
//
//! @file      GUI/Model/Device/MultiInstrumentNotifier.h
//! @brief     Defines class MultiInstrumentNotifier
//!
//! @homepage  http://www.bornagainproject.org
//! @license   GNU General Public License v3 or higher (see COPYING)
//! @copyright Forschungszentrum Jülich GmbH 2018
//! @authors   Scientific Computing Group at MLZ (see CITATION, AUTHORS)
//
//  ************************************************************************************************

#ifndef BORNAGAIN_GUI_MODEL_DEVICE_MULTIINSTRUMENTNOTIFIER_H
#define BORNAGAIN_GUI_MODEL_DEVICE_MULTIINSTRUMENTNOTIFIER_H

#include "GUI/Model/Device/InstrumentModel.h"
#include <QObject>

class InstrumentModel;
class InstrumentItem;
class RealItem;

//! Class to modify the instruments list or a single instrument and provide the necessary signaling
//! within BornAgain.
//!
//! An instance of this class is held in the project document (ProjectDocument). Whenever you want
//! to modify instruments of the current project, use this instance to ensure proper signaling of
//! changes. If you change an instrument without using any method in this class, you have to notify
//! this class about the modification by calling notifyInstrumentChanged.
//!
//! If you want to be notified about any changes of instruments in the current project, listen to
//! the signals of this instance.
//!
//! For uses other than the instruments in the current project (like e.g. for the instruments
//! library), you can create a dedicated instance and handle the instrument collection in question
//! with this separate instance.

class MultiInstrumentNotifier : public QObject {
    Q_OBJECT

public:
    MultiInstrumentNotifier(InstrumentModel* instruments);

    //! The list of existing instruments.
    InstrumentModel* instrumentModel();

    //! Add an instrument and emit the respective signal.
    template <typename T>
    T* addInstrumentItem();

    //! Add an instrument and emit the respective signal.
    void removeInstrument(InstrumentItem* instrument);

    //! Copy an instrument, set its name and emit the respective signal.
    InstrumentItem* addInstrumentItemCopy(const InstrumentItem* instrument, const QString& name);

    //! Set an instrument's name and emit the respective signal.
    void setInstrumentName(InstrumentItem* instrument, const QString& name);

    //! Calls the instrument's updateToRealData and emits the respective signal.
    void updateInstrumentToRealDataItem(InstrumentItem* instrument, const RealItem* realItem);

    //! Simply emits the instrumentChanged signal. Call this whenever you change an instrument's
    //! data without using this edit controller. By calling this method, the listeners will be
    //! notified about the changes.
    void notifyInstrumentChanged(InstrumentItem* instrument);

signals:
    //! Signals a change in the list of instruments.
    void instrumentAddedOrRemoved();

    //! Signals any change in the settings of the given instrument.
    //!
    //! Signals also a name change, which has its own additional signal
    void instrumentChanged(const InstrumentItem* instrument);

    //! Signals name change of the given instrument.
    //!
    //! In addition to this, instrumentChanged() will be emitted as well.
    void instrumentNameChanged(const InstrumentItem* instrument);

private:
    InstrumentModel* m_instruments; //!< The edited/controlled instruments. This pointer is
                                    //!< borrowed, not owned.
};

template <typename T>
T* MultiInstrumentNotifier::addInstrumentItem()
{
    auto* t = m_instruments->addInstrumentItem<T>();
    emit instrumentAddedOrRemoved();
    return t;
}

#endif // BORNAGAIN_GUI_MODEL_DEVICE_MULTIINSTRUMENTNOTIFIER_H
