package reflection;

import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.lang.reflect.Parameter;

import entidades.Cliente;

// Exemplos de uso da API java.reflection
public class Principal {

	public static void main(String[] args) {
		
		Cliente cliente = new Cliente(101, "João da Silva", "Rua Santana, 820");
		
		Class<?> classe = cliente.getClass();
		System.out.printf("\n\n==== Nome da classe: %s", classe.getSimpleName());
		
		System.out.println("\n===== Modificadores");
		System.out.printf("\npublic = %d", Modifier.PUBLIC);
		System.out.printf("\nprivate = %d", Modifier.PRIVATE);
		
		// mostra todos os campos da classe Cliente
		listarCampos(classe);
		// mostra todos os métodos da classe Cliente
		listarMetodos(classe);
		// retorna as informações do método passado
		infoMetodo(classe, "setNome");
		infoMetodo(classe, "getNome");
		// lista os parâmetros de um método
		Method[] metodos = classe.getMethods();
		listarParametros(metodos[0]);
		listarParametros(metodos[1]);
		listarParametros(metodos[2]);
		listarParametros(metodos[3]);
		listarParametros(metodos[4]);
		listarParametros(metodos[5]);
		
		executaMetodosGet(cliente);
		
		listaAnotacoesDaClasse(classe);
		
		listaAnotacoesDoMetodo(classe);
	
	}
	
	public static void listarCampos(Class<?> classe) {
		Field[] campos = classe.getDeclaredFields();
		System.out.printf("\n\n===== Campos da classe %s\n", classe.getSimpleName());
		for (Field campo : campos) {
			System.out.printf("\nCAMPO: %-15s  TIPO: %-15s   MODIFICADOR: %d",
					campo.getName(), campo.getType().getSimpleName(), campo.getModifiers());
		}
	}
	
	public static void listarMetodos(Class<?> classe) {
		Method[] metodos = classe.getMethods();
		System.out.printf("\n\n===== Métodos da classe %s\n", classe.getSimpleName());
		for (Method metodo : metodos) {
			System.out.println(metodo.getName());	
		}
	}
	
	public static void infoMetodo(Class<?> classe, String nomeMetodo) {
		Method[] metodos = classe.getMethods();
		for (Method metodo : metodos) {
			if (metodo.getName().equalsIgnoreCase(nomeMetodo)) {
				System.out.printf("\n\n==== Tipo de retorno do método %s = %s",
						nomeMetodo, metodo.getReturnType().getSimpleName());
				System.out.printf("\n\n==== Quantidade de Parâmetros do método %s = %d\n",
						nomeMetodo, metodo.getParameterCount());
			}
		}
	}
	
	public static void listarParametros(Method metodo) {
		Parameter[] parametros = metodo.getParameters();
		System.out.printf("\n\n===== Parâmetros do método %s\n", metodo.getName());
		for (Parameter parametro : parametros) {
			System.out.printf("\nNOME: %s   TIPO: %s", 
								parametro.getName(), parametro.getType().getSimpleName());
		}
	}
	
	public static void executaMetodosGet(Cliente cliente) {
		Class<?> classe = cliente.getClass();
		try {
			System.out.printf("\n\n===== Retorno dos métodos get");
			for (Method metodo : classe.getMethods()) {
				String nome = metodo.getName();
				// seleciona apenas métodos com nome iniciando por "get"
				if (nome.substring(0, 3).equalsIgnoreCase("get")) {
					metodo.setAccessible(true);
					Object valor = metodo.invoke(cliente, null);
					System.out.printf("\n %s() = %s", nome, valor);
				}
			}
			
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	
	public static void listaAnotacoesDaClasse(Class<?> classe) {
		Annotation[] anotacoes = classe.getAnnotations();
		System.out.printf("\n\n====== Anotações da classe %s\n", classe.getSimpleName());
		for (Annotation anotacao : anotacoes) {
			System.out.println(anotacao.toString());
		}
	}
	
	public static void listaAnotacoesDoMetodo(Class<?> classe) {
		Method[] metodos = classe.getMethods();
		for (Method metodo : metodos) {
			Annotation[] anotacoes = metodo.getAnnotations();
			
			if (anotacoes.length > 0) {
				System.out.printf("\n\n=== Anotações do método %s\n", metodo.getName());
				for (Annotation anotacao : anotacoes) {
					System.out.println(anotacao);
				}
			}
		}
	}

}
