/* ======================================================================
The Bodington System Software License, Version 1.0
 
Copyright (c) 2001 The University of Leeds.  All rights reserved.
 
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
 
1.  Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
 
2.  Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
 
3.  The end-user documentation included with the redistribution, if any,
must include the following acknowledgement:  "This product includes
software developed by the University of Leeds
(http://www.bodington.org/)."  Alternately, this acknowledgement may
appear in the software itself, if and wherever such third-party
acknowledgements normally appear.
 
4.  The names "Bodington", "Nathan Bodington", "Bodington System",
"Bodington Open Source Project", and "The University of Leeds" must not be
used to endorse or promote products derived from this software without
prior written permission. For written permission, please contact
d.gardner@leeds.ac.uk.
 
5.  The name "Bodington" may not appear in the name of products derived
from this software without prior written permission of the University of
Leeds.
 
THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
WARRANTIES, INCLUDING, BUT NOT LIMITED TO,  TITLE,  THE IMPLIED WARRANTIES
OF QUALITY  AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO
EVENT SHALL THE UNIVERSITY OF LEEDS OR ITS CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
=========================================================
 
This software was originally created by the University of Leeds and may contain voluntary
contributions from others.  For more information on the Bodington Open Source Project, please
see http://bodington.org/
 
====================================================================== */

package org.bodington.installation;

import java.io.*;
import java.net.*;
import java.net.InetAddress;
import java.util.Enumeration;
import java.util.zip.*;

import sun.security.tools.KeyTool;

