package eu.dnetlib.dlms.impl.daos;

import java.util.Collection;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.annotation.Required;

import eu.dnetlib.dlms.config.SystemSetsHelper;
import eu.dnetlib.dlms.impl.hibobjects.SetDAOHibernate;
import eu.dnetlib.dlms.lowlevel.LowLevelException;
import eu.dnetlib.dlms.lowlevel.objects.Set;
import eu.dnetlib.dlms.union.objects.UnionSet;

/**
 * Extension of SetDAOHibernate class to register new sets in the system through the use of system sets created at
 * initialization (see eu.dnetlib.dlms.config classes). This class should be used to save Sets of kind atom, structure
 * and obj. For other kinds see ExtUnionSetDAOHibernate and ExtRelSetDAOHibernate.
 * 
 * Note that if a Set is lazy created its information won't be available in the system until it is actually created.
 * 
 * @author lexis
 * 
 */
public class ExtSetDAOHibernate extends SetDAOHibernate {
	/** Logger. */
	private static final Log log = LogFactory.getLog(ExtSetDAOHibernate.class);

	/** Instance to help working with system sets. */
	private SystemSetsHelper systemSetHelper;

	/**
	 * 
	 * {@inheritDoc}
	 * 
	 * @see eu.dnetlib.dlms.impl.hibobjects.SetDAOHibernate#save(eu.dnetlib.dlms.lowlevel.objects.Set). Before saving
	 *      the set we should create its describing structure to be used as system information. 1. check the kind of the
	 *      set 2. create the appropriate structure to add in the appropriate system set 3. add the structure into the
	 *      unionset SystemSets.
	 */
	@Override
	public void save(final Set s) {
		log.debug("Saving a set");
		if (s.getId() == 0) {
			super.save(s);
			this.systemSetHelper.createStructureFor(s);
		} else {
			super.save(s);
			//need to save the unionsets this set is included so that the triples are up to date for union sets!
			for (final UnionSet us : this.getUnionSetIncluding(s))
				this.systemSetHelper.getUnionSetDAO().save(us);
		}
	}

	/**
	 * 
	 * {@inheritDoc}
	 * 
	 * @see eu.dnetlib.dlms.impl.hibobjects.SetDAOHibernate#delete(long)
	 */
	@Override
	public void delete(final long id) {
		final Set s = (Set) this.getHibernateTemplate().get(Set.class, id);
		if (s == null) {
			throw new LowLevelException("Id " + id + " is not an existing set identifier");
		} else {
			this.systemSetHelper.removeSystemEntryFor(s);
			super.delete(s);
		}
	}

	/**
	 * 
	 * {@inheritDoc}
	 * 
	 * @see eu.dnetlib.dlms.impl.hibobjects.SetDAOHibernate#delete(eu.dnetlib.dlms.lowlevel.objects.Set)
	 */
	@Override
	public void delete(final Set set) {
		this.systemSetHelper.removeSystemEntryFor(set);
		super.delete(set);
	}

	/**
	 * Gets the UnionSets that include the given Set.
	 * 
	 * @param set
	 *            Set instance
	 * @return a collection of the UnionSet that include set
	 */
	@SuppressWarnings("unchecked")
	private Collection<UnionSet> getUnionSetIncluding(final Set set) {
		return this.getHibernateTemplate().findByNamedParam("FROM UnionSet WHERE :set IN elements(sets)", "set", set);
	}

	public SystemSetsHelper getSystemSetHelper() {
		return this.systemSetHelper;
	}

	@Required
	public void setSystemSetHelper(final SystemSetsHelper systemSetHelper) {
		this.systemSetHelper = systemSetHelper;
	}

}
