package org.mockejb.interceptor;

import java.lang.reflect.Method;

/**
 * Tests if the given class matches the class
 * provided to the constructor of ClassPointcut.
 * 
 * @author Alexander Ananiev
 */
public class ClassPointcut implements Pointcut {

    private Class clazz;
    private boolean matchSubclasses = false;
    
    
    /**
     * Creates a new instance of ClassPoincut
     * It will not match subclasses.
     * 
     * @param clazz class to match
     * 
     */
    public ClassPointcut( final Class clazz ){
        this.clazz = clazz;
    }

    /**
     * Creates a new instance of ClassPoincut
     * @param clazz class to match
     * @param matchSubclasses if true, the pointcut will also match all subclasses/
     * subinterfaces of the provided class. 
     */
    public ClassPointcut( final Class clazz, final boolean matchSubclasses ){
        this.clazz = clazz;
        this.matchSubclasses = matchSubclasses;
    }
    
    
    /**
     * Tests if the class of the provided method is the same with the 
     * the class provided to the constructor of this pointcut.
     * Note that it uses class equality, not instanceof. 
     * 
     * @return true if the provided method should be intercepted
     */
    public boolean matchesJointpoint( Method method ) {

        boolean matches = false;
        if ( matchSubclasses ) {
            matches = clazz.isAssignableFrom( method.getDeclaringClass() );    
        }
        else {
            matches = method.getDeclaringClass().equals( clazz );
        }
    
        return matches;
    
    }
    
    /**
     * Returns true if the given object is of type ClassPointcut and 
     * it handles the same class and handlesSubclasses flag is set to the 
     * same value 
     */
    public boolean equals( Object obj ){
        if ( ! (obj instanceof ClassPointcut) )
            return false;
        
        ClassPointcut classPointcut = (ClassPointcut ) obj;
        
        return ( clazz.equals( classPointcut.clazz ) && 
            matchSubclasses == classPointcut.matchSubclasses );
    }

    public int hashCode() {
        // as per "Effective Java Programming"
        int result = 17;
        result = 37*result+clazz.hashCode();
        result = 37*result+(matchSubclasses ? 0 : 1);
        return result; 
    }    
    
}