package org.polyforms.repository.spring;

import java.lang.reflect.Method;
import java.lang.reflect.Modifier;

import org.polyforms.repository.aop.RepositoryInterceptor;
import org.polyforms.repository.spi.RepositoryMatcher;
import org.polyforms.util.AopUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.aop.support.DefaultPointcutAdvisor;
import org.springframework.aop.support.StaticMethodMatcherPointcut;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.ClassUtils;
import org.springframework.util.ReflectionUtils;

/**
 * {@link org.springframework.aop.Advisor} for methods which are in repository.
 * 
 * @author Kuisong Tong
 * @since 1.0
 */
@Component
public final class RepositoryAdvisor extends DefaultPointcutAdvisor {
    private static final Logger LOGGER = LoggerFactory.getLogger(RepositoryAdvisor.class);
    private static final long serialVersionUID = 618599462955606986L;

    /**
     * Create an instance with {@link RepositoryInterceptor}.
     */
    @Autowired
    public RepositoryAdvisor(final RepositoryInterceptor repositoryInterceptor,
            final RepositoryMatcher repositoryMatcher) {
        super(new RepositoryMatcherPointcut(repositoryMatcher), repositoryInterceptor);
    }

    private static final class RepositoryMatcherPointcut extends StaticMethodMatcherPointcut {
        private final RepositoryMatcher repositoryMatcher;

        protected RepositoryMatcherPointcut(final RepositoryMatcher repositoryMatcher) {
            super();
            this.repositoryMatcher = repositoryMatcher;
        }

        /**
         * {@inheritDoc}
         */
        public boolean matches(final Method method, final Class<?> targetClass) {
            final Class<?> clazz = deProxy(targetClass, method);
            final Method specificMethod = ClassUtils.getMostSpecificMethod(method, clazz);
            if (!Modifier.isAbstract(specificMethod.getModifiers())) {
                LOGGER.trace("Skip concret method {}.", specificMethod);
                return false;
            }

            final boolean matches = repositoryMatcher.matches(clazz);
            if (matches) {
                LOGGER.trace("Found repository {}.", clazz);
            }
            return matches;
        }

        private Class<?> deProxy(final Class<?> targetClass, final Method method) {
            for (final Class<?> clazz : AopUtils.deproxy(targetClass)) {
                if (ReflectionUtils.findMethod(clazz, method.getName(), method.getParameterTypes()) != null) {
                    return clazz;
                }
            }
            return targetClass;
        }
    }
}

@@ -601,57 +601,8 @@
 ils;
-%0Aimport org.springframework.util.ReflectionUtils;
 %0A%0A/*
@@ -1768,24 +1768,29 @@
             
+for (
 final Class%3C
@@ -1802,13 +1802,22 @@
 azz 
-= deP
+: AopUtils.dep
 roxy
@@ -1832,19 +1832,17 @@
 lass
-, method);%0A
+)) %7B%0A    
     
@@ -1944,32 +1944,15 @@
     
-if (!Modifier.isAbstract
+    if 
 (spe
@@ -1966,24 +1966,18 @@
 thod
-.getM
+ != meth
 od
-ifiers())
 ) %7B%0A
@@ -1996,99 +1996,133 @@
     
-LOGGER.trace(%22Skip concret method %7B%7D.%22, specificMethod);%0A                return false;%0A    
+    return doMatch(clazz, specificMethod);%0A                %7D%0A            %7D%0A%0A            return doMatch(targetClass, method);%0A
     
@@ -2136,25 +2136,23 @@
         
-    final
+private
  boolean
@@ -2156,137 +2156,210 @@
 ean 
-m
+doM
 atch
-es = repositoryMatcher.matches(clazz);%0A            if (matches) %7B%0A                LOGGER.trace(%22Found repository %7B%7D.%22, clazz
+(final Class%3C?%3E clazz, final Method specificMethod) %7B%0A            if (!Modifier.isAbstract(specificMethod.getModifiers())) %7B%0A                LOGGER.trace(%22Skip concret method %7B%7D.%22, specificMethod
 );%0A 
@@ -2359,32 +2359,24 @@
 hod);%0A      
-      %7D%0A
             
@@ -2377,24 +2377,20 @@
     
-  
 return 
-matches
+false
 ;%0A  
@@ -2387,32 +2387,36 @@
  false;%0A        
+    
 %7D%0A%0A        priva
@@ -2414,306 +2414,158 @@
     
-private Class%3C?%3E deProxy(final Class%3C?%3E targetClass, final Method method) %7B%0A            for (final Class%3C?%3E clazz : AopUtils.deproxy(targetClass)) %7B%0A                if (ReflectionUtils.findMethod(clazz, method.getName(), method.getParameterTypes()) != null) %7B%0A                    return
+    final boolean matches = repositoryMatcher.matches(clazz);%0A            if (matches) %7B%0A                LOGGER.trace(%22Found repository %7B%7D.%22,
  clazz
+)
 ;%0A
-    
     
@@ -2590,39 +2590,21 @@
     
-%7D%0A            return targetClas
+return matche
 s;%0A 

remove duplicate finding of specific method.