/*
 * $Id$
 *
 * Copyright 1996-2008 Sun Microsystems, Inc.  All Rights Reserved.
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * This code is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 only, as
 * published by the Free Software Foundation.  Sun designates this
 * particular file as subject to the "Classpath" exception as provided
 * by Sun in the LICENSE file that accompanied this code.
 *
 * This code is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * version 2 for more details (a copy is included in the LICENSE file that
 * accompanied this code).
 *
 * You should have received a copy of the GNU General Public License version
 * 2 along with this work; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
 * CA 95054 USA or visit www.sun.com if you need additional information or
 * have any questions.
 */
package com.sun.javatest;

import java.io.File;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Iterator;

import com.sun.interview.WizPrint;
import com.sun.javatest.httpd.JThttpProvider;
import com.sun.javatest.httpd.PageGenerator;
import com.sun.javatest.httpd.RootRegistry;
import com.sun.javatest.httpd.httpURL;
import com.sun.javatest.util.I18NResourceBundle;
import com.sun.javatest.util.PropertyArray;
import com.sun.javatest.util.StringArray;

class HarnessHttpHandler extends JThttpProvider
    implements Harness.Observer
{
    HarnessHttpHandler(Harness harness) {
	this.harness = harness;
	harness.addObserver(this);
    }

    public void serviceRequest(httpURL requestURL, PrintWriter out) {
	String nf = requestURL.getNextFile();
	if (nf == null) {			    // request for root
	    beginGood(out);
	    printHtml(out);
	}
	else if (nf.equals("env")) {		    // environment dump
	    beginGood(out);
	    printEnv(out);
	}
	else if (nf.equals("interview")) {	    // interview dump
	    beginGood(out);
	    printInterview(out);
	}
	else if (nf.equals("text"))		    // get text only data
	    printText(requestURL, out);
	else if (nf.equals("stop")) {	    // stop the harness
	    if (!harness.isRunning()) {
		println(out, i18n.getString("harnessHttp.noStop"));
	    }
	    else { 
		// generate the token if it hasn't already been
		beginGood(out);
		if (magicToken == null) {
		    long num = Math.round(Math.floor(Math.random() * 30000.0 ));
		    magicToken = Integer.toString((int)num);
		}

		PageGenerator.writeHeader(out, i18n.getString("harnessHttp.stop.hdr"));
		PageGenerator.startBody(out);

		String token = requestURL.getValue("token");
		if (token == null)
		    printStopConfirm(out);
		else if (token.equals(magicToken)) {
		    harness.stop();
		    println(out, i18n.getString("harnessHttp.stopped"));
		}
		else {
		    printStopErr(out);
		}

		out.println("<hr>");
		PageGenerator.writeFooter(out);
		PageGenerator.endBody(out);
		PageGenerator.writeEndDoc(out);
	    }
	}
	else {				    // bad url
	    if (debug)
		System.out.println("TRT.HH-remainder of URL unknown (" + nf + ")");

	    beginBad(out);
	    printHtml(out);
	}

	out.close();
    }

    private void beginGood(PrintWriter out) {
	PageGenerator.generateOkHttp(out);
	PageGenerator.generateDocType(out, PageGenerator.HTML32);
    }

    private void beginBad(PrintWriter out) {
	PageGenerator.generateBadHttp(out);
	PageGenerator.generateDocType(out, PageGenerator.HTML32);
    }

    /**
     * Print the basic HTML page for Harness.
     */
    private void printHtml(PrintWriter out) {
	PageGenerator.writeBeginDoc(out);

	printIndex(out);

	out.println("<hr>");
	PageGenerator.writeFooter(out);
	PageGenerator.endBody(out);
	PageGenerator.writeEndDoc(out);
    }

    /**
     * Print the environment settings in formatted HTML.
     */
    private void printEnv(PrintWriter out) {
	PageGenerator.writeBeginDoc(out);
	PageGenerator.writeHeader(out, i18n.getString("harnessHttp.env.title"));

	out.print("<h3>");
	print(out, i18n.getString("harnessHttp.env.hdr"));
	out.println("</h3>");

	Parameters params = harness.getParameters();
	if (params != null)
	    printEnv(out, params.getEnv());
	else
	    out.println(i18n.getString("harnessHttp.env.none"));

	out.println("<hr>");
	PageGenerator.writeFooter(out);
	PageGenerator.endBody(out);
	PageGenerator.writeEndDoc(out);
    }

    /**
     * Print the interview settings in formatted HTML.
     */
    private void printInterview(PrintWriter out) {
	PageGenerator.writeBeginDoc(out);
	PageGenerator.writeHeader(out, i18n.getString("harnessHttp.interview.title"));

	out.print("<h3>");
	print(out, i18n.getString("harnessHttp.interview.hdr"));
	out.println("</h3>");

	try {
	    Parameters params = harness.getParameters();
	    if (params == null ||
		!(harness.getParameters() instanceof InterviewParameters)) {
		println(out, i18n.getString("harnessHttp.interview.none"));
	    }
	    else {
		InterviewParameters interview = (InterviewParameters)(harness.getParameters());
		WizPrint wp = new WizPrint(interview);
		wp.setShowResponses(true);
		wp.setShowResponseTypes(true);
		wp.setShowTags(true);
		wp.write(out);
	    }	// else

	    out.println("<hr>");
	    PageGenerator.writeFooter(out);
	    PageGenerator.endBody(out);
	    PageGenerator.writeEndDoc(out);
	}   // try
	catch (IOException e) {
	    println(out, i18n.getString("harnessHttp.ioProblem"));
	}   // catch
    }

    /** 
     * Access to raw text output pages.
     * We choose to not including the standard HTTP response header when
     * returning plain text.  This makes it easier to process on the client side.
     */
    private void printText(httpURL requestURL, PrintWriter out) {
	// write directly to out in this method, we are not
	// transmitting HTML encoded data
	Parameters params = harness.getParameters();
	String nf = requestURL.getNextFile();
	if (nf == null) {
	    beginGood(out);
	    printIndex(out);
	}
	else if (nf.equals("env")) {
	    // special case for incomplete interview?

	    TestEnvironment env = params.getEnv();

	    if (env == null) {
		print(out, i18n.getString("harnessHttp.env.none"));
		return;
	    }

	    /* does not fit in the properties style output
	    out.print(i18n.getString("harnessHttp.env.name"));
	    out.println(env.getName());
	    */

	    String[] pa = new String[0];
		
	    for (Iterator i = env.elements().iterator(); i.hasNext(); ) {
		TestEnvironment.Element elem = (TestEnvironment.Element) (i.next());
		// this is stunningly inefficient and should be fixed
		pa = PropertyArray.put(pa, elem.getKey(), elem.getValue());
	    }

	    try {
		PropertyArray.save(pa, out);
	    }
	    catch (IOException e) {
		// this is probably useless since problems with out
		// probably caused this
		out.println(i18n.getString("harnessHttp.ioProblem"));
	    }
	}
	else if (nf.equals("config")) {
	    if (params == null) {
		out.print(i18n.getString("harnessHttp.text.unavail"));
		return;
	    }

	    // test suite info
	    TestSuite ts = params.getTestSuite();
	    out.print(i18n.getString("harnessHttp.text.ts.path"));
	    out.print("=");
	    if (ts != null) {
		out.println(ts.getPath());
	    }
	    else
		out.println(i18n.getString("harnessHttp.text.empty"));

	    out.print(i18n.getString("harnessHttp.text.ts.name"));
	    out.print("=");
	    if (ts != null) {
		out.println(ts.getName());
	    }
	    else
		out.println(i18n.getString("harnessHttp.text.empty"));

	    out.print(i18n.getString("harnessHttp.text.wd.val"));
	    out.print("=");
	    WorkDirectory wd = params.getWorkDirectory();
	    if (wd != null)
		out.println(wd.getPath());
	    else
		out.println(i18n.getString("harnessHttp.text.empty"));
	}
	else if (nf.equals("tests")) {
	    if (params == null) {
		out.print(i18n.getString("harnessHttp.text.unavail"));
		return;
	    }

	    String[] tests = params.getTests();
	    if (tests != null && tests.length != 0) {
		for (int i = 0; i < tests.length; i++) {
		    out.print("url");
		    out.print(Integer.toString(i));
		    out.print("=");
		    out.println(tests[i]);
		}   // for
	    }
	}
	else if (nf.equals("stats")) {
	    if (!harness.isRunning()) {
		out.println("");
		return;
	    }

	    stats[Status.NOT_RUN] = harness.getTestsFoundCount() - stats[Status.PASSED] -
	    			stats[Status.FAILED] - stats[Status.ERROR];

	    for (int i = 0; i < Status.NUM_STATES; i++) {
		out.print((Status.typeToString(i)).replace(' ', '_'));
		out.print("=");
		out.println(stats[i]);
	    }   // for
	}
	else if (nf.equals("state")) {
	    // provide information about the Harness' state
	    print(out, i18n.getString("harnessHttp.state.run.val"));
	    out.println(harness.isRunning());
	}
	else if (nf.equals("results")) {
	    // test dump
	    TestResultTable trt = harness.getResultTable();
	    TestFilter[] filters = params.getFilters();
	    String[] tests = params.getTests();

	    Iterator it = null;
	    if (tests == null || tests.length == 0)
		it = trt.getIterator(filters);
	    else
		it = trt.getIterator(params.getTests(), filters);

	    while (it.hasNext()) {
		TestResult tr = (TestResult)(it.next());
		out.println(tr.getTestName());
		out.println(tr.getStatus().toString());
	    }	// while
	}
	else {
	    if (debug)
		System.out.println("TRT.HH-remainder of URL unknown (" + nf + ")");

	    println(out, i18n.getString("harnessHttp.badRequest", requestURL.getFullPath()));
	}
    }

    private void printStopConfirm(PrintWriter out) {
	out.print("<h2>");
	print(out, i18n.getString("harnessHttp.stopConfirm.hdr"));
	out.println("</h2>");
	out.print("<h4>");
	print(out, i18n.getString("harnessHttp.stopConfirm.txt"));
	out.println("</h4>");
	out.print("<Form method=get enctype=application/x-www-form-urlencoded>");

	out.print("<p><Input align=center type=submit value=");
	out.print(i18n.getString("harnessHttp.stopConfirm.btn"));
	out.println(">");
	out.print("<Input type=hidden name=token value=");
	out.print(magicToken);
	out.println("></Form>");
    }

    private void printStopErr(PrintWriter out) {
	out.println("<h2>");
	println(out, i18n.getString("harnessHttp.stopErr.hdr"));
	out.println("</h2>");
	out.println("<b>");
	println(out, i18n.getString("harnessHttp.stopErr.text1"));
	println(out, i18n.getString("harnessHttp.stopErr.text2"));
	out.println("</b>");
	out.println("<p>");
	println(out, i18n.getString("harnessHttp.stopErr.text3"));
	out.println("<a href=\"/harness/stop\">");
	println(out, i18n.getString("harnessHttp.stopErr.text4"));
	out.println("</a>");
	println(out, i18n.getString("harnessHttp.stopErr.text5"));
    }

    private void printIndex(PrintWriter out) {
	PageGenerator.writeHeader(out, i18n.getString("harnessHttp.index.title"));
	PageGenerator.startBody(out);
	out.println("<h2>");
	out.print("JT Harness &#8482; ");
	println(out, i18n.getString("harnessHttp.index.hdr"));
	out.println("</h2>");

	Parameters params = harness.getParameters();
	if (params == null) {
	    out.println(i18n.getString("harnessHttp.parameters.noParams"));
	    return;
	}

	// print test suite
	print(out, i18n.getString("harnessHttp.parameters.tsName"));
	String name = params.getTestSuite().getName();
	println(out, (name == null ?
		      i18n.getString("harnessHttp.parameters.noTs") :
		      name));

	out.println("<br>");
	print(out, i18n.getString("harnessHttp.parameters.tsPath"));
	File tsr = params.getTestSuite().getRoot();
	println(out, (tsr == null ?
		      i18n.getString("harnessHttp.parameters.noTs") :
		      tsr.getPath()));

	out.println("<br>");

	// print workdir
	print(out, i18n.getString("harnessHttp.parameters.wd"));

	WorkDirectory wd = params.getWorkDirectory();
	if (wd != null)
	    println(out, wd.getPath());
	else
	    print(out, i18n.getString("harnessHttp.parameters.noWd"));

	out.println("<p>");

	// print parameters
	printParameters(out, params);

	// print results link
	TestResultTable currentResults = harness.getResultTable();
	out.println("<h3>");
	println(out, i18n.getString("harnessHttp.results.hdr"));
	out.println("</h3>");
	if (currentResults != null) {
	    JThttpProvider trtProv = RootRegistry.getObjectHandler(currentResults);
	    if (trtProv != null && trtProv.getRootURL() != null) {
		out.print("<a href=\"");
		out.print(trtProv.getRootURL());
		out.print("\">");
		print(out, i18n.getString("harnessHttp.trt.link"));
		out.println("</a>");
	    }
	}
	else {
	    out.print(i18n.getString("harnessHttp.trt.none"));
	}
    }

    private void printParameters(PrintWriter out, Parameters params) {
	out.println("<h3>");
	println(out, i18n.getString("harnessHttp.parameters.hdr"));
	out.println("</h3>");

	print(out, i18n.getString("harnessHttp.parameters.env"));
	TestEnvironment tev = params.getEnv();
	if (tev != null) {
	    out.print("<a href=\"");
	    out.print(getRootURL());
	    out.print("/env\">");

	    print(out, tev.getName());
	    out.println("</a>");
	}
	else {
	    println(out, i18n.getString("harnessHttp.parameters.noEnv"));
	}

	out.println("<br>");

	print(out, i18n.getString("harnessHttp.parameters.interview"));
	if (params instanceof InterviewParameters) {
	    InterviewParameters ip = (InterviewParameters)params;
	    File ipf = ip.getFile();

	    out.print("<a href=\"");
	    out.print(getRootURL());
	    out.print("/interview\">");
	    print(out, (ipf == null ?
		       i18n.getString("harnessHttp.parameters.noInterviewFile") :
		       ipf.getPath()));
	    out.println("</a>");
	}
	else {
	    println(out, i18n.getString("harnessHttp.parameters.noInterview"));
	}

	out.println("<p>");

	// initial files info
	out.println("<ul>");
	out.print("<li>");
	print(out, i18n.getString("harnessHttp.parameters.urls"));
	printTests(out);

	// jtx info
	out.print("<li>");
	print(out, i18n.getString("harnessHttp.parameters.jtx"));
	Parameters.ExcludeListParameters exclParams = params.getExcludeListParameters();

	if (exclParams instanceof Parameters.MutableExcludeListParameters) {
	    Parameters.MutableExcludeListParameters e = 
		(Parameters.MutableExcludeListParameters) (exclParams);
	    File[] jtx = e.getExcludeFiles();
	    if (jtx == null || jtx.length == 0)
		println(out, i18n.getString("harnessHttp.parameters.emptyJtx"));
	    else {
		out.println("<ul>");
		for (int i = 0; i < jtx.length; i++)
		    out.println("<li>" + jtx[i].getPath());

		out.println("</ul>");
	    }
	}
	else {
	    println(out, i18n.getString("harnessHttp.parameters.noJtx"));
	}

	// keyword info
	/* removed until output can be improved
	out.print("<li>");
	print(out, i18n.getString("harnessHttp.parameters.keyw"));
	out.println(params.getKeywords());
	*/

	out.println("</ul>");

	// status
    }

    private void printTests(PrintWriter out) {
	String[] tests = harness.getParameters().getTests();
	if (tests == null || tests.length == 0) {
	    print(out, i18n.getString("harnessHttp.parameters.noTests"));
	}
	else {
	    out.println("<ul>");

	    for (int i = 0; i < tests.length; i++) {
		out.println("<li>");
		println(out, tests[i]);
	    }

	    out.println("</ul>");
	}
    }   // printTests()

    private void printEnv(PrintWriter out, TestEnvironment env) {
	out.print(i18n.getString("harnessHttp.env.name"));
	println(out, env.getName());

	String keyHeader = "Key";
	String valHeader = "Value";
	    
	out.println("<Table Border>");

	StringBuffer buf = new StringBuffer(50);

	// write the table header
	buf.append("<tr><th>");
	buf.append(filterTags(keyHeader));
	buf.append("<th>");
	buf.append(filterTags(valHeader));
	buf.append("</tr>");
	out.println(buf.toString());

	for (Iterator keys = env.keys().iterator(); keys.hasNext(); ) {
	    String key = (String) (keys.next());
	    out.println("<tr>");
	    buf.setLength(0);
	    buf.append("<td>");
	    buf.append(key.toString());
	    buf.append("<td>");
	    try {
		buf.append(filterTags(StringArray.join((env.lookup(key)))));
	    }
	    catch (TestEnvironment.Fault f) {
		buf.append(i18n.getString("harnessHttp.env.error"));
	    }

	    out.println(buf.toString());
	    out.println("</tr>");
	}   // while

	out.println("</Table>");
    }

    // ------------ instance vars ------------
    private Harness harness;
    private boolean debug = false;
    private String magicToken;
    private int[] stats = new int[Status.NUM_STATES];
    private TestFinderQueue tfq;
    private static I18NResourceBundle i18n = I18NResourceBundle.getBundleForClass(HarnessHttpHandler.class);
	
    // ------------ Harness.Observer ------------
    public void startingTestRun(Parameters params) { }

    public void startingTest(TestResult tr) { }

    public void finishedTest(TestResult tr) {
	stats[tr.getStatus().getType()]++;
    }

    public void stoppingTestRun() { }
    public void finishedTesting() { }
    public void finishedTestRun(boolean allOK) { }

    public void error(String msg) { }
}
