// Upgrade2to3.java
// $Id: Upgrade2to3.java,v 1.3 1997/07/25 11:43:40 abaird Exp $
// (c) COPYRIGHT MIT and INRIA, 1996.
// Please first read the full copyright statement in file COPYRIGHT.html

package w3c.jigsaw.upgrade;

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

import w3c.jigsaw.upgrade.from2to3.*;
import w3c.jigsaw.http.httpd;

public class Upgrade2to3 implements Upgrader {
    public static final int DO_PROPS    = (1<<0);
    public static final int DO_STORES   = (1<<1);
    public static final int DO_INDEXERS = (1<<2);
    Properties p = null;
    File confdir = null;
    int  flags   = 0;
    PrintStream prttrace = null;
    File        tracefile = null;

    /**
     * Emit an upgrade trace:
     * @param msg The message to emit.
     */

    protected String indent = "";
    public void trace(String msg) {
	prttrace.println(indent+msg);
    }

    public void trace(String indent, String msg) {
	this.indent = "";
	trace(msg);
	this.indent = indent;
    }
    
    public void warning(String msg) {
	prttrace.println("* "+msg);
    }

    public void error(String msg) {
	prttrace.println("*** Error: "+msg);
    }

    /**
     * Emit a message, upgrade has performed successfully.
     */
    
    public void upgradeDone() {
	System.err.println("+ Upgrade 1.0alpha5 to 1.0beta successful.");
	prttrace.println("If any problem, check the file "
		         + tracefile
			 + " for lines starting with \"***\" (errors) "
			 + " or lines starting with \"*\" (warnings).");
	trace("upgrade finished.");
    }

    protected void saveProperties() {
	File newfile = new File(confdir, "http-server.props");
	try {
	    OutputStream out = new FileOutputStream(newfile);
	    p.save(out, "# Saved by \""
                         + getClass().getName()
			 + "\" on "+new Date());
	} catch (Exception ex) {
	    error("unable to save upgraded properties to ["
		  + newfile.getAbsolutePath()
		  + "]: "+ex.getMessage());
	}
	trace("upgraded properties save to \""
              + newfile.getAbsolutePath()
	      + "\".");
    }

    /**
     * Upgrade the properties.
     * The difference between version 1 and version 2, with regard to 
     * properties is the counter version (bumped to 3)
     */

    protected void upgradeProperties() {
	trace("\t", "upgrading properties...");
	// Bump the version counter:
	p.put("w3c.jigsaw.version.counter", "3");
	p.put("w3c.jigsaw.server", "1.0beta");
	saveProperties();
	trace ("", "properties upgraded successfully.");
    }

    /**
     * Upgrade resource stores.
     */

    protected void upgradeSimpleResourceStore(File repository) {
	int count = 0;
	trace("\t\t", "\tnow upgrading: "+repository);
	// This is kind of hairy, but it really doesn't matter, beleive me
	try {
	    SimpleResourceStore store = new SimpleResourceStore();
	    store.initialize(repository);
	    Enumeration enum = store.enumerateResourceIdentifiers();
	    while ( enum.hasMoreElements() ) {
		count++;
		String id = (String) enum.nextElement();
		try {
		    store.upgrade(id);
		} catch (Exception ex) {
		    error("Unable to upgrade resource "
			  + id + " of store " + repository
			  + " use the -force flag to drop that resource.");
		}
	    }
	    store.save();
	} catch (Exception ex) {
	    ex.printStackTrace();
	    error("unable to upgrade resource store \""
		  + repository
		  + "\".");
	}
	trace(repository+": "+count+" resources upgraded.");
    }

    protected void upgradeStores() {
	File storedir   = new File(confdir, "stores");
	trace ("\t", "upgrading resource stores in "+storedir+"...");
	// Remove resource manager state, to have it salvaged !
	File fstate = new File(storedir, "state");
	if ( fstate.exists() ) 
	    fstate.delete();
	// Upgrade all available stores:
	String stores[] = storedir.list(new StoreDirectoryFilter());
	for (int i = 0 ; i < stores.length; i++)
	    upgradeSimpleResourceStore(new File(storedir, stores[i]));
	trace("", "all resource stores upgraded.");
    }

