#ifndef __SimpleAdviceContainer_h_
#define __SimpleAdviceContainer_h_

#include <cstdio>
#include "JoinPointInfo.h"
#include "DynamicJoinPoint.h"

// we support only one Advice per Joinpoint,
// so we don't need a 'next' pointer or something
struct SimpleAdviceContainerAroundJoinPoint : public DynamicJoinPoint {
  /**
   * the action object holds some information which are specific
   * to the JoinPoint like the _fptr, but also some information, which is specific
   * to the call (like args). Think of recursive calling. Therefore may not be static
   */
  AC::Action &_action;	
  AC::Action& action() { return _action; }

  //! calls base c'tor and saves action object
  SimpleAdviceContainerAroundJoinPoint(AC::Action &action) 
    : DynamicJoinPoint(), _action(action) {}
	

  // assumes we only have one advice per JP
  void proceed() {
    _action.trigger();
  };
};

/* sime base class for shared functions, which should not be duplicated
 * on every Joinpoint/template instance
 */

struct SimpleAdviceContainerBase {
  static bool triggerAdvice(JoinPointInfo *jpinfo);
  static bool triggerAdvice(JoinPointInfo *jpinfo, void *djp);
  static bool registerAdvice(JoinPointInfo &jpinfo, void *ptr);
  static bool unregisterAdvice(JoinPointInfo &jpinfo, void *ptr);
};

//*! can register only one advice
template<int JPID, int REPOID>
struct SimpleAdviceContainer : public SimpleAdviceContainerBase {

  //! THE authoritative jpinfo for this joinpoint
  static JoinPointInfo jpinfo;
  
  typedef DynamicJoinPoint DJP;
  typedef SimpleAdviceContainerAroundJoinPoint ADJP;

  static DJP make_djp() {
    return DJP();
  }

  static ADJP make_adjp(AC::Action& action) {
    return ADJP(action);
  }
  
  static bool registerBeforeAdvice(void *ptr, bool hasContext) {
    return registerAdvice(jpinfo, ptr);
  }
  
  static bool registerAfterAdvice(void *ptr, bool hasContext) {
    return registerAdvice(jpinfo, ptr);
  }
  
  static bool registerAroundAdvice(void *ptr) { 
    return registerAdvice(jpinfo, ptr);
  }
	
			
  static bool unregisterBeforeAdvice(void *ptr) {
    return registerAdvice(jpinfo, ptr);
  }

  static bool unregisterAfterAdvice(void *ptr) {
    return unregisterAdvice(jpinfo, ptr);
  }
  
  static bool unregisterAroundAdvice(void *ptr) {
    return unregisterAdvice(jpinfo, ptr);
  }


  // very simple methods because we only have one possible advice
  static bool runBeforeAdvice() { 
    // printf("Checking for Joinpoint Id %d\n", JPID);
    // fprintf(stderr, "checking for advice at jpinfo(%x)\n", &jpinfo);
    return jpinfo.trigger();
  }

  static bool runAfterAdvice() { 
    return jpinfo.trigger();
  }

  // not much point: around without context
  // static bool runAroundAdvice() { return triggerAdvice(jpinfo); }


  // we assert the caller knows that he has registered with JPInfos
  // with Contextinforamtion at this point

  static bool runBeforeAdvice(void *djp) { 
    // fprintf(stderr, "checking for advice at jpinfo(%x)\n", &jpinfo);
    return jpinfo.trigger(djp);
  }

  static bool runAfterAdvice(void *djp) {
    return jpinfo.trigger(djp);
  }

  static bool runAroundAdvice(void *djp) { 
    // fprintf(stderr, "%s: checking for advice at jpinfo(%x)\n", __PRETTY_FUNCTION__, &jpinfo);
    return jpinfo.trigger(djp); 
  }
};

template<int JPID, int REPOID>
JoinPointInfo SimpleAdviceContainer<JPID, REPOID>::jpinfo = { (void *) 0 };

#endif

// Local Variables: 
// mode:c++
// End:
