#include <iostream>
#include <iomanip>
#include "JPTL.h"


template<typename MemberInfo, typename CONTEXT>
struct MemberLookup {
  // helper template for checking if two types are the same
  template<typename T, typename U>
  struct TypeCompare {
    enum { IS_SAME = 0 };
  };
  template<typename T>
  struct TypeCompare<T,T> {
    enum { IS_SAME = 1 };
  };
  // the actual EXEC struct for use with JPTL::MemberIterator<...>
  struct EXEC {
    typedef typename CONTEXT::EntityInfo EntityInfo; // pass through
    enum { FOUND = (TypeCompare<EntityInfo, MemberInfo>::IS_SAME == 1) ? 1 : CONTEXT::FOUND,
           INDEX = (FOUND == 1) ? CONTEXT::INDEX : CONTEXT::INDEX + 1 }; // stop counting if found
  };
};
template<typename T>
struct MemberLookupInit {
  // initial EXEC
  typedef T EntityInfo;
  enum { FOUND = 0, INDEX = 0 };
};

template<typename TypeInfo, typename CONTEXT>
struct EntityInfoLookup {
  // helper template for conditional type selection
  template<typename T, typename U, unsigned int USE_FIRST>
  struct TypeSelect {
    typedef T Type;
  };
  template<typename T, typename U>
  struct TypeSelect<T, U, 0> {
    typedef U Type;
  };
  // the actual EXEC struct for use with JPTL::BaseIterator<...>
  struct EXEC {
    typedef typename CONTEXT::EntityInfo EntityInfo; // pass through
    typedef JPTL::MemberIterator<TypeInfo, MemberLookup, MemberLookupInit<EntityInfo> > MIT;
    enum { FOUND = MIT::EXEC::FOUND ? 1 : 0 }; // do we have a positive lookup for this base class?

    typedef typename TypeSelect<typename TypeInfo::That, typename CONTEXT::TargetClass, FOUND>::Type TargetClass;
    enum { INDEX = (FOUND == 1) ? static_cast<unsigned int>(MIT::EXEC::INDEX) : static_cast<unsigned int>(CONTEXT::INDEX) };
  };
};
template<typename T>
struct EntityInfoLookupInit {
  // initial EXEC
  typedef T EntityInfo;
  typedef void TargetClass;
  enum { INDEX = 0 };
};


// ---- some pretty printing stuff ---
template<typename T, unsigned int INDEX, int AVAIL=AC::TypeInfo<T>::AVAILABLE>
struct Printer {
  static const char* signature() { return AC::TypeInfo<T>::signature(); }
  static const char* name() { return AC::TypeInfo<T>::template Member<INDEX>::name(); }
};
template<typename T, unsigned int INDEX>
struct Printer<T, INDEX, 0> {
  static const char* signature() { return "<unknown>"; }
  static const char* name() { return "<unknown>"; }
};

// ---- the test code ---
class A {
public:
  int x;
  int y;
  char z;
  int foo[42];
  static short global;
};

short A::global = 0;

class B : public A {};

class C : public A { public: int c; };

class D : public B, public C {};

static int stat = 0;
int var = 1;

int main() {
    std::cout << std::setw(30) << "JoinPoint::signature()" << "\t\tJoinPoint::EntityInfo::name()" << std::endl
              << std::setw(30) << "======================" << "\t\t=============================" << std::endl;
  C c;
  c.y = 42;
  c.foo[0] = 3;
  c.foo[4] = c.A::z++;
  A::global++;
  c.global--;
  A::global = 5;
  c.c = 5;

  var = ++stat;

  int *p = &c.y;
  *p = 0;
  return 0;
};

aspect EntityInfoPrinter {
  advice get("% ...::%") || set("% ...::%") : before() {
    typedef typename JPTL::BaseIterator<AC::TypeInfo<JoinPoint::Target>, EntityInfoLookup, EntityInfoLookupInit<typename JoinPoint::EntityInfo> >::EXEC Lookup;

    std::cout << std::setw(30) << JoinPoint::signature() << "\t\t"
              << Printer<typename Lookup::TargetClass, Lookup::INDEX>::signature() << "::"
              << Printer<typename Lookup::TargetClass, Lookup::INDEX>::name() << std::endl;
  }
};

