/**
 * Copyright (c) 2010 Sonatype, Inc. All rights reserved.
 *
 * This program is licensed to you under the Apache License Version 2.0,
 * and you may not use this file except in compliance with the Apache License Version 2.0.
 * You may obtain a copy of the Apache License Version 2.0 at http://www.apache.org/licenses/LICENSE-2.0.
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the Apache License Version 2.0 is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the Apache License Version 2.0 for the specific language governing permissions and limitations there under.
 */
package org.sonatype.guice.bean.scanners;

import java.lang.annotation.Annotation;
import java.net.URL;

import javax.inject.Qualifier;

import org.objectweb.asm.AnnotationVisitor;
import org.objectweb.asm.ClassVisitor;
import org.objectweb.asm.Opcodes;
import org.sonatype.guice.bean.reflect.ClassSpace;

/**
 * {@link ClassSpaceVisitor} that reports types annotated with {@link Qualifier} annotations.
 */
public final class QualifiedTypeVisitor
    extends EmptyClassVisitor
    implements ClassSpaceVisitor
{
    // ----------------------------------------------------------------------
    // Implementation fields
    // ----------------------------------------------------------------------

    private final QualifierCache qualifierCache = new QualifierCache();

    private final QualifiedTypeListener listener;

    private ClassSpace space;

    private String source;

    private String clazzName;

    private Class<?> clazz;

    // ----------------------------------------------------------------------
    // Constructors
    // ----------------------------------------------------------------------

    public QualifiedTypeVisitor( final QualifiedTypeListener listener )
    {
        this.listener = listener;
    }

    // ----------------------------------------------------------------------
    // Public methods
    // ----------------------------------------------------------------------

    public void visit( final ClassSpace _space )
    {
        space = _space;
        source = _space.toString();
    }

    public ClassVisitor visitClass( final URL url )
    {
        clazzName = null;
        clazz = null;
        return this;
    }

    @Override
    public void visit( final int version, final int access, final String name, final String signature,
                       final String superName, final String[] interfaces )
    {
        if ( ( access & ( Opcodes.ACC_INTERFACE | access & Opcodes.ACC_ABSTRACT | Opcodes.ACC_SYNTHETIC ) ) == 0 )
        {
            clazzName = name; // concrete type
        }
    }

    @Override
    public AnnotationVisitor visitAnnotation( final String desc, final boolean visible )
    {
        if ( null != clazzName )
        {
            final Class<Annotation> qualifierType = qualifierCache.qualify( space, desc );
            if ( null != qualifierType )
            {
                if ( null == clazz )
                {
                    clazz = space.loadClass( clazzName.replace( '/', '.' ) );
                }
                listener.hear( clazz.getAnnotation( qualifierType ), clazz, source );
            }
        }
        return null;
    }
}

@@ -1535,24 +1535,51 @@
 ace space;%0A%0A
+    private URL location;%0A%0A
     private 
@@ -1589,24 +1589,24 @@
 ing source;%0A
-
 %0A    private
@@ -2229,25 +2229,12 @@
 e = 
-_space.toString()
+null
 ;%0A  
@@ -2288,32 +2288,56 @@
 URL url )%0A    %7B%0A
+        location = url;%0A
         clazzNam
@@ -3128,32 +3128,32 @@
               %7B%0A
-
                 
@@ -3213,16 +3213,389 @@
 '.' ) );
+%0A%0A                    // compressed record of class location%0A                    final String path = location.getPath();%0A                    if ( null == source %7C%7C !path.startsWith( source ) )%0A                    %7B%0A                        final int i = path.indexOf( clazzName );%0A                        source = i %3C 0 ? path : path.substring( 0, i );%0A                    %7D
 %0A       

Optimize source storage