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

import com.capgemini.framework.teamcenter.authent.TcSession;
import com.capgemini.framework.teamcenter.exceptions.ConnectionMisconguredException;
import com.capgemini.framework.teamcenter.exceptions.KurtException;
import com.capgemini.framework.teamcenter.exceptions.MalformedDataSetException;
import com.capgemini.framework.teamcenter.files.FileManagement;
import com.capgemini.framework.teamcenter.files.FileManagement.FileType;
import com.capgemini.framework.teamcenter.policies.PolicyLocation;
import com.capgemini.reports.database.javabean.DbReport;
import com.capgemini.reports.exceptions.InvalidDatasetException;
import com.capgemini.reports.execution.AbstractExecutionReport;
import com.capgemini.reports.execution.actions.AbstractPostExecutionStep;
import com.teamcenter.services.loose.core._2006_03.FileManagement.GetDatasetWriteTicketsInputData;
import lombok.EqualsAndHashCode;
import lombok.extern.slf4j.Slf4j;

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

/**
 * This class is an action of creating a dataset, and can be performed automatically upon a report execution completion.
 *
 * @param <T> the Class of the caller report
 */
@Slf4j
@EqualsAndHashCode(callSuper = true)
public class CreateDatasetAction<T extends AbstractExecutionReport<T, ?>> extends AbstractPostExecutionStep<T, GetDatasetWriteTicketsInputData> {

    private static final long serialVersionUID = -1516821856454786852L;

    private static final PolicyLocation POLICY_XML_DATASET = PolicyLocation.make("policy_dataset", "xml/policies/common/policy_dataset.xml");

    private final SerializableProvider<File> fileProvider;
    private final SerializableProvider<String> datasetNameProvider;

    /**
     * Creates a {@link CreateDatasetAction} to be executed when a report completes.
     *
     * @param <NP>                Name Provider class. Must be both {@link Serializable} and a {@link String} {@link Provider}.
     * @param <FP>                File Provider class. Must be both {@link Serializable} and a {@link File} {@link Provider}.
     * @param reportClass         the caller report Class
     * @param datasetNameProvider a {@link Provider} which will eventually {@link Provider#get() provide} a dataset name
     * @param fileProvider        a {@link Provider} which will eventually {@link Provider#get() provide} a file
     */
    public <NP extends Provider<String> & Serializable, FP extends Provider<File> & Serializable> CreateDatasetAction(final Class<T> reportClass,
                                                                                                                      final NP datasetNameProvider, FP fileProvider) {
        super(reportClass);
        // Cast is OK, because the cast interface extends both input classes
        this.datasetNameProvider = (SerializableProvider<String>) datasetNameProvider;
        this.fileProvider = (SerializableProvider<File>) fileProvider;
    }

    /**
     * Creates a dataset, with a file in it.
     *
     * @param session     an active tc session
     * @param datasetName the desired dataset name
     * @param file        the file to add to the dataset
     * @param report      the requesting report
     * @return a Token registering the dataset request data
     * @throws InvalidDatasetException if something occurred
     */
    public static GetDatasetWriteTicketsInputData createDataset(final TcSession session, final String datasetName, final File file,
                                                                final AbstractExecutionReport<?, ?> report) throws InvalidDatasetException {
        String dataSetDescription = report.getReportIdentifier().getReportTitle();

        // Perform the upload
        GetDatasetWriteTicketsInputData data;
        try {
            data = FileManagement.addSingleDataSet(session, datasetName, dataSetDescription, file, FileType.FICHE_ARTICLE);
        } catch (MalformedDataSetException | ConnectionMisconguredException e) {
            throw new InvalidDatasetException("Unable to create the dataset for the report " + report.getReportIdentifier().getReportCode() + " UID=" + report.getReportTechnicalUid(), e);
        }
        return data;
    }

    @Override
    public GetDatasetWriteTicketsInputData performPostActionOnReport(final TcSession session, final T report,
                                                                     final DbReport theExecutingReport, final String fileNameWithExtension) throws KurtException {
        session.setObjectPropPolicy(POLICY_XML_DATASET);

        String datasetName = datasetNameProvider.get();

        // Create a new dataset
        log.debug("Wokflow launch: Creating dataset {}", datasetName);
        return createDataset(session, datasetName, fileProvider.get(), report);
    }

}