    protected void upgradeIndexers() {
	File indexdir = new File(confdir, "indexers");
	trace("\t", "upgrading indexers...");
	// Create the indexdir if needed:
	if ( ! indexdir.exists() ) {
	    if ( ! indexdir.mkdir() ) {
		error("Unable to create indexers directory: "+indexdir);
		return;
	    }
	}
	// Check for 1.0alpha5 ext and dir databases:
	File ext = new File(confdir, "exts.db");
	File dir = new File(confdir, "dirs.db");
	if ( ext.exists() ) {
	    trace("\t", "Upgrading extension database...");
	    upgradeSimpleResourceStore(ext);
	    trace("\t", "re-installing extensions: "+ext);
	    File target = new File(indexdir, "default-e.db");
	    File tmp    = new File(indexdir, "default-e.tmp");
	    if ( target.exists() ) {
		if ( ! target.renameTo(tmp) )
		    target.delete();
	    }
	    // Move that file as default indexer extensions:
	    if ( ! ext.renameTo(target) ) {
		error("Failed to upgrade extensions: "+ext+" to "+target);
		tmp.renameTo(target);
	    } else {
		tmp.delete();
	    }
	}
	if ( dir.exists() ) {
	    trace("\t", "Upgrading directory database...");
	    upgradeSimpleResourceStore(dir);
	    trace("\t", "re-installing directories: "+dir);
	    File target = new File(indexdir, "default-d.db");
	    File tmp    = new File(indexdir, "default-d.tmp");
	    if ( target.exists() ) {
		if ( ! target.renameTo(tmp) )
		    target.delete();
	    }
	    if ( ! dir.renameTo(target) ) {
		error("Failed to upgrade directories: "+dir+" to "+target);
		tmp.renameTo(target);
	    } else {
		tmp.delete();
	    }
	}
    }

    public void upgrade(String args[])
	throws UpgradeException
    {
	parse(args);
	this.tracefile = new File(confdir, "upgrade2to3.txt");
	System.err.println("+ Upgrading config from 1.0alpha5 to 1.0beta");
	System.err.println("+ Will emit traces in file " + tracefile);
	try {
	    this.prttrace  = new PrintStream(new FileOutputStream(tracefile));
	} catch (Exception ex) {
	    System.err.println("Unable to create trace file, using stderr.");
	    this.prttrace = System.err;
	}
	// Upgrade the property file:
	if ((flags & DO_PROPS) == DO_PROPS)
	    upgradeProperties();
	// Upgrade the stores:
	if ((flags & DO_STORES) == DO_STORES)
	    upgradeStores();
	// Upgrade the indexers:
	if ((flags & DO_INDEXERS) == DO_INDEXERS)
	    upgradeIndexers();
	// That's it for differences between version 1 and 2
	upgradeDone();
    }

    protected void parse(String args[])
	throws UpgradeException
    {
	String root = null;
	String conf = null; 
	for (int i = 0 ; i < args.length; i++) {
	    if ( args[i].equals("-config") && (i+1 < args.length)) {
		conf = args[++i];
	    } else if ( args[i].equals("-store") ) {
		this.flags += DO_STORES;
	    } else if ( args[i].equals("-props") ) {
		this.flags += DO_PROPS;
	    } else if ( args[i].equals("-indexers") ) {
		this.flags += DO_INDEXERS;
	    } else if ( args[i].equals("-root") && (i+1 < args.length)) {
		root = args[++i];
	    } else {
		continue;
	    }
	}
	// Check values, or use defaults:
	File rootdir = ((root == null)
			? new File(System.getProperty("user.dir", null))
			: new File(root));
	this.confdir = ((conf == null)
			? new File(rootdir, "config")
			: new File(rootdir, conf));
	if ((confdir == null) || ! confdir.exists() ) {
	    String err = ("Unable to locate Jigsaw config directory "
			  + ((confdir != null) ? confdir.toString() : "\"\"")
			  + ". Restart Jigsaw with the -config option.");
	    throw new UpgradeException(err);
	}
	// Set flags to all if not specified:
	if ( flags == 0 )
	    flags = DO_PROPS+DO_STORES+DO_INDEXERS;
	// Load properties:
	this.p = new Properties();
	try {
	    p.load(new FileInputStream(new File(confdir,"http-server.props")));
	} catch (Exception ex) {
	    String err = ("Unable to load default properties from "
			  + new File(confdir, "http-server.props")
			  + ". Restart Jigsaw with the -p option.");
	    throw new UpgradeException(err);
	}
    }

    public static void usage() {
	PrintStream p = System.out;
	p.println("upgrade -config <config directory>");
	p.println("\t[-store]: upgrade all resource stores only.");
	p.println("\t[-props]: upgrade properties only.");
    }

    public static void main(String args[]) {
	Upgrade2to3 upgrader = new Upgrade2to3();
	try {
	    upgrader.upgrade(args);
	} catch (UpgradeException ex) {
	    System.err.println("*** Unable to upgrade configuration.");
	    ex.printStackTrace();
	}
    }

    public Upgrade2to3() {
	super();
    }

}
