package com.jamonapi;

/** Class used to test all classes in JAMon.  It is only used during testing.  Mostly it calls other classes Main method.  JAMon
 *  places test code in main() methods.  TestClass also adds test code of its own
 **/

public class TestClass extends java.lang.Object implements Runnable {
    
    static final int THREADS=25000;
    private int threadNum;
    public TestClass(int threadNum, long lobits, long hibits, Monitor mon) {
        this.threadNum=threadNum;
        this.lobits=lobits;
        this.hibits=hibits;
        this.mon=mon;
    }
    
 
    public void run() {
        // Alternating threads are either setting the high or lo bit.  The idea is that if a thread
        // is interrupted before mon.increase(...) we may get a different value in mon than expected.
        // The expected value is compared to the actual value in main(...).
        try {
            long incr=0;
            if (threadNum%2==0) {
                incr=lobits;
            }
            else 
                incr=hibits;

            mon.add(incr);
        } catch(Exception e) {
            throw new RuntimeException(e.getMessage());
        }
    }
    long lobits, hibits;
    Monitor mon;
    static private class TimingMonitorThreads implements Runnable {
        Monitor mon;
        TimingMonitorThreads(Monitor mon) {
            this.mon=mon;
        }
        public void run() {
            mon.start().stop();
            MonitorFactory.start("multi-threaded test").stop();
            MonitorFactory.start("multi-threaded test").stop();
            MonitorFactory.start("multi-threaded test").stop();
            MonitorFactory.start("multi-threaded test").stop();
        }
    }
    
    public static void testMonKey(String label) {
        System.out.println("\n***** Testing getLabel, getUnits, getMonKey, getRange for "+label);
        Monitor mon=MonitorFactory.start(label).stop();
        System.out.println(mon.getMonKey());
        System.out.println(mon.getLabel());
        System.out.println(mon.getUnits());
        System.out.println(mon.getMonKey().getValue("label"));
        System.out.println(mon.getMonKey().getValue("Units"));
        System.out.println(mon.getRange());

    }
    public static void main(String[] args) throws Exception {
    	Monitor totalMon=MonitorFactory.start();
        System.out.println("***** Class unit tests");
        System.out.println("\nMonitorFactory.main()");
        MonitorFactory.main(null);
        System.out.println("\nTestClassPerformance.main()");
        TestClassPerformance.main(args);

        Monitor timingMon;
        System.out.println("\n***** MonitorFactory.getData():");

        Monitor m1=MonitorFactory.start("pages.purchase.test");
        Monitor m2=MonitorFactory.start("steve.souza.test");
        Thread.sleep(350);
        m1.stop();
        Thread.sleep(650);
        m2.stop();
        Object[][] rows=MonitorFactory.getData();
        for (int i=0; i<rows.length; i++) {
            String rowData="row"+i+"=[";
            for (int j=0; j<rows[0].length; j++) {
                rowData+=rows[i][j]+", ";
            }
            System.out.println(rowData+"]");
        }
        
        System.out.println("\n***** Multi-threaded test");

        long LOBIT=0x00000001;//1
        long HIBIT=0x10000000;//268,435,456
        timingMon=MonitorFactory.start();
        ThreadGroup threadGroup=new ThreadGroup("threadGroup");
        //Note mon1 is shared by all instances of the thread and so will test concurrent access.
        Monitor mon1=MonitorFactory.getTimeMonitor("mon1");
        for (int i=0; i<THREADS; i++) // mon1 should be THREADS*1
            new Thread(threadGroup, new TestClass(i, LOBIT, LOBIT, mon1)).start();
        Monitor mon2=MonitorFactory.getTimeMonitor("mon2");
        for (int i=0; i<THREADS; i++)//THREADS*HIBIT
            new Thread(threadGroup, new TestClass(i, HIBIT, HIBIT, mon2)).start();
        Monitor mon3=MonitorFactory.getTimeMonitor("mon3");
        for (int i=0; i<THREADS; i++)  //(THREADS/2)*LOBIT + (THREADS/2)*HIBIT  
            new Thread(threadGroup, new TestClass(i, LOBIT, HIBIT, mon3)).start();
        while(threadGroup.activeCount()!=0)
            ;
        System.out.println("Threads have finished processing. It took "+timingMon.stop());
        System.out.println("Total should equal "+THREADS+" - "+mon1);
        System.out.println("Total should equal "+THREADS*HIBIT+" - "+mon2);
        double threadCount=THREADS/2;
        System.out.println("Total should equal "+(threadCount*LOBIT + threadCount*HIBIT) +" - "+mon3);
        Monitor mon4=MonitorFactory.start("mon4");
        System.out.println("\nStarting mon4 thread test");
        Monitor mon4ThreadTest=MonitorFactory.start();
        threadGroup=new ThreadGroup("timingMonitorThreads");
        for (int i=0; i<THREADS; i++)
            new Thread(threadGroup, new TimingMonitorThreads(mon4)).start();
        while(threadGroup.activeCount()!=0)
            ;
        System.out.println("hits should be "+(THREADS+1)+"= "+mon4.stop());
        System.out.println("'multi-threaded test' hits should equal "+THREADS*4+" - "+MonitorFactory.getMonitor("multi-threaded test","ms."));
        System.out.println("Time for mon4 thread test="+mon4ThreadTest.stop());
        System.out.println("\n***** MonitorFactory.getHeader():");
        String[] header=MonitorFactory.getHeader();

        for (int i=0; i<header.length; i++)
           System.out.println(header[i]);

        testMonKey("TestingMonKey");
        MonitorFactory.disable();
        testMonKey("DisableTestingMonKey");
        MonitorFactory.enable();

        JAMonListenerFactory.main(null);
        ListenerType.main(null);
        
        System.out.println("\n***** MonitorFactory.getReport() 1:");
        System.out.println(MonitorFactory.getReport());
        System.out.println("\n***** Total Execution Time="+totalMon.stop());
    }
}


