package com.atlassian.stash.internal.participant;

import com.atlassian.stash.internal.HibernateUtils;
import com.atlassian.stash.internal.Initializable;
import com.atlassian.stash.internal.entity.InternalAbstractEntity;
import com.atlassian.stash.internal.user.InternalApplicationUser;

import javax.annotation.Nonnull;
import javax.persistence.FetchType;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.MappedSuperclass;

import static com.google.common.base.Preconditions.checkNotNull;

@MappedSuperclass
public abstract class InternalAbstractParticipant<P extends InternalAbstractParticipant<P>>
        extends InternalAbstractEntity
        implements Initializable, InternalParticipant<P> {

    @JoinColumn(name = "user_id", nullable = false, updatable = false)
    @ManyToOne(fetch = FetchType.LAZY, optional = false)
    private InternalApplicationUser user; //Yes, not final. See initialize()

    protected InternalAbstractParticipant() {
    }

    protected InternalAbstractParticipant(AbstractParticipantBuilder<?, ?> builder) {
        super(builder);

        user = builder.user;
    }

    @Nonnull
    @Override
    public InternalApplicationUser getUser() {
        return user;
    }

    @Override
    public void initialize() {
        user = HibernateUtils.initialize(getUser());
    }

    protected abstract static class AbstractParticipantBuilder<B extends AbstractParticipantBuilder<B, E>, E extends InternalAbstractParticipant<E>>
            extends AbstractEntityBuilder<B, E> {

        private InternalApplicationUser user;

        protected AbstractParticipantBuilder() {
        }

        protected AbstractParticipantBuilder(@Nonnull E participant) {
            super(participant);

            user = participant.getUser();
        }

        @Nonnull
        public B user(@Nonnull InternalApplicationUser value) {
            user = checkNotNull(value, "user");

            return self();
        }
    }
}
