package com.capgemini.reports.definition.r03report.visitors.snecmaobject;

import com.capgemini.framework.common.DoubleFormatter;
import com.capgemini.framework.common.LanguageHelper;
import com.capgemini.reports.definition.r03report.visitors.R03VisitorKeys;
import com.capgemini.reports.snecmaobjects.admin.RFAdminAGRevision;
import com.capgemini.reports.snecmaobjects.admin.RFAdminAPRevision;
import com.capgemini.reports.snecmaobjects.admin.RFAdminARevision;
import com.capgemini.reports.snecmaobjects.admin.RFAdminRevision;
import com.capgemini.reports.snecmaobjects.descriptif.DescriptifRevision;
import com.capgemini.reports.snecmaobjects.generic.GenericAssembRevision;
import com.capgemini.reports.snecmaobjects.generic.GenericRevision;
import com.capgemini.reports.snecmaobjects.mockup.MockupRevision;
import com.capgemini.reports.snecmaobjects.part.*;
import com.capgemini.reports.snecmaobjects.product.ProductRevision;
import com.capgemini.reports.snecmaobjects.rf.RFGenericRevision;
import com.capgemini.reports.snecmaobjects.rf.RFPartAssembRevision;
import com.capgemini.reports.snecmaobjects.rf.RFPartRevision;
import com.capgemini.reports.snecmaobjects.supermodel.SuperModelRevision;
import com.capgemini.reports.snecmaobjects.visitor.IComponentVisitor;

import java.util.EnumMap;
import java.util.HashMap;
import java.util.Map;

/**
 * Visit a Component SnecmaObject to make a R03 report.
 */
public class R03ComponentVisitor implements IComponentVisitor<Map<R03VisitorKeys, String>> {

    private static final long serialVersionUID = -1358969880241440037L;

    private static final int MASS_SIGNIFICANT_DIGITS = 15;
    private static final String EMPTY_STRING = "";
    private static final String PART_MAT = "PartMat";
    private static final String SEPARATOR = " / ";
    private static final String VALUE_MATIERE = "matière";
    private static final String PARAM_NON = "Non";
    private static final String SOLO_SEPARATOR = "/";

