package eu.dnetlib.xml.database.exist;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.StringReader;
import java.io.StringWriter;

import eu.dnetlib.enabling.is.store.BulkResourceImporter;
import org.apache.commons.io.IOUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Required;

/**
 * Persistent exist.
 *
 * TODO: this is copy&paste from TemporaryExistDatase. Refactor common stuff.
 *
 * @author marko
 *
 */
public class PersistentExistDatabase extends ExistDatabase {

	/**
	 * logger.
	 */
	private static final Log log = LogFactory.getLog(PersistentExistDatabase.class); // NOPMD by marko on 11/24/08 5:02 PM

	/**
	 * db directory.
	 */
	private transient File dbDirectory;

	/**
	 * this config file will be copied to a newly created temporary directory.
	 */
	private String configTemplate = "default-exist-conf.xml";

	/**
	 * db root path.
	 */
	private String dbRootPath;

	/**
	 * bulk importer.
	 */
	@Autowired
	private BulkResourceImporter bulkImporter;

	/**
	 * exist config file.
	 */
	private File existConfigFile;

	/**
	 * true if the database permits execution of java code from xquery.
	 */
	private boolean XQueryJavaEnabled;

	/**
	 * {@inheritDoc}
	 *
	 * @see eu.dnetlib.xml.database.exist.ExistDatabase#start()
	 */
	@Override
	public void start() {
		log.warn("STARTING PERSISTENT EXIST DATABASE");
		dbDirectory = new File(dbRootPath);

		if (dbDirectory.exists()) {
			getBulkImporter().setEnabled(false);
			existConfigFile = new File(dbDirectory, "conf.xml");
			enableJava(existConfigFile, isXQueryJavaEnabled());
			setConfigFile(existConfigFile.getAbsolutePath());
		} else {
			createPersistentDatabase();
		}

		super.start();
	}

	@Override
	public void stop() {
		log.info("shutting down xmldb");
		super.stop();
		log.info("xmldb closed");
	}

	protected void enableJava(final File conf, final boolean enabled) {
		final StringWriter buffer = new StringWriter();
		if (conf.exists()) {
			try {
				IOUtils.copy(new FileReader(conf), buffer);
				final String newConf = patchConfigFileEnableJava(buffer.toString(), enabled);
				if (!newConf.equals(buffer.toString())) {
					FileWriter writer = new FileWriter(conf);
					try {
						IOUtils.copy(new StringReader(newConf), writer);
					} finally {
						writer.close();
					}
				}
			} catch (final FileNotFoundException e) {
				log.warn("cannot patch eXist conf file", e);
			} catch (final IOException e) {
				log.warn("cannot patch eXist conf file", e);
			}
		}
	}

	/**
	 * @param conf
	 *            content of the configuration file
	 * @param enabled
	 *            enabled or disabled
	 * @return new conf file
	 */
	protected String patchConfigFileEnableJava(final String conf, final boolean enabled) {
		return conf.replaceAll("enable-java-binding=\"[^\"]*\"", "enable-java-binding=\"" + (enabled ? "yes" : "no") + "\"");
	}

	/**
	 * create a temporary directory and copy the default configuration file.
	 */
	protected void createPersistentDatabase() {
		log.debug("creating persistent database");
		try {
			new File(dbDirectory, "data").mkdirs();

			final InputStream defaultConf = getClass().getResourceAsStream(getConfigTemplate());
			if (defaultConf == null)
				throw new IOException("cannot find " + getConfigTemplate());

			existConfigFile = new File(dbDirectory, "conf.xml");
			final FileOutputStream confOutput = new FileOutputStream(existConfigFile);

			try {
				IOUtils.copy(defaultConf, confOutput);
			} finally {
				confOutput.close();
			}
			enableJava(existConfigFile, isXQueryJavaEnabled());

			setConfigFile(existConfigFile.getAbsolutePath());
		} catch (final IOException e) {
			log.fatal("creating database dir", e);
			throw new IllegalStateException(e);
		}
		log.debug("created temp database");
	}

	public File getDbDirectory() {
		return dbDirectory;
	}

	public void setDbDirectory(final File dbDirectory) {
		this.dbDirectory = dbDirectory;
	}

	public String getConfigTemplate() {
		return configTemplate;
	}

	public void setConfigTemplate(final String configTemplate) {
		this.configTemplate = configTemplate;
	}

	public BulkResourceImporter getBulkImporter() {
		return bulkImporter;
	}

	public void setBulkImporter(final BulkResourceImporter bulkImporter) {
		this.bulkImporter = bulkImporter;
	}

	public File getExistConfigFile() {
		return existConfigFile;
	}

	public void setExistConfigFile(final File existConfigFile) {
		this.existConfigFile = existConfigFile;
	}

	@Required
	public String getDbRootPath() {
		return dbRootPath;
	}

	public void setDbRootPath(final String dbRootPath) {
		this.dbRootPath = dbRootPath;
	}

	public boolean isXQueryJavaEnabled() {
		return XQueryJavaEnabled;
	}

	public void setXQueryJavaEnabled(final boolean xQueryJavaEnabled) {
		XQueryJavaEnabled = xQueryJavaEnabled;
	}

}
