package shapes77.dbg;
/* UTF-8 codepage: Příliš žluťoučký kůň úpěl ďábelské ó. ÷ × ¤ */

import java.util.function.Function;



/********************************************************************************
 * Knihovní třída {@code ClassInfo} definuje metody
 * pomáhající s analýzou mateřské třídy zadané instance,
 * resp. třídy zadané jejím class-objektem.
 *
 * @author  Rudolf PECINOVSKÝ
 * @version 0.00.0000 — 20yy-mm-dd
 */
public class ClassInfo
{
    {
        System.out.println("Třída ClassInfo se natahuje");
    }
//\CC== CLASS CONSTANTS (CONSTANT CLASS/STATIC ATTRIBUTES/FIELDS) ==============

    /** Přírustek odsazení při zanoření do doalší hladiny. */
    private static final String D_INDENT = "   ";



//\CV== CLASS VARIABLES (VARIABLE CLASS/STATIC ATTRIBUTES/FIELDS) ==============



//##############################################################################
//\CI== CLASS (STATIC) INITIALIZER (CLASS CONSTRUCTOR) =========================
//\CF== CLASS (STATIC) FACTORY METHODS =========================================
//\CG== CLASS (STATIC) GETTERS AND SETTERS =====================================
//\CM== CLASS (STATIC) REMAINING NON-PRIVATE METHODS ===========================

    public static void analyze(Object obj)
    {
        String[] lines = signatureOf(obj);
        for (String line : lines) {
            System.out.println(line);
        }
    }


    public static void printMembersOf(Object obj)
    {
        String[] lines = membersOf(obj);
        for (String line : lines) {
            System.out.println(line);
        }
    }


    public static void printLines(Object obj)
    {
        String[] lines = membersOf(obj);
        for (int i=0;   i < lines.length;  i++) {
            System.out.println(lines[i]);
        }
    }



//\CP== CLASS (STATIC) PRIVATE AND AUXILIARY METHODS ===========================

    /****************************************************************************
     * Přidá do zadaného stringbuilderu informace o veřejných
     * členech zadané třídy.
     *
     * @param cls       //Class-objekt analyzované třídy
     * @param sb        //Stringbuilder, do nějž se ukládají výsledky
     * @param indent    //Odsazení ukládaných řádků textu
     * @param memberFinder  // Metoda vracející pole hledaných objektů
     */
    private static void addMembersOf(
            Class<?> cls, StringBuilder sb, String indent,
            Function<Class<?>, Object[]> memberFinder)
    {
        for(Object member : memberFinder.apply(cls)) {
            sb.append(indent)
              .append(member)
              .append('\n');
        }
    }


    /****************************************************************************
     * Přidá do zadaného stringbuilderu informace o interfejsech
     * implementovaných zadanou třídou.
     *
     * @param cls       //Class-objekt analyzované třídy
     * @param sb        //Stringbuilder, do nějž se ukládají výsledky
     * @param indent    //Odsazení ukládaných řádků textu
     */
    private static void addImplementedInterfacesOf(
            Class<?> cls, StringBuilder sb, String indent)
    {
        sb.append(indent).append("Implementované interfejsy:\n");
        addMembersOf(cls, sb, indent+D_INDENT, Class::getInterfaces);
    }


    /****************************************************************************
     * Přidá do zadaného stringbuilderu informace o veřejných
     * polích zadané třídy.
     *
     * @param cls       //Class-objekt analyzované třídy
     * @param sb        //Stringbuilder, do nějž se ukládají výsledky
     * @param indent    //Odsazení ukládaných řádků textu
     */
    private static void addFieldsOf(
            Class<?> cls, StringBuilder sb, String indent)
    {
        sb.append(indent).append("Veřejné atributy:\n");
        addMembersOf(cls, sb, indent+D_INDENT, Class::getFields);
    }


    /****************************************************************************
     * Přidá do zadaného stringbuilderu informace o veřejných
     * konstruktorech zadané třídy.
     *
     * @param cls       //Class-objekt analyzované třídy
     * @param sb        //Stringbuilder, do nějž se ukládají výsledky
     * @param indent    //Odsazení ukládaných řádků textu
     */
    private static void addConstructorsOf(
            Class<?> cls, StringBuilder sb, String indent)
    {
        sb.append(indent).append("Veřejné konstruktory:\n");
        addMembersOf(cls, sb, indent+D_INDENT, Class::getConstructors);
    }


