package com.capgemini.reports.definition.r26report;

import com.capgemini.framework.teamcenter.authent.TcSession;
import com.capgemini.framework.teamcenter.object.types.SnecmaObjectTypes;
import com.teamcenter.soa.client.model.ModelObject;
import com.teamcenter.soa.client.model.strong.*;

import java.util.ArrayList;
import java.util.Calendar;
import java.util.List;

/**
 * Manager for RF PU for making report R26.
 */
public class RfPUManager {

    /**
     * A partir de l'item revision passé en paramètre, retourne tous les RF en Produit/Unit trouvés via where used.
     */
    static List<ItemRevision> getRfPUs(TcSession session, RevisionRule revRule, ItemRevision itemRev) {
        List<ItemRevision> rfPUs = new ArrayList<>();
        List<ItemRevision> parents = session.whereUsed(itemRev, 1, revRule);
        if (parents.isEmpty() && isRfPU(session, itemRev) && isLastReleasedRfPURev(session, itemRev)) {
            rfPUs.add(itemRev);
        }
        for (ItemRevision parent : parents) {
            addRfPUs(session, revRule, parent, rfPUs);
        }
        return rfPUs;
    }

    /**
     * Récupère tous les RF en PU trouvé récursivement.
     */
    private static void addRfPUs(TcSession session, RevisionRule revRule, ItemRevision itemRev, List<ItemRevision> rfPUs) {
        List<ItemRevision> parents = session.whereUsed(itemRev, 1, revRule);

        if (parents.isEmpty() && isRfPU(session, itemRev) && isLastReleasedRfPURev(session, itemRev)) {
            rfPUs.add(itemRev);
            return;
        }
        for (ItemRevision currentParent : parents) {
            addRfPUs(session, revRule, currentParent, rfPUs);
        }
    }

    /**
     * Récupère tous les RF en PU.
     */
    static List<ItemRevision> getRfPURevisions(TcSession session, RevisionRule reportRevisionRule, ItemRevision secondLevelParentRev) {
        List<ItemRevision> rfPUs = new ArrayList<>();
        if (isRfPU(session, secondLevelParentRev)) {
            // si l'object courant est un RF et a une effectivité en PU
            rfPUs.add(secondLevelParentRev);
        } else {
            rfPUs.addAll(getRfPUs(session, reportRevisionRule, secondLevelParentRev));
        }
        return rfPUs;
    }

    /**
     * Retourne true si l'itemRev est un RF en PU.
     */
    static boolean isRfPU(TcSession session, ItemRevision itemRev) {
        return SnecmaObjectTypes.isRFRevision(itemRev.getTypeObject().getName())
                && EffectivityHelper.isEffectivityWithUnitRange(session, itemRev.get_release_status_list());
    }

    /**
     * Si une autre révision de l'objet courant possède la même effectivité, seule la révision la plus récente (last released) sera traitée.
     * Retourne true si c'est la révision la plus récente, false sinon.
     */
    static boolean isLastReleasedRfPURev(TcSession session, ItemRevision rfRev) {
        ReleaseStatus[] statuses = rfRev.get_release_status_list();

        session.loadProperties(rfRev, "items_tag");
        Item item = rfRev.get_items_tag();
        session.loadProperties(item, "revision_list");
        ModelObject[] revisions = item.get_revision_list();

        Calendar releaseDate1 = rfRev.get_date_released();

        for (ModelObject currentEffectivity : EffectivityHelper.getEffectivities(statuses)) {
            Effectivity effectivity = (Effectivity) currentEffectivity;
            session.loadProperties(effectivity, "unit_range_text");
            String effText1 = effectivity.get_unit_range_text();

            for (ModelObject currentRev: revisions) {
                ItemRevision itemRev = (ItemRevision) currentRev;
                if (!rfRev.equals(itemRev)) {
                    Calendar releaseDate2 = itemRev.get_date_released();
                    ReleaseStatus[] statuses2 = itemRev.get_release_status_list();

                    for (ModelObject currentEffectivity2 : EffectivityHelper.getEffectivities(statuses2)) {
                        Effectivity effectivity2 = (Effectivity) currentEffectivity2;
                        session.loadProperties(effectivity2, "unit_range_text");
                        String effText2 = effectivity2.get_unit_range_text();

                        if (effText1.equals(effText2) && releaseDate1.before(releaseDate2)) {
                            return false;
                        }
                    }
                }
            }
        }
        return true;
    }
}
