// Purpose.  Decorator design pattern demo.
// 
// Discussion.  Decorators allow an object's behavior to be incrementally
// extended by "wrapping" the core object in successive layers of optional
// functionality.  It has been said that the Strategy pattern lets you
// change the guts of an object, while the Decorator pattern lets you
// change its skin.  The client commits only to the abstract base class's
// interface, and composes (at run-time) the desired "composite" object.
// When a method is called for, the request is first forwarded to the core
// object, followed by successive invocations (from the inside out) of
// each specified Decorator layer.

#include <iostream.h>

class VisualComponent {
public:
    virtual void draw() = 0;
};


class Decorator : public VisualComponent {
public:
    Decorator( VisualComponent* comp ) { _component = comp; }
    virtual void draw()                { _component->draw(); }
private:
    VisualComponent* _component;
};

class BorderDecorator : public Decorator {
public:
    BorderDecorator( VisualComponent* comp, int width ) :
		Decorator(comp), _width(width) { }
    virtual void draw() {
		Decorator::draw();
		drawBorder(); }
private:
    void drawBorder() { cout << "   border width = " << _width << endl; }
    int _width;
};

class HScrollDecorator : public Decorator {
public:
    HScrollDecorator( VisualComponent* comp ) : Decorator(comp) { }
    virtual void draw() {
		Decorator::draw();
		drawHScroll(); }
private:
    void drawHScroll() { cout << "   horizontal scroll bar" << endl; }
};

class VScrollDecorator : public Decorator {
public:
    VScrollDecorator( VisualComponent* comp ) : Decorator(comp) { }
    virtual void draw() {
		Decorator::draw();
		drawVScroll(); }
private:
    void drawVScroll() { cout << "   vertical scroll bar" << endl; }
};


class TextView : public VisualComponent {
public:
    TextView( int w, int h ) { _width = w; _height = h; }
    virtual void draw() {
		cout << "TextView: " << _width << ", " << _height << endl; }
private:
    int  _width, _height;
};


main ()
{
	VisualComponent*  widgets[2];
	widgets[0] =
		new BorderDecorator(
			new BorderDecorator(
				new VScrollDecorator(
					new TextView(300, 240)), 3), 5);
	widgets[1] =
		new VScrollDecorator(
			new HScrollDecorator(
				new TextView(200, 150)));

	for (int i=0; i < 2; i++)
		widgets[i]->draw();
}

// TextView: 300, 240
//    vertical scroll bar
//    border width = 3
//    border width = 5
// TextView: 200, 150
//    horizontal scroll bar
//    vertical scroll bar

