package com.capgemini.reports.definition.r13report.datapreparator;

import com.capgemini.framework.common.DateHelper;
import com.capgemini.framework.common.TeamcenterDateFormatter;
import com.capgemini.framework.teamcenter.authent.TcSession;
import com.capgemini.framework.teamcenter.exceptions.KurtException;
import com.capgemini.framework.teamcenter.queries.saved.AbstractReplicatedQuery;
import com.capgemini.reports.definition.r13report.execution.AbstractExecutionR13;
import com.capgemini.reports.execution.IDataReportPreparator;
import com.capgemini.reports.execution.strategies.IExecutionStrategy;
import com.capgemini.reports.printing.PrintParameters;
import com.teamcenter.soa.client.model.strong.ItemRevision;
import com.teamcenter.soa.client.model.strong.ReleaseStatus;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * This class will allow to prepare common data for the R13 report.
 *
 * @param <T> the daughter class: CR or FPP
 */
public abstract class AbstractDataReportPreparatorR13<T extends AbstractExecutionR13> implements IDataReportPreparator<T> {
    private static final long serialVersionUID = -3275014753104915202L;
    private static final Logger LOGGER = LoggerFactory.getLogger(AbstractDataReportPreparatorR13.class);

    @Override
    public String print(TcSession session, T execution, IExecutionStrategy executionStrategy) throws KurtException {
        PrintParameters printParameters = prepareData(session, execution);
        executionStrategy.print(printParameters, execution);
        return executionStrategy.getReportFileName(execution) + printParameters.getOuputFileExtension();
    }

    /**
     * Method will allow to prepare data in common between report R13CR and R13FPP.
     *
     * @param session , the session of TC
     * @param report  the execution report
     * @return a List of the Objects which will make up the report's content
     */
    private PrintParameters prepareData(final TcSession session, final T report) throws KurtException {
        LOGGER.debug("PrepareData started on: {}", report.getReportIdentifier().getReportTitle());
        session.setObjectPropPolicy(report.getFullPolicy());
        return buildValidatedChangeObjects(session, report);
    }

    void addParamPeriod(final AbstractReplicatedQuery<?, ?> query, final T report) {
        if (report.getStartDate() != null) {
            query.addAfterDate(report.getStartDate().getFormattedDateForTcRequest());
        }
        if (report.getFinalDate() != null) {
            query.addBeforeDate(TeamcenterDateFormatter.translateDateFormatForRequest(DateHelper.getDatePlusOneWithReferenceCalendar(report.getFinalDate().getDateTime())));
        }
    }

    /**
     * Detects invalid status.
     */
    boolean isStatusValid(final TcSession session, final ItemRevision itemRev) {
        session.loadProperties(itemRev, "release_status_list");
        ReleaseStatus[] releaseStatuses = itemRev.get_release_status_list();
        session.loadProperties(releaseStatuses);
        for (ReleaseStatus status : releaseStatuses) {
            if (!validateStatusByName(status.get_name())) {
                return false;
            }
        }
        return true; // By default, if no status exist then the PR must be in the report
    }

    /**
     * Excludes specific statuses.
     *
     * @param statusName the input status name
     * @return <code>true</code> if the status name is valid, <code>false</code> if it should be discarded
     */
    protected abstract boolean validateStatusByName(final String statusName);

    /**
     * Specific validation tests of an item, for each version of the R13.
     */
    protected abstract boolean specificValidation(final TcSession session, final ItemRevision itemRev);

    protected abstract PrintParameters buildValidatedChangeObjects(final TcSession session, T report) throws KurtException;
}
