/*
 * $Header: /home/cvspublic/jakarta-slide/src/share/org/apache/slide/util/Configuration.java,v 1.22 2004/12/30 13:38:59 draier Exp $
 * $Revision: 1.22 $
 * $Date: 2004/12/30 13:38:59 $
 *
 * ====================================================================
 *
 * Copyright 1999-2002 The Apache Software Foundation
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 */

package org.apache.slide.util;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;

import org.apache.slide.common.Domain;
import org.apache.slide.store.Store;

/**
 * Provides default configuration for Slide components from the
 * <tt>slide.properties</tt> configuration file. All slide features
 * rely on the central configuration file.
 * <p>
 * The configuration file is loaded from the Java <tt>lib</tt>
 * directory, the classpath and the Castor JAR. Properties set in the
 * classpath file takes precedence over properties set in the Java library
 * configuration file and properties set in the Slide JAR, allowing for
 * each customization. All three files are named <tt>slide.properties</tt>.
 * <p>
 * For example, to change the domain init file in use, create a new
 * configuration file in the current directory, instead of modifying
 * the global one.
 *
 * @version $Revision: 1.22 $ $Date: 2004/12/30 13:38:59 $
 */
public abstract class Configuration {
    
    
    // --------------------------------------------------- Property Inner Class
    
    
    /**
     * Names of properties used in the configuration file.
     */
    public static class Property {
        
        
        // ---------------------------------------------------------- Constants
        
        
        /**
         * Property specifying the domain XML initialization file to use.
         * <pre>
         * org.apache.slide.domain
         * </pre>
         */
        public static final String DomainInitFilename =
            "org.apache.slide.domain";
        
        
        /**
         * Property specifying that internal security checking is enabled.
         * <pre>
         * org.apache.slide.security
         * </pre>
         */
        public static final String IntegratedSecurity =
            "org.apache.slide.security";
        
        
        /**
         * Property specifying that internal locking checks are enabled.
         * <pre>
         * org.apache.slide.lock
         * </pre>
         */
        public static final String IntegratedLocking = "org.apache.slide.lock";
        
        
        /**
         * Property specifying that version control is enabled.
         * <pre>
         * org.apache.slide.versioncontrol
         * </pre>
         */
        public static final String VersionControl = "org.apache.slide.versioncontrol";
        
        
        /**
         * Property specifying that search is enabled.
         * <pre>
         * org.apache.slide.versioncontrol
         * </pre>
         */
        public static final String Search = "org.apache.slide.search";
        
        
        /**
         * Property specifying that the binding is enabled.
         * <pre>
         * org.apache.slide.binding
         * </pre>
         */
        public static final String Binding = "org.apache.slide.binding";


        /**
         * Property specifying if events are enabled.
         * <pre>
         * org.apache.slide.events
         * </pre>
         */
        public static final String Events = "org.apache.slide.events";


        /**
         * Property specifying that redirect references are enabled.
         * <pre>
         * org.apache.slide.redirectreferences
         * </pre>
         */
        public static final String RedirectReferences = "org.apache.slide.redirectreferences";


        /**
         * Property specifying if UTF-8 should be used to encode URLs.
         * <pre>
         * org.apache.slide.urlEncoding
         * </pre>
         */
        public static final String UseUtf = "org.apache.slide.useUtf8";

        /**
         * Property specifying the encoding for URLs when it's not UTF-8.
         * <pre>
         * org.apache.slide.urlEncoding
         * </pre>
         */
        public static final String UrlEncoding = "org.apache.slide.urlEncoding";
        
        
        /**
         * Property specifying whether principal-identified locks are supported.
         * <pre>
         * org.apache.slide.principalIdentifiedLocks
         * </pre>
         */
        public static final String PrincipalIdentifiedLocks = "org.apache.slide.principalIdentifiedLocks";


