/*
  Jar Jar Links - A utility to repackage and embed Java libraries
  Copyright (C) 2004  Tonic Systems, Inc.

  This program is free software; you can redistribute it and/or modify
  it under the terms of the GNU General Public License as published by
  the Free Software Foundation; either version 2 of the License, or
  (at your option) any later version.

  This program is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  GNU General Public License for more details.

  You should have received a copy of the GNU General Public License
  along with this program; see the file COPYING.  if not, write to
  the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
  Boston, MA 02111-1307 USA
*/

package com.tonicsystems.jarjar;

import org.objectweb.asm.*;

class PackageTransformer extends ClassAdapter implements ClassTransformer
{
    private Rules rules;
    private String className;
    
    public PackageTransformer(Rules rules) {
        super(null);
        this.rules = rules;
    }
    
    public void setTarget(ClassVisitor target) {
        cv = target;
    }

    private String[] fixNames(String[] names) {
        if (names == null)
            return null;
        String[] fixed = new String[names.length];
        for (int i = 0; i < names.length; i++) {
            fixed[i] = rules.fixName(names[i]);
        }
        return fixed;
    }

    private Object fixValue(Object value) {
        if (value instanceof String) {
            return rules.fixString(className, (String)value);
        } else {
            return value;
        }
    }
    
    public void visit(int version, int access, String name, String signature, String superName, String[] interfaces) {
        className = name.replace('/', '.');
        cv.visit(version, access, rules.fixName(name), rules.fixSignature(signature), rules.fixName(superName), fixNames(interfaces));
    }

    public void visitAttribute(Attribute attr) {
        cv.visitAttribute(rules.fixAttribute(attr));
    }

    public AnnotationVisitor visitAnnotation(String desc, boolean visible) {
        return new AnnotationFixer(cv.visitAnnotation(rules.fixDesc(desc), visible));
    }
    
    public FieldVisitor visitField(int access, String name, String desc, String signature, Object value) {
        return new FieldFixer(cv.visitField(access, name, rules.fixDesc(desc), rules.fixSignature(signature), fixValue(value)));
    }

    public void visitInnerClass(String name, String outerName, String innerName, int access) {
        cv.visitInnerClass(rules.fixName(name), rules.fixName(outerName), innerName, access);
    }

    public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) {
        return new MethodFixer(cv.visitMethod(access, name, rules.fixMethodDesc(desc), rules.fixSignature(signature), fixNames(exceptions)));
    }

    private class FieldFixer implements FieldVisitor
    {
        private FieldVisitor fv;

        public FieldFixer(FieldVisitor fv) {
            this.fv = fv;
        }

        public AnnotationVisitor visitAnnotation(String desc, boolean visible) {
            return new AnnotationFixer(fv.visitAnnotation(rules.fixDesc(desc), visible));
        }
        
        public void visitAttribute(Attribute attr) {
            fv.visitAttribute(rules.fixAttribute(attr));
        }
        
        public void visitEnd() {
            fv.visitEnd();
        }
    }

    private class MethodFixer extends MethodAdapter
    {
        public MethodFixer(MethodVisitor mv) {
            super(mv);
        }

        public AnnotationVisitor visitAnnotation(String desc, boolean visible) {
            return new AnnotationFixer(mv.visitAnnotation(rules.fixDesc(desc), visible));
        }

        public AnnotationVisitor visitAnnotationDefault() {
            return new AnnotationFixer(mv.visitAnnotationDefault());
        }

        public void visitTypeInsn(int opcode, String desc) {
            mv.visitTypeInsn(opcode, (desc.charAt(0) == '[') ? rules.fixDesc(desc) : rules.fixName(desc));
        }

        public void visitFieldInsn(int opcode, String owner, String name, String desc) {
            mv.visitFieldInsn(opcode, rules.fixName(owner), name, rules.fixDesc(desc));
        }

        public void visitMethodInsn(int opcode, String owner, String name, String desc) {
            mv.visitMethodInsn(opcode, rules.fixName(owner), name, rules.fixMethodDesc(desc));
        }

        public void visitLdcInsn(Object cst) {
            mv.visitLdcInsn(fixValue(cst));
        }

        public void visitMultiANewArrayInsn(String desc, int dims) {
            mv.visitMultiANewArrayInsn(rules.fixDesc(desc), dims);
        }

        public void visitTryCatchBlock(Label start, Label end, Label handler, String type) {
            mv.visitTryCatchBlock(start, end, handler, rules.fixName(type));
        }

        public void visitLocalVariable(String name, String desc, String signature, Label start, Label end, int index) {
            mv.visitLocalVariable(name, rules.fixDesc(desc), rules.fixSignature(signature), start, end, index);
        }

        public void visitAttribute(Attribute attr) {
            mv.visitAttribute(rules.fixAttribute(attr));
        }
    }

    private class AnnotationFixer extends AnnotationAdapter
    {
        public AnnotationFixer(AnnotationVisitor av) {
            super(av);
        }
        
        public void visit(String name, Object value) {
            av.visit(name, fixValue(value));
        }

        public AnnotationVisitor visitAnnotation(String name, String desc) {
            return new AnnotationFixer(av.visitAnnotation(name, rules.fixDesc(desc)));
        }

        public void visitEnum(String name, String desc, String value) {
            av.visitEnum(name, rules.fixDesc(desc), (String)fixValue(value));
        }
    }
}

@@ -2406,30 +2406,41 @@
 ) %7B%0A        
-return
+FieldVisitor fv =
  new FieldFi
@@ -2538,24 +2538,81 @@
 e(value)));%0A
+        return (fv != null) ? new FieldFixer(fv) : null;%0A
     %7D%0A%0A    p
@@ -2930,31 +2930,27 @@
     
-return new MethodFixer(
+MethodVisitor mv = 
 cv.v
@@ -3053,17 +3053,74 @@
 ptions))
-)
+;%0A        return (mv != null) ? new MethodFixer(mv) : null
 ;%0A    %7D%0A
@@ -3922,36 +3922,35 @@
          return 
-new 
+fix
 AnnotationFixer(
@@ -3935,37 +3935,32 @@
 rn fixAnnotation
-Fixer
 (mv.visitAnnotat
@@ -4077,36 +4077,35 @@
          return 
-new 
+fix
 AnnotationFixer(
@@ -4098,21 +4098,16 @@
 notation
-Fixer
 (mv.visi
@@ -5865,36 +5865,35 @@
          return 
-new 
+fix
 AnnotationFixer(
@@ -5886,21 +5886,16 @@
 notation
-Fixer
 (av.visi
@@ -6088,32 +6088,32 @@
 xValue(value));%0A
-
         %7D%0A    %7D%0A
@@ -6111,11 +6111,148 @@
  %7D%0A    %7D
+%0A%0A    private AnnotationVisitor fixAnnotation(AnnotationVisitor av) %7B%0A        return (av != null) ? new AnnotationFixer(av) : null;%0A    %7D
 %0A%7D%0A

visitors can be null