package shapes77.dbg;
// Příliš žluťoučký kůň úpěl ďábelské ó - PŘÍLIŠ ŽLUŤOUČKÝ KŮŇ ÚPĚL ĎÁBELSKÉ Ó

import java.util.List;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Set;



/********************************************************************************
 * Instances of class <b>{@code $CLASSNAME}</b> represents ...
 */
public class ThreadMessages
{
//== CONSTANT CLASS ATTRIBUTES =================================================
//
//    /** Deafult sign initializing meessages in the current thread. */
//    private static final Character DEFAULT_THREAD_SIGN = '-';

    /** Indent informing about next level. */
    private static final String INDENT = "> ";

    /** Start of measure. */
    private static final long TIME = System.currentTimeMillis();

    /** List of trailing strings creating indent. */
    private static final List<String> gap = new ArrayList<String>();
//
//    // Define/create thread local variable
//    private static final ThreadLocal<Integer> threadLevel =
//                                              new ThreadLocal<Integer>();
//    private static final ThreadLocal<Character> threadSign =
//                                                new ThreadLocal<Character>();

    /** Thread local variable with information for each thread. */
    private static final ThreadInfo threadInfo = new ThreadInfo();



//== VARIABLE CLASS ATTRIBUTES =================================================

    private static Character[] threadSigns = {'-', '+', '#', '*', '=', '?'};

    private static int threadCount = 0;



//== STATIC INITIALIZER - STATIC CONSTRUCTOR ===================================

    static {
        gap.add("");
    }



//== CONSTANT INSTANCE ATTRIBUTES ==============================================
//== VARIABLE INSTANCE ATTRIBUTES ==============================================
//== CLASS GETTERS AND SETTERS =================================================

    /***************************************************************************
     * Sets a new set of thread signs.
     *
     * @param threadSigns The set set
     */
    public static void setThreadSigns(Character[] threadSigns)
    {
        ThreadMessages.threadSigns = threadSigns;
    }



//== OTHER NON-PRIVATE CLASS METHODS ===========================================
//
//    /***************************************************************************
//     * @todo threadMsgInit - Je třeba ještě doplnit komentář
//     */
//    public void threadMsgInitialize()
//    {
//        threadLevel.set(0);
//        threadSign .set(threadSigns[0]);
//
//    }
//

    /***************************************************************************
     * Message announcing starting of some action - mostly a method.
     * As a sideefect the indent level of all subsequent messages
     * in the current thread increases.
     *
     * @param text Text of the sent message
     */
    public static synchronized void msgS(String text)
    {
        Info info = threadInfo.get();
        msg("Started:  " + text, info);
        int level = info.level + 1;
        if (level >= gap.size()) {
            gap.add(gap.get(level-1) + INDENT);
        }
        info.level = level;
    }


    /***************************************************************************
     * Message announcing finishing of some action - mostly a method.
     * As a sideefect the indent level of all subsequent messages
     * in the current thread decreases.
     *
     * @param text Text of the sent message
     */
    public static synchronized void msgF(String text)
    {
        Info info = threadInfo.get();
        info.level--;
        msg("Finished: " + text, info);
    }


    /***************************************************************************
     * Message informing about something.
     *
     * @param text Text of the sent message
     */
    public static synchronized void msg(String text)
    {
        Info info = threadInfo.get();
        msg(text, info);
    }



//##############################################################################
//== CONSTRUCTORS AND FACTORY METHODS ==========================================

    /** Private constructor protects creating of instances */
    private ThreadMessages() {}



//== ABSTRACT METHODS ==========================================================
//== INSTANCE GETTERS AND SETTERS ==============================================
//== OTHER NON-PRIVATE INSTANCE METHODS ========================================
//== PRIVATE AND AUXILIARY CLASS METHODS =======================================

