#include <stdio.h>

int f1 (int a) { return a + 1; }
int f2 (int a, int) { return a + 2; }
int f3 (int a, int, int) { return a + 2; }
void var_arg_fct (const char *fmt, ...) { }

class C {
  int _val;
public:
  C () : _val (4711) {}
  operator int () { return _val; }
  int val () const { return _val; }
  C &operator = (const C &obj) {
    return *this;
  }
  C dup () { 
    C duplicate;
    duplicate = *this;
    return duplicate;
  }
  C operator ! () { return *this; }
  int operator + (int) { return 0; }
  void cnst () const { printf ("the const function\n"); }
  void cnst () { printf ("the non-const version\n"); };
  static void stat (int = 0) { printf ("in a static member\n"); }
};

bool operator + (C, C) { return false; }
int operator ~ (C) { return 0; }

class B1 {
public:
  void f (int) {}
  virtual void g () { printf ("in the base function - OK\n"); }
};

class B2 : public B1 {
public:
  void f () { B1::f (0); }
  void g () { printf ("in the derived function - ERROR\n"); }
};

struct ABase {
  C c1;
  mutable C c2;
};

class A : public ABase {
public:
  void f () const { c1.cnst (); c2.cnst (); }
  void g () { c1.cnst (); c2.cnst (); }
};

class OpTester {
public:
  void run () {
    C c1, c2;
    c1 + c2;
    ~c1;
  }
};

int main () {
  printf ("CallAdvice:\n");
  printf ("=============================================================\n");
  printf ("here we check the code generation for all kinds of functions\n");
  C inst;
  C inst2 (inst.dup ());
  printf ("result is %d\n", f1 (f2 (3, 4)) + inst.dup ().dup ().val ());
  f3 (f1 (f2 (5, 6)), f2 (7, 8), 1);
  !!!!inst;
  inst + 0;
  inst + f1 (2);
  inst + inst;
  ~inst;
  inst.cnst ();
  const C cc;
  cc.cnst ();
  printf ("-------------------------------------------------------------\n");
  printf ("static member called:\n");
  C::stat ();
  printf ("-------------------------------------------------------------\n");
  printf ("static member called with object:\n");
  inst.stat (3);
  printf ("-------------------------------------------------------------\n");
  printf ("function with variable argument list:\n");
  var_arg_fct ("bla %s %d %d", "a string", 4711, true);
  var_arg_fct ("bla %f", 3.14);
  printf ("-------------------------------------------------------------\n");
  printf ("calls with fully qualified name:\n");
  B2 b2;
  b2.f ();
  b2.B1::g ();
  printf ("-------------------------------------------------------------\n");
  printf ("calls in const member function:\n");
  A a;
  a.f ();
  a.g ();
  printf ("-------------------------------------------------------------\n");
  printf ("operator calls from within non-static methods:\n");
  OpTester ot;
  ot.run ();
  printf ("-------------------------------------------------------------\n");
  printf ("calls to conversion functions:\n");
  C c;
  int i;
  i = c;
  // i = (int)c; <-- this should also be affected by advice
  printf ("=============================================================\n");
  return 0;
}

aspect CallTracer {
  advice call ("% ...::%(...)") && !call ("% printf(...)") : around () {
    printf ("before %s", tjp->signature ());
    tjp->proceed ();
  }
};

aspect CallTracer2 {
  advice call ("% ...::%(...)") && !call ("% printf(...)") : before () {
    printf ("\n");
  }
};