        /**
         * Property specifying whether to run in debug mode.
         * <pre>
         * org.apache.slide.debug
         * </pre>
         */
        public static final String Debug = "org.apache.slide.debug";
        
        
        /**
         * The name of the configuration file.
         * <pre>
         * slide.properties
         * </pre>
         */
        public static final String FileName = "slide.properties";
        
        
        static final String ResourceName =
            "/org/apache/slide/slide.properties";
        
    }
    
    
    // -------------------------------------------------------------- Variables
    
    
    /**
     * The default properties loaded from the configuration file.
     */
    private static Properties _default;
    
    
    /**
     * True if the default configuration specified debugging.
     */
    private static boolean _debug;
    
    
    /**
     * True if integrated security checks are performed.
     */
    private static boolean _security;
    
    
    /**
     * True if integrated locking is used.
     */
    private static boolean _locking;
    
    
    /**
     * True if version control is used.
     */
    private static boolean _versioncontrol;
    
    
    /**
     * True if search is enabled.
     */
    private static boolean _search;
    
    
    /**
     * True if bind is enabled.
     */
    private static boolean _binding;

    
    /**
     * True if events should be fired
     */
    private static boolean _events;


    /**
     * True if redirect references are enabled.
     */
    private static boolean _redirectReferences;


    /**
     * Use UTF-8 encoding
     */
    private static boolean _useUtf8;

    /**
     * URL encoding.
     */
    private static String _urlEncoding;
    
    
    /**
     * Principal identified locks.
     */
    private static boolean _principalIdentifiedLocks;


    // ------------------------------------------------------------- Properties
    
    
    /**
     * Returns true if the default configuration specified debugging.
     */
    public static boolean debug() {
        return _debug;
    }
    
    
    /**
     * Returns true if integrated security checking is used.
     */
    public static boolean useIntegratedSecurity() {
        return _security;
    }
    
    
    /**
     * Returns true if integrated lock checking is used.
     */
    public static boolean useIntegratedLocking() {
        return _locking;
    }
    
    
    /**
     * Returns true if version control is used.
     */
    public static boolean useVersionControl() {
        return _versioncontrol;
    }
    
    
    /**
     * Returns true if search is enabled.
     */
    public static boolean useSearch () {
        return _search;
    }
    
    // TODO: move somewhere else?
    public static boolean useBinding (Store store) {
        return _binding && store.useBinding();
    }

    
    /**
     * TODO: dump?
     * Returns true if binding is enabled.
     */
    public static boolean useGlobalBinding () {
        return _binding;
    }

    
    /**
     * Returns true if events are enabled by default
     */
    public static boolean fireEvents() {
        return _events;
    }

    
    /**
     * Returns true if redirect references are enabled.
     */
    public static boolean useRedirectReferences () {
        return _redirectReferences;
    }


    /**
     * Returns true if UTF-8 should be used to encode urls.
     */
    public static boolean useUTF8() {
        return _useUtf8;
    }

    /**
     * Returns the used URL encoding when non UTF-8.
     */
    public static String urlEncoding() {
        return _urlEncoding;
    }
    
    /**
     * Returns the used URL encoding.
     */
    public static String realUrlEncoding() {
        return _useUtf8 ? "UTF-8" : _urlEncoding;
    }

    /**
     * Returns true if Principal identified locks are enabled.
     */
    public static boolean usePrincipalIdentifiedLocks() {
        return _principalIdentifiedLocks;
    }

    /**
     * Generic accessor to properties.
     * @param name property name
     * @return value or <code>null</code>.
     */
    public static String getProperty(String name) {
        return _default.getProperty(name);
    }
    
