/*******************************************************************************
 * This file is part of the Polyglot extensible compiler framework.
 *
 * Copyright (c) 2000-2012 Polyglot project group, Cornell University
 * Copyright (c) 2006-2012 IBM Corporation
 * All rights reserved.
 *
 * This program and the accompanying materials are made available under
 * the terms of the Eclipse Public License v1.0 which accompanies this
 * distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * This program and the accompanying materials are made available under
 * the terms of the Lesser GNU Public License v2.0 which accompanies this
 * distribution.
 * 
 * The development of the Polyglot project has been supported by a
 * number of funding sources, including DARPA Contract F30602-99-1-0533,
 * monitored by USAF Rome Laboratory, ONR Grants N00014-01-1-0968 and
 * N00014-09-1-0652, NSF Grants CNS-0208642, CNS-0430161, CCF-0133302,
 * and CCF-1054172, AFRL Contract FA8650-10-C-7022, an Alfred P. Sloan 
 * Research Fellowship, and an Intel Research Ph.D. Fellowship.
 *
 * See README for contributors.
 ******************************************************************************/

package polyglot.types.reflect;

import java.io.DataInputStream;
import java.io.EOFException;
import java.io.IOException;

/**
 * Method represents a method in a Java classfile.  A method's name and
 * value (the types of its parameters and its return type) are modeled
 * as indices into it class's constant pool.  A method has modifiers 
 * that determine whether it is public, private, static, final, etc.
 * Methods have a number of attributes such as their Code and any
 * Exceptions they may throw.
 *
 * @see polyglot.types.reflect Code
 * @see polyglot.types.reflect Exceptions
 *
 * @author Nate Nystrom
 *         (<a href="mailto:nystrom@cs.purdue.edu">nystrom@cs.purdue.edu</a>)
 */
public class Method {
    protected ClassFile clazz;
    protected DataInputStream in;

    protected int modifiers;
    protected int name;
    protected int type;
    protected Attribute[] attrs;
    protected Exceptions exceptions;
    protected boolean synthetic;

    // From the VM spec. Unaccountably not exposed by Modifier class.
    static final int ACC_BRIDGE = 0x0040;
    static final int ACC_VARARGS = 0x0080;
    static final int ACC_SYNTHETIC = 0x1000;

    /**
     * Constructor.  Read a method from a class file.
     *
     * @param in
     *        The data stream of the class file.
     * @param clazz
     *        The class file containing the method.
     * @exception IOException
     *        If an error occurs while reading.
     */
    public Method(DataInputStream in, ClassFile clazz) {
        this.clazz = clazz;
        this.in = in;
    }

    public void initialize() throws IOException {
        modifiers = in.readUnsignedShort();

        name = in.readUnsignedShort();
        type = in.readUnsignedShort();

        int numAttributes = in.readUnsignedShort();

        attrs = new Attribute[numAttributes];

        for (int i = 0; i < numAttributes; i++) {
            int nameIndex = in.readUnsignedShort();
            int length = in.readInt();

            Constant name = clazz.getConstants()[nameIndex];

            if (name != null) {
                if ("Exceptions".equals(name.value())) {
                    exceptions = new Exceptions(clazz, in, nameIndex, length);
                    attrs[i] = exceptions;
                }
                if ("Synthetic".equals(name.value())) {
                    synthetic = true;
                }
            }

            //if (0 != (modifiers & ACC_SYNTHETIC)) synthetic = true;

            if (attrs[i] == null) {
                long n = in.skip(length);
                if (n != length) {
                    throw new EOFException();
                }
            }
        }
        this.in = null; // RMF 7/23/2008 - Don't need the input stream any more, so don't hang onto it
    }

    public boolean isSynthetic() {
        return synthetic;
    }

    public boolean isBridge() {
        return (0 != (modifiers & ACC_BRIDGE));
    }

    public Attribute[] getAttrs() {
        return attrs;
    }

    public ClassFile getClazz() {
        return clazz;
    }

    public Exceptions getExceptions() {
        return exceptions;
    }

    public int getModifiers() {
        return modifiers;
    }

    public int getName() {
        return name;
    }

    public int getType() {
        return type;
    }

    public String name() {
        return (String) clazz.getConstants()[this.name].value();
    }
}