    /**
     * Extracts left side of a string of the form "French text / English text".<br>
     * 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 Map<R03VisitorKeys, String> visitComponent(final ProductRevision aProductRev) {
        // No used in R03 report
        return new EnumMap<>(R03VisitorKeys.class);
    }

    @Override
    public Map<R03VisitorKeys, String> visitComponent(final GenericRevision aGenericRev) {
        // No used in R03 report
        return new EnumMap<>(R03VisitorKeys.class);
    }

    @Override
    public Map<R03VisitorKeys, String> visitComponent(SuperModelRevision aSuperModelRev) {
        return null;
    }

    @Override
    public Map<R03VisitorKeys, String> visitComponent(final GenericAssembRevision aGenericAssembRev) {
        // No used in R03 report
        return new EnumMap<>(R03VisitorKeys.class);
    }

    @Override
    public Map<R03VisitorKeys, String> visitComponent(final AlternateRevision anAlternateRev) {
        Map<R03VisitorKeys, String> theMap = getPartProperties(anAlternateRev);
        theMap.put(R03VisitorKeys.TYPE_REFERENCE, french(anAlternateRev.getTypeAlt1()) + SEPARATOR + french(anAlternateRev.getTypeAlt2()));
        return theMap;
    }

    @Override
    public Map<R03VisitorKeys, String> visitComponent(final DETRevision aDetRev) {
        Map<R03VisitorKeys, String> theMap = getPartProperties(aDetRev);
        theMap.put(R03VisitorKeys.TYPE_REFERENCE, french(aDetRev.getTypeDet1()) + SEPARATOR + french(aDetRev.getTypeDet2()));
        return theMap;
    }

    @Override
    public Map<R03VisitorKeys, String> visitComponent(final PartAeroRevision aPartAeroRev) {
        Map<R03VisitorKeys, String> theMap = getPartProperties(aPartAeroRev);
        theMap.put(R03VisitorKeys.TYPE_REFERENCE, french(aPartAeroRev.getTypeAero1()) + SEPARATOR + french(aPartAeroRev.getTypeAero2()) + SEPARATOR + french(aPartAeroRev.getTypeAero3()));
        return theMap;
    }

    @Override
    public Map<R03VisitorKeys, String> visitComponent(final PartNoAeroRevision aPartNoAeroRev) {
        Map<R03VisitorKeys, String> theMap = getPartProperties(aPartNoAeroRev);
        theMap.put(R03VisitorKeys.TYPE_REFERENCE, french(aPartNoAeroRev.getTypeNoAero()));
        return theMap;
    }

    @Override
    public Map<R03VisitorKeys, String> visitComponent(final PartAssembRevision aPartAssembRev) {
        Map<R03VisitorKeys, String> theMap = getPartProperties(aPartAssembRev);
        theMap.put(R03VisitorKeys.TYPE_REFERENCE, french(aPartAssembRev.getTypePartMontage1()) + SEPARATOR + french(aPartAssembRev.getTypePartMontage2()));
        return theMap;
    }

    @Override
    public Map<R03VisitorKeys, String> visitComponent(final PartMatRevision aPartMatRev) {
        Map<R03VisitorKeys, String> theMap = getPartProperties(aPartMatRev);
        theMap.put(R03VisitorKeys.TYPE_REFERENCE, VALUE_MATIERE);
        theMap.put(R03VisitorKeys.CLASSEMENT, aPartMatRev.getClassementMat());
        theMap.put(R03VisitorKeys.SUIVI_UTILISATION, PARAM_NON);
        theMap.put(R03VisitorKeys.SUIVI_DUREE_VIE, PARAM_NON);
        theMap.put(R03VisitorKeys.MASSE_INDICATIVE, EMPTY_STRING);
        theMap.put(R03VisitorKeys.UNITE_DE_MASSE, EMPTY_STRING);
        return theMap;
    }

    @Override
    public Map<R03VisitorKeys, String> visitComponent(final StandardRevision aStandardRev) {
        Map<R03VisitorKeys, String> theMap = getPartProperties(aStandardRev);
        theMap.put(R03VisitorKeys.TYPE_REFERENCE, french(aStandardRev.getTypeStandard()));
        return theMap;
    }

    /**
     * Get Component Part properties to make a R03 report.
     *
     * @param anAbstractPart AbstractPart
     * @return theMap Map<R03VisitorKeys,String>
     */
    private Map<R03VisitorKeys, String> getPartProperties(final AbstractPart anAbstractPart) {
        Map<R03VisitorKeys, String> theMap = new EnumMap<>(R03VisitorKeys.class);
        theMap.put(R03VisitorKeys.REF_FABRICANT_REF_SNECMA, anAbstractPart.getItemId());
        theMap.put(R03VisitorKeys.NOM_REFERENCE, anAbstractPart.getName());
        theMap.put(R03VisitorKeys.REVISION_REFERENCE, anAbstractPart.getRevisionId());
        theMap.put(R03VisitorKeys.ALTERNATIVE, EMPTY_STRING);
        theMap.put(R03VisitorKeys.DESIGNATION_EN, anAbstractPart.getDesignationEN());
        theMap.put(R03VisitorKeys.REFERENCE_CONCEPTEUR, anAbstractPart.getRefCompleteConcepteur());
        theMap.put(R03VisitorKeys.REFERENCE_TRANSPOSEE, anAbstractPart.getRefTransposeeSnecma());
        theMap.put(R03VisitorKeys.RESPONSABLE_CONCEPTION, anAbstractPart.getResponsableConception());
        if (!PART_MAT.equals(anAbstractPart.getType())) {
            theMap.put(R03VisitorKeys.CLASSEMENT, anAbstractPart.getClassement());
            theMap.put(R03VisitorKeys.SUIVI_UTILISATION, french(anAbstractPart.getSuiviUtilisation()));
            theMap.put(R03VisitorKeys.SUIVI_DUREE_VIE, french(anAbstractPart.getSuiviDureeVie()));
            theMap.put(R03VisitorKeys.MASSE_INDICATIVE, DoubleFormatter.toSignificantDigits(anAbstractPart.getMass(), MASS_SIGNIFICANT_DIGITS));
            theMap.put(R03VisitorKeys.UNITE_DE_MASSE, anAbstractPart.getMassUnit());
        }
        return theMap;
    }

