// PutListResource.java
// $Id: PutListFrame.java,v 1.9 1998/08/14 11:06:30 bmahe Exp $
// (c) COPYRIGHT MIT and INRIA, 1996.
// Please first read the full copyright statement in file COPYRIGHT.html

package org.w3c.jigsaw.filters;

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

import org.w3c.util.*;
import org.w3c.tools.resources.*;
import org.w3c.tools.resources.ProtocolException;
import org.w3c.cvs.*;
import org.w3c.jigsaw.auth.AuthFilter;
import org.w3c.jigsaw.http.*;
import org.w3c.jigsaw.frames.*;
import org.w3c.www.http.*;
import org.w3c.jigsaw.forms.*;
import org.w3c.jigsaw.resources.*;
import org.w3c.jigsaw.html.*;

public class PutListFrame extends PostableFrame {

    PutListResource putlist = null;

    public void registerResource(FramedResource resource) {
	super.registerResource(resource);
	if (resource instanceof PutListResource) {
	    putlist = (PutListResource) resource;
	}
    }

    /**
     * perform the request.
     * @param req the incomming request.
     * @exception org.w3c.tools.resources.ProtocolException if a protocol 
     * error occurs
     * @exception org.w3c.tools.resources.ResourceException if a server 
     * error occurs
     */
    public ReplyInterface perform(RequestInterface req) 
	throws ProtocolException, ResourceException
    {
	if (putlist == null) {
	    Request request = (Request) req;
	    Reply error = request.makeReply(HTTP.INTERNAL_SERVER_ERROR) ;
	    error.setContent("The PutListFrame must be associated "+
			     "with a PutListResource only!!");
	    throw new HTTPException(error);
	}
	return super.perform(req);
    }

    /**
     * Dump the list of modified files.
     * @param request The request to handle.
     * @return A Reply instance.
     * @exception org.w3c.tools.resources.ProtocolException if a protocol 
     * error occurs
     * @exception org.w3c.tools.resources.ResourceException if a server 
     * error occurs
     */

    public Reply get(Request request) 
	throws ProtocolException, ResourceException
    {
	HtmlGenerator g = new HtmlGenerator("Modified files");
	addStyleSheet(g);
	g.append("<h1>List of recently published files</h1>");
	g.append("<ul>");
	Enumeration enum = putlist.published.elements();
	while ( enum.hasMoreElements() ) {
	    PutedEntry e      = (PutedEntry) enum.nextElement();
	    String     url    = e.getURL();
	    g.append("<li><em><a href=\"",
		     url,
		     "\">"+url+"</a></em>");
	    g.append("<br>Published by <em>"+e.getAuthor()+"</em> on <strong>",
		     new Date(e.getTime()).toString(),
		     "</strong>.</li>");
	}
	g.append("</ul><hr>");

	g.append("<h1>List of modified files</h1>");
	g.append("<form action=\""+request.getURL()+"\" method=\"POST\">");
	g.append("<dl>");
	// Dump all entries:
	enum = putlist.entries.elements();
	while ( enum.hasMoreElements() ) {
	    PutedEntry e      = (PutedEntry) enum.nextElement();
	    String     fname  = e.getFilename();
	    String     author = e.getAuthor();
	    long       time   = e.getTime();
	    String     url    = e.getURL();

	    g.append("<dt><input type=\"checkbox\" name=\""+
		     e.getKey() + "\" value =\"mark\">",
		     (fname != null) ? fname : url,
		     "</dt><dd>");
	    if ( fname != null ) {
		File         file    = new File(fname);
		File         dir     = new File(file.getParent());
		// Compute the CVS directory URL for the file:
		URL          cvsurl  = null;
		try {
		    cvsurl  = new URL(new URL(url), "CVS");
		} catch (Exception ex) {
		    cvsurl = null;
		}
		// Display status:
		int st = -1;
		try {
		    // Local status first:
		    CvsDirectory cvs = CvsDirectory.getManager(dir,
							       putlist.props);
		    st  = cvs.status(file.getName());
		    if ( cvsurl != null )
			g.append("Status: <em><a href=\""+cvsurl+ "\">"
				 , cvs.statusToString(st)
				 , "</a></em><br>");
		    else
			g.append("Status: <em>"
				 , cvs.statusToString(st)
				 , "</em><br>");

		    if (url != null)
			g.append("URL: <em><a href=\"",
				 url,
				 "\">"+url+"</a></em><br>");
	  
		} catch (CvsException ex) {
		    g.append("Status: <strong>CVS ERROR</strong>: "
			     , ex.getMessage()
			     , "<br>");
		}
		// Publish status next (when possible)
		if ( st != CVS.FILE_Q ) {
		    try {
			File         sf  = putlist.getServerFile(file); 
			File         sd  = new File(sf.getParent());
			CvsDirectory sc  = 
			    CvsDirectory.getManager(sd, putlist.props);
			int          sst = sc.status(file.getName());
			if ((st == CVS.FILE_M) || (sst != CVS.FILE_OK))
			    g.append("Publish: (needed) <em>"
				     , sc.statusToString(sst)
				     , "</em><br>");
			else
			    g.append("Publish: <em>"
				     , sc.statusToString(sst)
				     , "</em><br>");
		    } catch (CvsException ex) {
			g.append("Publish: <strong>CVS ERROR</strong>: "
				 , ex.getMessage()
				 , "<br>");
		    }
		}
	    }
	    // Display author:
	    if ( author != null )
		g.append("Modified by <em>"+author+"</em> on <strong>"+
			 new Date(time).toString() + "</strong>.<br>");
	    else
		g.append("Modified on <strong>"+
			 new Date(time).toString()+
			 "</strong>.<br>");
	}
	g.append("</dl>");
	// The command button:
	g.append ("<hr>Perform action on marked entries:<p>") ;
	g.append("<input type=\"radio\" name=\"action\" value=\"publish\">"
		 + "Publish ");
	g.append("<input type=\"radio\" name=\"action\" value=\"remove\">"
		 + "Remove ");
	g.append ("</p>") ;
	g.append("<input type=\"submit\" name=\"submit\" value=\"do !\">") ;
	g.append ("</form>") ;
	g.close();
	Reply reply = createDefaultReply(request, HTTP.OK);
	reply.addPragma("no-cache");
	reply.setNoCache();
	reply.setStream(g);
	return reply;
    }

