package com.capgemini.reports.definition.r19report;

import com.capgemini.framework.common.LanguageHelper;
import com.capgemini.framework.teamcenter.authent.TcSession;
import com.capgemini.framework.teamcenter.exceptions.KurtException;
import com.capgemini.framework.teamcenter.object.types.SnecmaObjectTypes;
import com.capgemini.reports.definition.r19report.ExecutionR19.ReportDataR19;
import com.capgemini.reports.definition.r19report.snecmaobject.R19ComponentVisitor;
import com.capgemini.reports.documentationobjects.*;
import com.capgemini.reports.execution.mapconstructor.AbstractStaticTemplateMapConstructor;
import com.capgemini.reports.printing.PrintParameters;
import com.capgemini.reports.snecmaobjects.AbstractSnecmaObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.*;

/**
 * Printer R19 Report construct a final list of datas for jasper.
 */
public class R19Printer extends AbstractStaticTemplateMapConstructor<ExecutionR19, ReportDataR19> {
    private static final long serialVersionUID = 5734951633170674016L;

    private static final String NORME_POUR_ARTICLES_STANDARDS = "Norme pour articles standards";
    private static final String REPRESENTATION_2D_DRAWING = "Représentation 2D";
    private static final String EMPTY = "";
    private static final Logger LOGGER = LoggerFactory.getLogger(R19Printer.class);

    private final R19ComponentVisitor componentBehaviour = new R19ComponentVisitor();

    private static String check(final Object anInput) {
        return anInput == null ? EMPTY : anInput.toString();
    }

    /* Extracts left side of a string of the form "French text / English text". */
    /* Separator slash may have *any* number (0+) of white spaces around them. */
    private static String french(final String string) {
        return LanguageHelper.french(string);
    }

    @Override
    public void constructDataMaps(TcSession session, final PrintParameters printParameters, final ReportDataR19 data) throws KurtException {
        // Retrieve parts properties
        boolean isDocumentDataPrint = false;
        AbstractDoc abstractDoc = data.getDocument();

        List<Map<R19Keys, String>> lstMapData = new ArrayList<>();
        // If no object give an empty list with document
        if (data.getObjectsWhereReferenced().isEmpty()) {
            lstMapData.add(giveDocumentData(abstractDoc));
            lstMapData.add(giveEmptyPart());
        } else {
            for (AbstractSnecmaObject elem : data.getObjectsWhereReferenced()) {
                Map<R19Keys, String> component = elem.accept(componentBehaviour);

                // Retrieve other properties
                if (!isDocumentDataPrint) {
                    component.putAll(giveDocumentData(abstractDoc));
                    isDocumentDataPrint = true;
                } else {
                    component.putAll(giveEmptyDocument());
                }

                // Add to list
                lstMapData.add(component);
            }
        }
        // Give the list to jasper
        printParameters.addReportData(translate(lstMapData));
    }

