/*
* JBoss, Home of Professional Open Source
* Copyright 2010 Red Hat and individual contributors
* by the @authors tag. See the copyright.txt in the distribution for a
* full listing of individual contributors.
*
* This is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This software 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this software; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*
* @authors Andrew Dinn
*/
package org.jboss.byteman.agent.adapter;

import org.objectweb.asm.Label;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.tree.AbstractInsnNode;
import org.objectweb.asm.tree.InsnList;
import org.objectweb.asm.tree.LabelNode;
import org.objectweb.asm.tree.LocalVariableNode;

import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;

/**
 */
public class BMInsnList extends InsnList
{
    // the local variables list managed by the method node which owns this instruction list
    List localvariables;
    
    public BMInsnList(List localVariables)
    {
        this.localvariables = localVariables;
    }
    public void accept(final MethodVisitor mv)
    {
        // this method visitor must implement LocalScopeMethodVisitor or else we would not be here
        
        LocalScopeMethodVisitor lsmv = (LocalScopeMethodVisitor) mv;
        
        // first index all local vars by start and end label
        HashMap<Label, LinkedList<LocalVariableNode>> localStarts = new HashMap<Label, LinkedList<LocalVariableNode>>();
        HashMap<Label, LinkedList<LocalVariableNode>> localEnds = new HashMap<Label, LinkedList<LocalVariableNode>>();

        Iterator iterator = localvariables.iterator();
        while (iterator.hasNext()) {
            LocalVariableNode local = (LocalVariableNode)iterator.next();
            Label label = local.start.getLabel();
            LinkedList<LocalVariableNode> locals = localStarts.get(label);
            if (locals == null) {
                locals = new LinkedList<LocalVariableNode>();
                localStarts.put(label, locals);
            }
            locals.addLast(local);
            label = local.end.getLabel();
            locals = localEnds.get(label);
            if (locals == null) {
                locals = new LinkedList<LocalVariableNode>();
                localEnds.put(label, locals);
            }
            locals.addLast(local);
        }

        // now visit the instructions intercepting labels
        AbstractInsnNode insn = getFirst();
        while (insn != null) {
            insn.accept(mv);
            if (insn.getType() == AbstractInsnNode.LABEL) {
                LabelNode labelNode = (LabelNode) insn;
                Label label = labelNode.getLabel();
                List<LocalVariableNode> localStart = localStarts.get(label);
                List<LocalVariableNode> localEnd = localEnds.get(label);
                if (localStart != null) {
                    for (LocalVariableNode local : localStart) {
                        lsmv.visitLocalScopeStart(local.name, local.desc, local.signature, local.index, label.getOffset());
                    }
                }
                if (localEnd != null) {
                    for (LocalVariableNode local : localEnd) {
                        lsmv.visitLocalScopeEnd(local.name, local.desc, local.signature, local.index, label.getOffset());
                    }
                }
            }
            insn = insn.getNext();
        }
    }
}
