/**
 * 
 */
package eu.dnetlib.dlms.impl.daos;

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.config.SystemSetsNames;
import eu.dnetlib.dlms.lowlevel.objects.Relation;
import eu.dnetlib.dlms.lowlevel.objects.RelationDAO;
import eu.dnetlib.dlms.lowlevel.objects.RelationSet;
import eu.dnetlib.dlms.lowlevel.objects.RelationSetDAO;
import eu.dnetlib.dlms.lowlevel.objects.Set;
import eu.dnetlib.dlms.lowlevel.objects.structures.Structure;
import eu.dnetlib.dlms.lowlevel.types.RelationType;
import eu.dnetlib.dlms.lowlevel.types.RelationTypeDAO;
import eu.dnetlib.dlms.union.objects.UnionSet;

/**
 * Extension of UnionSetDAOHibernate 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 union. For other
 * kinds see ExtSetDAOHibernate and ExtRelSetDAOHibernate.
 * 
 * Note that if a Set is lazy created its information won't be available in the system until it is actually created.
 * setDAO bean should be set to an ExtSetDAOHibernate instance.
 * 
 * @author lexis
 * 
 */
public class ExtUnionSetDAOHibernate extends UnionSetDAOImpl {
	/** Logger. */
	private static final Log log = LogFactory.getLog(ExtUnionSetDAOHibernate.class);

	/** Instance to help working with system sets. */
	private SystemSetsHelper systemSetHelper;
	private RelationTypeDAO relTypeDAO;
	private RelationDAO relDAO;
	private RelationSetDAO relSetDAO;

	/**
	 * {@inheritDoc}
	 * 
	 * @see eu.dnetlib.dlms.union.objects.UnionSetDAOHibernate#delete(eu.dnetlib.dlms.union.objects.UnionSet)
	 */
	@Override
	public void delete(final UnionSet set) {
		this.systemSetHelper.removeSystemEntryFor(set);
		//TODO: check that the relation between the included sets is removed as well
		super.delete(set);

	}

	/**
	 * {@inheritDoc}
	 * 
	 * @see eu.dnetlib.dlms.union.objects.UnionSetDAOHibernate#save(eu.dnetlib.dlms.union.objects.UnionSet)
	 */
	@Override
	public void save(final UnionSet set) {
		log.debug("Saving a UnionSet");
		if (set.getId() == 0) {
			super.save(set);
			//final UnionSet systemAllSets = this.systemSetHelper.getUnionSetDAO().getUnionSetByName(SystemSetsNames.ALL_SETS);
			//1. create and save a Structure that represents set in the SystemUnionSets Set and add it to SystemSets.
			final Structure systemStructure = this.systemSetHelper.createStructureFor(set);
			final RelationType includedType = this.relTypeDAO.getByName(SystemSetsNames.TYPE_INCLUDES_SET);
			final RelationSet includesSet = this.relSetDAO.getRelationSetByLabel(SystemSetsNames.INCLUDES_SET);
			//2. for each Set included we need to find its corresponding Structure in system sets and its wrapper in SystemSets
			for (final Set s : set.getSets()) {
				final Structure sSystemStruct = this.systemSetHelper.findSystemStructureFor(s);
				//3. create a relation in set SystemIncludedSets between the structure for set and the wrapper
				final Relation includesRel = this.relDAO.create();
				includesRel.setFstObj(systemStructure);
				includesRel.setSndObj(sSystemStruct);
				includesRel.setObjectType(includedType);
				this.relDAO.save(includesRel);
				this.relSetDAO.addToSet(includesSet, includesRel);
				this.relDAO.save(includesRel);
			}
			this.relSetDAO.save(includesSet);
		} else
			super.save(set);
		log.debug("UnionSet saved");
	}

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

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

	public RelationTypeDAO getRelTypeDAO() {
		return this.relTypeDAO;
	}

	@Required
	public void setRelTypeDAO(final RelationTypeDAO relTypeDAO) {
		this.relTypeDAO = relTypeDAO;
	}

	public RelationDAO getRelDAO() {
		return this.relDAO;
	}

	@Required
	public void setRelDAO(final RelationDAO relDAO) {
		this.relDAO = relDAO;
	}

	public RelationSetDAO getRelSetDAO() {
		return this.relSetDAO;
	}

	@Required
	public void setRelSetDAO(final RelationSetDAO relSetDAO) {
		this.relSetDAO = relSetDAO;
	}

}
