/**
 * Copyright (c) 2000-2013 Liferay, Inc. All rights reserved.
 *
 * The contents of this file are subject to the terms of the Liferay Enterprise
 * Subscription License ("License"). You may not use this file except in
 * compliance with the License. You can obtain a copy of the License by
 * contacting Liferay, Inc. See the License for the specific language governing
 * permissions and limitations under the License, including but not limited to
 * distribution rights of the Software.
 *
 *
 *
 */

package com.liferay.portal.util;

import com.liferay.portal.configuration.ConfigurationImpl;
import com.liferay.portal.kernel.configuration.Configuration;
import com.liferay.portal.kernel.configuration.Filter;
import com.liferay.portal.kernel.log.Log;
import com.liferay.portal.kernel.log.LogFactoryUtil;
import com.liferay.portal.kernel.servlet.WebDirDetector;
import com.liferay.portal.kernel.util.CharPool;
import com.liferay.portal.kernel.util.ClassUtil;
import com.liferay.portal.kernel.util.GetterUtil;
import com.liferay.portal.kernel.util.PropsKeys;
import com.liferay.portal.kernel.util.ReleaseInfo;
import com.liferay.portal.kernel.util.ServerDetector;
import com.liferay.portal.kernel.util.StringPool;
import com.liferay.portal.kernel.util.StringUtil;
import com.liferay.portal.kernel.util.SystemProperties;
import com.liferay.portal.kernel.util.UnicodeProperties;
import com.liferay.portal.model.Company;
import com.liferay.portal.model.CompanyConstants;
import com.liferay.portal.security.auth.CompanyThreadLocal;

import java.util.HashMap;
import java.util.Map;
import java.util.Properties;

import javax.servlet.Servlet;

/**
 * @author Brian Wing Shun Chan
 */
public class PropsUtil {

	public static void addProperties(Company company, Properties properties) {
		_instance._addProperties(company, properties);
	}

	public static void addProperties(
		Company company, UnicodeProperties unicodeProperties) {

		_instance._addProperties(company, unicodeProperties);
	}

	public static void addProperties(Properties properties) {
		_instance._addProperties(properties);
	}

	public static void addProperties(UnicodeProperties unicodeProperties) {
		_instance._addProperties(unicodeProperties);
	}

	public static boolean contains(String key) {
		return _instance._contains(key);
	}

	public static String get(String key) {
		return _instance._get(key);
	}

	public static String get(String key, Filter filter) {
		return _instance._get(key, filter);
	}

	public static String[] getArray(String key) {
		return _instance._getArray(key);
	}

	public static String[] getArray(String key, Filter filter) {
		return _instance._getArray(key, filter);
	}

	public static Properties getProperties() {
		return getProperties(false);
	}

	public static Properties getProperties(boolean includeSystem) {
		Properties properties = _instance._getProperties();

		if (!includeSystem) {
			return properties;
		}

		Properties systemCompanyProperties = _instance._getProperties(
			CompanyConstants.SYSTEM);

		Properties mergedProperties =
			(Properties)systemCompanyProperties.clone();

		mergedProperties.putAll(properties);

		return mergedProperties;
	}

	public static Properties getProperties(
		String prefix, boolean removePrefix) {

		return _instance._getProperties(prefix, removePrefix);
	}

	public static void reload() {
		_instance = new PropsUtil();
	}

	public static void removeProperties(Properties properties) {
		_instance._removeProperties(properties);
	}

	public static void set(String key, String value) {
		_instance._set(key, value);
	}

