#include <iostream>
#include <memory>
#include <string>

// Forward declaration
class Document;
class DraftState;
class ModerationState;
class PublishedState;

// ---------- Abstract State ----------
class State {
public:
    virtual ~State() = default;
    virtual std::string name() const = 0;
    virtual void edit(Document& doc) {
        std::cout << "Current state (" << name() << ") does not allow editing.\n";
    }
    virtual void submitForReview(Document& doc) {
        std::cout << "Current state (" << name() << ") does not allow submitting for review.\n";
    }
    virtual void approve(Document& doc) {
        std::cout << "Current state (" << name() << ") does not allow approval.\n";
    }
    virtual void reject(Document& doc) {
        std::cout << "Current state (" << name() << ") does not allow rejection.\n";
    }
    virtual void publish(Document& doc) {
        std::cout << "Current state (" << name() << ") does not allow direct publishing.\n";
    }
};

// ---------- Context: Document ----------
class Document {
    std::unique_ptr<State> state;
    std::string content;
public:
    explicit Document(std::unique_ptr<State> initialState)
        : state(std::move(initialState)) {}

    void setState(std::unique_ptr<State> newState) {
        state = std::move(newState);
    }

    void edit()            { state->edit(*this); }
    void submitForReview() { state->submitForReview(*this); }
    void approve()         { state->approve(*this); }
    void reject()          { state->reject(*this); }
    void publish()         { state->publish(*this); }

    void setContent(const std::string& c) { content = c; }
    const std::string& getContent() const { return content; }
    std::string getStateName() const { return state->name(); }
};

// ---------- Concrete State: Draft ----------
class DraftState : public State {
public:
    std::string name() const override { return "Draft"; }

    void edit(Document& doc) override {
        std::cout << "Editing document...\n";
        doc.setContent("Document content (draft version)");
    }

    // Declaration; implementation follows after ModerationState is defined
    void submitForReview(Document& doc) override;

    void publish(Document& doc) override {
        std::cout << "Draft cannot be published directly. Submit for review first.\n";
    }
};

// ---------- Concrete State: Under Review ----------
class ModerationState : public State {
public:
    std::string name() const override { return "Under Review"; }

    void edit(Document& doc) override {
        std::cout << "Cannot edit document while under review.\n";
    }

    // Declaration; implementation follows after PublishedState is defined
    void approve(Document& doc) override;
    void reject(Document& doc) override;
};

// ---------- Concrete State: Published ----------
class PublishedState : public State {
public:
    std::string name() const override { return "Published"; }

    void edit(Document& doc) override {
        std::cout << "Published documents cannot be edited.\n";
    }

    void submitForReview(Document& doc) override {
        std::cout << "Published documents do not need review again.\n";
    }

    void publish(Document& doc) override {
        std::cout << "Document is already published.\n";
    }
};

// ---------- Deferred implementation (all concrete states are now fully defined) ----------
void DraftState::submitForReview(Document& doc) {
    std::cout << "Submitting for review.\n";
    doc.setState(std::make_unique<ModerationState>());
}

void ModerationState::approve(Document& doc) {
    std::cout << "Review approved, document published.\n";
    doc.setState(std::make_unique<PublishedState>());
}

void ModerationState::reject(Document& doc) {
    std::cout << "Review rejected, returning to draft.\n";
    doc.setState(std::make_unique<DraftState>());
}

// ---------- Main Function ----------
int main() {
    Document doc(std::make_unique<DraftState>());
    std::cout << "Initial state: " << doc.getStateName() << "\n\n";

    doc.edit();
    std::cout << "Current state: " << doc.getStateName() << "\n\n";

    doc.publish();   // should be rejected
    std::cout << "Current state: " << doc.getStateName() << "\n\n";

    doc.submitForReview();
    std::cout << "Current state: " << doc.getStateName() << "\n\n";

    doc.edit();      // cannot edit while under review
    std::cout << "Current state: " << doc.getStateName() << "\n\n";

    doc.approve();   // publish
    std::cout << "Current state: " << doc.getStateName() << "\n\n";

    doc.edit();      // cannot edit once published
    std::cout << "Current state: " << doc.getStateName() << "\n\n";

    // Demonstrate rejection path
    Document doc2(std::make_unique<DraftState>());
    std::cout << "\n--- Demonstrating rejection path with a new document ---\n";
    doc2.edit();
    doc2.submitForReview();
    doc2.reject();   // return to draft
    std::cout << "Current state: " << doc2.getStateName() << "\n\n";
    doc2.edit();     // now editable again

    return 0;
}

results matching ""

    No results matching ""