package com.capgemini.reports.definition.r20report;

import com.capgemini.framework.common.SettingsHelper;
import com.capgemini.framework.teamcenter.object.pom.status.StatusEnum;
import com.capgemini.framework.teamcenter.policies.PolicyLocation;
import com.capgemini.reports.ReportEnum;
import com.capgemini.reports.ReportLaunchTypeEnum;
import com.capgemini.reports.builder.R20Builder;
import com.capgemini.reports.builder.ReportBuilder;
import com.capgemini.reports.changeobjects.UnitRevision;
import com.capgemini.reports.changeobjects.change.TcChangeRequestRevision;
import com.capgemini.reports.database.javabean.enumeration.ReportCriteriaEnum;
import com.capgemini.reports.database.manager.MngCriteriaVal.CriteriaValue;
import com.capgemini.reports.definition.r20report.ExecutionR20.ReportDataR20;
import com.capgemini.reports.definition.r20report.checker.R20LMRChecker;
import com.capgemini.reports.definition.r20report.checker.R20UnitRevisionChecker;
import com.capgemini.reports.execution.AbstractExecutionReport;
import com.capgemini.reports.execution.IDataReportPreparator;
import com.capgemini.reports.printing.Printer.PrintFormat;
import com.capgemini.reports.reports.parameters.IChecker;
import com.capgemini.reports.reports.parameters.ProductUnit;
import com.capgemini.reports.reports.parameters.checker.ProductChecker;
import com.capgemini.reports.snecmaobjects.generic.AbstractGeneric;
import com.capgemini.reports.snecmaobjects.part.PartAeroRevision;
import com.capgemini.reports.snecmaobjects.product.ProductRevision;
import lombok.AccessLevel;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.Setter;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;

/**
 * Executes a R20 report.
 */
@Getter
@Setter(value = AccessLevel.PROTECTED)
@EqualsAndHashCode(callSuper = true)
public class ExecutionR20 extends AbstractExecutionReport<ExecutionR20, ReportDataR20> {

    /**
     * The authorized status for unit before.
     */
    public static final StatusEnum[] R20_STATUS_BEFORE =
            {StatusEnum.OPENING_IN_PROCESS, StatusEnum.OPEN, StatusEnum.J3A, StatusEnum.J3B, StatusEnum.FROZEN_IN_PROCESS, StatusEnum.FROZEN};
    /**
     * The authorized status for units after.
     */
    public static final StatusEnum[] R20_STATUS_AFTER =
            {StatusEnum.OPENING_IN_PROCESS, StatusEnum.OPEN, StatusEnum.J3A, StatusEnum.J3B, StatusEnum.FROZEN_IN_PROCESS};
    // Revision rule parameter
    static final String REPORT_REVISION_RULE =
            SettingsHelper.getPropertyWithDefaultValue("common.bom.revisionRule.REPORT_R20", DEFAULT_REVISION_RULE);
    private static final long serialVersionUID = -1700414458622831247L;
    // Policies
    private static final PolicyLocation R20_POLICY_XML_LIGHT =
            PolicyLocation.make("R20_policy_light", "/xml/policies/r20report/R20_policy_light.xml");
    private static final PolicyLocation R20_POLICY_XML_FULL = PolicyLocation.make("R20_policy_full", "/xml/policies/r20report/R20_policy_full.xml");
    // Priority parameter
    private static final int REPORT_PRIORITY = SettingsHelper.getPriority(ReportEnum.REPORT_R20);
    // Launch type parameter
    private static final ReportLaunchTypeEnum REPORT_LAUNCH_TYPE = ReportLaunchTypeEnum.getReportLaunchType("common.launch.launchType.REPORT_R20");
    // Report parameters
    private final ProductUnit productUnitBefore;
    private final ProductUnit productUnitAfter;
    private final String matriculeMoteur;
    private final Classe classe;
    private final MajorMinor majorMinor;
    private final ConjointUnique conjointUnique;

    /**
     * The List of Removed Modifications IDs.
     */
    private final List<String> lmrList;


