package com.atlassian.stash.internal.participant;

import com.atlassian.stash.internal.AbstractHibernateDao;
import org.hibernate.SessionFactory;
import org.springframework.beans.factory.annotation.Autowired;

import javax.annotation.Nonnull;

import static com.atlassian.stash.internal.HibernateUtils.initialize;

public abstract class AbstractHibernateParticipantDao<P extends InternalParticipant<P>>
        extends AbstractHibernateDao<Long, P> {

    @Autowired
    protected AbstractHibernateParticipantDao(SessionFactory sessionFactory) {
        super(sessionFactory);
    }

    /**
     * Creates and persists a new participant for a given entity. Which entity to use is taken from the participant's
     * {@link InternalParticipant#getEntity() getEntity()} method.
     *
     * @param participant the participant to add and persist
     * @return the persisted participant
     */
    @Nonnull
    @Override
    public P create(@Nonnull P participant) {
        session().save(participant);

        InternalParticipable<P> entity = participant.getEntity();
        entity.addParticipant(participant);
        session().update(entity);

        return participant;
    }

    /**
     * Deletes a participant from an entity. Which entity to use is taken from the participant's
     * {@link InternalParticipant#getEntity() getEntity()} method.
     *
     * @param participant the participant to remove
     */
    @Override
    public void delete(@Nonnull P participant) {
        InternalParticipable<P> entity = participant.getEntity();
        entity.removeParticipant(participant);
        session().update(entity);

        session().delete(participant);
    }

    @Override
    public void deleteById(Long id) {
        //The base implementation cannot be used because it doesn't chase pointers in the cache correctly.
        P participant = getById(id);
        if (participant != null) {
            delete(participant);
        }
    }

    @Nonnull
    @Override
    public P update(@Nonnull P participant) {
        return initialize(super.update(participant));
    }
}