public class Install
{
    // Install within Catalina release of Tomcat?
    private static final boolean catalina = true;
    
    
    public void process()
    {
        String windows_service_cmd=null;
        
        try
        {
            DataInputStream din = new DataInputStream( System.in );
            String line;
            boolean windows=false;
            boolean unix=false;
            boolean started=false;
            boolean browser=false;
            boolean xrs = false;
            boolean password = false;
            
            File destination=null;
            File jdk_home=null;
            
            System.out.println( "===============================================================================" );
            System.out.println( "                      Bodington System Installation" );
            System.out.println( "This program installs a copy of Tomcat, the open source web server from Apache " );
            System.out.println( "with the Bodington System pre-installed inside it as a Web Application.  When  " );
            System.out.println( "this installation is complete you can use a web browser to access pages to "     );
            System.out.println( "setup a connection between the Bodington System and a database product. Before " );
            System.out.println( "you continue make sure you have installed a suitable relational database " );
            System.out.println( "management system product on this computer (or on a computer situated on the " );
            System.out.println( "same network).  Suitable database products are Oracle 8i standard edition,   " );
            System.out.println( "MS SQL Server 2000 (Windows 2000 only) or PostgreSQL (UNIX only)." );
            System.out.println( "===============================================================================" );
            System.out.print( "Do you want to continue? (Y/N)" );
            line = din.readLine();
            if ( !(line.equalsIgnoreCase( "y" ) || line.equalsIgnoreCase( "yes" )) )
            {
                System.out.println( "===============================================================================" );
                System.out.println( "Setup abandoned." );
                System.exit( 1 );
            }
            System.out.println( "===============================================================================" );
            System.out.println( "PLEASE STUDY THE OUTPUT OF THIS PROGRAM CAREFULLY AS YOU PROCEDE." );
            
            
            String os_arch 	= System.getProperty( "os.arch"		);
            String os_name 	= System.getProperty( "os.name"		);
            String os_version = System.getProperty( "os.version"	);
            String java_home 	= System.getProperty( "java.home"	);
            String java_vendor = System.getProperty( "java.vendor"	);
            String java_version = System.getProperty( "java.version"	);
            
            System.out.println( "===============================================================================" );
            System.out.println( "Operating System Information" );
            System.out.println( "Architecture: " + os_arch    );  //x86
            System.out.println( "        Name: " + os_name    );  //Windows NT
            System.out.println( "     Version: " + os_version );  //4.0
            System.out.println( "===============================================================================" );
            
            boolean problem=false;
            windows = os_name.startsWith( "Windows" );
            
            unix = System.getProperty("path.separator").equals(":") &&
            !os_name.startsWith("Mac") &&
            (os_name.endsWith("X") || os_name.endsWith("x"));
            
            if ( windows )
            {
                if ( (!os_name.equals( "Windows 2000" ) && !os_name.equals( "Windows NT" )) ||
                (!os_version.equals( "5.0" ) && !os_version.equals( "4.0" ))           )
                {
                    System.out.println( "WARNING: The software has only been tested on versions 4.0 and 5.0 of Windows NT/Windows 2000." );
                    problem=true;
                }
                else
                    System.out.println( "You are installing on a supported version of MS Windows." );
            }
            else
            {
                if ( unix )
                {
                    System.out.println( "You are installing on some flavour of UNIX." );
                }
                else
                {
                    System.out.println( "It seems that you are using an operating system other than " );
                    System.out.println( "Windows or UNIX." );
                    System.out.println( "Some elements of the installation process will have to be " );
                    System.out.println( "performed manually. In particular you will need to work out " );
                    System.out.println( "how to start and stop the Apache Tomcat web server.  Please " );
                    System.out.println( "consult documentation at http://jakarta.apache.org/ " );
                    problem=true;
                    System.out.println();
                    System.out.println( "===============================================================================" );
                }
            }
            
            System.out.print( "Do you still want to continue? (Y/N)" );
            line = din.readLine();
            if ( !(line.equalsIgnoreCase( "y" ) || line.equalsIgnoreCase( "yes" )) )
            {
                System.out.println( "===============================================================================" );
                System.out.println( "Setup abandoned." );
                System.exit( 1 );
            }
            
            
            System.out.println( "Java Runtime Information" );
            System.out.println( "        Home: " + java_home    );
            System.out.println( "      Vendor: " + java_vendor  );
            System.out.println( "     Version: " + java_version );
            System.out.println( "===============================================================================" );
            
            jdk_home = new File( java_home ).getParentFile();
            jdk_home = new File( java_home ).getParentFile();
            File tools_jar = new File( jdk_home, "lib" + File.separator + "tools.jar" );
            if ( !tools_jar.exists() )
            {
                System.out.println( "===============================================================================" );
                System.out.println( "ERROR - CAN'T FIND COMPILER" );
                System.out.println();
                System.out.println( "Bodington requires the Java compiler (tools.jar) that comes with the Java" );
                System.out.println( "development Kit but it couldn't be found.  The Java runtime is not suitable." );
                System.out.println( "Please run this installation with the command 'java' from the Development Kit" );
                System.out.println( "NOT the runtime." );
                System.exit( 1 );
            }
            
            if ( !java_vendor.equals( "Sun Microsystems Inc." ) )
            {
                System.out.println( "The Bodington System has only been tested with the JDK produced by Sun Microsystems Inc." );
                System.out.print( "Do you still want to continue? (Y/N)" );
                line = din.readLine();
                if ( !(line.equalsIgnoreCase( "y" ) || line.equalsIgnoreCase( "yes" )) )
                {
                    System.out.println( "===============================================================================" );
                    System.out.println( "Setup abandoned." );
                    System.exit( 1 );
                }
            }
            
            if ( !java_version.startsWith( "1.4." ) )
            {
                System.out.println( "The Bodington System needs version 1.4.x of Java" );
                System.out.print( "Do you still want to try and proceed anyway? (Y/N)" );
                line = din.readLine();
                if ( !(line.equalsIgnoreCase( "y" ) || line.equalsIgnoreCase( "yes" )) )
                {
                    System.out.println( "===============================================================================" );
                    System.out.println( "Setup abandoned." );
                    System.exit( 1 );
                }
            }
            
            if ( windows )
            {
                if ( java_version.startsWith( "1.3.1" ) || java_version.startsWith( "1.4." ) )
                {
                    xrs = true;
                }
                else
                {
                    System.out.println( "There is a bug in version 1.3.0 of Java for Windows that causes Java running " );
                    System.out.println( "as a background service to crash when someone logs out of the PC running the " );
                    System.out.println( "service.  The bug is fixed in version 1.3.1 of Java by the addition of a new " );
                    System.out.println( "startup option -xrs." );
                    if ( !java_version.equals( "1.3.0" ) )
                    {
                        System.out.println( "===============================================================================" );
                        System.out.println( "Unable to determine if your version of Java supports the -xrs option" );
                        System.out.print( "Do you want to use the -xrs option? " );
                        line = din.readLine();
                        xrs = line.equalsIgnoreCase( "y" ) || line.equalsIgnoreCase( "yes" );
                        System.out.println( "===============================================================================" );
                    }
                }
            }
            
            
            
            try
            {
                Class.forName( "javax.mail.Transport" );
                Class.forName( "javax.activation.MimeType" );
                Class.forName( "com.sun.mail.smtp.SMTPTransport" );
            }
            catch ( ClassNotFoundException cnfe )
            {
                System.out.println( "===============================================================================" );
                System.out.println( "Java Mail and/or JavaBeans Activation Framework were not found.  You need to" );
                System.out.println( "Install Mail API 1.3 and JavaBeans Activation Framework API 1.0.2 in the JDK" );
                System.out.println( "You can do that by copying the files mail.jar and activation.jar into" );
                System.out.println( java_home + File.separator + "lib" + File.separator + "ext" + File.separator );
                System.out.println( "===============================================================================" );
                System.out.println( "Setup abandoned." );
                System.exit( 1 );
            }
            
            System.out.println( "===============================================================================" );
            System.out.println( "Which of the following database products do you plan to use with Bodington?" );
            System.out.println();
            System.out.println( "Microsoft SQL Server 2000  (enter m)" );
            System.out.println();
            System.out.println( "Oracle 8i Standard Edition (enter o)" );
            System.out.println();
            System.out.println( "PostgreSQL                 (enter p)" );
            System.out.println();
            System.out.println( "None of the above          (enter n)" );
            System.out.println();
            line = din.readLine();
            
            if ( line.equalsIgnoreCase( "m" ) )
            {
                try
                {
                    Class.forName( "com.microsoft.jdbc.sqlserver.SQLServerDriver" );
                    Class.forName( "com.microsoft.jdbc.base.BaseDriver" );
                    Class.forName( "com.microsoft.util.UtilException" );
                }
                catch ( ClassNotFoundException cnfe )
                {
                    System.out.println( "===============================================================================" );
                    System.out.println( "One or more of the Microsoft JDBC driver jar files is not available.  " );
                    System.out.println( "You need to install the JDBC driver in the following way;" );
                    System.out.println( "1) Go to the Microsoft web site and download the SQL 2000 JDBC driver." );
                    System.out.println( "2) Run the installation program on your personal PC or a spare workstation." );
                    System.out.println( "3) In the installation directory find the three jar files and copy them into." );
                    System.out.println( "   the Java Development Kit in the directory;" );
                    System.out.println( java_home + File.separator + "lib" + File.separator + "ext" + File.separator );

                    System.out.println( "4) Restart this installation program." );
                    System.out.println( "===============================================================================" );
                    System.exit( 1 );
                }
            }
            else if ( line.equalsIgnoreCase( "o" ) )
            {
                try
                {
                    Class.forName( "oracle.jdbc.driver.OracleDriver" );
                }
                catch ( ClassNotFoundException cnfe )
                {
                    System.out.println( "===============================================================================" );
                    System.out.println( "The Oracle JDBC driver jar file is not available.  You need to " );
                    System.out.println( "install the JDBC driver in the following way;" );
                    System.out.println( "1) Find the pure java (type 4) Oracle JDBC jar file appropriate for JDK 1.4 "  );
                    System.out.println( "   in your Oracle installation. " );
                    System.out.println( "2) Copy the jar file into the Java Development Kit in the directory;" );
                    System.out.println( java_home + File.separator + "lib" + File.separator + "ext" + File.separator );

                    System.out.println( "3) Restart this installation program." );
                    System.out.println( "===============================================================================" );
                    System.exit( 1 );
                }
            }
            else if ( line.equalsIgnoreCase( "p" ) )
            {
                try
                {
                    Class.forName( "org.postgresql.Driver" );
                }
                catch ( ClassNotFoundException cnfe )
                {
                    System.out.println( "===============================================================================" );
                    System.out.println( "The PostgreSQL JDBC driver jar file is not available.  Please install it by;" );
                    System.out.println( "1) Find the PostgreSQL JDBC jar file appropriate for the version of PostgreSQL " );
                    System.out.println( "   that you have installed.                                                    " );
                    System.out.println( "2) Copy the jar file into the Java Development Kit in the directory;" );
                    System.out.println( java_home + File.separator + "lib" + File.separator + "ext" + File.separator );

                    System.out.println( "3) Restart this installation program." );
                    System.out.println( "===============================================================================" );
                    System.exit( 1 );
                }
            }
            else
            {
                System.out.println( "   Bodington only supports the 3 specific database products mentioned above." );
                System.out.println( "   Only the specific versions listed above are suitable." );
                System.out.println();
                System.exit( 1 );
            }

            
            System.out.println( "===============================================================================" );
            System.out.println( "   Managing a serious database product is not to be taken lightly.  Please" );
            System.out.println( "   study the administration documentation and make yourself familiar with" );
            System.out.println( "   study procedures for routine maintainance and management." );
            System.out.println();
            
            System.out.println( "   Before you complete installation of Bodington you need to create an empty" );
            System.out.println( "   database within the database product.  You should set up scheduled backups " );
            System.out.println( "   as appropriate to your needs - in some database products if you fail to do  " );
            System.out.println( "   this the database data file will grow in size uncontrollably and eventually " );
            System.out.println( "   fail to record updates to records.  If you really don't want to make backups" );
            System.out.println( "   you must configure the database not to retain transaction logs.  " );
            System.out.println( "   Create a new user/login for the database with access to create and update" );
            System.out.println( "   records.          " );
            System.out.println( "   The database must be configured to support Unicode." );
            System.out.println( "   The database must be configured to never close idle connections." );
            System.out.println();
            System.out.print( "Have you completed configuration of the database? (Y/N)" );
            line = din.readLine();
            if ( !(line.equalsIgnoreCase( "y" ) || line.equalsIgnoreCase( "yes" )) )
            {
                System.out.println( "===============================================================================" );
                System.out.println( "Setup abandoned." );
                System.exit( 1 );
            }

            
            
            InetAddress address = InetAddress.getByName( "localhost" );
            Socket socket;
            OutputStream out;
            
            int[] required_ports =
            { 443, 8005, 8009, 80 };
            
            for ( int rp=0; rp < required_ports.length; rp++ )
            {
                try
                {
                    socket = new Socket( address, required_ports[rp] );
                    out = socket.getOutputStream();
                    out.write( 'H' );
                    out.write( 'E' );
                    out.write( 'L' );
                    out.write( 'L' );
                    out.write( 'O' );
                    out.write( '\r' );
                    out.write( '\n' );
                    socket.close();
                    System.out.println( "===============================================================================" );
                    System.out.println( "ERROR: There is a service/daemon listening on port " + required_ports[rp] + "." );
                    port_advice();
                    System.out.print( "Do you want to continue anyway? (Y/N)" );
                    line = din.readLine();
                    if ( !(line.equalsIgnoreCase( "y" ) || line.equalsIgnoreCase( "yes" )) )
                    {
                        System.out.println( "===============================================================================" );
                        System.out.println( "Setup abandoned." );
                        System.exit( 1 );
                    }
                }
                catch ( IOException ioex )
                {
                    System.out.println( "Port " + required_ports[rp] + " free." );
                    // the exeception is a good thing - it means the port is free
                }
            }
            
            
            System.out.println( "===============================================================================" );
            if ( windows )
            {
                System.out.println( "Suggested installation location: c:\\bodington" );
                destination = new File( "c:\\Bodington" );
            }
            else if ( unix )
            {
                System.out.println( "Suggested installation location: /usr/bodington" );
            }
            else
            {
                System.out.println( "Unable to suggest an installation location for this OS." );
            }
            
            System.out.print( "Enter the destination directory name: " );
            line = din.readLine();
            destination = new File( line );
            
            
            System.out.println( "===============================================================================" );
            System.out.println( "Unpacking main installation file to temporary directory." );
            
            InputStream zipfilein = getClass().getResourceAsStream( "/bodington.zip" );
            if ( zipfilein == null )
            {
                System.out.println( "Unable to access the software archive for setup." );
                System.exit( 1 );
            }
            
            File bodzip = File.createTempFile( "bod", ".zip" );
            System.out.println( "Temp file = " + bodzip.getAbsoluteFile() );
            FileOutputStream fout = new FileOutputStream( bodzip );
            byte[] buffer = new byte[4096];
            
            int b;
            while ( (b=zipfilein.read(buffer)) > 0 )
                fout.write(buffer, 0, b );
            
            fout.close();
            zipfilein.close();
            
            bodzip.deleteOnExit();
            
            System.out.println( "===============================================================================" );
            System.out.println( "Installing Tomcat and Bodington files to destination directory." );
            
            ZipFile zip = new ZipFile( bodzip );
            ZipEntry zip_entry;
            Enumeration list = zip.entries();
            File file_item, file_parent;
            while ( list.hasMoreElements() )
            {
                zip_entry = (ZipEntry)list.nextElement();
                //System.out.println( zip_entry.getName() );
                System.out.print( "." );
                if ( zip_entry.isDirectory() )
                {
                    file_item = new File( destination, zip_entry.getName() );
                    if ( !file_item.exists() )
                        file_item.mkdirs();
                }
                else
                {
                    file_item = new File( destination, zip_entry.getName() );
                    if ( file_item.exists() )
                    {
                        System.out.println( "===============================================================================" );
                        System.out.println( "Cannot continue setup because a file exists already in the destination." );
                        System.out.println( "Backup and delete all files in the destination to reinstall." );
                        System.exit( 1 );
                    }
                    // in case zip file doesn't include directory entries
                    // check to see of destination sub directory exists
                    file_parent = file_item.getParentFile();
                    if ( !file_parent.exists() )
                        file_parent.mkdirs();
                    zipfilein = zip.getInputStream( zip_entry );
                    fout = new FileOutputStream( file_item );
                    while ( (b=zipfilein.read( buffer )) >0 )
                        fout.write( buffer, 0, b );
                    fout.close();
                    zipfilein.close();
                }
            }
            
            File keystore = new File( destination,   File.separator +
            "conf" +
            File.separator +
            "keystore" );
            
            System.out.println( "===============================================================================" );
            System.out.println( "Your host computer may have one or more Internet alias names.  Enter the fully " );
            System.out.println( "qualified (i.e. including the domain) host name that you intend users to use   " );
            System.out.println( "to access this server.        " );
            String host_alias;
            InetAddress inet_test;
            do
            {
                System.out.print( "Enter IP host name: " );
                host_alias = din.readLine();
                try
                {
                    inet_test = InetAddress.getByName( host_alias );
                }
                catch ( Exception ie )
                {
                    inet_test = null;
                }
                if ( inet_test == null )
                    System.out.println( "The host name couldn't be resolved, please enter a valid name." );
            }
            while ( inet_test == null );
            generateKeyStore( keystore, host_alias );
            
            
            System.out.println( "===============================================================================" );
            System.out.println( "Saving configuration settings....." );
            
            File w = new File( destination,   File.separator +
            "conf" +
            File.separator +
            "wrapper.properties" );
            
            File scpt = new File( destination,   File.separator +
            "bin" +
            File.separator +
            "bodington" );
            
            
            
            if ( windows )
            {
                if ( catalina )
                    windows_service_cmd = wrapper_for_catalina( w, destination, jdk_home, xrs );
                else
                {
                    wrapper( w, destination, jdk_home, xrs );
                    File service = new File( destination,   File.separator +
                    "bin" +
                    File.separator +
                    "jk_nt_service" );
                    windows_service_cmd = service.getAbsolutePath() + " -I Bodington " + w.getAbsolutePath();
                }
            }
            else if ( unix )
            {
                script( scpt, destination, jdk_home );
            }
            else
            {
                System.out.println( "WARNING: It was not possible to create a start/stop script for this OS." );
                System.out.println( "Please consult product documentation for help with creating your own." );
                System.out.print( "Do you want to continue? (Y/N)" );
                line = din.readLine();
                if ( !(line.equalsIgnoreCase( "y" ) || line.equalsIgnoreCase( "yes" )) )
                {
                    System.out.println( "===============================================================================" );
                    System.out.println( "Setup abandoned." );
                    System.exit( 1 );
                }
            }
            
            
            Runtime rt = Runtime.getRuntime();
            Process p;
            if ( windows )
            {
                System.out.println( "===============================================================================" );
                System.out.println( "Registering a new Windows service." );
                p = rt.exec( windows_service_cmd );
                p.waitFor();
                System.out.println( "Exit code for registration:" + p.exitValue() );
                System.out.println( "===============================================================================" );
                System.out.println( "Starting the new Windows service." );
                p = rt.exec( "net start Bodington" );
                p.waitFor();
                System.out.println( "Exit code for startup:" + p.exitValue() );
                System.out.println( "===============================================================================" );
                
                if ( p.exitValue() != 0 )
                {
                    System.out.println( "UNABLE TO START THE BODINGTON SERVICE - TERMINATING SETUP." );
                }
                else
                    started=true;
            }
            else if ( unix )
            {
                System.out.println( "===============================================================================" );
                System.out.println( "Starting the Bodington System daemon via shell script." );
                String cmd = scpt.getAbsolutePath() + " start";
                System.out.println( "Using command: " + cmd );
                System.out.println( "(Consult your OS documentation to find out how to install this script " );
                System.out.println( "into the list of automatically started daemon scripts.) " );
                p = rt.exec( cmd );
                p.waitFor();
                System.out.println( "Exit code for startup:" + p.exitValue() );
                System.out.println( "===============================================================================" );
                
                if ( p.exitValue() != 0 )
                {
                    System.out.println( "UNABLE TO START THE BODINGTON SERVICE - TERMINATING SETUP." );
                }
                else
                    started=true;
            }
            
            Thread.currentThread().sleep( 5000 );
            
            if ( started )
            {
                System.out.println( "===============================================================================" );
                System.out.println( "Final setting up the Bodington System is carried out using a web browser.  To  " );
                System.out.println( "prevent unauthorised use of the web setup procedure it is protected by a       " );
                System.out.println( "password." );
                System.out.print( "Please enter your preferred password>" );
                line = din.readLine();
                line = line.trim();
                
                File adminpw = new File( destination, "webapps" + File.separator +
                "bodington" + File.separator +
                "WEB-INF" + File.separator + "adminpw.txt" );
                FileWriter adminpwdout = new FileWriter( adminpw );
                adminpwdout.write( line );
                adminpwdout.close();
                
                System.out.println( "Password was recorded as [" + line + "] in the file " );
                System.out.println( adminpw.getAbsolutePath() );
                System.out.println( "When setup is complete this file should be deleted to prevent " );
                System.out.println( "further use of the setup servlet. " );
                
                if ( windows )
                {
                    System.out.println( "===============================================================================" );
                    System.out.print( "Do you want to launch the browser on this computer? (Y/N)" );
                    line = din.readLine();
                    browser = line.equalsIgnoreCase( "y" ) || line.equalsIgnoreCase( "yes" );
                    if ( browser )
                    {
                        File urlfile = new File( destination, "home.url" );
                        generateURLFile( urlfile, host_alias );
                        System.out.println( "Starting web browser to continue setup." );
                        p = rt.exec( "cmd /C " + urlfile.getAbsolutePath() );
                        p.waitFor();
                        if ( p.exitValue() == 0 )
                            System.exit( 0 );
                    }
                }
            }
            
            if ( !started )
            {
                System.out.println( "===============================================================================" );
                System.out.println( "The Bodington service (contained within Tomcat) must be started before you " );
                System.out.println( "continue. Use the appropriate operating system tool to start it." );
                System.out.println( "===============================================================================" );
            }
            
            
            if ( unix )
            {
                System.out.println( "===============================================================================" );
                System.out.print( "If lynx is installed on this computer you can continue with setup by using the   " );
                System.out.println( "following command at this machine;" );
                System.out.print( "lynx http://localhost/" );
            }
            
            System.out.println( "===============================================================================" );
            System.out.println( "Next you need to access the Bodington System setup using a web browser." );
            System.out.println( "This can be done on this PC or any other PC that can connect to this one via " );
            System.out.println( "the network.  The web address is probably:" );
            System.out.println();
            System.out.println( "http://" + InetAddress.getLocalHost().getCanonicalHostName() + "/" );
            System.out.println( "or" );
            System.out.println( "http://" + InetAddress.getLocalHost().getHostAddress() + "/" );
            System.out.println();
            System.out.println( "If you use a web browser on the same computer as the Bodington System " );
            System.out.println( "then use the web address:" );
            System.out.println();
            System.out.println( "http://localhost/" );
            
            if ( !started )
            {
                System.out.println( "===============================================================================" );
                System.out.println( "The setup servlet uses the password, pingpong to prevent unauthorised use.     " );
                System.out.println( "When prompted please provide that password.  It is a security risk to leave the " );
                System.out.println( "Bodington System service running without completing the setup procedure and at  " );
                System.out.println( "end delete the setup servlet password file." );
            }
            System.out.println( "===============================================================================" );
            
            
            System.exit( 1 );
        }
        catch ( Exception ex )
        {
            System.err.println( ex.getMessage() );
            ex.printStackTrace();
        }
    }

    
        public void generateURLFile( File urlfile, String host )
    throws IOException
    {
        PrintWriter writer = new PrintWriter( new FileWriter( urlfile ) );
        writer.println( "[InternetShortcut]" );
        writer.print( "URL=http://" );
        writer.print( host );
        writer.println( "/index.html" );
        writer.close();
    }
    
