/*
 * Copyright (c) 2009, 2011 Oracle and/or its affiliates. All rights reserved.
 * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
 */

/*
 * $Id: ClientGenerator.java 62523 2011-04-14 22:07:00Z dougd $
 */
 
package com.sun.ts.tests.jsf.common.util;

import java.io.BufferedOutputStream;
import java.io.FileOutputStream;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;

/**
 * <p>Utility class to generate clients for API tests.</p>
 */ 
public class ClientGenerator {
    private static final String NL = System.getProperty("line.separator", "\n");
    
    Class testClass;
    String contextRoot;
    
    public ClientGenerator(Class testClass, String contextRoot) {
        this.testClass = testClass;
        this.contextRoot = contextRoot;
    }
    
    public static void main(String[] args) {
        if (args.length > 1) {
            Class testClass = loadClass(args[0]);
            if (testClass == null) {
                System.out.println("Unable to load specified class: '" + args[0] + "'");
                System.exit(1);
                
            }
            ClientGenerator generator = new ClientGenerator(testClass, args[1]);
            generator.generateClient();
        }
    }
    
    public void generateClient() {
        String packageName = testClass.getPackage().getName();
        String[] testMethods = getTestEntries();
        StringBuffer sb = new StringBuffer(2048);
        writeClassHeader(sb, packageName, contextRoot);
        for (String testMethod : testMethods) {
            writeTestEntry(sb, testMethod);
        }
        writeEndClass(sb);
        try {
            writeBytesToFile(sb.toString().getBytes("UTF-8"));
        } catch (Throwable t) {
            // ignore
        }
       
    }
        
    private static Class loadClass(String className) {
        Class clazz = null;
        String clsName = className;
        if (clsName.indexOf('/') != -1) {
            clsName = clsName.replace('/', '.');
        }
        try {
            clazz = Thread.currentThread().getContextClassLoader().loadClass(clsName);
        } catch (Throwable t) {
            System.err.println(t.toString());
            // do nothing...return null;
        }
        return clazz;
    }
    
    private void writeBytesToFile(byte[] bytes) {
        BufferedOutputStream out = null;
        try {
            out = new BufferedOutputStream(
                    new FileOutputStream("URLClient.java"));        
            out.write(bytes);
            out.flush();          
        } catch (Throwable t) {
            System.err.println("Error writing client: " + t.toString());
            t.printStackTrace();
            System.exit(1);
        } finally {
            if (out != null) {
                try {
                    out.close();
                } catch (Throwable t) {
                    // ignore
                }
            }
        }
    }
    
    private String[] getTestEntries() {
        Method[] methods = testClass.getMethods();
        List<String> methodList = new ArrayList<String>();
        for (Method method : methods) {
            String methodName = method.getName();
            if (methodName.endsWith("Test")) {
                methodList.add(methodName);
            }
        }
        return methodList.toArray(new String[methodList.size()]);
    }
    
    private void writeClassHeader(StringBuffer buffer, String packageName, String contextRoot) {
        buffer.append("/*" + NL);
        buffer.append(" * Copyright (c) 2005, 2011 Oracle and/or its affiliates. All rights reserved." + NL);
        buffer.append(" * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms." + NL);
        buffer.append(" *" + NL);
        buffer.append("/*" + NL);
        buffer.append(NL);
        buffer.append(" * ").append('%').append("W% %").append('G').append("%" + NL);
        buffer.append(" *" + NL);
        buffer.append(NL);
        buffer.append("package ").append(packageName).append(";" + NL);
        buffer.append(NL);
        buffer.append("import java.io.PrintWriter;" + NL);
        buffer.append("import com.sun.javatest.Status;" + NL);
        buffer.append("import com.sun.ts.tests.jsf.common.client.AbstractUrlClient;" + NL);
        buffer.append(NL);
        buffer.append("public final class URLClient extends AbstractUrlClient {" + NL);
        buffer.append(NL);
        buffer.append("    private static final String CONTEXT_ROOT = \"");
        buffer.append(contextRoot).append("\";" + NL);
        buffer.append("    public static void main(String[] args) {" + NL);
        buffer.append("        URLClient theTests = new URLClient();" + NL);     
        buffer.append("        Status s = theTests.run(args," + NL);
        buffer.append("                                new PrintWriter(System.out, true)," + NL);
        buffer.append("                                new PrintWriter(System.err, true));" + NL);
        buffer.append("        s.exit();" + NL);
        buffer.append("    }" + NL);
        buffer.append("    public Status run(String[] args, PrintWriter out, PrintWriter err) {" + NL);
        buffer.append("        setContextRoot(CONTEXT_ROOT);" + NL);
        buffer.append("        setServletName(DEFAULT_SERVLET_NAME);" + NL);
        buffer.append("         return super.run(args, out, err);" + NL);
        buffer.append("    }" + NL);        
        buffer.append("    /*" + NL);
        buffer.append("     * @class.setup_props: webServerHost; webServerPort; ts_home;" + NL);
        buffer.append("     *" + NL);
        buffer.append("    /* Test Declarations *" + NL);
    }
    
    private void writeTestEntry(StringBuffer buffer, String testName) {
        buffer.append(NL);
        buffer.append("    /*" + NL);
        buffer.append("     * @").append("testName: ").append(testName).append(NL);
        buffer.append("     * @assertion_ids: PENDING: add assertion ID(s)" + NL);
        buffer.append("     * @test_Strategy: PENDING: add test strategy" + NL);
        buffer.append("     */" + NL);
        buffer.append("    public void ").append(testName).append("() throws Fault {" + NL);
        buffer.append("        TEST_PROPS.setProperty(APITEST, \"").append(testName).append("\");" + NL);
        buffer.append("        invoke();" + NL);
        buffer.append("    }" + NL);
    }
    
    private void writeEndClass(StringBuffer buffer) {
        buffer.append(NL);
        buffer.append("} // end of URLClient" + NL);
    }
        
}
