package org.jboss.aerogear.unifiedpush;

import java.beans.PropertyVetoException;
import java.io.IOException;
import java.util.Properties;

import javax.persistence.EntityManagerFactory;
import javax.sql.DataSource;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.PropertiesFactoryBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
import org.springframework.core.env.Environment;
import org.springframework.core.io.ClassPathResource;
import org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor;
import org.springframework.orm.jpa.JpaTransactionManager;
import org.springframework.orm.jpa.JpaVendorAdapter;
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
import org.springframework.orm.jpa.vendor.AbstractJpaVendorAdapter;
import org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.util.StringUtils;

import com.mchange.v2.c3p0.ComboPooledDataSource;

@Configuration
@PropertySource(value = { "classpath:db.properties", "file://${org.jboss.aerogear.unifiedpush.conf}/db.properties" }, ignoreResourceNotFound = true)
public class PersistenceJPAConfig {
	private static final Logger logger = LoggerFactory.getLogger(PersistenceJPAConfig.class);
	private static String[] RESOURCES = new String[] { 
			"META-INF/orm.xml", 
			"org/jboss/aerogear/unifiedpush/api/Installation.hbm.xml",
			"org/jboss/aerogear/unifiedpush/api/Category.hbm.xml", 
			"org/jboss/aerogear/unifiedpush/api/PushMessageInformation.hbm.xml",
			"org/jboss/aerogear/unifiedpush/api/VariantMetricInformation.hbm.xml" 
	};
	
	private static final String SYS_KEY_DB_NAME = "org.jboss.aerogear.unifiedpush.initdb.database";

	@Autowired
	private Environment env;

	@Bean
	public DataSource dataSource() {
		final ComboPooledDataSource dataSource = new ComboPooledDataSource();
		String databaseName;
		
		try {
			dataSource.setDriverClass(env.getProperty("jdbc.driverClassName"));
		} catch (final PropertyVetoException e) {
			logger.error("Error while loading datasource driver!", e);
		}
		
		// Override databaseName from -D if exists
		if (System.getProperties().contains(SYS_KEY_DB_NAME) && !StringUtils.isEmpty(System.getProperties().get(SYS_KEY_DB_NAME))){
			databaseName = System.getProperties().getProperty(SYS_KEY_DB_NAME);
		}else {
			databaseName = env.getProperty("jdbc.database");
		}
		
		
		dataSource.setJdbcUrl(String.format(env.getProperty("jdbc.url"), databaseName));
		dataSource.setUser(env.getProperty("jdbc.username"));

		return dataSource;
	}

	@Bean
	public EntityManagerFactory entityManagerFactory() {
		final LocalContainerEntityManagerFactoryBean em = new LocalContainerEntityManagerFactoryBean();
		em.setDataSource(dataSource());
		em.setMappingResources(RESOURCES);
		
		final JpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
		((AbstractJpaVendorAdapter) vendorAdapter).setGenerateDdl(true);
		em.setJpaVendorAdapter(vendorAdapter);
		em.setJpaProperties(additionalProperties());
		em.afterPropertiesSet();

		return em.getObject();
	}

	@Bean
	public PlatformTransactionManager transactionManager() {
		return new JpaTransactionManager(entityManagerFactory());
	}

	@Bean
	public PersistenceExceptionTranslationPostProcessor exceptionTranslation() {
		return new PersistenceExceptionTranslationPostProcessor();
	}

	Properties additionalProperties() {
		Properties props = null;
		final PropertiesFactoryBean propertiesBean = new PropertiesFactoryBean();
		propertiesBean.setLocation(new ClassPathResource("hbm.properties"));

		try {
			propertiesBean.afterPropertiesSet();
			props = propertiesBean.getObject();
		} catch (final IOException e) {
			logger.error("Error while reading hbm.properties from class path", e);
			props = new Properties();
		}
		// Add Hibernate Dialect from db.properties
		props.setProperty("hibernate.dialect", env.getProperty("hibernate.dialect"));
		props.setProperty("hibernate.hbm2ddl.auto", env.getProperty("hibernate.hbm2ddl.auto"));
		return props;
	}

}
@@ -767,16 +767,90 @@
 cessor;%0A
+import org.springframework.jdbc.datasource.lookup.SingleDataSourceLookup;%0A
 import o
@@ -1019,32 +1019,189 @@
 gerFactoryBean;%0A
+import org.springframework.orm.jpa.persistenceunit.DefaultPersistenceUnitManager;%0Aimport org.springframework.orm.jpa.persistenceunit.PersistenceUnitManager;%0A
 import org.sprin
@@ -3244,68 +3244,55 @@
 .set
-DataSource(dataSource());%0A%09%09em.setMappingResources(RESOURCES
+PersistenceUnitManager(persistenceUnitManager()
 );%0A%09
@@ -3575,24 +3575,420 @@
 ject();%0A%09%7D%0A%0A
+%09@Bean%0A%09public PersistenceUnitManager persistenceUnitManager()%7B%0A%09%09DefaultPersistenceUnitManager pm = new DefaultPersistenceUnitManager();%0A%09%09DataSource dataSource = dataSource();%0A%09%09%0A%09%09pm.setDataSourceLookup(new SingleDataSourceLookup(dataSource()));%0A%09%09pm.setDefaultDataSource(dataSource);%0A%09%09pm.setMappingResources(RESOURCES);%0A%09%09pm.setDefaultPersistenceUnitRootLocation(null);%0A%09%09%0A%09%09return pm;%0A%09%7D%0A%09%0A
 %09@Bean%0A%09publ

Fix javax.persistence.PersistenceException: Unable to resolve persistence unit root URL