package com.capgemini.reports.execution.actions.ondataset;

import com.capgemini.framework.teamcenter.authent.TcSession;
import com.capgemini.framework.teamcenter.exceptions.FailedRelationshipActionException;
import com.capgemini.framework.teamcenter.exceptions.KurtException;
import com.capgemini.reports.database.javabean.DbReport;
import com.capgemini.reports.execution.AbstractExecutionReport;
import com.capgemini.reports.execution.actions.AbstractPostExecutionStep;
import com.teamcenter.soa.client.model.ModelObject;
import com.teamcenter.soa.client.model.strong.Item;
import lombok.EqualsAndHashCode;

import javax.inject.Provider;
import java.io.Serializable;

import static com.capgemini.framework.teamcenter.TeamcenterObjectTypes.IMAN_REFERENCE;

/**
 * This class is an action that may be performed after a report execution has completed.
 *
 * @param <T> the class of the calling report
 */
@EqualsAndHashCode(callSuper = true)
public class LinkFicheArticleAction<T extends AbstractExecutionReport<T, ?>> extends AbstractPostExecutionStep<T, Void> {

    private static final long serialVersionUID = 2717496737388126196L;

    private final SerializableProvider<? extends Item> partProvider;
    private final SerializableProvider<? extends ModelObject> datasetProvider;

    /**
     * Create a {@link LinkFicheArticleAction} that can be triggered after a report has completed its execution.
     *
     * @param <PP>            class of the part provider. Must be both {@link Serializable} and an {@link Item} {@link Provider}
     * @param <DSP>           class of the dataset provider. Must be both {@link Serializable} and an {@link ModelObject} {@link Provider}
     * @param reportClass     the Class of the report.
     * @param partProvider    an {@link Item} {@link Provider} which can eventually {@link Provider#get() provide} a part
     * @param datasetProvider a {@link ModelObject} {@link Provider} which can eventually {@link Provider#get() provide} a dataset
     */
    public <PP extends Provider<? extends Item> & Serializable, DSP extends Provider<? extends ModelObject> & Serializable> LinkFicheArticleAction(
            Class<T> reportClass, PP partProvider, final DSP datasetProvider) {
        super(reportClass);
        // Both casts are safe because a Serializable Provider is both Serializable... and a Provider
        this.partProvider = (SerializableProvider<? extends Item>) partProvider;
        this.datasetProvider = (SerializableProvider<? extends ModelObject>) datasetProvider;
    }

    /**
     * Links a Part to a dataset.<br>
     * If successful, a Relationship is created between the Part and the Dataset.<br>
     * If unsuccessful, the provided dataset will be deleted, to make sure it is not left orphaned (attached to nothing)
     *
     * @param session an active session
     * @param thePart the target part
     * @param dataset the dataset to attach
     * @throws FailedRelationshipActionException whenever something fails (in which case the provided dataset is destroyed)
     */
    public static void linkDatasetToPart(final TcSession session, final Item thePart, final ModelObject dataset)
            throws FailedRelationshipActionException {
        try {
            session.createRelation(thePart, dataset, IMAN_REFERENCE);
        } catch (FailedRelationshipActionException e) {
            // Unable to link back the dataset to the part. Let's cleanup behind us and destroy that orphan dataset!
            session.deleteObjects(dataset);
            throw e;
        }
    }

    @Override
    protected Void performPostActionOnReport(TcSession session, T reportRaw, DbReport theExecutingReport,
                                             String fileNameWithExtension) throws KurtException {
        linkDatasetToPart(session, partProvider.get(), datasetProvider.get());
        return null;
    }
}