    public void generateKeyStore( File keystore, String host )
    {
        String dname = "CN=" + host + ",OU=Demo,O=Demo,c=GB";
        String[] params = 
        {
            "-genkey",
            "-alias",
            "tomcat",
            "-keyalg",
            "RSA",
            "-keystore",
            keystore.getAbsolutePath(),
            "-storepass",
            "notverysecret",
            "-keypass",
            "notverysecret",
            "-dname",
            dname
        };
        
        KeyTool.main( params );
        /*
        URL[] url_list = new URL[1];
        url_list[0] = new URL( "file", null, tools_jar.getAbsolutePath() );
        URLClassLoader class_loader = new URLClassLoader( url_list, this.getClass().getClassLoader() );
        
        Class 
        */
    }
    
    
    
    public String wrapper_for_catalina( File wrapperfile, File bod_home, File java_home, boolean xrs )
    throws IOException
    {
        StringBuffer command = new StringBuffer();
        
        
        // set CATALINA_BASE=c:\jakarta-tomcat-4.0.3-LE-jdk14
        // set JAVA_ENDORSED_DIRS=%BASEDIR%\bin;%BASEDIR%\common\lib
        
        // set _EXECJAVA=Tomcat -install Tomcat %JAVA_HOME%\jre\bin\client\jvm.dll
        // set INSTALL_EXEC=%_EXECJAVA% -Xrs %JAVA_OPTS% %CATALINA_OPTS% %DEBUG_OPTS% -Djava.endorsed.dirs=%JAVA_ENDORSED_DIRS%
        // -Djava.class.path=%CLASSPATH% -Dcatalina.base=%CATALINA_BASE% -Dcatalina.home=%CATALINA_HOME%
        // -Djava.io.tmpdir=%CATALINA_TMPDIR% -start %MAINCLASS%
        // -params start -out %CATALINA_BASE%\stdout.log -err %CATALINA_BASE%\stderr.log -current %CATALINA_BASE%
        
        command.append( bod_home.getAbsolutePath() );
        command.append( "\\bin\\Tomcat -install Bodington \"" );
        command.append( java_home.getAbsolutePath() );
        command.append( "\\jre\\bin\\server\\jvm.dll\" " );
        
        if ( xrs )
            command.append( "-Xrs " );
        
        command.append( "-Xms64m -Xmx64m " );
        command.append( "-Djava.endorsed.dirs=" );
        command.append( bod_home.getAbsolutePath() );
        command.append( "\\bin;" );
        command.append( bod_home.getAbsolutePath() );
        command.append( "\\common\\lib " );
        command.append( "-Djava.class.path=\"" );
        command.append( java_home.getAbsolutePath() );
        command.append( "\\lib\\tools.jar;" );
        command.append( bod_home.getAbsolutePath() );
        command.append( "\\bin\\bootstrap.jar\" " );
        command.append( "-Dcatalina.base=" );
        command.append( bod_home.getAbsolutePath() );
        command.append( " -Dcatalina.home=" );
        command.append( bod_home.getAbsolutePath() );
        command.append( " -Djava.io.tmpdir=" );
        command.append( bod_home.getAbsolutePath() );
        command.append( "\\temp -start org.apache.catalina.startup.Bootstrap -params start -out " );
        command.append( bod_home.getAbsolutePath() );
        command.append( "\\stdout.log -err " );
        command.append( bod_home.getAbsolutePath() );
        command.append( "\\stderr.log -current " );
        command.append( bod_home.getAbsolutePath() );
        
        System.out.println( "Executing " + command.toString() );
        System.out.println( "=================================================================" );
        System.out.println( "The command about to execute will register a Windows Service." );
        System.out.println( "This command affects the Windows registry at;                " );
        System.out.println( "HKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet\\Services\\Bodington" );
        System.out.println( "The Java VM for the web server can be reconfigured with regedit." );
        System.out.println( "=================================================================" );
        PrintWriter writer = new PrintWriter( new FileWriter( wrapperfile ) );
        writer.println( command.toString() );
        writer.close();
        
        return command.toString();
    }
    
