use strict;

package W3C::JVM::Method;
use W3C::JVM::Definition;
use W3C::JVM::Access;

use vars qw(@ISA);
@ISA = qw(W3C::JVM::Definition);

sub new_unpack {
    my ($proto, $index, $pBits, $constPool, $jvm) = @_;
    my $class = ref($proto) || $proto;
    my $self = $class->SUPER::new_unpack($index, $pBits, $constPool);

    # Need constant pool to find the CODE attribute.
    # Delay parsing until fixupRefs.
    $self->{BYTE_CODE} = [];
    $self->{EXCEPTIONS} = [];
    $self->{CODE_ATTRIBUTES} = [];

    $self->{JVM} = $jvm; # handy for disassembling
    return $self;
}

sub fixupRefs {
    my ($self, $pool, $classRef) = @_;
    $self->{CONST_POOL} = $pool;
    my @ret = $self->SUPER::fixupRefs($pool);
    $self->{METHOD_REF} = $pool->ensureMethodRef($classRef, $self->{NAME_REF}, $self->{TYPE_REF});
    my $idxCode = $pool->getUtf8Index('Code');
    for (my $i = 0; $i < @{$self->{ATTRIBUTES}}; $i++) {
	my $attribute = $self->{ATTRIBUTES}[$i];
	if ($attribute->getName() == $idxCode) {
	    splice (@{$self->{ATTRIBUTES}}, $i, 1);

	    my ($len, $byteCode, $exceptions, $codeAttributes, $bits);
	    ($self->{MAX_STACK}, $self->{MAX_LOCALS}, $len, $bits) = unpack ('n2Na*', $attribute->getData());

	    ($byteCode, $exceptions, $bits) = unpack ("a${len}na*", $bits);
	    @{$self->{BYTE_CODE}} = unpack ('C*', $byteCode);
	    for (my $i = 0; $i < $exceptions; $i++) {
		push (@{$self->{EXCEPTIONS}}, new_unpack W3C::JVM::Exception($i, \ $bits));
	    }

	    ($codeAttributes, $bits) = unpack ("na*", $bits);
	    for (my $i = 0; $i < $codeAttributes; $i++) {
		push (@{$self->{CODE_ATTRIBUTES}}, new_unpack W3C::JVM::Attribute($i, \ $bits));
	    }
	}
    }
}

sub getByteCode {
    my ($self) = @_;
    return $self->{BYTE_CODE};
}

sub getMethodRef {
    my ($self) = @_;
    return $self->{METHOD_REF};
}

sub toString {
    my ($self, $flags) = @_;
    $flags ||= {};
    my @ret = $self->SUPER::toString();
    if ($flags->{-ordinal} == 16) {
	push (@ret, join (' ', "bytes: ", map { sprintf "%#02x", $_ } @{$self->{BYTE_CODE}}));
    } else {
	push (@ret, join (' ', "bytes: ", @{$self->{BYTE_CODE}}));
    }
    if ($self->{JVM}) {
	push (@ret, @{$self->{JVM}->disassemble($self->{BYTE_CODE}, $self->{CONST_POOL}, $flags)});
#	push (@ret, @{$self->{JVM}->compile($self, $self->{CONST_POOL})});
    }
    return join ("\n", @ret);
}

sub _RenderAccess { # protected
    my ($self) = @_;
    return &RenderAccess($self->{ACCESS}, \%ACC_2STR_method, 'method access')
}

1;

