package org.mockejb.interceptor;

import java.lang.reflect.Method;
import java.util.*;

/**
 * Provides the implementation of the AspectSystem by adding aspects to the 
 * list and providing access to this list.
 * Note that all "add" method first check if the same aspect
 * is already in the list. If it is, the aspect is removed from the list and then added again. 
 * This is to prevent having the same aspect in the list multiple times. 
 * Aspect's "equals" method is used to compare aspects/interceptors, so it is 
 * the aspect providers must have this method implemented. 
 *   
 * @author Alexander Ananiev
 */
public class AspectSystemImpl implements AspectSystem {
    
    
    /**
     * Note the synchronization
     */
    private List aspectList = Collections.synchronizedList(new LinkedList());
    
    
    /**
     * 
     * @see org.mockejb.interceptor.AspectSystem#add(org.mockejb.interceptor.Aspect)
     */
    public void add(Aspect aspect) {
        
        removeIfExists( aspect );
        
        aspectList.add( aspect );
    
    }

    /** 
     * 
     * @see org.mockejb.interceptor.AspectSystem#addFirst(org.mockejb.interceptor.Aspect)
     */
    public void addFirst(Aspect aspect) {
        
        removeIfExists( aspect );
        
        aspectList.add( 0, aspect );
    
    }

        
    /**
     * @see org.mockejb.interceptor.AspectSystem#add(org.mockejb.interceptor.Pointcut, org.mockejb.interceptor.Interceptor)
     */
    public void add(Pointcut pointcut, Interceptor interceptor) {
        
        Aspect aspect = new InterceptorContainerAspect( pointcut, interceptor );
        
        removeIfExists( aspect );
        
        aspectList.add( aspect );
    
    }

        
    /**
     * @see org.mockejb.interceptor.AspectSystem#addFirst(org.mockejb.interceptor.Pointcut, org.mockejb.interceptor.Interceptor)
     */
    public void addFirst(Pointcut pointcut, Interceptor interceptor) {
        
        Aspect aspect = new InterceptorContainerAspect( pointcut, interceptor );
        
        removeIfExists( aspect );
        
        aspectList.add( 0, aspect );
    
    }
    
    protected void removeIfExists( Aspect aspect ){
        
        aspectList.remove( aspect );
    }
    
    
    /**
     * @see org.mockejb.interceptor.AspectSystem#getAspectList()
     */
    public List getAspectList() {
            
        return aspectList;
    }
    
    /**
     * Clears the list of aspects for this AspectSystem 
     *
     */
    public void clear(){

        aspectList.clear();
        
    }

    /**
     * @see org.mockejb.interceptor.AspectSystem#findInterceptors(java.lang.reflect.Method, java.lang.reflect.Method)
     */
    public List findInterceptors( Method proxyMethod, Method targetMethod ) {
        
        //System.out.println("Intercepted method: "+interceptedMethod+" Target method: "+targetMethod);
        
        List resultList = new ArrayList();
        for( Iterator i=aspectList.iterator(); i.hasNext();){
            Aspect aspect = (Aspect) i.next();
            
            if ( proxyMethod != null && aspect.getPointcut().matchesJointpoint( proxyMethod ) || 
                    targetMethod!=null && aspect.getPointcut().matchesJointpoint( targetMethod ) ) {
                
                resultList.add( aspect );
            }
        }
        
        return resultList;
        
    }

}