    /**
     * Constructor of an Execution for R20.
     *
     * @param aProductUnitBefore {@link ProductUnit} before
     * @param aProductUnitAfter  {@link ProductUnit} after
     * @param aMatricule         String
     * @param lmr                {@link List} of String
     * @param aClasse            enum {@link Classe}
     * @param aMajorMinor        enum {@link MajorMinor}
     * @param aConjointUnique    enum {@link ConjointUnique}
     */
    public ExecutionR20(final ProductUnit aProductUnitBefore, final ProductUnit aProductUnitAfter, final String aMatricule, final List<String> lmr,
                        final Classe aClasse, final MajorMinor aMajorMinor, final ConjointUnique aConjointUnique) {
        super(REPORT_PRIORITY, REPORT_REVISION_RULE, REPORT_LAUNCH_TYPE);
        productUnitBefore = aProductUnitBefore;
        productUnitAfter = aProductUnitAfter;
        matriculeMoteur = aMatricule;
        lmrList = lmr;
        classe = aClasse;
        majorMinor = aMajorMinor;
        conjointUnique = aConjointUnique;
    }

    @Override
    public List<CriteriaValue> getLaunchData() {
        List<CriteriaValue> theCriteria = new ArrayList<>();
        theCriteria.add(new CriteriaValue(ReportCriteriaEnum.UNIT_BEFORE, productUnitBefore.getUnitStr()));
        theCriteria.add(new CriteriaValue(ReportCriteriaEnum.PRODUCT_BEFORE, productUnitBefore.getProductID()));
        theCriteria.add(new CriteriaValue(ReportCriteriaEnum.UNIT_AFTER, productUnitAfter.getUnitStr()));
        theCriteria.add(new CriteriaValue(ReportCriteriaEnum.PRODUCT_AFTER, productUnitAfter.getProductID()));
        theCriteria.add(new CriteriaValue(ReportCriteriaEnum.MATRICULE, matriculeMoteur));
        theCriteria.add(new CriteriaValue(ReportCriteriaEnum.LMR, R20Builder.packLMR(lmrList)));
        theCriteria.add(new CriteriaValue(ReportCriteriaEnum.CLASSE, classe.toString()));
        theCriteria.add(new CriteriaValue(ReportCriteriaEnum.MAJOR_MINOR, majorMinor.toString()));
        theCriteria.add(new CriteriaValue(ReportCriteriaEnum.CONJOINT_UNIQUE, conjointUnique.toString()));
        return theCriteria;
    }

    @Override
    public String getSpecifiedFileName() {
        return "R20_" + productUnitAfter.getProductID() + "_" + productUnitAfter.getUnitStr() + "_" + productUnitBefore.getUnitStr();
    }

    @Override
    public PrintFormat getPrintingFormat() {
        return PrintFormat.PDF;
    }

    @Override
    public ReportEnum getReportIdentifier() {
        return ReportEnum.REPORT_R20;
    }

    @Override
    public List<IChecker> getQuickChecks() {
        List<IChecker> quickChecks = new ArrayList<>();
        ProductChecker productChecker = new ProductChecker(productUnitAfter.getProductID());
        quickChecks.add(productChecker);
        quickChecks.add(new R20UnitRevisionChecker(productUnitAfter, true));
        quickChecks.add(new R20UnitRevisionChecker(productUnitBefore, false));
        if (!lmrList.isEmpty()) {
            quickChecks.add(new R20LMRChecker(lmrList, productUnitBefore, productChecker));
        }
        return quickChecks;
    }

    @Override
    public List<IChecker> getLongChecks() {
        return new ArrayList<>();
    }

    @Override
    public PolicyLocation getPropertyPolicyForLongChecks() {
        return R20_POLICY_XML_LIGHT;
    }

    @Override
    public PolicyLocation getFullPolicy() {
        return R20_POLICY_XML_FULL;
    }

    @Override
    public String getTemplateLocation() {
        return "/Jasper/template/report_r20/report_r20_master.jrxml";
    }

    @Override
    public IDataReportPreparator<ExecutionR20> getDataPreparator() {
        return new DataReportPreparatorR20();
    }

