// PICSFilter.java
// $Id: PICSFilter.java,v 1.7 1997/05/21 12:55:18 bmahe Exp $
// (c) COPYRIGHT MIT and INRIA, 1996.
// Please first read the full copyright statement in file COPYRIGHT.html

package w3c.jigsaw.pics ;

import java.io.* ;
import java.util.*;
import java.net.*;

import w3c.tools.store.*;
import w3c.www.http.*;
import w3c.jigsaw.http.* ;
import w3c.jigsaw.resources.*;
import w3c.jigsaw.html.HtmlGenerator ;

/** 
 * This package implements a PICS filter. The PICS filters allows server
 * administrator to rate the documents they deliver. The references for this
 * protocol is <a href="http://www.w3.org/hypertext/WWW/PICS/">here</a>.</p>
 * <p>The PICS filter defines the following attributes:</p>
 * <table border>
 * <caption>The list of parameters</caption>
 * <tr> 
 * <th align=left>Parameter name</th> 
 * <th align=left>Semantics</th>
 * <th align=left>Default value</th> 
 * <th align=left>Type</th>
 * </tr>
 * <tr> 
 * <th align=left>bureau</th> 
 * <th align=left>The label bureau to query for this entity labels.</th>
 * <th align=left><em>none</em></th> 
 * <th align=left>java.lang.String</th>
 * </tr>
 * </table>
 */

public class PICSFilter extends ResourceFilter {
    /**
     * The PICS protocol version that this filter handles.
     */
    public  static final String PICS_PROTOCOL_ID = "PICS-1.1" ;

    /**
     * The bag describing the PICS extension:
     */
    public static HttpBag PICS_EXTENSION = null;

    static {
	HttpBag headers = HttpFactory.makeBag("headers");
	headers.addItem("PICS-label");
	PICS_EXTENSION = HttpFactory.makeBag(PICS_PROTOCOL_ID);
	PICS_EXTENSION.addBag(headers);
    }

    /**
     * Attribute index - The identifier of our bureau.
     */
    protected static int ATTR_BUREAU_IDENTIFIER = -1 ;

    static {
	Attribute a   = null ;
	Class     cls = null ;
	try {
	    cls = Class.forName("w3c.jigsaw.pics.PICSFilter");
	} catch (Exception ex) {
	    ex.printStackTrace() ;
	    System.exit(1) ;
	}
	// The bureau identifier attribute
	a = new FileAttribute("bureau"
			      , null
			      , Attribute.EDITABLE|Attribute.MANDATORY) ;
	ATTR_BUREAU_IDENTIFIER = AttributeRegistry.registerAttribute(cls, a);
    }

    /**
     * Our loaded lable bureau.
     */
    protected LabelBureauInterface bureau      = null ;

    /**
     * Get our label bureau identifier.
     */

    public File getBureauIdentifier() {
	return (File) getValue(ATTR_BUREAU_IDENTIFIER, null) ;
    }

    /**
     * Make sure our label bureau is loaded.
     */

    protected final void acquireBureau() {
	if ( bureau != null )
	    return ;
	File file = getBureauIdentifier();
	if ( file == null )
	    // Not initialize yet:
	    return ;
	bureau = LabelBureauFactory.getLabelBureau(file);
    }

    /**
     * Check the query to examine if it requires some PICS handling. 
     * If this is the case, it returns a <em>Bag</em> object
     * corresponding to the part of the <em>Accept-Protocol</em> header that
     * relates with PICS.
     * @param request The request to be checked.
     * @return A Bag object if PICS handling required, <string>null</strong>
     *         otherwise.
     */

    protected HttpBag isPICSQuery (Request request) 
	throws HTTPException
    {
	// If the request doesn't ask for labels, return right now.
	HttpBag requested = request.getProtocolRequest();
	if ( requested == null )
	    return null ;
	if ( ! requested.hasBag (PICS_PROTOCOL_ID) )
	    return null ;
	// Now, the request has some PICS stuff in it, let look inside this:
	HttpBag pics = null ;
	try {
	    pics = requested.getBag(PICS_PROTOCOL_ID) ;
	} catch (ClassCastException e) {
	    return null ;
	}
	return pics ;
    }



    public Reply outgoingFilter (Request request, Reply reply) 
	throws HTTPException
    {
	HttpBag pics = isPICSQuery (request) ;
	if ( pics == null )
	    return reply ;
	// Get the requested services:
	HttpBag params    = pics.getBag("params") ;
	HttpBag services  = params.getBag("services") ;
	URL url       = request.getURL();
	int format    = LabelBureauInterface.FMT_MINIMAL ;
	// Get any format parameter:
	if ( params.hasItem ("minimal") ) {
	    format = LabelBureauInterface.FMT_MINIMAL ;
	} else if ( params.hasItem ("short") ) {
	    format = LabelBureauInterface.FMT_SHORT ;
	} else if ( params.hasItem ("full") ) {
	    format = LabelBureauInterface.FMT_FULL ;
	} else if ( params.hasItem ("signed") ) {
	    format = LabelBureauInterface.FMT_SIGNED ;
	} else {
	    Reply error = request.makeReply(HTTP.BAD_REQUEST) ;
	    error.setContent ("Invalid label format: "+format) ;
	    throw new HTTPException (error) ;
	}
	// Get labels for each service, building out the ret hashtable
	StringBuffer sb = new StringBuffer(128) ;
	Enumeration  e  = services.keys() ;
	sb.append ("("+PICS_PROTOCOL_ID) ;
    sloop:
	while ( e.hasMoreElements() ) {
	    String                n = (String) e.nextElement() ;
	    LabelServiceInterface s = bureau.getLabelService (n) ;
	    if ( s == null ) {
		sb.append (" error "
			   + "(service-unavailable \"unknown service\")") ;
		continue sloop ;
	    } 
	    s.dump(sb, format) ;
	    LabelInterface l = s.getSpecificLabel (url) ;
	    if ( (l == null) && ((l = s.getGenericLabel (url)) == null) ) {
		sb.append (" error (not-labeled \"" + url +"\")") ;
	    }  else {
		sb.append (" labels ") ;
		l.dump (sb, format) ;
	    }
	}
	sb.append (")") ;
	// Add additional reply headers:
	reply.setProtocol(PICS_EXTENSION);
	reply.setValue("PICS-label", sb.toString());
	return reply ;
    }

    public void initialize (Object values[]) {
	super.initialize(values);
	acquireBureau() ;
    }
}
