package com.capgemini.reports.definition.r24report;

import com.capgemini.framework.common.*;
import com.capgemini.framework.teamcenter.policies.PolicyLocation;
import com.capgemini.reports.JasperTemplate;
import com.capgemini.reports.ReportEnum;
import com.capgemini.reports.ReportLaunchTypeEnum;
import com.capgemini.reports.builder.R24Builder;
import com.capgemini.reports.builder.ReportBuilder;
import com.capgemini.reports.database.javabean.enumeration.ReportCriteriaEnum;
import com.capgemini.reports.database.manager.MngCriteriaVal;
import com.capgemini.reports.definition.r23report.ExecutionR23;
import com.capgemini.reports.documentationobjects.DocNorm;
import com.capgemini.reports.documentationobjects.DocNormStandard;
import com.capgemini.reports.documentationobjects.DocTechnic;
import com.capgemini.reports.exceptions.FileLoadingException;
import com.capgemini.reports.exceptions.ReportPrintException;
import com.capgemini.reports.execution.AbstractExecutionReport;
import com.capgemini.reports.execution.IDataReportPreparator;
import com.capgemini.reports.printing.PrintParameters;
import com.capgemini.reports.printing.Printer;
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.reports.parameters.checker.ProductUnitChecker;
import com.capgemini.reports.snecmaobjects.admin.RFAdminRevision;
import com.capgemini.reports.snecmaobjects.generic.AbstractGenericRevision;
import com.capgemini.reports.snecmaobjects.part.PartAeroRevision;
import com.capgemini.reports.snecmaobjects.rf.RFGenericRevision;
import com.teamcenter.soa.client.model.strong.Item;
import lombok.AccessLevel;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.Setter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.List;

/**
 * This class controls the execution of a R24 report.
 */
@Getter
@Setter(value = AccessLevel.PROTECTED)
@EqualsAndHashCode(callSuper = true)
public class ExecutionR24 extends AbstractExecutionReport<ExecutionR24, ExecutionR24> {
    protected static final String FRENCH_LANGUAGE = "Francais";
    private static final long serialVersionUID = -5076506178171189943L;
    private static final Logger LOGGER = LoggerFactory.getLogger(ExecutionR23.class);
    // Policies
    private static final PolicyLocation R24_POLICY_XML_FULL = PolicyLocation.make("R24_policy_full", "/xml/policies/r24report/R24_policy_full.xml");
    private static final PolicyLocation R24_POLICY_XML_LIGHT = PolicyLocation.make("R24_policy_light", "/xml/policies/r24report/R24_policy_light.xml");
    // Priority parameter
    private static final int REPORT_PRIORITY = SettingsHelper.getPriority(ReportEnum.REPORT_R24);
    // Revision rule parameter
    private static final String REPORT_REVISION_RULE = SettingsHelper.getPropertyWithDefaultValue("common.bom.revisionRule.REPORT_R24", DEFAULT_REVISION_RULE);
    // Launch type parameter
    private static final ReportLaunchTypeEnum REPORT_LAUNCH_TYPE = ReportLaunchTypeEnum.getReportLaunchType("common.launch.launchType.REPORT_R24");
    // Configuration
    private static final String FILE_SEPARATOR = "_";
    private static final String PATTERN_DATE = "dd-MM-yyyy";
    // Report parameters
    protected final boolean french;
    protected final String frenchInput;
    // Documents gathered
    protected final List<DocNorm> docNormList = new ArrayList<>();
    protected final List<DocNormStandard> docNormStandardList = new ArrayList<>();
    protected final List<DocTechnic> docTechnicList = new ArrayList<>();
    // Raw input parameters
    protected final ProductUnit productUnit;
    protected final Item genericItem;
    // Internal working data
    protected final String typeImpression;
    protected final boolean isDefCertifiee;
    // Data gathered
    protected String dateReleased = "";
    protected String revisionArticle = "";
    protected String typeProduit;
    protected String clausePropriete;
    protected RFGenericRevision rfGenericRev;
    // Data gathered
    protected AbstractGenericRevision genericRev;
    protected List<PartAeroRevision> partNumberRevList = new ArrayList<>();
    protected RFAdminRevision rfAdminRev;
    protected String frontiereAvion = "";
    protected String frontiereCooperant = "";
    private String productLine;

    /**
     * Constructor.
     *
     * @param produitUnit    {@link ProductUnit} - the Product id and the Unit range.
     * @param typeImpression {@link String} - the type of impression of the report
     * @param langage        {@link String} - the language selected by the user
     */
    public ExecutionR24(final ProductUnit produitUnit, final String typeImpression, final String langage) {
        this(produitUnit, null, typeImpression, langage);
    }

