package com.capgemini.framework.teamcenter.queries.saved;

import com.capgemini.framework.teamcenter.authent.TcSession;
import com.teamcenter.soa.client.model.ModelObject;
import com.teamcenter.soa.client.model.strong.Item;
import com.teamcenter.soa.client.model.strong.ItemRevision;
import lombok.extern.slf4j.Slf4j;

/**
 * This class is able to look for some objects in Teamcenter using replicated queries with custom name that CANNOT be translated by Teamcenter before evaluation.
 *
 * @param <OBJECT> the expected type of the Object: either {@link Item} or {@link ItemRevision}
 * @param <QUERY> The type of the actual daughter class. Provided to chain requests.
 */
@Slf4j
public abstract class AbstractReplicatedQuery<OBJECT extends ModelObject, QUERY extends AbstractReplicatedQuery<OBJECT, QUERY>>
        extends AbstractSavedQuery<OBJECT, QUERY> {

    // Reporting prefix convention
    /**
     * Common prefix for all columns used by replicated queries for reports.
     **/
    protected static final String REPCOL_PREFIX = "report_";
    /**
     * Keyword for query parameter: Item ID.
     */
    protected static final String PARAM_ITEM_ID = REPCOL_PREFIX + "item_id";

    // Parameter name suffixes
    /**
     * Keyword for query parameter: object name.
     */
    protected static final String PARAM_OBJECT_NAME = REPCOL_PREFIX + "Name";
    /**
     * Keyword for query parameter: Product type name.
     */
    protected static final String PARAM_NOM_TYPE_PRODUIT = REPCOL_PREFIX + "pv_nom_type_produit";
    /**
     * Common prefix for all replicated queries used by reports.
     **/
    private static final String REPQUERY_PREFIX = "__Report_";
    /**
     * Keyword for query parameter: Revision.
     */
    private static final String PARAM_ITEM_REVISION_ID = REPCOL_PREFIX + "Revision";
    /**
     * Keyword for query parameter: object ID.
     */
    private static final String PARAM_END_ITEM_ID = REPCOL_PREFIX + "end_item_id";
    /**
     * Keyword for query parameter: Effectivity Unit of introduction.
     */
    private static final String PARAM_EFFECTIVITY_UNITS_INTRO = REPCOL_PREFIX + "effectivity_units_intro";
    /**
     * Keyword for query parameter: Creation Date before.
     */
    private static final String PARAM_DATE_AVANT = REPCOL_PREFIX + "cree_avant";
    /**
     * Keyword for query parameter: Creation Date after.
     */
    private static final String PARAM_DATE_APRES = REPCOL_PREFIX + "cree_apres";

    protected AbstractReplicatedQuery(final TcSession session, final String queryNameSuffix, final int maxQueries, final int paging) {
        super(session, REPQUERY_PREFIX + queryNameSuffix, maxQueries, paging);
    }

    protected AbstractReplicatedQuery(final TcSession session, final String queryNameSuffix) {
        super(session, REPQUERY_PREFIX + queryNameSuffix);
    }

    @Override
    public QUERY searchID(final String itemID) {
        return this.addParam(PARAM_ITEM_ID, itemID);
    }

    @Override
    public QUERY searchRevision(final String revision) {
        return this.addParam(PARAM_ITEM_REVISION_ID, revision);
    }

    @Override
    public QUERY searchName(final String itemName) {
        return this.addParam(PARAM_OBJECT_NAME, itemName);
    }

    /**
     * Search all the possible objects within limitation of number of retrieved elements (no return limit).
     *
     * @return this QUERY, updated to return the list of all the OBJECT elements
     */
    public QUERY searchAllObjects() {
        this.searchID("*");
        this.changeMaxNumberValues(-1);
        return selfCast();
    }

    /**
     * Specify an end item Identifier. The returned objects will be below this end item.
     *
     * @param endItemID the end item identifier (a {@link String})
     * @return the same query
     */
    public AbstractReplicatedQuery<OBJECT, QUERY> addEndItemID(final String endItemID) {
        parameters.put(PARAM_END_ITEM_ID, endItemID);
        return this;
    }

    /**
     * Specify an Unit of introduction.
     *
     * @param effectivityUnit the unit (a {@link String})
     * @return the same query
     */
    public AbstractReplicatedQuery<OBJECT, QUERY> addEffectivityUnitIntro(final String effectivityUnit) {
        parameters.put(PARAM_EFFECTIVITY_UNITS_INTRO, effectivityUnit);
        return this;
    }

    /**
     * Specify a before date.<br/>
     * The objects should be create BEFORE this date.
     *
     * @param date the date (a {@link String})
     * @return the same query
     */
    public AbstractReplicatedQuery<OBJECT, QUERY> addBeforeDate(final String date) {
        parameters.put(PARAM_DATE_AVANT, date);
        return this;
    }

    /**
     * Specify an after date.<br/>
     * The objects should be create AFTER this date.
     *
     * @param date the date (a {@link String})
     * @return the same query
     */
    public AbstractReplicatedQuery<OBJECT, QUERY> addAfterDate(final String date) {
        parameters.put(PARAM_DATE_APRES, date);
        return this;
    }

    @Override
    public QUERY addParam(final String aParamName, final String aParamValue) {
        // Check if current query is specific for reports
        // For these queries, all columns should begin by the "report_" prefix
        if (!savedQueryName.startsWith(REPQUERY_PREFIX) || !aParamName.startsWith(REPCOL_PREFIX)) {
            log.error("The current parameter is not compliant with report queries structure: " + aParamName);
        } else {
            parameters.put(aParamName, aParamValue);
        }
        return selfCast();
    }

    protected abstract QUERY selfCast();

}
