/**
 * UGENE - Integrated Bioinformatics Tools.
 * Copyright (C) 2008-2023 UniPro <ugene@unipro.ru>
 * http://ugene.net
 *
 * 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.
 *
 * 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.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
 * MA 02110-1301, USA.
 */

#pragma once

#include <U2Core/U2OpStatus.h>

#include <U2Lang/URLAttribute.h>

namespace U2 {

class DatasetsListWidget;
class URLDelegate;
class URLListController;
class URLListWidget;
class UrlItem;

/************************************************************************/
/* DatasetsController */
/************************************************************************/
class U2DESIGNER_EXPORT DatasetsController : public QObject {
    Q_OBJECT
public:
    DatasetsController(const QSet<GObjectType>& compatibleObjTypes = QSet<GObjectType>(), QObject* parent = nullptr);

    virtual void update();
    virtual void renameDataset(int dsNum, const QString& newName, U2OpStatus& os) = 0;
    virtual void deleteDataset(int dsNum) = 0;
    virtual void addDataset(const QString& name, U2OpStatus& os) = 0;
    virtual void onUrlAdded(URLListController* ctrl, URLContainer* url) = 0;

    virtual const QSet<GObjectType>& getCompatibleObjTypes() const;

signals:
    void si_attributeChanged();
    void si_datasetRenamed(QPair<QString, QString>&); //QPair "oldName", "newName"

protected:
    virtual QStringList names() const = 0;
    void checkName(const QString& name, U2OpStatus& os, const QString& exception = "");

private:
    QSet<GObjectType> compatibleObjTypes;
};

class U2DESIGNER_EXPORT AttributeDatasetsController : public DatasetsController {
    Q_OBJECT
public:
    AttributeDatasetsController(QList<Dataset>& sets, const QSet<GObjectType>& compatibleObjTypes);
    ~AttributeDatasetsController() override;

    void renameDataset(int dsNum, const QString& newName, U2OpStatus& os) override;
    void deleteDataset(int dsNum) override;
    void addDataset(const QString& name, U2OpStatus& os) override;
    void onUrlAdded(URLListController* ctrl, URLContainer* url) override;

    QWidget* getWidget();
    QList<Dataset> getDatasets();
    QStringList names() const override;

private:
    DatasetsListWidget* datasetsWidget;
    QList<Dataset*> sets;

private:
    void initSets(const QList<Dataset>& s);
    void initialize();
    URLListWidget* createDatasetWidget(Dataset* dSet);
};

class U2DESIGNER_EXPORT PairedReadsController : public DatasetsController {
public:
    PairedReadsController(const QList<Dataset>& sets1, const QList<Dataset>& sets2, const QString& label1, const QString& label2);
    ~PairedReadsController() override;

    void renameDataset(int dsNum, const QString& newName, U2OpStatus& os) override;
    void deleteDataset(int dsNum) override;
    void addDataset(const QString& name, U2OpStatus& os) override;
    void onUrlAdded(URLListController* ctrl, URLContainer* url) override;

    QWidget* getWidget();
    /** num == 0 || num == 1*/
    QList<Dataset> getDatasets(int num);

protected:
    QStringList names() const override;

private:
    QString label1;
    QString label2;
    typedef QPair<Dataset*, Dataset*> SetsPair;
    typedef QPair<URLListController*, URLListController*> CtrlsPair;
    QList<SetsPair> sets;
    QList<CtrlsPair> ctrls;
    DatasetsListWidget* datasetsWidget;

private:
    void initSets(const QList<Dataset>& sets1, const QList<Dataset>& sets2);
    void initialize();
    QWidget* createDatasetWidget(const SetsPair& pair);
    int pairNumByCtrl(URLListController* ctrl) const;
    URLListController* pairedCtrl(URLListController* ctrl) const;
};

class U2DESIGNER_EXPORT UrlAndDatasetController : public DatasetsController {
    Q_OBJECT
public:
    UrlAndDatasetController(const QList<Dataset>& urls, const QList<Dataset>& sets, const QString& _urlLabel, const QString& _datasetLabel);
    ~UrlAndDatasetController() override;

    void renameDataset(int dsNum, const QString& newName, U2OpStatus& os) override;
    void deleteDataset(int dsNum) override;
    void addDataset(const QString& name, U2OpStatus& os) override;
    void onUrlAdded(URLListController* /*ctrl*/, URLContainer* /*url*/) override {
    }

    QWidget* getWidget();
    QList<Dataset> getDatasets() const;
    QList<Dataset> getUrls() const;

protected:
    QStringList names() const override;

private slots:
    void sl_urlChanged(QWidget* widget);

private:
    QString urlLabel;
    QString datasetLabel;
    typedef QPair<URLDelegate*, URLListController*> CtrlsPair;
    QStringList urls;
    QList<Dataset*> sets;
    QList<CtrlsPair> ctrls;
    DatasetsListWidget* datasetsWidget;

private:
    void initSets(const QList<Dataset>& _urls, const QList<Dataset>& sets);
    void initialize();
    QWidget* createDatasetPageWidget(Dataset* set);
    QWidget* createUrlWidget(URLDelegate* ctrl, const QString& value);
    QWidget* createDatasetWidget(URLListController* ctrl);
    QString getUrlByDataset(Dataset* set) const;
};

/************************************************************************/
/* URLListController */
/************************************************************************/
class U2DESIGNER_EXPORT URLListController : public QObject {
    Q_OBJECT
public:
    URLListController(DatasetsController* parent, Dataset* set);

    void addUrl(const QString& url, U2OpStatus& os);
    void replaceUrl(int pos, int newPos);
    void deleteUrl(int pos);
    void updateUrl(UrlItem* item);

    URLListWidget* getWidget();
    Dataset* dataset();
    const QSet<GObjectType>& getCompatibleObjTypes() const;

private:
    URLListWidget* widget;
    DatasetsController* controller;
    Dataset* set;
    QMap<UrlItem*, URLContainer*> urlMap;

private:
    void addItemWidget(URLContainer* url);
    void createWidget();
    URLContainer* getUrl(int pos);
};

}  // namespace U2
