/*
 * Copyright 2015 Michael Rozumyanskiy
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package io.michaelrocks.lightsaber.processor.signature;

import io.michaelrocks.lightsaber.processor.ProcessorContext;
import org.objectweb.asm.Type;
import org.objectweb.asm.signature.SignatureReader;
import org.objectweb.asm.signature.SignatureVisitor;

import static org.objectweb.asm.Opcodes.ASM5;

public class TypeSignatureParser extends SignatureVisitor {
    private final ProcessorContext processorContext;

    private Type classType;
    private Type classTypeParameter;
    private boolean isValid = true;

    private TypeSignature typeSignature;

    public TypeSignatureParser(final ProcessorContext processorContext) {
        super(ASM5);
        this.processorContext = processorContext;
    }

    public static TypeSignature parseTypeSignature(final ProcessorContext processorContext, final String signature,
            final Type fieldType) {
        final TypeSignature typeSignature;
        if (signature == null) {
            typeSignature = null;
        } else {
            final SignatureReader signatureReader = new SignatureReader(signature);
            final TypeSignatureParser signatureParser = new TypeSignatureParser(processorContext);
            signatureReader.acceptType(signatureParser);
            typeSignature = signatureParser.getTypeSignature();
        }
        return typeSignature != null ? typeSignature : TypeSignature.fromType(fieldType);
    }

    public TypeSignature getTypeSignature() {
        if (isValid && typeSignature == null) {
            typeSignature = new TypeSignature(classType, classTypeParameter);
        }
        return typeSignature;
    }

    @Override
    public void visitClassType(final String name) {
        if (classType == null) {
            classType = Type.getObjectType(name);
        } else if (classTypeParameter == null) {
            classTypeParameter = Type.getObjectType(name);
        } else {
            reportError(classType + " has multiple type arguments");
        }
    }

    @Override
    public SignatureVisitor visitTypeArgument(final char wildcard) {
        if (wildcard == INSTANCEOF) {
            return this;
        }

        reportError("Injectable type cannot have wildcards in its signature");
        return this;
    }

    // Prohibited callbacks.

    @Override
    public void visitInnerClassType(final String name) {
        reportError("Injectable type cannot have an inner class type in its signature");
    }

    @Override
    public void visitBaseType(final char descriptor) {
        reportError("Injectable type cannot be a primitive type");
    }

    @Override
    public SignatureVisitor visitArrayType() {
        reportError("Injectable type cannot be an array");
        return this;
    }

    @Override
    public void visitTypeVariable(final String name) {
        reportError("Injectable type cannot have type variables in its signature");
    }

    @Override
    public void visitTypeArgument() {
        reportError("Injectable type cannot have unbounded type arguments in its signature");
    }

    private void reportError(final String message) {
        processorContext.reportError(message);
        isValid = false;
    }
}

@@ -2278,32 +2278,271 @@
  String name) %7B%0A
+        visitType(Type.getObjectType(name));%0A    %7D%0A%0A    @Override%0A    public void visitBaseType(final char descriptor) %7B%0A        visitType(Type.getType(Character.toString(descriptor)));%0A    %7D%0A%0A    private void visitType(final Type type) %7B%0A
         if (clas
@@ -2586,32 +2586,12 @@
 e = 
-Type.getObjectType(name)
+type
 ;%0A  
@@ -2674,32 +2674,12 @@
 r = 
-Type.getObjectType(name)
+type
 ;%0A  
@@ -3244,151 +3244,8 @@
  %7D%0A%0A
-    @Override%0A    public void visitBaseType(final char descriptor) %7B%0A        reportError(%22Injectable type cannot be a primitive type%22);%0A    %7D%0A%0A
     

Allow primitive types in type signatures.