//  Test program for COW objects

#include <stdio.h>
#include "cow.h"

class Foo_COW : Obj_COW {
    friend class Foo;
public:
    //  Construtors & destructors
    Foo_COW(int l, int m, int n) { a = l; b = m; c = n; }
    //  Functions
    Obj_COW *dup(void)
      { return((Obj_COW *)new Foo_COW(a, b, c)); }
private:
    //  Data
    int a, b, c;
};

class Foo : Obj_Virt {
public:
    //  Construtors & destructors
    Foo(int i = 1, int j = 2, int k = 3)
      { set_ptr(new Foo_COW(i, j, k)); }
    Foo(const Foo& f2) : Obj_Virt((Obj_Virt &)f2) { }
    //  Functions
    Foo&    operator = (Foo& f2)
              { set_ptr(f2.get_ptr()); return(*this); }
    int     get_a(void) { return(actual()->a); }
    int     get_b(void) { return(actual()->b); }
    int     get_c(void) { return(actual()->c); }
    void    print(char *msg);
    void    reset(int i = 1, int j = 2, int k = 3);
private:
    //  Functions
    Foo_COW *actual(void)
      { return((Foo_COW *)get_ptr()); }
};

//  Foo::print - print current values
void Foo::print(char *msg)
{
    printf("%-12s: this = %p, ", msg, this);
    Obj_Virt::print();
    printf("    a, b, c = %d %d %d\n", actual()->a,
      actual()->b, actual()->c);
}

//  Foo::reset - reset values in real object
void Foo::reset(int i, int j, int k)
{
    split();
    actual()->a = i;
    actual()->b = j;
    actual()->c = k;
}

main()
{
    Foo *pa1 = new Foo;
    Foo *pa2 = new Foo(*pa1);
    Foo *pa3 = new Foo(4, 5, 6);

    pa1->print("a1");
    pa2->print("a2 (= a1?)");
    pa3->print("a3");

    *pa3 = *pa2;
    pa3->print("a3 (= a2?)");
    pa2->print("a2 (same?)");

    pa3->reset(7, 8, 9);
    pa3->print("a3 reset");
    pa2->print("a2 (same?)");

    delete pa1;
    delete pa2;
    delete pa3;
}
