package brn.distsim.ormapper.util;


import org.hibernate.HibernateException;
import org.hibernate.event.EventSource;
import org.hibernate.event.SaveOrUpdateEvent;
import org.hibernate.event.def.DefaultSaveOrUpdateEventListener;
import org.hibernate.persister.entity.EntityPersister;
import org.python.core.PyInstance;
import org.python.core.PyProxy;

import brn.distsim.ormapper.class2hbm.MapGenerator;

public class SaveEventHandler extends DefaultSaveOrUpdateEventListener {

	/**
	 *
	 */
	private static final long serialVersionUID = 981339706527130682L;

	private MapGenerator generator;

	private DBSaver dbSaver;

	public SaveEventHandler(DBSaver dbSaver, MapGenerator generator) {
		this.generator = generator;
		this.dbSaver = dbSaver;
	}

	/**
	 * fix polymorphic Class and Array in collections
	 *
	 */
	public void onSaveOrUpdate(SaveOrUpdateEvent event) {
		Class saveClass = event.getObject().getClass();

		synchronized (generator) {
			if (!generator.isMapped(saveClass)) {
				if (saveClass.isArray()) {
					// prevent infinite recursion
					throw new HibernateException(
							"You can't save polymorphic references to arrays!");
				}
				dbSaver.setBadInstance(event.getObject());
				throw new ClassNotMappedException(saveClass);
			}

		}
    if (event.getObject() instanceof PyProxy) {
      PyProxy proxy = (PyProxy) event.getObject();
      PyInstance pyInstance = proxy._getPyInstance();

      event.setEntityName(pyInstance.instclass.__name__);
    }
		super.onSaveOrUpdate(event);
	}

	/**
	 * Handles to calls needed to perform post-save cascades.
	 *
	 * @param source
	 *            The session from which the event originated.
	 * @param persister
	 *            The entity's persister instance.
	 * @param entity
	 *            The entity beng saved.
	 * @throws HibernateException
	*/
	protected void cascadeAfterSave(EventSource source,
			EntityPersister persister, Object entity, Object anything)
			throws HibernateException {

		// cascade-save to collections AFTER the collection owner was saved
		// hack map-cascading into it ...
		source.getPersistenceContext().incrementCascadeLevel();
		try {
			new CascadeMap(getCascadeAction(),
					CascadeMap.AFTER_INSERT_BEFORE_DELETE, source).cascade(
					persister, entity, anything);
		} finally {
			source.getPersistenceContext().decrementCascadeLevel();
		}
	}


}