    /***************************************************************************
     * Message informing about something.
     *
     * @param text Text of the sent message
     * @param info Thread local variable with some information
     */
    private static synchronized void msg(String text, Info info)
    {
        double time  = (System.currentTimeMillis() - TIME) / 1000.0;
        System.out.printf("%8.3f %c %s%s%n",
                          time, info.sign, gap.get(info.level), text);
        time = 0;
    }



//== PRIVATE AND AUXILIARY INSTANCE METHODS ====================================
//== EMBEDDED AND INNER CLASSES ================================================

    /***************************************************************************
     * Instances of class {@code ThreadInfo} represents thread local variable
     * containtg some importatn information for debug print
     */
    private static class ThreadInfo extends ThreadLocal<Info>
    {
    //== CONSTANT CLASS ATTRIBUTES =============================================

        /** Set of registered threads. */
        private static final Set<Thread> threadSet = new HashSet<Thread>();


    //== VARIABLE CLASS ATTRIBUTES =============================================
    //== STATIC CONSTRUCTOR (CLASS INITIALIZER, STATIC INICITALIZING BLOCK) ====
    //== CONSTANT INSTANCE ATTRIBUTES ==========================================
    //== VARIABLE INSTANCE ATTRIBUTES ==========================================
    //== CLASS GETTERS AND SETTERS =============================================
    //== OTHER NON-PRIVATE CLASS METHODS =======================================

    //##########################################################################
    //== CONSTRUCTORS AND FACTORY METHODS ======================================

        /************************************************************************
         *
         */
        private ThreadInfo()
        {
        }



    //== ABSTRACT METHODS ======================================================
    //== INSTANCE GETTERS AND SETTERS ==========================================
    //== OTHER NON-PRIVATE INSTANCE METHODS ====================================

        /************************************************************************
         *
         * @return xxx
         */
        @Override
        protected final Info initialValue()
        {
            Thread thread = Thread.currentThread();
            if (threadSet.contains(thread)) {
                throw new IllegalStateException(
                    "\nThread variable for the current thread is already "
                    + "initialized - thread: " + thread);
            }
            int id = threadSet.size();
            Info info = new Info(id, thread);
            threadSet.add(thread);
            return info;
        }


        @Override
        public void remove()
        {
            throw new UnsupportedOperationException(
                  "Removing this variables is not allowed");
        }


        @Override
        public void set(Info value)
        {
            throw new UnsupportedOperationException(
                  "Setting into this variables is not allowed");
        }



    //== PRIVATE AND AUXILIARY CLASS METHODS ===================================
    //== PRIVATE AND AUXILIARY INSTANCE METHODS ================================
    //== EMBEDDED TYPES AND INNER CLASSES ======================================
    //== TESTING CLASSES AND METHODS ===========================================
    }



///#############################################################################
///#############################################################################
///#############################################################################

    /***************************************************************************
     * Instances of class {@code Info} represents ...
     */
    private static class Info
    {
        private final int       id;
        private final Thread    thread;
        private final Character sign;
        private       int       level;


    //##########################################################################
    //== CONSTRUCTORS AND FACTORY METHODS ======================================

        /************************************************************************
         *
         */
        private Info(int id, Thread thread)
        {
            this.id     = id;
            this.thread = Thread.currentThread();
            this.sign   = threadSigns[id];
            this.level  = 0;
        }



    //== ABSTRACT METHODS ======================================================
    //== INSTANCE GETTERS AND SETTERS ==========================================
    //== OTHER NON-PRIVATE INSTANCE METHODS ====================================
    //== PRIVATE AND AUXILIARY CLASS METHODS ===================================
    //== PRIVATE AND AUXILIARY INSTANCE METHODS ================================
    //== EMBEDDED TYPES AND INNER CLASSES ======================================
    //== TESTING CLASSES AND METHODS ===========================================
    }



///#############################################################################
///#############################################################################
///#############################################################################

//== TESTING CLASSES AND METHODS ===============================================
//
//    /***************************************************************************
//     * Testing method.
//     */
//    public static void test()
//    {
//    }
//    /** @param args Command line arguments - not used. */
//    public static void main( String[] args )  {  test();  }
}
