/*
   Copyright 2009-2011 Attila Szegedi

   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 org.dynalang.dynalink;

import java.lang.invoke.MethodType;
import java.lang.BootstrapMethodError;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;
import java.util.StringTokenizer;

/**
 * A descriptor of a call site. Used in place of passing a real call site to
 * guarding linkers so they aren't tempted to do nasty things to it; also it
 * carries the tokenized name of the method, which is not available in the call
 * site object itself.
 *
 * @author Attila Szegedi
 * @version $Id: $
 */
public class CallSiteDescriptor {
    private final List<String> tokenizedName;
    private final String name;
    private final MethodType methodType;

    /**
     * Create a new call site descriptor from explicit information.
     *
     * @param tokenizedName the tokenized name of the method
     * @param methodType the method type
     */
    public CallSiteDescriptor(List<String> tokenizedName, MethodType methodType) {
        this(untokenizeName(tokenizedName), internElements(tokenizedName),
                methodType);
    }

    /**
     * Create a new call site descriptor from explicit information.
     *
     * @param name the name of the method
     * @param methodType the method type
     */
    public CallSiteDescriptor(String name, MethodType methodType) {
        this(name, tokenizeName(name), methodType);
    }

    private CallSiteDescriptor(String name, List<String> tokenizedName,
            MethodType methodType) {
        this.name = name;
        this.tokenizedName = Collections.unmodifiableList(tokenizedName);
        this.methodType = methodType;
    }

    /**
     * The type of the method at the call site.
     *
     * @return type of the method at the call site.
     */
    public MethodType getMethodType() {
        return methodType;
    }

    /**
     * Returns the tokenized name of the method at the call site.
     *
     * @return name of the method at the call site. Returned is an unmodifiable
     * list of interned strings representing the name tokenized at colon ":"
     * characters.
     */
    public List<String> getTokenizedName() {
        return tokenizedName;
    }

    /**
     * Returns the untokenized name of the method at the call site.
     *
     * @return name of the method at the call site.
     */
    public String getName() {
        return name;
    }

    /**
     * Checks that the method type has exactly the desired number of arguments,
     * throws an exception if it doesn't.
     *
     * @param count the desired parameter count
     * @throws BootstrapMethodError if the parameter count doesn't match
     */
    public void assertParameterCount(int count) {
        if(methodType.parameterCount() != count) {
            throw new BootstrapMethodError(tokenizedName
                    + " must have exactly " + count + " parameters");
        }
    }

    private static List<String> tokenizeName(String name) {
        final ArrayList<String> lname = new ArrayList<String>(3);
        final StringTokenizer tok = new StringTokenizer(name, ":");
        while(tok.hasMoreTokens()) {
            lname.add(tok.nextToken().intern());
        }
        lname.trimToSize();
        return lname;
    }

    private static List<String> internElements(Collection<String> list) {
        final List<String> l = new ArrayList<String>(list);
        for(ListIterator<String> it = l.listIterator(); it.hasNext();) {
            it.set(it.next().intern());
        }
        return l;
    }

    private static String untokenizeName(List<String> l) {
        final StringBuilder b = new StringBuilder();
        final Iterator<String> it = l.iterator();
        if(it.hasNext()) {
            b.append(it.next());
            while(it.hasNext()) {
                b.append(':').append(it.next());
            }
        }
        return b.toString();
    }

    /**
     * Creates a new call site descriptor from this descriptor, which is
     * identical to this, except it drops few of the trailing arguments from the
     * method type
     *
     * @param argCount the number of arguments to drop
     * @return a new call site descriptor with the arguments dropped.
     */
    public CallSiteDescriptor dropArguments(int argCount) {
        final int paramCount = methodType.parameterCount();
        return new CallSiteDescriptor(name, tokenizedName, methodType
                .dropParameterTypes(paramCount - argCount, paramCount));
    }

    public CallSiteDescriptor changeParameterType(int num, Class<?> newType) {
        return new CallSiteDescriptor(name, tokenizedName, methodType
                .changeParameterType(num, newType));
    }
}
@@ -682,48 +682,8 @@
 e;%0D%0A
-import java.lang.BootstrapMethodError;%0D%0A
 impo
@@ -738,123 +738,33 @@
 tion
-;%0D%0Aimport java.util.Collections;%0D%0Aimport java.util.Iterator;%0D%0Aimport java.util.List;%0D%0Aimport java.util.ListIterator
+s;%0D%0Aimport java.util.List
 ;%0D%0Ai
@@ -1361,414 +1361,8 @@
 n.%0D%0A
-     *%0D%0A     * @param tokenizedName the tokenized name of the method%0D%0A     * @param methodType the method type%0D%0A     */%0D%0A    public CallSiteDescriptor(List%3CString%3E tokenizedName, MethodType methodType) %7B%0D%0A        this(untokenizeName(tokenizedName), internElements(tokenizedName),%0D%0A                methodType);%0D%0A    %7D%0D%0A%0D%0A    /**%0D%0A     * Create a new call site descriptor from explicit information.%0D%0A     *%0D%0A
     
@@ -3503,675 +3503,8 @@
 %0D%0A%0D%0A
-    private static List%3CString%3E internElements(Collection%3CString%3E list) %7B%0D%0A        final List%3CString%3E l = new ArrayList%3CString%3E(list);%0D%0A        for(ListIterator%3CString%3E it = l.listIterator(); it.hasNext();) %7B%0D%0A            it.set(it.next().intern());%0D%0A        %7D%0D%0A        return l;%0D%0A    %7D%0D%0A%0D%0A    private static String untokenizeName(List%3CString%3E l) %7B%0D%0A        final StringBuilder b = new StringBuilder();%0D%0A        final Iterator%3CString%3E it = l.iterator();%0D%0A        if(it.hasNext()) %7B%0D%0A            b.append(it.next());%0D%0A            while(it.hasNext()) %7B%0D%0A                b.append(':').append(it.next());%0D%0A            %7D%0D%0A        %7D%0D%0A        return b.toString();%0D%0A    %7D%0D%0A%0D%0A
     

Remove unused constructor