    // ------------------------------------------------------------ Initializer
    
    
    static {
        getDefault();
    }
    
    
    // --------------------------------------------------------- Public Methods
    
    
    /**
     * Returns the default configuration file. Changes to the returned
     * properties set will affect all Castor functions relying on the
     * default configuration.
     *
     * @return The default configuration
     */
    public static synchronized Properties getDefault() {
        if (_default == null) {
            load();
        }
        return _default;
    }
    
    
    // ------------------------------------------------------ Protected Methods
    
    
    /**
     * Called by {@link #getDefault} to load the configuration the
     * first time. Will not complain about inability to load
     * configuration file from one of the default directories, but if
     * it cannot find the JAR's configuration file, will throw a
     * run time exception.
     */
    protected static void load() {
        
        File file;
        InputStream is;
        
        // Get detault configuration from the Slide JAR.
        _default = new Properties();
        try {
            _default.load(Configuration.class.getResourceAsStream
                          (Property.ResourceName));
        } catch (Exception except) {
            // This should never happen
            //throw new RuntimeException
            //    (Messages.format("conf.notDefaultConfigurationFile",
            //                     Property.FileName));
        }
        
        // Get overriding configuration from the Java
        // library directory, ignore if not found.
        file = new File(System.getProperty("java.home"), "lib");
        file = new File(file, Property.FileName);
        if (file.exists()) {
            _default = new Properties(_default);
            try {
                _default.load(new FileInputStream(file));
                Domain.info("Configuration found in java.home");
            } catch (IOException except) {
                // Do nothing
            }
        }
        
        // Get overriding configuration from the classpath,
        // ignore if not found.
        try {
            is = Configuration.class.getResourceAsStream("/"
                                                         + Property.FileName);
            if ( is != null ) {
                _default = new Properties(_default);
                _default.load(is);
                Domain.info("Configuration found in classpath");
            }
        } catch (Exception except) {
            // Do nothing
        }
        
        String prop;
        
        prop = _default.getProperty(Property.Debug, "false");
        if (prop.equalsIgnoreCase("true") || prop.equalsIgnoreCase("on")) {
            _debug = true;
        }
        
        prop = _default.getProperty(Property.IntegratedSecurity, "true");
        if (prop.equalsIgnoreCase("true") || prop.equalsIgnoreCase("on")) {
            _security = true;
        } else {
            _security = false;
        }
        
        prop = _default.getProperty(Property.IntegratedLocking, "true");
        if (prop.equalsIgnoreCase("true") || prop.equalsIgnoreCase("on")) {
            _locking = true;
        } else {
            _locking = false;
        }
        
        prop = _default.getProperty(Property.VersionControl, "true");
        if (prop.equalsIgnoreCase("true") || prop.equalsIgnoreCase("on")) {
            _versioncontrol = true;
        } else {
            _versioncontrol = false;
        }
        
        prop = _default.getProperty(Property.Search, "true");
        if (prop.equalsIgnoreCase("true") || prop.equalsIgnoreCase("on")) {
            _search = true;
        } else {
            _search = false;
        }
        
        prop = _default.getProperty(Property.Binding, "true");
        if (prop.equalsIgnoreCase("true") || prop.equalsIgnoreCase("on")) {
            _binding = true;
        } else {
            _binding = false;
        }

        prop = _default.getProperty(Property.Events, "false");
        if (prop.equalsIgnoreCase("true") || prop.equalsIgnoreCase("on")) {
            _events = true;
        } else {
            _events = false;
        }

        prop = _default.getProperty(Property.RedirectReferences, "true");
        if (prop.equalsIgnoreCase("true") || prop.equalsIgnoreCase("on")) {
            _redirectReferences = true;
        } else {
            _redirectReferences = false;
        }

        prop = _default.getProperty(Property.PrincipalIdentifiedLocks, "false");
        if (prop.equalsIgnoreCase("true") || prop.equalsIgnoreCase("on")) {
            _principalIdentifiedLocks = true;
        } else {
            _principalIdentifiedLocks = false;
        }

        prop = _default.getProperty(Property.UseUtf, "true");
        if (prop.equalsIgnoreCase("true") || prop.equalsIgnoreCase("on")) {
            _useUtf8 = true;
        } else {
            _useUtf8 = false;
        }

        String defaultEncoding = new java.io.InputStreamReader(System.in).getEncoding();
        _urlEncoding = _default.getProperty(Property.UrlEncoding, defaultEncoding);
        
    }
    
}