    private Map<R19Keys, String> giveDocumentData(final AbstractDoc abstractDoc) {
        String refDoc = "";
        String revDoc = "";
        String typeDoc = "";
        String indiceDoc = "";
        String nomDoc = "";
        String designationAnglaise = "";

        if (SnecmaObjectTypes.DOC_DRAWING_REVISION.equals(abstractDoc.getType())) {
            DocDrawing docDrawing = (DocDrawing) abstractDoc;
            refDoc = docDrawing.getDocId();
            revDoc = docDrawing.getRevision();
            typeDoc = REPRESENTATION_2D_DRAWING;
            indiceDoc = docDrawing.getIndicePlan();
            nomDoc = docDrawing.getName();
            designationAnglaise = docDrawing.getDesignationEn();
        } else if (SnecmaObjectTypes.DOC_NORM.equals(abstractDoc.getType())) {
            DocNorm docNorm = (DocNorm) abstractDoc;
            refDoc = docNorm.getDocId();
            revDoc = "";
            typeDoc = "";
            indiceDoc = "";
            nomDoc = docNorm.getItemName();
            designationAnglaise = "";
        } else if (SnecmaObjectTypes.DOC_NORM_STANDARD.equals(abstractDoc.getType())) {
            DocNormStandard docNormStandard = (DocNormStandard) abstractDoc;
            refDoc = docNormStandard.getDocId();
            revDoc = "";
            typeDoc = NORME_POUR_ARTICLES_STANDARDS;
            indiceDoc = "";
            nomDoc = docNormStandard.getItemName();
            designationAnglaise = "";
        } else if (SnecmaObjectTypes.DOC_TECHNIC_REVISION.equals(abstractDoc.getType())) {
            DocTechnic docTechnic = (DocTechnic) abstractDoc;
            refDoc = docTechnic.getDocId();
            revDoc = docTechnic.getRevision();
            typeDoc = french(docTechnic.getTypeDocTechnic1()) + " / " + french(docTechnic.getTypeDocTechnic2());
            indiceDoc = docTechnic.getIndice();
            nomDoc = docTechnic.getName();
            designationAnglaise = docTechnic.getDesignationEn();
        }

        Map<R19Keys, String> theMap = new EnumMap<>(R19Keys.class);
        theMap.put(R19Keys.REFERENCE_DOCUMENT, refDoc);
        theMap.put(R19Keys.REVISION_DOCUMENT, revDoc);
        theMap.put(R19Keys.TYPE_DOCUMENT, typeDoc);
        theMap.put(R19Keys.INDICE_DOCUMENT, indiceDoc);
        theMap.put(R19Keys.NOM_DOCUMENT, nomDoc);
        theMap.put(R19Keys.DESIGNATION_ANGLAISE_DOCUMENT, designationAnglaise);
        return theMap;
    }

    private Map<R19Keys, String> giveEmptyDocument() {
        Map<R19Keys, String> theMap = new EnumMap<>(R19Keys.class);
        theMap.put(R19Keys.REFERENCE_DOCUMENT, EMPTY);
        theMap.put(R19Keys.REVISION_DOCUMENT, EMPTY);
        theMap.put(R19Keys.TYPE_DOCUMENT, EMPTY);
        theMap.put(R19Keys.INDICE_DOCUMENT, EMPTY);
        theMap.put(R19Keys.NOM_DOCUMENT, EMPTY);
        theMap.put(R19Keys.DESIGNATION_ANGLAISE_DOCUMENT, EMPTY);
        return theMap;
    }

    private Map<R19Keys, String> giveEmptyPart() {
        Map<R19Keys, String> theMap = new EnumMap<>(R19Keys.class);
        theMap.put(R19Keys.OBJET, EMPTY);
        theMap.put(R19Keys.REFERENCE, EMPTY);
        theMap.put(R19Keys.REVISION_REFERENCE, EMPTY);
        theMap.put(R19Keys.NOM_REFERENCE, EMPTY);
        theMap.put(R19Keys.TYPE_REFERENCE, EMPTY);
        theMap.put(R19Keys.DESIGNATION_ENG, EMPTY);
        theMap.put(R19Keys.RESPONSABLE_CONCEPTION, EMPTY);
        theMap.put(R19Keys.PRODUIT, EMPTY);
        theMap.put(R19Keys.CLASSEMENT, EMPTY);
        theMap.put(R19Keys.DOCUMENT_DE_CONTROLE, EMPTY);
        theMap.put(R19Keys.OBTURATION, EMPTY);
        theMap.put(R19Keys.SUIVI_DUREE_VIE, EMPTY);
        theMap.put(R19Keys.DUREE_VIE, EMPTY);
        theMap.put(R19Keys.UNITE_DUREE_VIE, EMPTY);
        theMap.put(R19Keys.DMD, EMPTY);
        theMap.put(R19Keys.DMF, EMPTY);
        return theMap;
    }

    private List<Map<String, ?>> translate(final List<Map<R19Keys, String>> visitorMaps) {
        // Construct the map list expected by the printer
        List<Map<String, ?>> printerMaps = new ArrayList<>();
        for (Map<R19Keys, String> visitorMap : visitorMaps) {
            Map<String, String> printerMap = new HashMap<>();
            for (R19Keys key : R19Keys.values()) {
                printerMap.put(key.toString(), check(visitorMap.get(key)));
            }
            printerMaps.add(printerMap);
        }
        LOGGER.debug("Translate map " + printerMaps);
        return printerMaps;
    }
}