    @Override
    public Map<R03VisitorKeys, String> visitComponent(final RFGenericRevision aRfGenericRev) {
        return new EnumMap<>(R03VisitorKeys.class);
    }

    @Override
    public Map<R03VisitorKeys, String> visitComponent(final RFPartAssembRevision aRfPartAssembRev) {
        Map<R03VisitorKeys, String> theMap = new EnumMap<>(R03VisitorKeys.class);
        theMap.put(R03VisitorKeys.REPERE_FONCTIONNEL, aRfPartAssembRev.getName());
        theMap.put(R03VisitorKeys.REVISION_REPERE_FONCTIONNEL, aRfPartAssembRev.getRevisionId());
        theMap.put(R03VisitorKeys.EQUIVALENT_SNSSIN, EMPTY_STRING);
        return theMap;
    }

    @Override
    public Map<R03VisitorKeys, String> visitComponent(final RFPartRevision aRfPartRev) {
        Map<R03VisitorKeys, String> theMap = new EnumMap<>(R03VisitorKeys.class);
        theMap.put(R03VisitorKeys.REPERE_FONCTIONNEL, aRfPartRev.getName());
        theMap.put(R03VisitorKeys.REVISION_REPERE_FONCTIONNEL, aRfPartRev.getRevisionId());
        theMap.put(R03VisitorKeys.EQUIVALENT_SNSSIN, aRfPartRev.getEquivalentSnsSin());
        return theMap;
    }

    @Override
    public Map<R03VisitorKeys, String> visitComponent(final RFAdminRevision aRfAdminRev) {
        Map<R03VisitorKeys, String> theMap = new EnumMap<>(R03VisitorKeys.class);
        theMap.put(R03VisitorKeys.RESPONSABLE_REPERE, aRfAdminRev.getResponsableRepere());
        return theMap;
    }

    @Override
    public Map<R03VisitorKeys, String> visitComponent(final RFAdminARevision aRfAdminARev) {
        Map<R03VisitorKeys, String> theMap = new EnumMap<>(R03VisitorKeys.class);
        String[] suiviMontage = aRfAdminARev.getSuiviMontage().split(SEPARATOR);
        suiviMontage[0].split(SOLO_SEPARATOR);
        theMap.put(R03VisitorKeys.SUIVI_MONTAGE, suiviMontage[0]);
        theMap.put(R03VisitorKeys.RESPONSABLE_REPERE, aRfAdminARev.getResponsableRepere());
        return theMap;
    }

    @Override
    public Map<R03VisitorKeys, String> visitComponent(final RFAdminAPRevision aRfAdminAPRev) {
        Map<R03VisitorKeys, String> theMap = new EnumMap<>(R03VisitorKeys.class);
        String[] suiviMontage = aRfAdminAPRev.getSuiviMontage().split(SEPARATOR);
        suiviMontage[0].split(SOLO_SEPARATOR);
        theMap.put(R03VisitorKeys.SUIVI_MONTAGE, suiviMontage[0]);
        return theMap;
    }

    @Override
    public Map<R03VisitorKeys, String> visitComponent(final RFAdminAGRevision aRfAdminAGRev) {
        return new HashMap<>();
    }

    @Override
    public Map<R03VisitorKeys, String> visitComponent(final MockupRevision aMockupRev) {
        // This object is not use in this report
        return null;
    }

    @Override
    public Map<R03VisitorKeys, String> visitComponent(final DescriptifRevision aDescriptifRev) {
        // This object is not use in this report
        return null;
    }
}
