// main.cpp  - Frog Pond Listing 3
#include <frog.h>

main()
    {
    PMF_VV pf = &Creature::move;  // bound to a virtual
    Pond walden;
    Creature *p1;
    Creature *p2;

    p1 = Creature::newCreature(Tadpole("Wiggly") );
    walden.insert(p1);
    p2 = Creature::newCreature(Bullfrog("Croaker") );
    walden.insert(p2);

    cout << "First time -------------------\n";
    walden.activate( pf );  // Tell all creatures to move
    cout << "second time ------------------\n";
    walden.activate( pf );  // Tell all creatures to move
    cout << "third time -------------------\n";
    walden.activate( pf );  // Tell all creatures to move

    return 0;
    }

First time -------------------
WigglyAge 1 Swimming jerkily
Croaker - I'm jumping
second time ------------------
Wiggly Age 2 Swimming jerkily still, but changing into Bullfrog
Croaker - I'm jumping
third time -------------------
Wiggly - I'm jumping
Croaker - I'm jumping
//  Frog.h
#ifndef FROG_H
#define FROG_H
#include <iostream.h>
#include <rw/gslist.h>

class Creature
    {
public:
    Creature(Creature *ptr);
    Creature(const Creature &c) : object(c.object) {}
    virtual void move();
    virtual Creature *clone() const;
    static Creature *newCreature(const Creature&);
    virtual const char *getname() const
        {return object->getname(); }
    virtual ~Creature();
//    void change(Creature *c);
protected:
    Creature() { object = 0; }  // invoked by derived
    Creature *object;
    static Creature *altered;
    };

declare(GSlist,Creature)

class Frog : public Creature
    {
protected:
    const char *name;
public:
    Frog(const char *p);
    Frog(const Frog &f);
    ~Frog(); 
    virtual void move() = 0;
    virtual const char *getname() const { return name; }
    Creature * clone() const;
    };

class Tadpole : public Frog
    {
    int age;
public:
    Tadpole(const char *name = "Noname Tadpole");
    void move();
    Tadpole(const Tadpole& t) : Frog(t), age(t.age) { }
         // invoke Frog copy ctor
    Creature * clone() const;
    };

class Bullfrog : public Frog
    {
public:
    Bullfrog(const char *name="Noname frog");
    Bullfrog(const Bullfrog &b) : Frog(b) {}
    void move() { cout << name << " - I'm jumping\n"; }
    Creature * clone() const { return new Bullfrog(*this); }

class Pond
    {
    GSlist(Creature) list;  // singly linked creature list
public:
    void activate( void (Creature::*pf) () );
    void insert(Creature*);
    };

typedef void (Creature::*PMF_VV)();  
#endif
// Frog.cpp
#include <stdlib.h>
#include <frog.h>
#include <string.h>

Creature *Creature::altered = 0;  // private static data
void Pond::insert(Creature *f)
    {
    list.insert(f);
    }

void Pond::activate( PMF_VV pmf_vv )
    {
    GSlistIterator(Creature) it(list);
    Creature *resident;
    while ( resident = (Creature *)it() )
	{
	(resident->*pmf_vv)();  
	}
    }

Creature *Creature::newCreature(const Creature& prototype)
    {
    Creature *C = new Creature(prototype.clone());
    // we must return an envelope, clone just makes a letter
    return C;
    }


Creature * Tadpole::clone() const
    {
    Tadpole *t = new Tadpole(*this); // Tadpole copy ctor
    return t;
    }

Creature::Creature(Creature *objptr)  
    {
    object = objptr;  
    }

Creature::~Creature() { }

Creature *Creature::clone() const
     {
     Creature *p = object->clone();
     Creature *envelope = new Creature(p);
     return envelope;
     }

void Creature::move()
    {
    object->move();
    if ( altered )
	{
	delete object;
	object = altered;
	altered = 0;
	}
    }

Creature * Frog::clone() const  // never get here
    {
    return 0;
    }

Frog::Frog(const char *n) : name(n) { }

Frog::Frog(const Frog &f) : Creature(f), name (f.getname())
    {
    }
    
Tadpole::Tadpole(const char *n) : Frog(n),age(0) 
    {
    }

Bullfrog::Bullfrog(const char *n) : Frog(n) 
    {
    }

void Tadpole::move() 
    {
    age++;
    if ( age < 2 )
	cout << name << "Age " << age << " Swimming jerkily\n";
    else
    	{
	cout << name << " Age " << age << 
         " Swimming jerkily still, but changing into Bullfrog\n";
	Creature *f=Creature::newCreature(Bullfrog(name));
	Creature::altered = f;
	}
    }

Frog::~Frog() { }

