/* ===================================================================
 * AppContextInitializer.java
 * 
 * Created Feb 25, 2005 5:15:22 PM
 * 
 * Copyright (c) 2005 Matt Magoffin (spamsqr@msqr.us)
 * 
 * This program 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 2 of 
 * the License, or (at your option) any later version.
 * 
 * This program 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 this program; if not, write to the Free Software 
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 
 * 02111-1307 USA
 * ===================================================================
 * $Id: AppContextInitializer.java 90 2009-05-19 01:36:15Z msqr $
 * ===================================================================
 */

package magoffin.matt.ieat.web.util;

import java.util.List;
import java.util.Map;

import magoffin.matt.ieat.biz.DomainObjectFactory;
import magoffin.matt.ieat.web.WebConstants;
import magoffin.matt.xweb.XAppContext;
import magoffin.matt.xweb.XwebParameter;
import magoffin.matt.xweb.util.AppContextSupport;
import magoffin.matt.xweb.util.XwebParamDao;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.web.context.WebApplicationContext;

/**
 * Class to initialize the iEat AppContext data and cache in the 
 * servlet context.
 * 
 * <p>The configurable properties of this class are:</p>
 * 
 * <dl>
 *   <dt>domainObjectFactory</dt>
 *   <dd>The DomainObjectFactory to use for creating domain objects.</dd>
 * 
 *   <dt>applicationProperties</dt>
 *   <dd>Specific environment properties to make available to the application (e.g. view layer).</dd>
 *   
 *   <dt>parameterDao</dt>
 *   <dd>The {@link XwebParamDao} for loading database properties.</dd>
 *   
 *   <dt>jdbcTemplate</dt>
 *   <dd>The JdbcTemplate to use for accessing the Users table with.</dd>
 *   
 *   <dt>sqlAdminUserCount</dt>
 *   <dd>The SQL to use to return the count of admin users in the database.</dd>
 * </dl>
 * 
 * @author Matt Magoffin (spamsqr@msqr.us)
 * @version $Revision: 90 $ $Date: 2009-05-19 13:36:15 +1200 (Tue, 19 May 2009) $
 */
public class AppContextInitializer implements ApplicationContextAware {
	
	private final Log logger = LogFactory.getLog(getClass());
	
	private DomainObjectFactory domainObjectFactory;
	private Map<String, String> applicationProperties;
	private JdbcTemplate jdbcTemplate;
	private XwebParamDao parameterDao;
	private String sqlAdminUserCount = "select count(*) from Users where accessLevel > 0";

	/* (non-Javadoc)
	 * @see org.springframework.context.ApplicationContextAware#setApplicationContext(org.springframework.context.ApplicationContext)
	 */
	@SuppressWarnings("unchecked")
	public void setApplicationContext(ApplicationContext applicationContext)
			throws BeansException {
		if ( !(applicationContext instanceof WebApplicationContext) ) {
			throw new RuntimeException("Only the " +WebApplicationContext.class 
					+" application context is supported.");
		}
		
		WebApplicationContext webAppCtx = (WebApplicationContext)applicationContext;
		
		XAppContext appCtx = domainObjectFactory.newXAppContextInstance();
		for ( String key : applicationProperties.keySet() ) {
			XwebParameter param = domainObjectFactory.newXwebParameterInstance();
			param.setKey(key);
			param.setValue(applicationProperties.get(key));
			appCtx.getParam().add(param);
		}
		
		// get 'admin exists' property and make sure set in database
		if ( jdbcTemplate != null && parameterDao != null ) {
			int numAdminUsers = jdbcTemplate.queryForInt(this.sqlAdminUserCount);
			XwebParameter adminSetting = domainObjectFactory.newXwebParameterInstance();
			adminSetting.setKey(WebConstants.SETTING_KEY_ADMIN_USER_EXISTS);
			adminSetting.setValue(numAdminUsers > 0 ? Boolean.TRUE.toString() : Boolean.FALSE.toString());
			parameterDao.updateParameter(adminSetting);
			updateAppContextParam(appCtx, adminSetting);
		}
		if ( parameterDao != null ) {
			XwebParameter setupParam = parameterDao.getParameter(WebConstants.SETTING_KEY_SETUP_COMPLETE);
			if ( setupParam != null ) {
				updateAppContextParam(appCtx, setupParam);
			}
		}
		
		// cache the configuration in the servlet context
		
		AppContextSupport appCtxSupport = new AppContextSupport(appCtx);

		if ( logger.isDebugEnabled() ) {
			logger.debug("Storing AppContext [" +appCtx +"] with " +appCtx.getParam().size()
					+" properties in the servlet context at ["
					+WebConstants.APP_KEY_APP_CONTEXT +"]");
		}
		
		webAppCtx.getServletContext().setAttribute(WebConstants.APP_KEY_APP_CONTEXT,
				appCtxSupport);
	}

	@SuppressWarnings("unchecked")
	private void updateAppContextParam(XAppContext appCtx, XwebParameter newParam) {
		boolean found = false;
		for ( XwebParameter param : (List<XwebParameter>)appCtx.getParam() ) {
			if ( newParam.getKey().equals(param.getKey()) ) {
				found = true;
				param.setValue(newParam.getValue());
				break;
			}
		}
		if ( !found ) {
			appCtx.getParam().add(newParam);
		}
	}
	
	/**
	 * @return the domainObjectFactory
	 */
	public DomainObjectFactory getDomainObjectFactory() {
		return domainObjectFactory;
	}
	
	/**
	 * @param domainObjectFactory the domainObjectFactory to set
	 */
	public void setDomainObjectFactory(DomainObjectFactory domainObjectFactory) {
		this.domainObjectFactory = domainObjectFactory;
	}
	
	/**
	 * @return the jdbcTemplate
	 */
	public JdbcTemplate getJdbcTemplate() {
		return jdbcTemplate;
	}
	
	/**
	 * @param jdbcTemplate the jdbcTemplate to set
	 */
	public void setJdbcTemplate(JdbcTemplate jdbcTemplate) {
		this.jdbcTemplate = jdbcTemplate;
	}
	
	/**
	 * @return the sqlAdminUserCount
	 */
	public String getSqlAdminUserCount() {
		return sqlAdminUserCount;
	}
	
	/**
	 * @param sqlAdminUserCount the sqlAdminUserCount to set
	 */
	public void setSqlAdminUserCount(String sqlAdminUserCount) {
		this.sqlAdminUserCount = sqlAdminUserCount;
	}

	/**
	 * @return the applicationProperties
	 */
	public Map<String, String> getApplicationProperties() {
		return applicationProperties;
	}

	/**
	 * @param applicationProperties the applicationProperties to set
	 */
	public void setApplicationProperties(Map<String, String> applicationProperties) {
		this.applicationProperties = applicationProperties;
	}

	/**
	 * @return the parameterDao
	 */
	public XwebParamDao getParameterDao() {
		return parameterDao;
	}

	/**
	 * @param parameterDao the parameterDao to set
	 */
	public void setParameterDao(XwebParamDao parameterDao) {
		this.parameterDao = parameterDao;
	}
	
}
