/*
 * Click nbfs://nbhost/SystemFileSystem/Templates/Licenses/license-default.txt to change this license
 * Click nbfs://nbhost/SystemFileSystem/Templates/Classes/Class.java to edit this template
 */

/**
 *
 * @author developer2
 */

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.Serializable;
import java.lang.reflect.Field;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Set;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.math3.random.RandomDataGenerator;
import org.reflections.Reflections;

public class GeneradorCodigo {
    private static final String TAB = "    ";

    private static final String GETTER = TAB
            + TAB + "public %s get%s() {\n" + TAB + "return %s;\n" + TAB + "}";

    private static final String SETTER = TAB
            + TAB + "public void set%s(%s %s) {\n" + TAB + "this.%s = %s;\n" + TAB + "}";

    public static void main(String[] args) {
        String packOrigen = "com.qsoft.rs.sincoar.model";
        String packDestino = "com.qsoft.rs.sincoar.";
        String destino = "/home/developer2/NetBeansProjects/rs-sincoar-domain/src/main/java/com/qsoft/rs/sincoar/dto/";
        generarCodigo(packOrigen, packDestino, destino, false);
        System.out.println("" + generarEntidadEnum(packOrigen));
    }
    
    public static String generarEntidadEnum(String packOrigen){
        Reflections reflections = new Reflections(packOrigen);
        Set<Class<? extends Serializable>> clases = reflections.getSubTypesOf(Serializable.class);
        System.out.println("ENTIDAD ENUM");
        String salto = System.getProperty("line.separator");
        StringBuilder buil = new StringBuilder();
        for (Class t : clases) {
            //Catalogo(Catalogo.class, CatalogoDTO.class, CatalogoMapper.class),
            buil.append(TAB).append(t.getSimpleName()).append("(").append(t.getSimpleName()).append(".class, ").
                    append(t.getSimpleName()).append("DTO.class, ").append(t.getSimpleName()).append("Mapper.class),").append(salto);
        }
        return buil.toString();
    }

    /**
     * 
     * @param packOrigen
     * @param packDestino
     * @param urlDestino
     * @param override 
     */
    public static void generarCodigo(String packOrigen, String packDestino, String urlDestino, boolean override) {

        Reflections reflections = new Reflections(packOrigen);
        Set<Class<? extends Serializable>> clases = reflections.getSubTypesOf(Serializable.class);
        System.out.println("BUSCAR CLASES ");
        for (Class t : clases) {
            String data = crearMapper(t, packDestino);
            String name = urlDestino.replace("/dto/", "/dominio/mapper/") + t.getSimpleName().replace(".java", "") + "Mapper.java";
            escribirData(name, data, false);
            
            data = crearDTO(t, packDestino);
            name = urlDestino + t.getSimpleName().replace(".java", "") + "DTO.java";
            escribirData(name, data, false);

        }
    }

    /**
     *
     * @param clase
     * @param paquete
     * @return
     */
    public static String crearMapper(Class clase, String paquete) {
        StringBuilder build = new StringBuilder();
        String nombre = clase.getSimpleName().concat("Mapper");
        String salto = System.getProperty("line.separator");
        build.append("package ").append(paquete).append("dominio.mapper").append(";").append(salto).append(salto);
        build.append("import ").append(clase.getName()).append(";").append(salto);
        build.append("import ").append(clase.getName().replace(".model", ".dto")).append("DTO;").append(salto);
        build.append("import org.mapstruct.Mapper;").append(salto);
        build.append("import org.mapstruct.factory.Mappers;").append(salto);
        build.append(salto).append("@Mapper").append(salto);
        build.append("public interface ").append(nombre).append(" {").append(salto).append(salto);

        build.append(TAB).append(nombre).append(" INSTANCE = Mappers.getMapper(").append(nombre).append(".class);").append(salto).append(salto);

        build.append(TAB).append(clase.getSimpleName()).append(" getEntidad(").append(clase.getSimpleName()).
                append("DTO ").append(StringUtils.uncapitalize(clase.getSimpleName())).append(");").append(salto).append(salto);
        
        build.append(TAB).append(clase.getSimpleName()).append("DTO getDto(").append(clase.getSimpleName()).append(" ").
                append(StringUtils.uncapitalize(clase.getSimpleName())).append(");").append(salto).append(salto);
       
        build.append("}");
        return build.toString();
    }

    /**
     *
     * @param clase
     * @param paquete
     * @return
     */
    public static String crearDTO(Class clase, String paquete) {
        StringBuilder build = new StringBuilder();
        String salto = System.getProperty("line.separator");
        build.append("package ").append(paquete).append("dto").append(";").append(salto);
        build.append(salto).append("import java.io.Serializable;").append(salto);
        build.append(salto).append("public class ").append(clase.getSimpleName()).append("DTO implements Serializable {").append(salto);
        Long serial = new RandomDataGenerator().nextLong(1000000000L, 999999999999999L);
        build.append(salto).append(TAB).append("private static final long serialVersionUID = ").
                append(serial).append("L;").append(salto).append(salto);
        Map<String, String> variables = new LinkedHashMap<>();
        for (Field f : clase.getDeclaredFields()) {
            String tipo = f.getType().getName();
            if (!f.getName().equalsIgnoreCase("serialVersionUID") && !tipo.equals("java.util.Collection")) {

                if (tipo.contains("java.lang") || tipo.contains("java.util")) {
                    tipo = tipo.replace("java.lang.", "");
                } else {
                    tipo = "Integer";
                }
                build.append(TAB).append("private ").append(tipo).append(" ").append(f.getName()).append(";").append(salto).append(salto);
                variables.put(f.getName(), tipo);
            }
        }
        for (Map.Entry<String, String> entry : variables.entrySet()) {
            String tipo = entry.getValue();
            String val = entry.getKey();
            String valC = StringUtils.capitalize(val);
            build.append(String.format(GETTER, tipo, valC, val)).append(salto).append(salto);
            build.append(String.format(SETTER, valC, tipo, val, val, val)).append(salto).append(salto);
        }
        build.append("}");
        return build.toString();
    }

    private static void escribirData(String file, String data, boolean override) {
        File salida = new File(file);
        if (!override && salida.exists()) {
            return;
        }
        try ( FileOutputStream os = new FileOutputStream(salida)) {
            os.write(data.getBytes());
        } catch (IOException ex) {
            ex.printStackTrace(System.out);
        }

    }
}