    protected void performAction(Request request, String action, String key) {
	PutedEntry pe = (PutedEntry) putlist.entries.get(key);
	if ( pe == null ) {
	    // We're in troubles !
	    if ( putlist.debug )
		System.out.println("PutList: "+key+" not found !");
	    return ;
	}
	if ( action.equals("publish") ) {
	    File file  = new File(pe.getFilename());
	    File sfile = putlist.getServerFile(file); 
	    try {
		// First step: does the private version needs commit ?
		File         d  = new File(file.getParent());
		CvsDirectory c  = CvsDirectory.getManager(d, putlist.props);
		if ( c.status(file.getName()) == CVS.FILE_M ) {
		    String author = pe.getAuthor();
		    String env [] = { "USER="+author , 
				      "LOGNAME="+author };
		    String msg    = ((author != null)
				     ? "Published by "+author+" through Jigsaw"
				     : "Published through Jigsaw");
		    c.commit(file.getName(), msg, env);
		} else if ( putlist.debug ) {
		    System.out.println("PutList: no commit needed on "+
				       file.getAbsolutePath()+
				       " st="+c.status(file.getName()));
		}
		// Second step: publish
		File         sd = new File(sfile.getParent());
		try {
		    CvsDirectory sc = 
			CvsDirectory.getManager(sd, putlist.props);
		    if (sc.status(sfile.getName()) != CVS.FILE_OK) {
			sc.update(sfile.getName());
		    } else if ( putlist.debug ) {
			System.out.println("PutList: no update needed on "+
					   sfile.getAbsolutePath()+
					   " st="+sc.status(sfile.getName()));
		    }
		} catch (UncheckedOutException ex) {
		    // perform a get from root
		    File root = new File(putlist.getRoot().getAbsolutePath());
		    CvsDirectory sc = CvsDirectory.getManager(root,  
							      putlist.props);
		    String fpath  = file.getAbsolutePath();
		    String fspace = putlist.getCvsSpace().getAbsolutePath();
		    String path   = fpath.substring(fspace.length()+1);
		    sc.get(path);
		}
		// Last step: remove published entries:
		putlist.entries.remove(key);
		// publication time
		pe.setValue(PutedEntry.ATTR_TIME, 
			    new Long(System.currentTimeMillis()));
		putlist.addPubEntry(pe);
	    } catch (CvsException ex) {
		ex.printStackTrace();
	    }
	} else if ( action.equals("remove") ) {
	    putlist.entries.remove(key);
	} else if ( putlist.debug ) {
	    System.out.println("PutList: "+action+" unknown.");
	}
    }

    /**
     * handle the request.
     * @param request the incomming request.
     * @param data the URLDecoder.
     * @exception org.w3c.tools.resources.ProtocolException if a protocol 
     * error occurs
     */

    public Reply handle(Request request, org.w3c.jigsaw.forms.URLDecoder data) 
	throws ProtocolException
    {
	// Get the action to perform:
	String action = data.getValue("action");
	if (action == null) {
	    Reply error = request.makeReply(HTTP.INTERNAL_SERVER_ERROR);
	    error.setContent("You must select the action to be performed.");
	    return error;
	}
	if (action.equals("publish"))
	    putlist.published = new Hashtable(11);

	// Check all entries and perform action:
	Enumeration enum = putlist.entries.keys();
	while ( enum.hasMoreElements() ) {
	    String key = (String) enum.nextElement();
	    if (data.getValue(key) != null) {
		// Perform action on that entry:
		if ( putlist.debug )
		    System.out.println("PutList: "+action+" on "+key);
		performAction(request, action, key);
	    } else {
		if ( putlist.debug )
		    System.out.println("PutList: "+key+" not marked !");
	    }
	}
	try {
	    return get(request);
	} catch (ResourceException ex) {
	    Reply error = request.makeReply(HTTP.INTERNAL_SERVER_ERROR);
	    error.setContent(ex.getMessage());
	    return error;
	}
    }
} // PutListFrame
