#pragma once

#include "data/project.h"

#include <QUndoCommand>

namespace Xybrid::Editing {
    class CompositeCommand;

    class ProjectCommand : public QUndoCommand {
        friend class CompositeCommand;
    protected:
        std::shared_ptr<Data::Project> project;
        bool composed = false;

    public:
        bool commit();
        bool cancel();
    };

    class ProjectSequencerDeltaCommand : public ProjectCommand {
        std::vector<Data::SequenceEntry> oldSeq;
        int oldSeqSel;
    public:
        std::vector<Data::SequenceEntry> seq;
        int seqSel;

        ProjectSequencerDeltaCommand(const std::shared_ptr<Data::Project>& project);
        ~ProjectSequencerDeltaCommand() override = default;

        int id() const override { return 1000; }

        bool mergeWith(const QUndoCommand*) override;
        void redo() override;
        void undo() override;
    };

    class ProjectPatternMoveCommand : public ProjectCommand {
        int from, to;
    public:
        ProjectPatternMoveCommand(const std::shared_ptr<Data::Project>& project, int from, int to);
        ~ProjectPatternMoveCommand() override = default;

        int id() const override { return 1001; }

        bool mergeWith(const QUndoCommand*) override;
        void redo() override;
        void undo() override;
    };

    class ProjectPatternAddCommand : public ProjectCommand {
        int at, atSeq;
        std::shared_ptr<Data::Pattern> copyOf;
    public:
        ProjectPatternAddCommand(const std::shared_ptr<Data::Project>& project, int at, int atSeq = -1, const std::shared_ptr<Data::Pattern>& copyOf = nullptr);
        ~ProjectPatternAddCommand() override = default;

        void redo() override;
        void undo() override;
    };

    class ProjectPatternDeleteCommand : public ProjectCommand {
        std::shared_ptr<Data::Pattern> pattern;
        std::vector<Data::SequenceEntry> oldSeq;
        int oldSeqSel;
    public:
        ProjectPatternDeleteCommand(const std::shared_ptr<Data::Project>& project, const std::shared_ptr<Data::Pattern>& pattern);
        ~ProjectPatternDeleteCommand() override = default;

        void redo() override;
        void undo() override;
    };

}
