/*
    Value vesus behaviour

    Vehicle::identify() was a virtual function in the original version
    of the program, and following that style group() is virtual in the
    revised version. Is a virtual function is the right way to capture 
    the difference between the characteristic strings "car" and "truck"?
    The difference between the derived classes is one of value and not
    behaviour. Objects ofthe derived classes do not behave differently
    nor use different algorithms. A difference in value can be recorded 
    more naturally in a data member than in a virtual function. A data
    member in Vehicle would be sufficient:

 */

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

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

private:
    char   *plate;
    char   *group;
};

/*
    The data member can receive its value from an additional argument
    to each Vehicle constructor, supplied by the corresponding derived
    constructor. The base and the derived classes interact only during 
    initialization, further reducing coupling. 
 */

Vehicle::~Vehicle()
{ 
    delete [] plate; 
}

class Car : public Vehicle
{
public:
    // Car() : Vehicle("car") { }
    Car(char *p = 0) : Vehicle("car", p) { };
};

class Truck : public Vehicle
{
public:
    // Truck() : Vehicle("truck") { }
    Truck(char *p = 0) : Vehicle("truck", p) { };
};


/*
    We can further reduce the code by using default argument in
    the constructors of the derived classes and so eliminating 
    the second cosntructors both in derived and the base classes.

    In the same time we must mentioned that when we eliminated a 
    virtual function we increased the size of the object. So the
    data versus function tradeoff has a size versus runtime 
    parallel. Here we should recognize, that eliminating the 
    virtual function also eliminated the v_ptr, se reduced size.
 */

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

 */