    public void wrapper( File wrapperfile, File bod_home, File java_home, boolean xrs )
    throws IOException
    {
        PrintWriter writer = new PrintWriter( new FileWriter( wrapperfile ) );
        
        writer.println( "wrapper.tomcat_home=" + bod_home.getAbsolutePath() );
        writer.println( "wrapper.java_home=" + java_home.getAbsolutePath() );
        
        writer.println( "wrapper.stdout=$(wrapper.tomcat_home)\\logs\\jvm.stdout" );
        writer.println( "wrapper.stderr=$(wrapper.tomcat_home)\\logs\\jvm.stderr" );
        
        writer.println( "wrapper.class_path=$(wrapper.tomcat_home)\\classes" );
        writer.println( "wrapper.class_path=$(wrapper.tomcat_home)\\lib\\jaxp.jar" );
        writer.println( "wrapper.class_path=$(wrapper.tomcat_home)\\lib\\parser.jar" );
        writer.println( "wrapper.class_path=$(wrapper.tomcat_home)\\lib\\webserver.jar" );
        writer.println( "wrapper.class_path=$(wrapper.tomcat_home)\\lib\\servlet.jar" );
        writer.println( "wrapper.class_path=$(wrapper.tomcat_home)\\lib\\jasper.jar" );
        writer.println( "wrapper.class_path=$(wrapper.tomcat_home)\\lib\\crimson.jar" );
        writer.println( "wrapper.class_path=$(wrapper.tomcat_home)\\lib\\bodxml.jar" );
        writer.println( "wrapper.class_path=$(wrapper.tomcat_home)\\lib\\bodserver.jar" );
        writer.println( "wrapper.class_path=$(wrapper.tomcat_home)\\lib\\j2ee.jar" );
        writer.println( "wrapper.class_path=$(wrapper.java_home)\\lib\\tools.jar" );
        
        
        writer.println( "wrapper.javabin=$(wrapper.java_home)\\bin\\java.exe" );
        
        writer.println( "wrapper.startup_class=org.apache.tomcat.startup.Tomcat" );
        
        writer.println( "wrapper.server_xml=$(wrapper.tomcat_home)\\conf\\server.xml" );
        writer.println( "wrapper.shutdown_port=8007" );
        writer.println( "wrapper.shutdown_protocol=ajp12" );
        writer.print( "wrapper.cmd_line=$(wrapper.javabin) " );
        
        if ( xrs )
            writer.print( "-Xrs " );
        
        writer.print( "-Xms64m -Xmx64m " );
        writer.print( "-Dtomcat.home=$(wrapper.tomcat_home) -classpath $(wrapper.class_path) " );
        writer.print( "$(wrapper.startup_class) -config $(wrapper.server_xml) " );
        writer.println( "-home $(wrapper.tomcat_home)" );
        
        writer.close();
    }
    
