package de.duehl.basics.caller;

/*
 * Copyright 2022 Christian Dühl. All rights reserved.
 *
 * This program is free software. You can redistribute it and/or
 * modify it under the same terms as perl:
 *
 * general:  http://dev.perl.org/licenses/
 * GPL:      http://dev.perl.org/licenses/gpl1.html
 * artistic: http://dev.perl.org/licenses/artistic.html
 */

import java.util.ArrayList;
import java.util.List;

import de.duehl.basics.collections.CollectionsHelper;

/**
 * Diese Klasse stellt fest, woher ein Aufruf kam.
 *
 * @version 1.01     2022-11-02
 * @author Christian Dühl
 */

public class CallerDeterminer {

    private static final int INDEX_WE_WANT = 5;

    /** Gibt eine ungekürzte Liste mit den Stacktrace-Elementen zurück. */
    public static List<NiceStackTraceElement> getStacktraceElements() {
        StackTraceElement[] stackTraceElements = Thread.currentThread().getStackTrace();

        List<NiceStackTraceElement> list = new ArrayList<>();
        for (StackTraceElement element : stackTraceElements) {
            NiceStackTraceElement niceElement = new NiceStackTraceElement(element);
            list.add(niceElement);
        }

        return list;
    }

    /** Ermittelt den Aufrufer des Objekts, welches diese Methode aufruft. */
    public static Class<?> determineCallingClass() {
        NiceStackTraceElement element = getCallerElement(0);
        return element.getClassObject();
    }

    /**
     * Ermittelt den Aufrufer des Objekts, welches diese Methode aufruft.
     *
     * @param addToIndex
     *            Erhöhung des Index zum Ermitteln der richtigen Aufrufklasse.
     * @return Klasse des Aufrufers.
     */
    public static Class<?> determineCallingClass(int addToIndex) {
        NiceStackTraceElement element = getCallerElement(addToIndex);
        return element.getClassObject();
    }

    /** Ermittelt den Klassennamen des Objekts, welches diese Methode aufruft. */
    public static String determineCallingClassName() {
        NiceStackTraceElement element = getCallerElement(0);
        return element.getClassName();
    }

    private static NiceStackTraceElement getCallerElement(int addToIndex) {
        List<NiceStackTraceElement> elements = getStacktraceElements();
        if (elements.size() < INDEX_WE_WANT + addToIndex) {
            throw new RuntimeException(
                    "Die Liste der Stack-Trace-Elemente ist nicht groß genug!\n\t"
                    + "elements = " + CollectionsHelper.listListNice(elements));
        }
        //CollectionsHelper.printListNice(elements); // TODO REMOVE
        NiceStackTraceElement element = elements.get(INDEX_WE_WANT + addToIndex);
        return element;
    }

    /** Ermittelt den Klassennamen des Objekts, welches diese Methode aufruft. */
    public static String determineCallingMethodName() {
        NiceStackTraceElement element = getCallerElement(0);
        return element.getMethodName();
    }

}
