/**************************************************************************************
 * Copyright (c) Jonas Bonér, Alexandre Vasseur. All rights reserved.                 *
 * http://aspectwerkz.codehaus.org                                                    *
 * ---------------------------------------------------------------------------------- *
 * The software in this package is published under the terms of the LGPL license      *
 * a copy of which has been included with this distribution in the license.txt file.  *
 **************************************************************************************/
package org.codehaus.aspectwerkz.transform.delegation;

import org.codehaus.aspectwerkz.definition.SystemDefinition;
import org.codehaus.aspectwerkz.expression.ExpressionContext;
import org.codehaus.aspectwerkz.expression.PointcutType;
import org.codehaus.aspectwerkz.reflect.ClassInfo;
import org.codehaus.aspectwerkz.reflect.impl.javassist.JavassistClassInfo;
import org.codehaus.aspectwerkz.transform.Context;
import org.codehaus.aspectwerkz.transform.Transformer;

import java.util.Iterator;
import java.util.List;

import javassist.CtClass;

/**
 * Prepares classes that are eligable for instrumentation.
 * 
 * @author <a href="mailto:jboner@codehaus.org">Jonas Bonér </a>
 * @author <a href="mailto:alex@gnilux.com">Alexandre Vasseur </a>
 */
public class PrepareAdvisedClassTransformer implements Transformer {
    /**
     * Makes the member method transformations.
     * 
     * @param context the transformation context
     * @param klass the class set.
     */
    public void transform(final Context context, final Klass klass) throws Exception {
        List definitions = context.getDefinitions();
        for (Iterator it = definitions.iterator(); it.hasNext();) {
            SystemDefinition definition = (SystemDefinition) it.next();
            final CtClass ctClass = klass.getCtClass();
            ClassInfo classMetaData = JavassistClassInfo.getClassInfo(ctClass, context.getLoader());

            ExpressionContext[] ctxs = new ExpressionContext[]{
                new ExpressionContext(PointcutType.EXECUTION, classMetaData, classMetaData),
                new ExpressionContext(PointcutType.CALL, null, classMetaData),
                new ExpressionContext(PointcutType.GET, classMetaData, classMetaData),
                new ExpressionContext(PointcutType.SET, classMetaData, classMetaData),
                new ExpressionContext(PointcutType.HANDLER, null, classMetaData),
                new ExpressionContext(PointcutType.STATIC_INITIALIZATION, classMetaData, classMetaData),
                new ExpressionContext(PointcutType.WITHIN, classMetaData, classMetaData)
            };
            if (classFilter(definition, ctxs, ctClass)) {
                continue;
            }
            JavassistHelper.addStaticClassField(ctClass, context);
            JavassistHelper.addJoinPointManagerField(ctClass, definition, context);
        }
    }

    /**
     * Filters the classes to be transformed.
     * 
     * @param definition the definition
     * @param ctxs expression contexts
     * @param cg the class to filter
     * @return boolean true if the method should be filtered away
     */
    public static boolean classFilter(final SystemDefinition definition, final ExpressionContext[] ctxs, final CtClass cg) {
        if (cg.isInterface()) {
            return true;
        }
        String className = cg.getName().replace('/', '.');
        if (definition.inExcludePackage(className)) {
            return true;
        }
        if (!definition.inIncludePackage(className)) {
            return true;
        }
        if (definition.inPreparePackage(className)) {
            return false;
        }
        if (definition.isAdvised(ctxs)) {
            return false;
        }
        return true;
    }
}