package com.capgemini.reports.releasestatus;

import com.capgemini.reports.bomlineholder.BOMLineHolder;
import lombok.EqualsAndHashCode;

import java.io.Serializable;
import java.util.regex.Pattern;

/**
 * This Helper class presents methods for specifying a visitor's behaviour regarding parts with effectivities.
 */
@EqualsAndHashCode
public final class EffectivityBehaviourHelper implements Serializable {

    private static final long serialVersionUID = 4967460714547927907L;
    private static final Pattern UNIT_EFFECTIVITY_PATTERN = Pattern.compile(".*((Configuré en utilisant Numéro d'unité)|(Configured Using Unit Number)).*");

    private final EffectivityBehaviourEnum behaviour;

    private EffectivityBehaviourHelper(final EffectivityBehaviourEnum behaviour) {
        this.behaviour = behaviour;
    }

    /**
     * Construct an TcEffectivity Behaviour which always visits Parts with any effectivity.
     *
     * @return the {@link EffectivityBehaviourHelper}.
     */
    public static EffectivityBehaviourHelper visitAnyPart() {
        return new EffectivityBehaviourHelper(EffectivityBehaviourEnum.ALWAYS_VISIT);
    }

    /**
     * Construct an TcEffectivity Behaviour which only visits Parts with UNIT effectivity.
     *
     * @return the {@link EffectivityBehaviourHelper}.
     */
    public static EffectivityBehaviourHelper visitOnlyUnitManagedParts() {
        return new EffectivityBehaviourHelper(EffectivityBehaviourEnum.ONLY_UNIT_MANAGED);
    }

    private static boolean referencesUnit(final String blConfigString) {
        return UNIT_EFFECTIVITY_PATTERN.matcher(blConfigString).matches();
    }

    /**
     * Returns true if the {@link BOMLineHolder} should be visited based on the behaviour specified and the effectivity list provided.<br>
     * Mostly used for {@link BOMLineHolder}s holding a RF Part because these objects might have both Unit and Date effectivity.<br>
     * The available behaviours are the following:
     * <ul>
     * <li> <code>ALWAYS_VISIT</code>.</li>
     * <li> <code>ONLY_UNIT_MANAGED</code>.</li>
     * <li> <code>ONLY_DATE_MANAGED</code>.</li>
     * </ul>
     *
     * @param aBomLineHolder the {@link BOMLineHolder} to investigate
     * @return <code>true</code> if the object should be visited, <code>false</code> otherwise
     */
    public boolean shouldVisit(final BOMLineHolder aBomLineHolder) {
        final String blConfigString = aBomLineHolder.getBomConfig(); // The reason this bomLine is here, explained by Tc in a String
        if (blConfigString == null || blConfigString.isEmpty()) {
            return true; // Unknown effectivity, keep the bomLine by default
        }
        boolean result;
        switch (behaviour) {
            case ALWAYS_VISIT:
                result = true;
                break;
            case ONLY_DATE_MANAGED:
                result = !referencesUnit(blConfigString);
                break;
            case ONLY_UNIT_MANAGED:
                result = referencesUnit(blConfigString);
                break;
            default:
                result = true;
                break;
        }
        return result;
    }

    /**
     * Desired behaviour regarding effectivities.
     */
    private enum EffectivityBehaviourEnum {
        /**
         * Always visit regardless of effectivities.
         */
        ALWAYS_VISIT,
        /**
         * Only visit if the object is managed in units.
         */
        ONLY_UNIT_MANAGED,
        /**
         * Only visit if the object is managed with date effectivities.
         */
        ONLY_DATE_MANAGED
    }
}
