package net.ranides.assira.reflection.impl;

import net.ranides.assira.reflection.*;

import java.io.Serializable;
import java.lang.invoke.MethodHandle;
import java.lang.reflect.Method;
import java.util.Collections;
import java.util.List;

/**
 * This implementation of IMethod does not store too much details about method,
 * but preserves it's name and signature .
 *
 * It does not store information about declaring class.
 *
 * Symbolic methods could be used for example, in bytecode generators,
 * where you don't need more than method signature.
 */
public class SMethod extends AMethod implements IMethod, Serializable {

    private static final long serialVersionUID = 1L;

    private static final String NSE = "Symbolic IMethod is not reflective nor callable.";

    private static final IAttributes ATTRS = IAttributes.of(IAttribute.SYMBOLIC).immutable();

    private final String name;

    private final IArguments args;

    private final IClass<?> rets;

    /**
     * Internal method: creates signature for method
     *
     * @param name name
     * @param args args
     * @param rets rets
     */
    public SMethod(String name, IArguments args, IClass<?> rets) {
        super(IContext.getDefault());
        this.name = name;
        this.args = args;
        this.rets = rets;
    }

    @Override
    public IMethod accessible() {
        return this;
    }

    @Override
    public boolean isAccessible() {
        return true;
    }

    @Override
    public Method reflective() {
        throw new IReflectiveException(NSE);
    }

    @Override
    public List<IClass<?>> params() {
        return Collections.emptyList();
    }

    @Override
    public IClass<?> returns() {
        return rets;
    }

    @Override
    public IArguments arguments() {
        return args;
    }

    @Override
    public List<IClass<?>> exceptions() {
        return Collections.emptyList();
    }

    @Override
    public IClass<?> parent() {
        return IClass.NULL;
    }

    @Override
    public Object invoke() {
        throw new IReflectiveException(NSE);
    }

    @Override
    public Object invoke(Object that) {
        throw new IReflectiveException(NSE);
    }

    @Override
    public Object invoke(Object that, Object... arguments) {
        throw new IReflectiveException(NSE);
    }

    @Override
    public Object call(Object... arguments) {
        throw new IReflectiveException(NSE);
    }

    @Override
    public MethodHandle handle() {
        throw new IReflectiveException(NSE);
    }

    @Override
    public String name() {
        return name;
    }

    @Override
    public IAttributes attributes() {
        return ATTRS;
    }

    @Override
    public IAnnotations annotations() {
        return IAnnotations.empty();
    }
}
