/*
 * @author Ranides Atterwim <ranides@gmail.com>
 * @copyright Ranides Atterwim
 * @license WTFPL
 * @url http://ranides.net/projects/assira
 */
package net.ranides.assira.system;

import java.util.LinkedList;
import java.util.List;
import net.ranides.assira.generic.PrivilegedActions;
import net.ranides.assira.math.Numeric;
import net.ranides.assira.trace.AdvLogger;
import net.ranides.assira.trace.LoggerUtils;

/**
 *
 * @author Ranides Atterwim <ranides@gmail.com>
 */
public final class RuntimeUtils {
    
    private static final AdvLogger LOGGER = LoggerUtils.getLogger();
    
    private RuntimeUtils() {
        // utility class
    }
    
    public static long getMemoryUse() {
        Runtime runtime = Runtime.getRuntime();
        return runtime.totalMemory() - runtime.freeMemory();
    }
    
    
    /**
     * Runs the garbage collector. 
     * @return 
     *      Estimated amount of memory released by GC
     *      
     */
    @SuppressWarnings("PMD.DoNotCallGarbageCollectionExplicitly")
    public static long performGC() {
        long prev = getMemoryUse();
        Runtime.getRuntime().gc();
        return prev - getMemoryUse();
    }
    
    /**
     * Forces releasing {@code SoftReferences}, by causing OutOfMemoryError in VM.
     * @return 
     *      Estimated amount of memory released by GC
     */
    @SuppressWarnings("PMD.DoNotCallGarbageCollectionExplicitly")
    public static long forceGC() {
        long prev = Runtime.getRuntime().totalMemory();
        int block = (int)Math.min(Integer.MAX_VALUE, Runtime.getRuntime().freeMemory());
        try {
            final List<long[]> memhog = new LinkedList<>();
            while(true) {
                memhog.add(new long[block]);
            }
        }
        catch(final OutOfMemoryError e) {
            // at this point all SoftReferences have been released - GUARANTEED
            long alloc = Runtime.getRuntime().totalMemory() - prev;
            LOGGER.fdebug("Forced OutOfMemoryError by allocation %s bytes", Numeric.format(alloc));
            Runtime.getRuntime().gc();
            // at this point we should use minimal amount of memory
            return prev - getMemoryUse();
        }
    }
    
    
    public static boolean invokedInsideMaven() {
        for(StackTraceElement item : new Exception().getStackTrace()) {
            if( item.getClassName().contains("org.apache.maven.surefire.junit4.JUnit4TestSet") ) { return true; }
        }
        return false;
    }

    public static boolean invokedInsideSingleTest() {
        return Li.SINGLE_TEST;
    }
    
    private static final class Li { // NOPMD lazy init idiom
        
        private static final boolean SINGLE_TEST = PrivilegedActions.getProperty("test") != null;
        
    }
}
