import org.apache.fop.fo.properties.NumberProperty;
import org.apache.fop.fo.properties.PropertyCache;

public class PropCacheTester {
    
    private static final PropertyCache cache = new PropertyCache();
    private static final java.util.Map map = java.util.Collections.synchronizedMap(new java.util.WeakHashMap());
    private static NumberProperty[] nps;
    

    /**
     * @param args the command-line arguments:
     *          args[0] number of entries to put in the cache/map
     *          args[1] number of distinct fetches to perform (should be < arg[0])
     *          args[2] number of times to repeat the distinct fetches
     *          args[3] number of concurrent threads to spawn (for MT-tests)
     */
    public static void main(String args[]) {
        
        int entries = Integer.parseInt(args[0]);
        int fetches = Integer.parseInt(args[1]);
        if (fetches >= entries) {
            return;
        }
        
        int loops = Integer.parseInt(args[2]);
        int threads = Integer.parseInt(args[3]);
        
        long start;
        long end;

        PropertyCache propCache = new PropertyCache();
        System.out.print("Performing " + (loops * fetches) + " null-fetches on an empty cache");
        start = System.currentTimeMillis();
        for (int i = (loops * fetches); --i >= 0;) {
            propCache.fetch(null);
        }
        end = System.currentTimeMillis();
        System.out.println(" took " + (end - start) + "ms.");
        
        System.out.print("Performing " + (loops * fetches) + " identical NumberProperty-fetches on an empty cache");
        NumberProperty np = NumberProperty.getInstance(0);
        start = System.currentTimeMillis();
        for (int i = (loops * fetches); --i >= 0;) {
            propCache.fetch(np);
        }
        end = System.currentTimeMillis();
        System.out.println(" took " + (end - start) + "ms.");
        
        System.out.print("Initializing an array of " + entries + " canonical NumberProperty instances");
        start = System.currentTimeMillis();
        nps = new NumberProperty[entries];
        for (int i = entries; --i >= 0;) {
            nps[i] = NumberProperty.getInstance(i);
        }
        end = System.currentTimeMillis();
        System.out.println(" took " + (end - start) + "ms.");
        System.out.print("Filling the static cache with " + entries + " elements");
        start = System.currentTimeMillis();
        for (int j = entries; --j >= 0;) {
            PropCacheTester.cache.fetch(nps[j]);
        }
        end = System.currentTimeMillis();
        System.out.println(" took " + (end - start) + "ms.");
        
        System.out.print("Filling the static map with " + entries + " elements");
        start = System.currentTimeMillis();
        for (int j = entries; --j >= 0;) {
            PropCacheTester.map.put(nps[j], nps[j]);
        }
        end = System.currentTimeMillis();
        System.out.println(" took " + (end - start) + "ms.");
        
        
        System.out.println("Multithread test: ");
        Thread tCache = null;
        Thread tMap = null;
        
        System.out.println("  Spawning " + threads + " threads and performing " + (loops * fetches) + " fetches (" + loops + " * " + fetches + ") in each thread...");
        for (int i = threads; --i >= 0;) {
            tCache = new Thread(new CacheTester((threads - i), loops, fetches));
            tMap = new Thread(new MapTester((threads - i), loops, fetches));
            tMap.start();
            tCache.start();
        }

    }
    
    public static class CacheTester implements Runnable {
        
        private int index;
        private int i;
        private int j;
        
        public CacheTester(int index, int i, int j) {
            this.index = index;
            this.i = i;
            this.j = j;
        }
        
        public void run() {
            long start;
            long end;
            
            start = System.currentTimeMillis();
            for (;--i >= 0;) {
                for (int j = this.j; --j >= 0;) {
                    cache.fetch(nps[j]);
                }
            }
            end = System.currentTimeMillis();
            System.out.println("  Thread " + index + " (PropertyCache) took " + (end - start) + "ms.");
        }
    }
    
    public static class MapTester implements Runnable {
        
        private int index;
        private int i;
        private int j;
        
        public MapTester(int index, int i, int j) {
            this.index = index;
            this.i = i;
            this.j = j;
        }
        
        public void run() {
            long start;
            long end;
            
            start = System.currentTimeMillis();
            for (;--i >= 0;) {
                for (int j = this.j; --j >= 0;) {
                    map.get(nps[j]);
                }
            }
            end = System.currentTimeMillis();
            System.out.println("  Thread " + index + " (synchronizedMap) took " + (end - start) + "ms.");
        }
    }
    
}

