/**
 * JOnAS: Java(TM) Open Application Server
 * Copyright (C) 1999-2008 Bull S.A.S.
 * Contact: jonas-team@ow2.org
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
 *
 * --------------------------------------------------------------------------
 * $Id$
 * --------------------------------------------------------------------------
 */

package org.ow2.jonas.commands.check;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.net.ServerSocket;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties;

/**
 * This class allows to check if the environment is correct for JOnAS.
 * @author Francois Fornaciari
 */
public final class CheckEnv {

    /**
     * Constant result of JOnAS's conf check [OK].
     */
    public static final int ENV_OK = 0;

    /**
     * Constant result of the JOnAS configuration check [Error].
     */
    public static final int ENV_ERROR = 1;

    /**
     * Constant JONAS_ROOT.
     */
    private static final String JONAS_ROOT = "jonas.root";

    /**
     * Constant JONAS_BASE.
     */
    private static final String JONAS_BASE = "jonas.base";

    /**
     * Constant JORAM deployment plan name.
     */
    private static final String JORAM_XML = "joram.xml";

    /**
     * JORAM admin configuration file.
     */
    private static final String JORAM_ADMIN_FILE = "joramAdmin.xml";

    /**
     * Property files to check.
     */
    private static List<String> propertyFilesToCheck = new ArrayList<String>();

    /**
     * Initialize files to check.
     */
    static {
        propertyFilesToCheck.add("conf/trace.properties");
        propertyFilesToCheck.add("conf/carol.properties");
        propertyFilesToCheck.add("conf/jonas-realm.xml");
    }

    /**
     * Jar files to check.
     */
    private static List<String> jarFilesToCheck = new ArrayList<String>();

    /**
     * Initialize jar files to check.
     */
    static {
        jarFilesToCheck.add("lib/client.jar");
        jarFilesToCheck.add("lib/jonas-client-core.jar");
        jarFilesToCheck.add("lib/bootstrap/client-bootstrap.jar");
        jarFilesToCheck.add("lib/bootstrap/jonas-launcher.jar");
        jarFilesToCheck.add("lib/bootstrap/jonas-commands.jar");
        jarFilesToCheck.add("lib/common/util-ant-tasks.jar");
        jarFilesToCheck.add("lib/common/ow_jonas_ant.jar");
    }

    /**
     * Status of the the JOnAS configuration check.
     */
    private int envStatus = ENV_OK;

    /**
     * JONAS_ROOT.
     */
    private String jonasRoot = null;

    /**
     * JONAS_BASE.
     */
    private String jonasBase = null;

    /**
     * Build new instance.
     * @param args command arguments
     */
    public CheckEnv(final String[] args) {
        // Get command arguments
        for (String arg : args) {
            if (arg.equals("-help") || arg.equals("-?")) {
                help();
                System.exit(0);
            }
        }

        jonasRoot = System.getProperty(JONAS_ROOT);
        jonasBase = System.getProperty(JONAS_BASE);

        // Perform the check
        envStatus = performCheck();
        if (envStatus == ENV_OK) {
            System.out.println("\nThe JOnAS environment seems correct.");
            System.exit(0);
        } else if (envStatus == ENV_ERROR) {
            System.out.println("\nERROR : The JOnAS environment is NOT correct.");
            System.exit(2);
        }
    }

    /**
     * Main function, creates a new {@link CheckEnv} instance.
     * @param args See {@link CheckEnv#ClientAdmin(String[])}.
     */
    public static void main(final String[] args) {
        new CheckEnv(args);
    }

    /**
     * Check the JOnAS's configuration.
     * @return check status
     */
    public int performCheck() {
        envStatus = ENV_OK;

        // Check JOnAS properties
        checkJOnASProperties();

        // Check declared property files
        for (String fileName : propertyFilesToCheck) {
            if (!fileExists(jonasBase, fileName)) {
                System.out.println("ERROR : '" + fileName + "' not accessible in " + jonasBase);
                envStatus = ENV_ERROR;
            }
        }

        // Check declared jar files
        for (String fileName : jarFilesToCheck) {
            if (!fileExists(jonasRoot, fileName)) {
                System.out.println("ERROR : '" + fileName + "' not accessible in " + jonasRoot);
                envStatus = ENV_ERROR;
            }
        }

        // Check JORAM RA configuration
        checkJORAM();

        // Check port availability
        checkPortAvailability();

        return envStatus;
    }

    /**
     * Check if a file exists.
     * @param parent The parent file
     * @param fileName The file name
     * @return True is the given file is accessible
     */
    private boolean fileExists(final String parent, final String fileName) {
        return new File(parent, fileName).exists();
    }

    /**
     * Print help message.
     */
    private void help() {
        System.out.println("This command allows to check that the JOnAS environment is correctly set.");
    }

    /**
     * Get all properties from a file.
     * @param fileName the file name
     * @return Properties for a given file
     */
    private Properties getProperties(final String fileName) {
        Properties props = null;
        InputStream is = getClass().getClassLoader().getResourceAsStream(fileName);
        if (is != null) {
            props = new Properties();
            try {
                props.load(is);
            } catch (IOException e) {
                props = null;
            }
        }
        return props;
    }

    /**
     * Check JOnAS properties.
     */
    private void checkJOnASProperties() {
        System.out.println("\nChecking jonas.properties file...");

        try {
            // Check jonas.properties file
            Properties properties = getProperties("jonas.properties");
            String services = properties.getProperty("jonas.services");

            if (services != null) {
                System.out.println("- jonas.services : " + services);
            } else {
                System.out.println("ERROR: jonas.services not defined in jonas.properties");
                envStatus = ENV_ERROR;
            }

            String jonasContent = properties.toString();
            if (jonasContent.length() == 0) {
                System.out.println("ERROR : jonas.properties is empty");
                envStatus = ENV_ERROR;
            }
        } catch (Exception e) {
            System.out.println("ERROR: 'jonas.properties' not accessible (" + e + ")");
            envStatus = ENV_ERROR;
        }
    }

    /**
     * Check JORAM RA configuration.
     */
    private void checkJORAM() {
        System.out.println("\nChecking JORAM configuration...");

        File deployDirectory = new File(jonasBase, "deploy");
        if (!new File(deployDirectory, JORAM_XML).exists()) {
            System.out.println("ERROR : the file '" + JORAM_XML + "' was not found in JONAS_BASE/deploy directory");
            envStatus = ENV_ERROR;
        }

        // Check presence of joramAdmin.xml
        File joramAdminFile = new File(jonasBase + File.separator + "conf" + File.separator + JORAM_ADMIN_FILE);
        if (!joramAdminFile.exists()) {
            System.out.println("ERROR : the file " + JORAM_ADMIN_FILE + " was not found in JONAS_BASE/conf directory");
            envStatus = ENV_ERROR;
        }
    }

    /**
     * Check port availability.
     */
    private void checkPortAvailability() {
        System.out.println("\nChecking port availability...");

        Properties carolProperties = getProperties("carol.properties");
        String protocols = carolProperties.getProperty("carol.protocols");

        int port = -1;

        for (String protocol : protocols.split(",")) {
            try {
                URI url = new URI(carolProperties.getProperty("carol." + protocol + ".url"));
                port = url.getPort();
                ServerSocket sock = new ServerSocket(port);
                sock.close();
            } catch (URISyntaxException e) {
                System.out.println("ERROR : the URL for the '" + protocol + "' protocol is malformed");
                envStatus = ENV_ERROR;
            } catch (IOException e) {
                System.out.println("ERROR : the port number " + port + " is already open");
                envStatus = ENV_ERROR;
            }
        }
    }
}
