// 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                                            

#ifndef __join_point_loc_list_h__
#define __join_point_loc_list_h__

#include <map>
#include <list>
using namespace std;

#include "Puma/CClassInfo.h"
#include "Puma/CFunctionInfo.h"
#include "Puma/CTypeInfo.h"
#include "JoinPointLoc.h"
using namespace Puma;

// This is just a simple container to manage the storage of join point
// location objects, which are used for scopes and world in the pointcut
// context

class JoinPointLocList {
  enum { METHODS = 0, CALLS, CONS, DESTS, CLASSES, ASPECTS, FUNCS, NO };
  typedef list<JoinPointLoc*> JPLL;
  JPLL _elements[NO];
  typedef map<CObjectInfo*, JoinPointLoc*> Map;
  typedef Map::value_type MapPair;
  Map _map;
    
public:

  // Result type for select ()
  typedef JPLL Selection;
  
  // destructor: delete all stored join point locations
  ~JoinPointLocList () {
    for (int l = 0; l < NO; l++) {
      for (JPLL::iterator iter = _elements[l].begin ();
           iter != _elements[l].end (); ++iter) {
        delete *iter;
      }
    }
  }

  // select and return all join points of a given type (any of them)
  void select (JoinPointLoc::join_point_type jpt, Selection &result) {
    for (int l = 0; l < NO; l++) {
      JPLL::iterator iter = _elements[l].begin ();
      if (iter != _elements[l].end () && ((*iter)->type () & jpt) != 0) {
        while (iter != _elements[l].end ()) {
          result.push_back (*iter);
          ++iter;
        }
      }
    }
  }
  
  // functions to store join point locations
  void new_method (CFunctionInfo *fi) {
    _elements[METHODS].push_back (new JPL_Method (fi));
  }
  
  void new_method_call (CFunctionInfo *called, CT_CallExpr *ce,
			CObjectInfo *caller, int local_id, bool memb_init = false) {
    _elements[CALLS].push_back (new JPL_MethodCall (called, ce, caller,
      local_id, memb_init));
  }
  
  void new_field_reference (CAttributeInfo *a, CTree *f, int local_id) {
//    _field_references.push_back (new JPL_FieldReference (a, f, local_id));
  }
  
  void new_field_assignment (CAttributeInfo *a, CT_CallExpr *as,
			     CTree *f, int local_id) {
//    _field_assignments.push_back (new JPL_FieldAssignment (a, as, f, local_id));
  }
  
  void new_construction (CFunctionInfo *fi) {
    _elements[CONS].push_back (new JPL_Construction (fi));
  }
  void new_destruction (CFunctionInfo *fi) {
    _elements[DESTS].push_back (new JPL_Destruction (fi));
  }
  void new_class (CClassInfo *c) {
    JoinPointLoc *new_elem = new JPL_Class (c);
    _elements[CLASSES].push_back (new_elem);
    _map.insert (MapPair (c, new_elem));
  }
  void new_aspect (ACAspectInfo *a) {
    JPL_Aspect *new_elem = new JPL_Aspect (a);
    _elements[ASPECTS].push_back (new_elem);
    _map.insert (MapPair (new_elem->class_info (), new_elem));
  }
  void new_function (CFunctionInfo *f) {
    JoinPointLoc *new_elem = new JPL_Function (f);
    _elements[FUNCS].push_back (new_elem);
    _map.insert (MapPair (f, new_elem));
  }
  JoinPointLoc *lookup (CObjectInfo *obj) {
    Map::iterator entry = _map.find (obj);
    return (entry == _map.end ()) ? 0 : (*entry).second;
  }
};

#endif // __join_point_loc_list_h__
