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

#ifndef BORNAGAIN_GUI_COREGUI_DATALOADERS_ABSTRACTDATALOADER_H
#define BORNAGAIN_GUI_COREGUI_DATALOADERS_ABSTRACTDATALOADER_H

class QString;
class QByteArray;
class QGroupBox;
class QCustomPlot;
class QTableWidget;
class RealDataItem;
class AbstractDataLoaderResultModel;

#include <QtCore>

//! Base class for all data loaders (classes which can import real data)

class AbstractDataLoader : public QObject {
    Q_OBJECT
public:
    virtual ~AbstractDataLoader() = default;

    //! The name shown in the format selection combo
    virtual QString name() const = 0;

    //! A name which can be used for save/load purposes (which will not change ever more)
    virtual QString persistentClassName() const = 0;

    //! Define the real data item on which the import shall work.
    void setRealDataItem(RealDataItem* item);

    //! The real data item on which the import shall work.
    RealDataItem* realDataItem();

    //! The real data item on which the import shall work.
    const RealDataItem* realDataItem() const;

    //! Fills the widget on the import dialog pane. This base class' implementation does nothing
    //! (meaning "no editable properties")
    virtual void populateImportSettingsWidget(QWidget* parent);

    //! Read all values from the properties UI into the internal variables
    virtual void applyImportSettings();

    //! Set import settings to defaults
    virtual void initWithDefaultImportSettings();

    //! Return the default import settings
    virtual QByteArray defaultImportSettings() const;

    //! Create a complete clone, including all internal states
    virtual AbstractDataLoader* clone() const = 0;

    //! Returns every internal setting so it can be restored completely
    virtual QByteArray serialize() const;

    //! Initialize from serialization data. If any error occurred, then a DeserializationException
    //! has to be thrown.
    //! The complete state has to be restored. Therefore if e.g. errors occurred in the former
    //! serialization, but errors are not serialized, then they have to be regenerated/recalculated
    //! in here.
    virtual void deserialize(const QByteArray& data);

    //! Sets the file contents to be imported. If the file was a compressed file, here already the
    //! decompressed content will be overhanded.
    virtual void setFileContents(const QByteArray& fileContent) = 0;

    //! Returns the original file content. If not available any more (like for legacy project file
    //! import), then an empty array will be returned.
    virtual QByteArray fileContent() const;

    //! Guess appropriate settings (for example the separator in a CSV file). Is called only once,
    //! directly after setting the file content.
    virtual void guessSettings();

    //! Process the file contents. Can be called more than once, e.g. if the import settings have
    //! changed.
    //! Any error has to be stored in the loader (see numErrors()).
    virtual void processContents() = 0;

    //! Number of errors found while processing the content. An error means that either a particular
    //! content (line) can't be used or may be suspicious (line related error), or that the whole
    //! content can't be used (e.g. only 1 line present).
    virtual int numErrors() const;

    //! Number of errors related to a specific line. Such an error means that a particular
    //! content (line) can't be used or may be suspicious.
    virtual int numLineRelatedErrors() const;

    //! Errors not related to a particular line.
    virtual QStringList lineUnrelatedErrors() const;

    //! Create a table model which contains the import information like original file content, raw
    //! content, processed content
    //! The returned pointer will be owned by the caller.
    //! This base class' implementation does nothing (return nullptr).
    virtual AbstractDataLoaderResultModel* createResultModel() const;

signals:
    //! Emitted whenever an import setting changed
    void importSettingsChanged();

    //! Emitted whenever contents have been processed
    void contentsProcessed();

protected:
    enum class Error { DifferendNumberOfColumns };

protected:
    RealDataItem* m_item; //< The real-data-item which owns this loader. Never delete this!
};

QDataStream& operator<<(QDataStream& stream, const AbstractDataLoader& s);
QDataStream& operator>>(QDataStream& stream, AbstractDataLoader& s);

#endif // BORNAGAIN_GUI_COREGUI_DATALOADERS_ABSTRACTDATALOADER_H