	private PropsUtil() {
		try {

			// Default liferay home directory

			SystemProperties.set(
				PropsKeys.DEFAULT_LIFERAY_HOME, _getDefaultLiferayHome());

			// Global shared lib directory

			String globalSharedLibDir = _getLibDir(Servlet.class);

			if (_log.isInfoEnabled()) {
				_log.info("Global shared lib directory " + globalSharedLibDir);
			}

			SystemProperties.set(
				PropsKeys.LIFERAY_LIB_GLOBAL_SHARED_DIR, globalSharedLibDir);

			// Global lib directory

			String globalLibDir = _getLibDir(ReleaseInfo.class);

			if (_log.isInfoEnabled()) {
				_log.info("Global lib directory " + globalLibDir);
			}

			SystemProperties.set(
				PropsKeys.LIFERAY_LIB_GLOBAL_DIR, globalLibDir);

			// Portal lib directory

			Class<?> clazz = getClass();

			ClassLoader classLoader = clazz.getClassLoader();

			String portalLibDir = WebDirDetector.getLibDir(classLoader);

			String portalLibDirProperty = System.getProperty(
				PropsKeys.LIFERAY_LIB_PORTAL_DIR);

			if (portalLibDirProperty != null) {
				if (!portalLibDirProperty.endsWith(StringPool.SLASH)) {
					portalLibDirProperty += StringPool.SLASH;
				}

				portalLibDir = portalLibDirProperty;
			}

			if (_log.isInfoEnabled()) {
				_log.info("Portal lib directory " + portalLibDir);
			}

			SystemProperties.set(
				PropsKeys.LIFERAY_LIB_PORTAL_DIR, portalLibDir);

			// Portal web directory

			String portalWebDir = WebDirDetector.getRootDir(portalLibDir);

			if (_log.isDebugEnabled()) {
				_log.debug("Portal web directory " + portalWebDir);
			}

			SystemProperties.set(
				PropsKeys.LIFERAY_WEB_PORTAL_DIR, portalWebDir);

			// Liferay home directory

			_configuration = new ConfigurationImpl(
				PropsUtil.class.getClassLoader(), PropsFiles.PORTAL);

			String liferayHome = _get(PropsKeys.LIFERAY_HOME);

			if (_log.isDebugEnabled()) {
				_log.debug("Configured Liferay home " + liferayHome);
			}

			SystemProperties.set(PropsKeys.LIFERAY_HOME, liferayHome);

			// Ehcache disk directory

			SystemProperties.set(
				"ehcache.disk.store.dir", liferayHome + "/data/ehcache");

			if (GetterUtil.getBoolean(
					SystemProperties.get("company-id-properties"))) {

				_configurations = new HashMap<Long, Configuration>();
			}
		}
		catch (Exception e) {
			if (_log.isErrorEnabled()) {
				_log.error("Unable to initialize PropsUtil", e);
			}
		}
	}

	private void _addProperties(Company company, Properties properties) {
		Configuration configuration = _getConfiguration(company);

		configuration.addProperties(properties);
	}

	private void _addProperties(
		Company company, UnicodeProperties unicodeProperties) {

		Properties properties = new Properties();

		properties.putAll(unicodeProperties);

		_addProperties(company, properties);
	}

	private void _addProperties(Properties properties) {
		Configuration configuration = _getConfiguration();

		configuration.addProperties(properties);
	}

	private void _addProperties(UnicodeProperties unicodeProperties) {
		Properties properties = new Properties();

		properties.putAll(unicodeProperties);

		_addProperties(properties);
	}

	private boolean _contains(String key) {
		Configuration configuration = _getConfiguration();

		return configuration.contains(key);
	}

	private String _get(String key) {
		Configuration configuration = _getConfiguration();

		return configuration.get(key);
	}

	private String _get(String key, Filter filter) {
		Configuration configuration = _getConfiguration();

		return configuration.get(key, filter);
	}

	private String[] _getArray(String key) {
		Configuration configuration = _getConfiguration();

		return configuration.getArray(key);
	}

	private String[] _getArray(String key, Filter filter) {
		Configuration configuration = _getConfiguration();

		return configuration.getArray(key, filter);
	}

	private Configuration _getConfiguration() {
		return _getConfiguration(CompanyThreadLocal.getCompanyId());
	}

	private Configuration _getConfiguration(long companyId) {
		if (_configurations == null) {
			return _configuration;
		}

		if (companyId > CompanyConstants.SYSTEM) {
			Configuration configuration = _configurations.get(companyId);

			if (configuration == null) {
				configuration = new ConfigurationImpl(
					PropsUtil.class.getClassLoader(), PropsFiles.PORTAL,
					companyId);

				_configurations.put(companyId, configuration);
			}

			return configuration;
		}
		else {
			return _configuration;
		}
	}