    @Override
    public AbstractExecutionReport<?, ?> cloneTemplateToExecution() {
        return new ExecutionR20(productUnitBefore, productUnitAfter, matriculeMoteur, lmrList, classe, majorMinor, conjointUnique);
    }

    @Override
    public Class<? extends ReportBuilder> getReportBuilderClass() {
        return R20Builder.class;
    }

    /**
     * POJO container for all data used in R20 report.
     */
    @Getter
    @Setter(value = AccessLevel.PROTECTED)
    public static class ReportDataR20 {
        // From TC datas
        private final ProductRevision product;
        private final UnitRevision unitBefore;
        private final UnitRevision unitAfter;
        // Report parameters
        private final String matriculeMoteur;
        private final Classe classe;
        private final MajorMinor majorMinor;
        private final ConjointUnique conjointUnique;

        /**
         * The List of Removed Modifications objects found in the unit After.
         */
        private Set<TcChangeRequestRevision> totalChangeRequestNotLMR;
        /**
         * The List of Removed Modifications objects that the user requested as LMR.
         */
        private Set<TcChangeRequestRevision> totalChangeRequestLMR;
        /**
         * {@link Map} of all the Generics under the Unit Before, which undergo a removed modification with rupture. Points to the non-empty {@link Set} of {@link TcChangeRequestRevision} from the LMR that mentionned this key generic.
         */
        private Map<AbstractGeneric, Set<TcChangeRequestRevision>> totalGenericsBeforeLMRWithRupture;
        /**
         * {@link Map} of all the Generics under the Unit After, which do not have a rupture of interchangeability.Points to the non-empty list of {@link TcChangeRequestRevision} that made a change to key generic.
         */
        private Map<AbstractGeneric, Set<TcChangeRequestRevision>> totalGenericsBeforeLMRWithoutRupture;
        /**
         * {@link Map} of all the Generics under the Unit After, which undergo a rupture of interchangeability. Points to the non-empty list of {@link TcChangeRequestRevision} that made a change to key generic.
         */
        private Map<AbstractGeneric, Set<TcChangeRequestRevision>> totalGenericsAfterWithRupture;
        /**
         * {@link Map} of all the Generics under the Unit After, which do not have a rupture of interchangeability.Points to the non-empty list of {@link TcChangeRequestRevision} that made a change to key generic.
         */
        private Map<AbstractGeneric, Set<TcChangeRequestRevision>> totalGenericsAfterWithoutRupture;
        /**
         * The List of Removed Modifications objects, LMR or not.
         */
        private Set<TcChangeRequestRevision> totalChangeRequest;
        /**
         * Maps each Generic with its PartAeroRevision, using the Unit Before.
         */
        private Map<AbstractGeneric, PartAeroRevision> genericsAndPartNumbersBefore;
        /**
         * Maps each Generic with its PartAeroRevision, using the Unit After.
         */
        private Map<AbstractGeneric, PartAeroRevision> genericsAndPartNumbersAfter;
        /**
         * {@link Set} of all the Generics.
         */
        private Set<AbstractGeneric> totalGenerics;

        /**
         * Simple constructor.
         *
         * @param product         the product
         * @param unitBefore      the unit before
         * @param unitAfter       the unit after
         * @param matriculeMoteur the 'matricule moteur' parameter
         * @param classe          the 'classe' parameter
         * @param majorMinor      the 'Major / minor' parameter
         * @param conjointUnique  the 'Conjoint/unique' parameter
         */
        ReportDataR20(final ProductRevision product, final UnitRevision unitBefore, final UnitRevision unitAfter, final String matriculeMoteur,
                      final Classe classe, final MajorMinor majorMinor, final ConjointUnique conjointUnique) {
            super();
            this.product = product;
            this.unitBefore = unitBefore;
            this.unitAfter = unitAfter;
            this.matriculeMoteur = matriculeMoteur;
            this.classe = classe;
            this.majorMinor = majorMinor;
            this.conjointUnique = conjointUnique;
        }
    }
}
