package org.gcube.application.geoportal.managers;

import java.io.IOException;
import java.io.UncheckedIOException;
import java.net.URL;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Properties;

import javax.persistence.EntityManagerFactory;
import javax.persistence.SharedCacheMode;
import javax.persistence.ValidationMode;
import javax.persistence.spi.ClassTransformer;
import javax.persistence.spi.PersistenceUnitInfo;
import javax.persistence.spi.PersistenceUnitTransactionType;
import javax.sql.DataSource;

import org.gcube.application.geoportal.model.db.DatabaseConnection;
import org.gcube.application.geoportal.model.fault.ConfigurationException;
import org.gcube.application.geoportal.utils.ISUtils;
import org.hibernate.cfg.AvailableSettings;
import org.hibernate.jpa.HibernatePersistenceProvider;

import jersey.repackaged.com.google.common.collect.ImmutableMap;
import lombok.extern.slf4j.Slf4j;

@Slf4j
public class DefatulEMFProvider implements EMFProvider {

	private static EntityManagerFactory emf=null;

	
	@Override
	public EntityManagerFactory getFactory() {
		if(emf==null) {
			try {
				DatabaseConnection conn=ISUtils.queryForDB("postgresql", "internal-db");
				log.debug("Found Internal Database : "+conn);

				emf = new HibernatePersistenceProvider().createContainerEntityManagerFactory(
						archiverPersistenceUnitInfo(),
						ImmutableMap.<String, Object>builder()
						.put(AvailableSettings.JPA_JDBC_DRIVER, "org.postgresql.Driver")
						.put(AvailableSettings.JPA_JDBC_URL, conn.getUrl())
						.put(AvailableSettings.DIALECT, org.hibernate.dialect.PostgreSQLDialect.class)
						.put(AvailableSettings.HBM2DDL_AUTO, org.hibernate.tool.schema.Action.UPDATE)
						.put(AvailableSettings.SHOW_SQL, false)
						.put(AvailableSettings.QUERY_STARTUP_CHECKING, false)
						.put(AvailableSettings.GENERATE_STATISTICS, false)
						.put(AvailableSettings.USE_REFLECTION_OPTIMIZER, false)
						.put(AvailableSettings.USE_SECOND_LEVEL_CACHE, false)
						.put(AvailableSettings.USE_QUERY_CACHE, false)
						.put(AvailableSettings.USE_STRUCTURED_CACHE, false)
						.put(AvailableSettings.STATEMENT_BATCH_SIZE, 20)
						.put(AvailableSettings.JPA_JDBC_USER, conn.getUser())
						.put(AvailableSettings.JPA_JDBC_PASSWORD,conn.getPwd())
//						.put(AvailableSettings.AUTO_CLOSE_SESSION, true)
						.build());

			}catch(ConfigurationException e) {
			   throw new RuntimeException("Unable to init EMF",e);
			}
		}
		return emf;
	}

	
	private static PersistenceUnitInfo archiverPersistenceUnitInfo() {

		final List<String> MANAGED_CLASSES=Arrays.asList(new String[] {
				"org.gcube.application.geoportal.model.Record",
				"org.gcube.application.geoportal.model.concessioni.Concessione",
				"org.gcube.application.geoportal.model.concessioni.LayerConcessione",
				"org.gcube.application.geoportal.model.concessioni.RelazioneScavo",

				"org.gcube.application.geoportal.model.content.AssociatedContent",
				"org.gcube.application.geoportal.model.content.GeoServerContent",
				"org.gcube.application.geoportal.model.content.OtherContent",
				"org.gcube.application.geoportal.model.content.PersistedContent",
				"org.gcube.application.geoportal.model.content.UploadedImage",
				"org.gcube.application.geoportal.model.content.WorkspaceContent",

				"org.gcube.application.geoportal.model.gis.ShapeFileLayerDescriptor",
		"org.gcube.application.geoportal.model.gis.SDILayerDescriptor"});


		return new PersistenceUnitInfo() {
			@Override
			public String getPersistenceUnitName() {
				return "ApplicationPersistenceUnit";
			}

			@Override
			public String getPersistenceProviderClassName() {
				return "org.hibernate.jpa.HibernatePersistenceProvider";
			}

			@Override
			public PersistenceUnitTransactionType getTransactionType() {
				return PersistenceUnitTransactionType.RESOURCE_LOCAL;
			}

			@Override
			public DataSource getJtaDataSource() {
				return null;
			}

			@Override
			public DataSource getNonJtaDataSource() {
				return null;
			}

			@Override
			public List<String> getMappingFileNames() {
				return Collections.emptyList();
			}

			@Override
			public List<URL> getJarFileUrls() {
				try {
					return Collections.list(this.getClass()
							.getClassLoader()
							.getResources(""));
				} catch (IOException e) {
					throw new UncheckedIOException(e);
				}
			}

			@Override
			public URL getPersistenceUnitRootUrl() {
				return null;
			}

			@Override
			public List<String> getManagedClassNames() {
				return MANAGED_CLASSES;
			}

			@Override
			public boolean excludeUnlistedClasses() {
				return true;
			}

			@Override
			public SharedCacheMode getSharedCacheMode() {
				return null;
			}

			@Override
			public ValidationMode getValidationMode() {
				return null;
			}

			@Override
			public Properties getProperties() {
				return new Properties();
			}

			@Override
			public String getPersistenceXMLSchemaVersion() {
				return null;
			}

			@Override
			public ClassLoader getClassLoader() {
				return null;
			}

			@Override
			public void addTransformer(ClassTransformer transformer) {

			}

			@Override
			public ClassLoader getNewTempClassLoader() {
				return null;
			}
		};
	}


	@Override
	public void shutdown() {
		if(emf!=null) {
			if(emf.isOpen()) emf.close();
			emf=null;
		}
	}

}
