// This file is part of the AspectC++ compiler 'ac++'.
// Copyright (C) 1999-2003  The 'ac++' developers (see aspectc.org)
//                                                                
// This program is free software;  you can redistribute it and/or 
// modify it under the terms of the GNU General Public License as 
// published by the Free Software Foundation; either version 2 of 
// the License, or (at your option) any later version.            
//                                                                
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of 
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the  
// GNU General Public License for more details.                   
//                                                                
// You should have received a copy of the GNU General Public      
// License along with this program; if not, write to the Free     
// Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, 
// MA  02111-1307  USA                                            

#include "JPAdvice.h"
#include "AdviceInfo.h"

#include "AspectInfo.h"

//& this planning is not perfect. We should think about it!

void JPAdvice::do_before (AdviceInfo *ai, const Condition &cond) { 
  if (_around) {
    next_level ();
    _next->do_before (ai, cond);
    _depth = _next->depth () + 1;
   }
  else
    _before.append (ai);
}

void JPAdvice::do_after (AdviceInfo *ai, const Condition &cond) {
  if (_around) {
    next_level ();
    _next->do_after (ai, cond);
    _depth = _next->depth () + 1;
  }
  else
    _after.prepend (ai);
}

void JPAdvice::do_around (AdviceInfo *ai, const Condition &cond) {
  if (_around) {
    next_level ();
    _next->do_around (ai, cond);
    _depth = _next->depth () + 1;
  }
  else {
    _around = ai;
    _conditional_around = cond;
  }
}

void JPAdvice::next_level () {
  if (!_next) {
    _next = new JPAdvice;
    _next->_parent = this;
  }
}

ostream &operator << (ostream &out, JPAdvice &jpa)
 {
   out << "before (" <<jpa.depth() << ") :" << endl;
   for (int a = 0; a < jpa._before.length (); a++)
     out << "[" << jpa._before[a]->Scope ()->Name () << "::" 
	 << (jpa._before[a]->name () + 1) << "]" << endl;
   if (jpa.around()) {
      out << "around (" << jpa.depth() << ") : [" 
	  << jpa.around ()->Scope ()->Name () << "::"
	  << (jpa.around()->name() + 1) << "]" << endl;
   }
   if (jpa._next) {
     out << *jpa._next;
   }
   out << "after (" << jpa.depth() << ") :" << endl;
   for (int a = 0; a < jpa._after.length (); a++)
     out << "[" << jpa._after[a]->Scope ()->Name () << "::" 
	 << (jpa._after[a]->name () + 1) << "]" << endl;
   return out;
 }

void JPAdvice::addTJPFlags(AdviceInfo &advice) {
  _tjp.merge (advice.code ().this_join_point ());

  if (advice.aspect()) {
    _tjp.merge (advice.aspect()->aspectof_this_join_point());
  }
  
  ThisJoinPoint context_vars;
  context_vars.setup (advice.code ().binding ());
  _tjp.merge (context_vars);
}

void JPAdvice::mergeTJPFlags() {
  _tjp.clear ();
  if (_next) {
    _next->mergeTJPFlags ();
    _tjp.merge (_next->tjp ());
  }
  for (int a = 0; a < _before.length(); a++) addTJPFlags(*_before[a]); 
  if (_around)  {
    addTJPFlags(*_around);
    if (_conditional_around) {
      _tjp.conditional ();
    }
  }
  for (int a = 0; a < _after.length(); a++) addTJPFlags(*_after[a]); 
}

void JPAdvice::gen_binding_templates (ostream &out, const char *jpname,
                                      const BackEndProblems &bep) {
  // later the individual bindings have to be passed from here, too.
  for (int a = 0; a < _before.length (); a++)
    _before[a]->gen_binding_template (out, jpname, bep);
  if (around())
    around ()->gen_binding_template (out, jpname, bep);
  if (_next)
    _next->gen_binding_templates (out, jpname, bep);
  for (int a = 0; a < _after.length (); a++)
    _after[a]->gen_binding_template (out, jpname, bep);
}
