package org.mockejb.interceptor;

import java.lang.reflect.Method;

/**
 * Provides a way to create conditional expressions from pointcuts.
 * 
 * @author Alexander Ananiev
 */
public class PointcutPair implements Pointcut {

    private Pointcut pointcut1;
    private Pointcut pointcut2;
    private boolean isOr = false;
    

    /**
     * Creates a new instance of PointcutPair.
     * AND condition will be used by "matchesJointpoint".   
     * 
     * @param pointcut1 first pointcut
     * @param pointcut2 second pointcut 
     * 
     */
    public static PointcutPair and( Pointcut pointcut1, Pointcut pointcut2 ){
        return new PointcutPair( pointcut1 ,pointcut2 );
    }

    /**
     * Creates a new instance of PointcutPair.
     * OR condition will be used by "matchesJointpoint".   
     * 
     * @param pointcut1 first pointcut
     * @param pointcut2 second pointcut 
     * 
     */
    public static PointcutPair or( Pointcut pointcut1, Pointcut pointcut2 ){
        return new PointcutPair( pointcut1 ,pointcut2, true );
    }
    
    
    /**
     * Creates a new instance of PointcutPair
     * @param pointcut1 first pointcut
     * @param pointcut2 second pointcut 
     * 
     */
    PointcutPair( final Pointcut pointcut1, final Pointcut pointcut2 ){
        this.pointcut1 =pointcut1;
        this.pointcut2 =pointcut2;
    }
    /**
     * Creates a new instance of PointcutPair
     * @param pointcut1 first pointcut
     * @param pointcut2 second pointcut 
     * @param isOr if true, use OR instead of AND
     */
    PointcutPair( final Pointcut pointcut1, final Pointcut pointcut2, boolean isOr ){
        this.pointcut1 =pointcut1;
        this.pointcut2 =pointcut2;
        this.isOr=isOr;
    }
    
    /**
     * Tests if both poincuts match 
     * 
     * @return true if the provided method should be intercepted
     */
    public boolean matchesJointpoint( Method method ) {
        if ( ! isOr )
            return pointcut1.matchesJointpoint( method ) && 
                pointcut2.matchesJointpoint( method );
        else
            return pointcut1.matchesJointpoint( method ) || 
                pointcut2.matchesJointpoint( method );
        
    }
    
    /**
     * Returns true if the given object is of the same type and 
     * it has the same pattern.
     */
    public boolean equals( Object obj ){
        if ( ! (obj instanceof PointcutPair) )
            return false;
        
        PointcutPair pointcutPair = (PointcutPair ) obj;
        
        return ( pointcut1.equals( pointcutPair.pointcut1 ) &&
                pointcut2.equals( pointcutPair.pointcut2 ) &&
                isOr== pointcutPair.isOr );
                
    }

    public int hashCode() { 
        int result = 17;
        result = 37*result+pointcut1.hashCode();
        result = 37*result+pointcut2.hashCode();
        result = 37*result+(isOr ? 0 : 1);

        return  result; 
    }    
    
    
}