    public void script( File wrapperfile, File bod_home, File java_home )
    throws IOException, InterruptedException
    {
        PrintWriter writer = new PrintWriter( new FileWriter( wrapperfile ) );
        
        writer.print( "#!/bin/sh\n" );
        writer.print( "# Shell script to start and stop the server\n" );
        
        if ( catalina )
        {
            writer.print( "CATALINA_HOME=" + bod_home.getAbsolutePath() + "\n" );
            writer.print( "CATALINA_BASE=" + bod_home.getAbsolutePath() + "\n" );
            writer.print( "CATALINA_TMPDIR=" + bod_home.getAbsolutePath() + "temp/\n" );
            writer.print( "JAVA_OPTS=\"-Xms64m -Xmx64m\"\n" );
            writer.print( "JAVACMD=" + java_home.getAbsolutePath() + "/bin/java\n" );
            
            
            writer.print( "export CATALINA_HOME\n" );
            writer.print( "export CATALINA_HOME\n" );
            writer.print( "export CATALINA_TMPDIR \n" );
            writer.print( "export JAVA_OPTS\n" );
            writer.print( "export JAVACMD\n" );
            writer.print( "${CATALINA_HOME}/bin/catalina.sh $1 &>${CATALINA_HOME}/logs/stdouterr.log\n" );
        }
        else
        {
            writer.print( "TOMCAT_HOME=" + bod_home.getAbsolutePath() + "\n" );
            writer.print( "TOMCAT_OPTS=\"-Xms64m -Xmx64m\"\n" );
            writer.print( "JAVACMD=" + java_home.getAbsolutePath() + "/bin/java\n" );
            
            writer.print( "TOMCAT_CP=${TOMCAT_HOME}/classes\n" );
            
            writer.print( "export TOMCAT_HOME\n" );
            writer.print( "export TOMCAT_OPTS\n" );
            writer.print( "export JAVACMD\n" );
            writer.print( "export TOMCAT_CP\n" );
            writer.print( "${TOMCAT_HOME}/bin/bodington2.sh $1 &>${TOMCAT_HOME}/logs/stdouterr.log\n" );
        }
        
        
        writer.close();
        
        Runtime rt = Runtime.getRuntime();
        Process p;
        int exit_code;
        String cmd;
        
        cmd = "chmod a+x " + wrapperfile.getAbsolutePath();
        p = rt.exec( cmd );
        p.waitFor();
        exit_code = p.exitValue();
        System.out.println( "Exit code for chmod:" + exit_code );
        
        File script2 = new File( bod_home, "bin" + File.separator + (catalina?"catalina.sh":"bodington2.sh") );
        cmd = "chmod a+x " + script2.getAbsolutePath();
        p = rt.exec( cmd );
        p.waitFor();
        exit_code = p.exitValue();
        System.out.println( "Exit code for second chmod:" + exit_code );
    }
    
    public void port_advice()
    {
        System.out.println( "This installation program installs the web server Tomcat which serves pages" );
        System.out.println( "via ports 80 and 443 and listens on port 8005 for shutdown messages and port " );
        System.out.println( "8009 for control instructions.  It is important that you shut down and  " );
        System.out.println( "disable any programs/services/daemons that listen on any of these ports." );
        System.out.println( "" );
        System.out.println( "If you have already installed Bodington you should stop and uninstall it." );
        System.out.println( "" );
        System.out.println( "Please be aware that certain firewall software products may make it seem " );
        System.out.println( "as if a service/daemon is listening on a port when this is not the case. " );
        System.out.println( "If you are running firewall software check to see if ports are in use " );
        System.out.println( "manually yourself. " );
        System.out.println( "" );
    }
    
    public static void main( String[] args )
    {
        Install thing = new Install();
        
        thing.process();
    }
}
