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

// Request class: reimbursement form
class ReimbursementRequest {
public:
    ReimbursementRequest(double amount, const std::string& description)
        : amount_(amount), description_(description) {}

    double getAmount() const { return amount_; }
    std::string getDescription() const { return description_; }

private:
    double amount_;
    std::string description_;
};

// Abstract approver
class Approver {
public:
    virtual ~Approver() = default;

    // Set next approver and return it for chaining
    Approver* setNext(Approver* next) {
        next_ = next;
        return next;
    }

    // Template method for handling requests
    void handleRequest(const ReimbursementRequest& request) {
        if (canApprove(request)) {
            approve(request);
        } else if (next_) {
            std::cout << "  -> Forwarding to next approver..." << std::endl;
            next_->handleRequest(request);
        } else {
            std::cout << "  -> No one can handle this request: " 
                      << request.getDescription() << " ($" 
                      << request.getAmount() << ")" << std::endl;
        }
    }

protected:
    // Determine whether the request can be handled
    virtual bool canApprove(const ReimbursementRequest& request) = 0;

    // Concrete approval logic
    virtual void approve(const ReimbursementRequest& request) = 0;

private:
    Approver* next_ = nullptr; // Successor approver (non-owning pointer)
};

// Concrete approver: Manager (approves ≤1000)
class Manager : public Approver {
protected:
    bool canApprove(const ReimbursementRequest& request) override {
        return request.getAmount() <= 1000;
    }

    void approve(const ReimbursementRequest& request) override {
        std::cout << "Manager approved: " << request.getDescription() 
                  << " ($" << request.getAmount() << ")" << std::endl;
    }
};

// Concrete approver: Director (approves ≤5000)
class Director : public Approver {
protected:
    bool canApprove(const ReimbursementRequest& request) override {
        return request.getAmount() <= 5000;
    }

    void approve(const ReimbursementRequest& request) override {
        std::cout << "Director approved: " << request.getDescription() 
                  << " ($" << request.getAmount() << ")" << std::endl;
    }
};

// Concrete approver: CEO (approves any amount)
class CEO : public Approver {
protected:
    bool canApprove(const ReimbursementRequest& request) override {
        return true; // CEO can approve all remaining requests
    }

    void approve(const ReimbursementRequest& request) override {
        std::cout << "CEO approved: " << request.getDescription() 
                  << " ($" << request.getAmount() << ")" << std::endl;
    }
};

int main() {
    // Create concrete approver objects on the stack
    Manager manager;
    Director director;
    CEO ceo;

    // Build the chain: Manager -> Director -> CEO
    manager.setNext(&director)->setNext(&ceo);
    // manager -> director -> ceo

    std::cout << "=== Testing complete chain (Manager -> Director -> CEO) ===" << std::endl;
    ReimbursementRequest req1(800, "Office supplies");
    ReimbursementRequest req2(3000, "Team building event");
    ReimbursementRequest req3(10000, "New server hardware");

    manager.handleRequest(req1);
    manager.handleRequest(req2);
    manager.handleRequest(req3);

    std::cout << "\n=== Testing incomplete chain (Director -> CEO only, Manager missing) ===" << std::endl;
    // Build another chain: Director -> CEO (skipping Manager)
    Director director2;
    CEO ceo2;
    director2.setNext(&ceo2);

    // Director handles requests ≤5000, CEO handles the rest
    director2.handleRequest(req1); // 800 -> handled directly by Director
    director2.handleRequest(req3); // 10000 -> forwarded to CEO

    std::cout << "\n=== Testing chain with no handler for high amount (Manager only) ===" << std::endl;
    Manager managerOnly;
    // No successor set, Manager can only handle ≤1000
    managerOnly.handleRequest(req1);  // 800 -> Manager handles
    managerOnly.handleRequest(req3);  // 10000 -> no one handles

    return 0;
}

results matching ""

    No results matching ""