	private Configuration _getConfiguration(Company company) {
		if (_configurations == null) {
			return _configuration;
		}

		long companyId = company.getCompanyId();

		Configuration configuration = _configurations.get(companyId);

		if (configuration == null) {
			configuration = new ConfigurationImpl(
				PropsUtil.class.getClassLoader(), PropsFiles.PORTAL, companyId,
				company.getWebId());

			_configurations.put(companyId, configuration);
		}

		return configuration;
	}

	private String _getDefaultLiferayHome() {
		String defaultLiferayHome = null;

		if (ServerDetector.isGeronimo()) {
			defaultLiferayHome =
				SystemProperties.get("org.apache.geronimo.home.dir") + "/..";
		}
		else if (ServerDetector.isGlassfish()) {
			defaultLiferayHome =
				SystemProperties.get("com.sun.aas.installRoot") + "/..";
		}
		else if (ServerDetector.isJBoss()) {
			defaultLiferayHome = SystemProperties.get("jboss.home.dir") + "/..";
		}
		else if (ServerDetector.isJOnAS()) {
			defaultLiferayHome = SystemProperties.get("jonas.base") + "/..";
		}
		else if (ServerDetector.isWebLogic()) {
			defaultLiferayHome =
				SystemProperties.get("env.DOMAIN_HOME") + "/..";
		}
		else if (ServerDetector.isJetty()) {
			defaultLiferayHome = SystemProperties.get("jetty.home") + "/..";
		}
		else if (ServerDetector.isResin()) {
			defaultLiferayHome = SystemProperties.get("resin.home") + "/..";
		}
		else if (ServerDetector.isTomcat()) {
			defaultLiferayHome = SystemProperties.get("catalina.base") + "/..";
		}
		else {
			defaultLiferayHome = SystemProperties.get("user.dir") + "/liferay";
		}

		defaultLiferayHome = StringUtil.replace(
			defaultLiferayHome, CharPool.BACK_SLASH, CharPool.SLASH);

		defaultLiferayHome = StringUtil.replace(
			defaultLiferayHome, StringPool.DOUBLE_SLASH, StringPool.SLASH);

		if (defaultLiferayHome.endsWith("/..")) {
			int pos = defaultLiferayHome.lastIndexOf(
				CharPool.SLASH, defaultLiferayHome.length() - 4);

			if (pos != -1) {
				defaultLiferayHome = defaultLiferayHome.substring(0, pos);
			}
		}

		if (_log.isDebugEnabled()) {
			_log.debug("Default Liferay home " + defaultLiferayHome);
		}

		return defaultLiferayHome;
	}

	private String _getLibDir(Class<?> clazz) {
		String path = ClassUtil.getParentPath(
			clazz.getClassLoader(), clazz.getName());

		int pos = path.lastIndexOf(".jar!");

		if (pos == -1) {
			pos = path.lastIndexOf(".jar/");
		}

		pos = path.lastIndexOf(CharPool.SLASH, pos);

		path = path.substring(0, pos + 1);

		return path;
	}

	private Properties _getProperties() {
		Configuration configuration = _getConfiguration();

		return configuration.getProperties();
	}

	private Properties _getProperties(long companyId) {
		Configuration configuration = _getConfiguration(companyId);

		return configuration.getProperties();
	}

	private Properties _getProperties(String prefix, boolean removePrefix) {
		Configuration configuration = _getConfiguration();

		return configuration.getProperties(prefix, removePrefix);
	}

	private void _removeProperties(Properties properties) {
		Configuration configuration = _getConfiguration();

		configuration.removeProperties(properties);
	}

	private void _set(String key, String value) {
		Configuration configuration = _getConfiguration();

		configuration.set(key, value);
	}

	private static Log _log = LogFactoryUtil.getLog(PropsUtil.class);

	private static PropsUtil _instance = new PropsUtil();

	private Configuration _configuration;
	private Map<Long, Configuration> _configurations;

}