/*
 * This file is part of Bunny.
 * Copyright (C) 2009 Bunny Develop Team.
 *
 * Bunny is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License any later version.
 *
 * Bunny 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 General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with Bunny. If not, see <http://www.gnu.org/licenses/>.
 */
package nuts.exts.app;

import java.io.InputStream;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Properties;

import javax.servlet.ServletContext;

import net.sf.json.JSONException;
import net.sf.json.JSONObject;

import nuts.core.io.IOUtils;
import nuts.core.lang.ClassLoaderUtils;
import nuts.core.orm.dao.DataAccessClient;
import nuts.core.orm.dao.DataAccessException;
import nuts.core.orm.dao.DataAccessSession;
import nuts.core.resource.DatabaseResourceLoader;
import nuts.exts.freemarker.DatabaseTemplateLoader;

import org.apache.commons.lang.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;


/**
 */
public class WebApplication {

	protected static Log log = LogFactory.getLog(WebApplication.class);

	protected static Properties properties;
	
	protected static Map cache;
	
	protected static DataAccessClient dataAccessClient;
	
	protected static DatabaseResourceLoader databaseResourceLoader;
	
	protected static DatabaseTemplateLoader databaseTemplateLoader;

	protected static ServletContext servletContext;
	
	protected static String appVersion;

	protected static List<String> localhosts;

	protected static String adminUsername;
	protected static String adminPassword;

	/**
	 * @return the log
	 */
	public static Log getLog() {
		return log;
	}

	/**
	 * @return the properties
	 */
	public static Properties getProperties() {
		return properties;
	}

	/**
	 * @param key key
	 * @return the property
	 */
	public static boolean getPropertyAsBoolean(String key) {
		return "true".equals(properties.getProperty(key));
	}

	/**
	 * @param key key
	 * @return the property
	 */
	public static int getPropertyAsInt(String key) {
		return Integer.parseInt(properties.getProperty(key));
	}

	/**
	 * @param key key
	 * @return the property
	 */
	public static int getPropertyAsInt(String key, int defaultVar) {
		try {
			return Integer.parseInt(properties.getProperty(key));
		}
		catch (NumberFormatException e) {
			return defaultVar;
		}
	}

	/**
	 * @param name resource name
	 * @return map value
	 */
	public static Map getPropertyAsMap(String name) {
		return getPropertyAsMap(name, null);
	}
	
	/**
	 * @param name resource name
	 * @param defaultValue default value
	 * @return map value
	 */
	public static Map getPropertyAsMap(String name, Map defaultValue) {
		Map map = defaultValue;

		String expr = getProperty(name);
		if (StringUtils.isNotEmpty(expr)) {
			expr = StringUtils.strip(expr);
			if (!expr.startsWith("{") || !expr.endsWith("}")) {
				expr = "{" + expr + "}";
			}

			String em = "Incorrect JSON Object expression: "
				+ name + " - " + expr;
			try {
				map = (Map)JSONObject.fromObject(expr);
			}
			catch (JSONException e) {
				throw new RuntimeException(em, e);
			}

			if (map == null) {
				throw new RuntimeException(em);
			}
		}

		return map;
	}

	/**
	 * @param key key
	 * @return the property
	 */
	public static String getProperty(String key) {
		return properties.getProperty(key);
	}

	/**
	 * @param key key
	 * @param def default value
	 * @return the property
	 */
	public static String getProperty(String key, String def) {
		return properties.getProperty(key, def);
	}

	public static String getPropertyAsPath(String name) {
		return getPropertyAsPath(name, null);
	}

	public static String getPropertyAsPath(String name, String defv) {
		String dir = getProperty(name, defv);
		if (dir.startsWith("/WEB-INF/")) {
			dir = WebApplication.getServletContext().getRealPath(dir);
		}
		return dir;
	}

	/**
	 * @return the cache
	 */
	public static Map getCache() {
		return cache;
	}

	/**
	 * @return the servletContext
	 */
	public static ServletContext getServletContext() {
		return servletContext;
	}

	/**
	 * @return the appVersion
	 */
	public static String getAppVersion() {
		return appVersion;
	}

	/**
	 * @return the localhosts
	 */
	public static List<String> getLocalhosts() {
		return localhosts;
	}

	/**
	 * @return the adminUsername
	 */
	public static String getAdminUsername() {
		return adminUsername;
	}

	/**
	 * @return the adminPassword
	 */
	public static String getAdminPassword() {
		return adminPassword;
	}

	/**
	 * @return the dataAccessSession
	 * @throws DataAccessException 
	 */
	public static DataAccessSession openDataAccessSession() throws DataAccessException {
		return dataAccessClient.openSession();
	}

	/**
	 * @return the dataAccessClient
	 */
	public static DataAccessClient getDataAccessClient() {
		return dataAccessClient;
	}

	/**
	 * @return the databaseResourceLoader
	 */
	public static DatabaseResourceLoader getDatabaseResourceLoader() {
		return databaseResourceLoader;
	}

	/**
	 * @return the databaseTemplateLoader
	 */
	public static DatabaseTemplateLoader getDatabaseTemplateLoader() {
		return databaseTemplateLoader;
	}

	protected static void loadProperties(String res) throws Exception {
		InputStream is = null;
		try {
			is = ClassLoaderUtils.getResourceAsStream(res);
			properties.load(is);
		}
		finally {
			IOUtils.closeQuietly(is);
		}
	}

	protected static void loadSystemProps() throws Exception {
		properties = new Properties();
		loadProperties("system.properties");
		loadProperties("nuts-dao.properties");

		try {
			loadProperties("test.properties");
		}
		catch (Exception e) {
			
		}

		appVersion = getProperty("prj.version.major") + "." 
			+ getProperty("prj.version.minor") + "."
			+ getProperty("prj.version.modif") + "."
			+ getProperty("prj.version.built");

		log.info("Version: " + appVersion);

		localhosts = Arrays.asList(StringUtils.split(
			getProperty("localhosts", "127.0.0.1  0.1.0.1  0:0:0:0:0:0:0:1")));

		adminUsername = getProperty("admin-username");
		adminPassword = getProperty("admin-password");
	}

	protected static String normalizePath(String path) {
		path.replace('\\', '/');
		if (!path.endsWith("/")) {
			path += "/";
		}
		return path;
	}

	protected static void startDaemonCronTask() throws Exception {
		//TODO
		if ("true".equals(properties.getProperty("daemon.cron"))) {
			log.info("Starting daemon cron task ...");
		}
	}
}
