#include <iostream>
using namespace std;

// ============================================================================
// OOP CONCEPT: CLASS & OBJECT
// Class: A blueprint defining state (attributes) and behavior (functions).
//
// OOP PILLAR 1: ENCAPSULATION
// Bundles data members and functions operating on them inside a single unit.
// ============================================================================
class Pizza {
    // ------------------------------------------------------------------------
    // OOP CONCEPT: DATA HIDING (Access Specifier: private)
    // Internal state is hidden from outside modification to enforce business rules.
    // ------------------------------------------------------------------------
    private:
        int basePri = 250;
        int nonBasePr = 400;
        int cheese = 50;
        int ncheese = 70;
        int topping = 80;
        int ntopping = 100;

        // Internal state flags (Encapsulated validation)
        bool isCheese = false;
        bool isTop = false;

    // ------------------------------------------------------------------------
    // OOP CONCEPT: ACCESS CONTROL (Access Specifier: protected)
    // Accessible only within this class and derived subclasses (Deluxe).
    // ------------------------------------------------------------------------
    protected:  
        bool isVeg;
        int total = 0;

    // ------------------------------------------------------------------------
    // OOP PILLAR 2: ABSTRACTION (Access Specifier: public)
    // Exposes essential actions while hiding implementation and calculation details.
    // ------------------------------------------------------------------------
    public:
        // --------------------------------------------------------------------
        // OOP CONCEPT: CONSTRUCTOR & 'this' POINTER
        // Invoked at object creation. 'this' refers to the current invoking instance.
        // --------------------------------------------------------------------
        Pizza(bool isVeg) {
            this->isVeg = isVeg;
            Base();
        }

        // OOP CONCEPT: VIRTUAL DESTRUCTOR
        // Essential in base classes to prevent undefined behavior when deleting via base pointer.
        virtual ~Pizza() = default;

        void Base() {
            if (this->isVeg) {
                this->total += this->basePri;
                cout << "Base Price :" << this->basePri << endl;
            } else {
                this->total += this->nonBasePr;
                cout << "Non Veg Base : " << this->nonBasePr << endl;
            }
        }

        void Cheese() {
            if (this->isCheese) return;
            if (this->isVeg) {
                this->total += this->cheese;
                cout << "Cheese Price :" << this->cheese << endl;
            } else {
                this->total += this->ncheese;
                cout << "Non Veg Cheese : " << this->ncheese << endl;
            }
            this->isCheese = true;
        }

        // --------------------------------------------------------------------
        // OOP PILLAR 4 (A): COMPILE-TIME POLYMORPHISM (Function Overloading)
        // Same function name 'Topping', different parameter list.
        // --------------------------------------------------------------------
        void Topping() {
            if (this->isTop) return;
            if (this->isVeg) {
                this->total += this->topping;
                cout << "Topping Price :" << this->topping << endl;
            } else {
                this->total += this->ntopping;
                cout << "Non Veg Topping : " << this->ntopping << endl;
            }
            this->isTop = true;
        }

        // Overloaded variant: accepts quantity of extra toppings
        void Topping(int extraCount) {
            Topping(); // Add standard topping first
            int rate = this->isVeg ? this->topping : this->ntopping;
            this->total += (extraCount * rate);
            cout << "Extra Toppings (" << extraCount << ") Added: " << (extraCount * rate) << endl;
        }

        // --------------------------------------------------------------------
        // OOP PILLAR 4 (B): RUNTIME POLYMORPHISM (Virtual Function)
        // 'virtual' enables dynamic dispatch via vtable so derived classes can override.
        // --------------------------------------------------------------------
        virtual double getBill() {
            int gst = this->total * 0.5;
            cout << "Total:" << this->total << endl;
            cout << "GST:" << gst << endl;
            int totalPr = this->total + gst;
            cout << "Bill To Pay:" << totalPr << endl;
            cout << "               " << endl;
            return totalPr;
        }
};

// ============================================================================
// OOP PILLAR 3: INHERITANCE (Derived Subclass)
// Models "IS-A" relationship: Deluxe IS A Pizza. Reuses Base, Cheese, Topping logic.
// ============================================================================
class Deluxe : public Pizza {
    public:
        // OOP CONCEPT: CONSTRUCTOR INITIALIZER LIST
        // Passes initialization arguments upstream to the base class constructor.
        Deluxe(bool isVeg) : Pizza(isVeg) {
            Cheese();
            Topping();
        }

        // --------------------------------------------------------------------
        // OOP PILLAR 4 (C): RUNTIME POLYMORPHISM (Method Overriding)
        // Replaces base implementation to provide a Deluxe combo discount.
        // --------------------------------------------------------------------
        double getBill() override {
            cout << "[Deluxe Combo Applied: 50 Flat Discount]" << endl;
            this->total = max(0, this->total - 50);
            return Pizza::getBill(); // Calls base logic with adjusted total
        }
};

int main() {
    // ------------------------------------------------------------------------
    // OBJECTS & METHOD OVERLOADING EXECUTION
    // ------------------------------------------------------------------------
    Pizza p1(false);
    p1.Cheese();
    p1.Topping(1); // Calls overloaded Topping(int) -> Compile-time Polymorphism
    p1.getBill();

    Deluxe dp(true);
    
    // ------------------------------------------------------------------------
    // RUNTIME POLYMORPHISM (Dynamic Dispatch via Base Pointer)
    // Base-class pointer pointing to derived-class object invokes Deluxe::getBill()
    // ------------------------------------------------------------------------
    Pizza* ptr = &dp;
    ptr->getBill(); // Executes Deluxe's overridden getBill() via vtable lookup

    return 0;
}