    /****************************************************************************
     * Přidá do zadaného stringbuilderu informace o veřejných
     * metodách zadané třídy.
     *
     * @param cls       //Class-objekt analyzované třídy
     * @param sb        //Stringbuilder, do nějž se ukládají výsledky
     * @param indent    //Odsazení ukládaných řádků textu
     */
    private static void addMethodsOf(
            Class<?> cls, StringBuilder sb, String indent)
    {
        sb.append(indent).append("Veřejné metody:\n");
        addMembersOf(cls, sb, indent+D_INDENT, Class::getMethods);
    }


    /****************************************************************************
     * Přidá do zadaného stringbuilderu informace o veřejných
     * metodách zadané třídy.
     *
     * @param cls       //Class-objekt analyzované třídy
     * @param sb        //Stringbuilder, do nějž se ukládají výsledky
     * @param indent    //Odsazení ukládaných řádků textu
     */
    private static void addNestedTypesOf(
            Class<?> cls, StringBuilder sb, String indent)
    {
        sb.append(indent).append("Veřejné interní typy:\n");
        addMembersOf(cls, sb, indent+D_INDENT, Class::getDeclaredClasses);
    }


    /****************************************************************************
     * Vráží pole stringů popisujících veřejné členy zadané třídy,
     * resp. mateřské třídy zadané instance.
     *
     * @param  obj Class-objekt analyzované třídy, resp. odkaz na její instanci
     * @return Pole signatur členů analyzované třídy
     */
    private static String[] membersOf(Object obj)
    {
        Class<?> cls = (obj instanceof Class)
                     ? (Class<?>)obj
                     : obj.getClass();
        StringBuilder sb = new StringBuilder();
        sb.append("Přehled veřejných členů třídy ").append(cls)
          .append('\n');
        addFieldsOf      (cls, sb, D_INDENT);
        addConstructorsOf(cls, sb, D_INDENT);
        addMethodsOf     (cls, sb, D_INDENT);
        String str = sb.toString();
        str = str.replaceAll("java\\.lang\\.", "");
        String[] lines = str.split("\n");
        return lines;
    }


    /****************************************************************************
     * Vráží pole stringů popisujících veřejné členy zadané třídy,
     * resp. mateřské třídy zadané instance.
     *
     * @param  obj Class-objekt analyzované třídy, resp. odkaz na její instanci
     * @return Pole signatur členů analyzované třídy
     */
    private static String[] signatureOf(Object obj)
    {
        Class<?> cls = (obj instanceof Class)
                     ? (Class<?>)obj
                     : obj.getClass();
        StringBuilder sb = new StringBuilder();
        sb.append("Analýza datového typu: ").append(cls.getSimpleName())
          .append('\n').append(D_INDENT)
              .append("Balíček: ")
              .append(cls.getPackage().getName())
          .append('\n').append(D_INDENT)
              .append("Majitel: ")
              .append(cls.getDeclaringClass().getName())
          .append('\n').append(D_INDENT)
              .append("Bezprostřední předek: ")
              .append(cls.getSuperclass().getName())
          .append('\n');
        addImplementedInterfacesOf(cls, sb, D_INDENT);
        addFieldsOf      (cls, sb, D_INDENT);
        addConstructorsOf(cls, sb, D_INDENT);
        addMethodsOf     (cls, sb, D_INDENT);
        addNestedTypesOf (cls, sb, D_INDENT);
        String str = sb.toString();
        str = str.replaceAll("java\\.lang\\.", "");
        String[] lines = str.split("\n");
        return lines;
    }



//##############################################################################
//\IC== INSTANCE CONSTANTS (CONSTANT INSTANCE ATTRIBUTES/FIELDS) ===============
//\IV== INSTANCE VARIABLES (VARIABLE INSTANCE ATTRIBUTES/FIELDS) ===============



//##############################################################################
//\II== INSTANCE INITIALIZERS (CONSTRUCTORS) ===================================

    /****************************************************************************
     */
    private ClassInfo()
    {
    }



//\IA== INSTANCE ABSTRACT METHODS ==============================================
//\IG== INSTANCE GETTERS AND SETTERS ===========================================
//\IM== INSTANCE REMAINING NON-PRIVATE METHODS =================================
//\IP== INSTANCE PRIVATE AND AUXILIARY METHODS =================================



//##############################################################################
//\NT== NESTED DATA TYPES ======================================================
    {
        System.out.println("Třída ClassInfo se natáhla");
    }
}
