// ProxyStatistics.java
// $Id: ProxyStatistics.java,v 1.6 1997/01/17 09:56:18 abaird Exp $
// (c) COPYRIGHT MIT and INRIA, 1996.
// Please first read the full copyright statement in file COPYRIGHT.html

package w3c.jigsaw.proxy ;

import java.util.*;

import w3c.tools.store.*;
import w3c.www.http.*;
import w3c.www.protocol.http.HttpManager;
import w3c.www.protocol.http.cache.*;

import w3c.jigsaw.html.*;
import w3c.jigsaw.http.*;
import w3c.jigsaw.resources.*;

public class ProxyStatistics extends FilteredResource {
    /**
     * Attribute index - The refresh reate.
     */
    protected static int ATTR_REFRESH = -1;

    static {
	Class     c = null;
	Attribute a = null;
	try {
	    c = Class.forName("w3c.jigsaw.proxy.ProxyStatistics");
	} catch (Exception ex) {
	    ex.printStackTrace();
	    System.exit(1);
	}
	// Register the refresh attribute:
	a = new IntegerAttribute("refresh"
				 , new Integer(10)
				 , Attribute.EDITABLE);
	ATTR_REFRESH = AttributeRegistry.registerAttribute(c, a);
    }
    /**
     * The statistics of the cache filter we are attached to.
     */
    cacheStatistics stats = null;

    /**
     * Get the refresh rate.
     * @return The refresh rate as a number of seconds.
     */

    public int getRefresh() {
	return getInt(ATTR_REFRESH, 10);
    }

    /**
     * Get this resource.
     * Dump the available statistics.
     * @param request The incoming request.
     * @return A Reply instance.
     */

    public Reply get(Request request) 
	throws HTTPException
    {
	HtmlGenerator g = new HtmlGenerator("Proxy statistics");
	Reply reply = createDefaultReply(request, HTTP.OK);
	if ( stats == null ) {
	    g.append("<h1>No cache filter found</h1>");
	    g.append("<p>This proxy probably doesn't use caching.");
	} else {
	    int hits    = stats.getHits();
	    int rhits   = stats.getRealHits();
	    int misses  = stats.getMisses();
	    int gvalid  = stats.getGoodRevalidations();
	    int bvalid  = stats.getBadRevalidations();
	    int pending = stats.getPending();
	    int ncache  = stats.getNotCachable();
	    g.meta("Refresh", Integer.toString(getRefresh()));
	    g.append("<h1>Proxy statistics</h1>");
	    g.append("<p>The proxy was last started at: <em>"
                     + new Date(stats.getStartTime())
		     + "</em>");
	    // The total number of hits to the proxy:
	    g.append("<hr><p>Total number of handled requests: <strong>"
		     + (hits+misses)
		     + "</strong>");
	    // The misses:
	    g.append("<dl><dt>misses<dd>The number of requests for which a "
		     + " cache entry wasn't found: <strong>" 
                     + misses + "</strong>");
	    g.append("<dl><dt>not cachable<dd>The number of not cachable "
		     + "replies: <strong>" + ncache + "</strong></dl>\n");
	    // The hits:
	    g.append("<dt>hits<dd>The number of requests for which an "
		     + " entry existed before: <strong>" + hits + "</strong>");
	    g.append("<dl><dt>Straight replies<dd>The number of replies "
		     + " the proxy was able to generate directly.<strong>"
		     + (hits-(gvalid+(bvalid-(misses-ncache-pending))))
		     + " / " + rhits
		     + "</strong>");
	    g.append("<dt>Successful revalidations<dd>The number of "
		     + " revalidations that ended up in <code>NOT_MODIFIED"
		     + "</code> replies. <strong>"+gvalid+"</strong>");
	    g.append("<dt>Unsuccessful revalidations<dd>The number of "
		     + " revalidations that triggered a full reply.<strong>"
		     // Each miss always account for a bad revalidation
		     + (bvalid-(misses-ncache-pending))
//		     + (misses-bvalid)
		     + "</strong>");
	    g.append("</dl></dl>");
	    g.append("<dl><dt>pending/errors<dd>The number of errors or "
		     + "requests in progress : <strong>" + pending
		     + "</strong></dl>\n");
	    g.append("<p>WARNING: The numbers related to the hits may be"
		     + " inaccurate in case of pending connections. The above"
		     + " number is the addition of the errors and pending "
		     + " connections.</p>");
	    // More infos:
	    g.append("<hr>");
	    g.append((new Date()).toString());
	}	    
	reply.setStream(g);
	return reply;
    }

    public void initialize(Object values[]) {
	super.initialize(values);
	// Try to get a pointer to the statistics
	CacheFilter filter = null;
	try {
	    Class       c = null;
	    HttpManager m = null;
	    c       = Class.forName("w3c.www.protocol.http.cache.CacheFilter");
	    m       = HttpManager.getManager(getServer().getProperties());
	    filter  = (CacheFilter) m.getGlobalFilter(c);
	} catch (Exception ex) {
	}
	stats = filter.getStatistics();
    }
}
