/*
        The inheritance hierarcy in this program is sound. Both Car and Truck
        are specialization of the base class Vehicle. Class Garage manages cars
        and truck uniformly with respect to the base class interface.

        The public inheritance establishes valid "is a kind of" relationships
        between the base class and the derived classes. Other part of the program
        can deal with Car and Truck objects knowing only that they are at least
        Vehicle objects and they react to the interface established by the public
        members of Vehicle.

        Although the inheritance is valid, the detailed distribution of code
        between the base and derived classes can be improved. To make a better
        version from the example, try to answer the following questions:
          - What is common among classes of an inheritance hierarcy
          - What are the differences between the derived classes

        The common properties of all vehicles are a license plate number and    
        the ability to identify themselves. These properties are captured in
        the plate base class data member, and virtual member fuction identify().

        Vhat is the difference between a Car and a Truck? The only difference
        is the string "car" or "truck" printed by identify(). In other words,
        truck and car differ only in value not in their behaviour.

        The similarity between Car::identify() and Truck::identify() is telling.
        In the following, we migrate common behaviour - represented by the
        identify() function - to the base class.

 */

#include <stdio.h>
#include <string.h>

class Vehicle
{
public:
    Vehicle() { plate = 0; }
    Vehicle(char *p)
    {
        plate = new char[strlen(p)+1];
        strcpy(plate, p);
    }
    virtual ~Vehicle() { delete [] plate; }
    void identify()     
        { 
                char *p = plate ? plate : "none";
                printf( "%s with plate %s\n", group(), p);
        }
protected:
        virtual char *group() = 0;

private:
    char   *plate;
};

/*
        The virtual behaviour identify() has been replaced by the virtual
        behaviour of group(). In fact, group() itselfmay be replaced with 
        a data member. Plate member has been moved from the protected area
        to private.

        Car and Vehicle has been also modified accordingly to the changes 
        at Vehicle.

 */

class Car : public Vehicle
{
public:
    Car() : Vehicle() { }
    Car(char *p) : Vehicle(p) { };

private:
        char *group()  { return "car"; }
};


class Truck : public Vehicle
{
public:
    Truck() : Vehicle() { }
    Truck(char *p) : Vehicle(p) { };

private:
        char *group()  { return "truck"; }
};

class Garage
{
public:
    Garage(int max);
   ~Garage();

    int       accept(Vehicle*);
    Vehicle  *release(int bay);
    void      listVehicles();
private:
    int       maxVehicles;
    Vehicle **parked;
};

Garage::Garage(int max)
{
    maxVehicles = max;
    parked = new Vehicle*[maxVehicles];
    for( int bay = 0; bay < maxVehicles; ++bay ) 
    {
        parked[bay] = 0;
    }
}

Garage::~Garage()
{
    delete [] parked;
}

int Garage::accept(Vehicle *veh)
{
    for( int bay = 0; bay < maxVehicles; ++bay )
        if( !parked[bay] )
        {
        parked[bay] = veh;
            return( bay );
        }
    return( -1 );       // No free bay
}

Vehicle *Garage::release(int bay)
{
    if( bay < 0 || bay > maxVehicles )
        return 0;
    Vehicle *veh = parked[bay];
    parked[bay] = 0;
    return( veh );
}

void    Garage::listVehicles()
{
    for( int bay = 0; bay < maxVehicles; ++bay )
        if( parked[bay] )
        {
        printf("Vehicle in bay %d is: ", bay);
            parked[bay]->identify();
        }
}

Car c1("AAA100");
Car c2("BBB200");
Car c3("CCC300");

Truck t1("TTT999");
Truck t2("SSS888");
Truck t3("UUU777");


int main( )
{
    Garage Park(14);

    Park.accept(&c1);
    int t2bay = Park.accept(&t2);
    Park.accept(&c3);
    Park.accept(&t2);

    Park.release(t2bay);

    Park.listVehicles();

    return 0;
}

/*
 
   The output of the program is the following:

Vehicle in bay 0 is: car with plate AAA100
Vehicle in bay 2 is: car with plate CCC300
Vehicle in bay 3 is: truck with plate SSS888

 */