    public ExecutionR24(final ProductUnit produitUnit, final Item generic, final String typeImpression, final String langage) {
        super(REPORT_PRIORITY, REPORT_REVISION_RULE, REPORT_LAUNCH_TYPE);
        this.genericItem = generic;
        this.frenchInput = langage;
        this.french = isFrench(langage);
        this.productUnit = produitUnit;
        this.isDefCertifiee = "Def_certifiee".equals(typeImpression);
        this.typeImpression = typeImpression;
    }

    protected static boolean isFrench(final String language) {
        return FRENCH_LANGUAGE.equals(language);
    }

    @Override
    public List<MngCriteriaVal.CriteriaValue> getLaunchData() {
        List<MngCriteriaVal.CriteriaValue> theCriteria = new ArrayList<>();
        theCriteria.add(new MngCriteriaVal.CriteriaValue(ReportCriteriaEnum.PRODUCT, productUnit.getProductID()));
        theCriteria.add(new MngCriteriaVal.CriteriaValue(ReportCriteriaEnum.UNIT, productUnit.getUnitStr()));
        theCriteria.add(new MngCriteriaVal.CriteriaValue(ReportCriteriaEnum.TYPE_IMPRESSION, typeImpression));
        theCriteria.add(new MngCriteriaVal.CriteriaValue(ReportCriteriaEnum.LANGUAGE, frenchInput));
        return theCriteria;
    }

    @Override
    public List<IChecker> getQuickChecks() {
        ArrayList<IChecker> quickChecks = new ArrayList<>();
        quickChecks.add(new ProductChecker(productUnit.getProductID()));
        quickChecks.add(new ProductUnitChecker(productUnit));
        return quickChecks;
    }

    @Override
    public String getTemplateLocation() {
        return JasperTemplate.TEMPLATE_R24.getFilepath();
    }

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

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

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

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

    /**
     * Format file expected : R24_"Critère produit"_"Ligne produit"_"Critère Unit"_"générique traité"_"date_système".XLSX
     */
    private String getSubReportFileName() {
        return setFileName(true).toString();
    }

    /**
     * Format file expected : R24_"Critère produit"_"Ligne produit"_"Critère Unit"_"date_système".zip
     *
     * @return zip filename
     */
    @Override
    public String getSpecifiedFileName() {
        return setFileName(false).toString();
    }

    private StringBuilder setFileName(Boolean addItemId) {
        StringBuilder filename = new StringBuilder("R24").append(FILE_SEPARATOR);
        filename.append(productUnit.getProductID()).append(FILE_SEPARATOR);
        filename.append(productLine.replaceAll(StringHelper.REGEXP_ALPHANUM, " ")).append(FILE_SEPARATOR);
        filename.append(productUnit.getUnitStr()).append(FILE_SEPARATOR);
        if (addItemId) {
            filename.append(genericItem.get_item_id()).append(FILE_SEPARATOR);
        }
        filename.append(TeamcenterDateFormatter.formatCalendarToPattern(Calendar.getInstance(), PATTERN_DATE));

        return filename;
    }

    @Override
    public Printer getPrinter() {
        return new Printer(Printer.AvailablePrinter.ZIP);
    }

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

    @Override
    public IDataReportPreparator<ExecutionR24> getDataPreparator() {
        return new DataReportPreparatorR24();
    }

    @Override
    public AbstractExecutionReport<?, ?> cloneTemplateToExecution() {
        return new ExecutionR24(productUnit, typeImpression, frenchInput);
    }

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

    public PrintParameters reportParameters() {
        return new PrintParameters(Printer.PrintFormat.ZIP, getFileNameOnDisc(), ReportFolderOutputHelper.getStorageFolderLocation(getLaunchType()));
    }

    public PrintParameters subReportParameters() throws ReportPrintException, FileLoadingException {
        String storageFolder = ReportFolderOutputHelper.getStorageFolderLocation(getLaunchType());
        String templateLocation = getTemplateLocation();
        try (InputStream templateStream = ResourceHelper.getResourceAsStream(templateLocation)) {
            PrintParameters printParameters = PrintParameters.createMainReport(getPrintingFormat(), getSubReportFileName(), storageFolder, templateStream);
            printParameters.setReportTitle(getReportIdentifier().getReportTitle());
            return printParameters;
        } catch (IOException e) {
            LOGGER.error("Unable to close the template file properly from " + templateLocation, e);
            return null; // IOException is only thrown by close() which, if it ever fails, means you have much bigger problems!
        }
    }
}
