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

import com.capgemini.framework.common.DoubleFormatter;
import com.capgemini.framework.common.LanguageHelper;
import com.capgemini.reports.definition.r22report.visitors.R22VisitorKeys;
import com.capgemini.reports.snecmaobjects.AbstractSnecmaObject;
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.AbstractRF;
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;

/**
 * Visitor for Components of the r22 report.
 */
public class R22ComponentVisitor implements IComponentVisitor<Map<R22VisitorKeys, String>> {
    private static final long serialVersionUID = -4087090295500160461L;

    // Formatting
    private static final int MASS_SIGNIFICANT_DIGITS = 9;
    private static final String SEPARATOR = " ; ";

    // Default content
    private static final String EMPTY_STRING = "";
    private static final String NON = "Non";

    /**
     * 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
     *
     * @param string
     * @return the left side (if any "side" exists), an empty string otherwise
     */
    private static String french(final String string) {
        return LanguageHelper.french(string);
    }

    @Override
    public Map<R22VisitorKeys, String> visitComponent(final ProductRevision aProductRev) {
        // Not used
        return new HashMap<>();
    }

    @Override
    public Map<R22VisitorKeys, String> visitComponent(final GenericRevision aGenericRev) {
        // Not used
        return new HashMap<>();
    }

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

    @Override
    public Map<R22VisitorKeys, String> visitComponent(final GenericAssembRevision aGenericAssembRev) {
        // Not used
        return new HashMap<>();
    }

    @Override
    public Map<R22VisitorKeys, String> visitComponent(final AlternateRevision aAlternateRev) {
        return getPartProperties(aAlternateRev);
    }

    @Override
    public Map<R22VisitorKeys, String> visitComponent(final DETRevision aDetRev) {
        return getPartProperties(aDetRev);
    }

    @Override
    public Map<R22VisitorKeys, String> visitComponent(final PartAeroRevision aPartAeroRev) {
        return getPartProperties(aPartAeroRev);
    }

    @Override
    public Map<R22VisitorKeys, String> visitComponent(final PartNoAeroRevision aPartNoAeroRev) {
        return getPartProperties(aPartNoAeroRev);
    }

    @Override
    public Map<R22VisitorKeys, String> visitComponent(final PartAssembRevision aPartAssembRev) {
        return getPartProperties(aPartAssembRev);
    }

    @Override
    public Map<R22VisitorKeys, String> visitComponent(final PartMatRevision aPartMatRev) {
        return getPartMatProperties(aPartMatRev);
    }

    @Override
    public Map<R22VisitorKeys, String> visitComponent(final StandardRevision aStandardRev) {
        return getPartProperties(aStandardRev);
    }

    @Override
    public Map<R22VisitorKeys, String> visitComponent(final RFGenericRevision aRfGenericRev) {
        // Not used
        return new HashMap<>();
    }

    @Override
    public Map<R22VisitorKeys, String> visitComponent(final RFPartAssembRevision aRfPartAssembRev) {
        return getReceptorProperties(aRfPartAssembRev);
    }

    @Override
    public Map<R22VisitorKeys, String> visitComponent(final RFPartRevision aRfPartRev) {
        return getReceptorProperties(aRfPartRev);
    }

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

    @Override
    public Map<R22VisitorKeys, String> visitComponent(final RFAdminARevision aRfAdminARev) {
        Map<R22VisitorKeys, String> theMap = new EnumMap<>(R22VisitorKeys.class);
        // Split because return value like oui/yes or Non/No
        theMap.put(R22VisitorKeys.SUIVI_MONTAGE, french(aRfAdminARev.getSuiviMontage()));
        theMap.put(R22VisitorKeys.RESPONSABLE_REPERE, aRfAdminARev.getResponsableRepere());
        return theMap;
    }

    @Override
    public Map<R22VisitorKeys, String> visitComponent(final RFAdminAPRevision aRfAdminAPRev) {
        Map<R22VisitorKeys, String> theMap = new EnumMap<>(R22VisitorKeys.class);
        // Split because return value like oui/yes or Non/No
        theMap.put(R22VisitorKeys.SUIVI_MONTAGE, french(aRfAdminAPRev.getSuiviMontage()));
        return theMap;
    }

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

    private Map<R22VisitorKeys, String> getAbstractSnecmaObjectProperties(final AbstractSnecmaObject snecmaObject) {
        Map<R22VisitorKeys, String> theMap = new EnumMap<>(R22VisitorKeys.class);
        // Correspond colonne -> Réf. fabricant / Réf. SNECMA ; Révision
        theMap.put(R22VisitorKeys.COMPOSANT,
                snecmaObject.getItemId() + SEPARATOR + snecmaObject.getRevisionId());
        theMap.put(R22VisitorKeys.DENOMINATION, snecmaObject.getName());
        theMap.put(R22VisitorKeys.ALTERNATIVE, EMPTY_STRING);
        return theMap;
    }

    private Map<R22VisitorKeys, String> getAbstractPartProperties(final AbstractPart part) {
        Map<R22VisitorKeys, String> theMap = new EnumMap<>(R22VisitorKeys.class);
        theMap.put(R22VisitorKeys.FABRICANT, part.getResponsableConception());
        theMap.put(R22VisitorKeys.CLASSEMENT, part.getClassement());
        theMap.put(R22VisitorKeys.SUIVI_UTILISATION, french(part.getSuiviUtilisation()));
        theMap.put(R22VisitorKeys.MASSE_INDICATIVE, DoubleFormatter.toSignificantDigits(part.getMass(), MASS_SIGNIFICANT_DIGITS));
        theMap.put(R22VisitorKeys.UNITE_DE_MASSE, part.getMassUnit());
        theMap.put(R22VisitorKeys.CONCEPTEUR, part.getRefCompleteConcepteur());
        return theMap;
    }

    private Map<R22VisitorKeys, String> getAbstractPartMatProperties(final PartMatRevision partMatRevision) {
        Map<R22VisitorKeys, String> theMap = new EnumMap<>(R22VisitorKeys.class);
        theMap.put(R22VisitorKeys.FABRICANT, partMatRevision.getResponsableConception());
        theMap.put(R22VisitorKeys.CLASSEMENT, partMatRevision.getClassementMat());
        theMap.put(R22VisitorKeys.SUIVI_UTILISATION, NON);
        theMap.put(R22VisitorKeys.MASSE_INDICATIVE, EMPTY_STRING);
        theMap.put(R22VisitorKeys.UNITE_DE_MASSE, EMPTY_STRING);
        theMap.put(R22VisitorKeys.CONCEPTEUR, EMPTY_STRING);
        return theMap;
    }

    private Map<R22VisitorKeys, String> getPartMatProperties(final PartMatRevision anAbstractSnecmaObject) {
        Map<R22VisitorKeys, String> theMap = getAbstractSnecmaObjectProperties(anAbstractSnecmaObject);
        theMap.putAll(getAbstractPartMatProperties(anAbstractSnecmaObject));
        return theMap;
    }

    private Map<R22VisitorKeys, String> getPartProperties(final AbstractPart anAbstractSnecmaObject) {
        Map<R22VisitorKeys, String> theMap = getAbstractSnecmaObjectProperties(anAbstractSnecmaObject);
        theMap.putAll(getAbstractPartProperties(anAbstractSnecmaObject));
        return theMap;
    }

    private Map<R22VisitorKeys, String> getReceptorProperties(final AbstractRF rf) {
        Map<R22VisitorKeys, String> theMap = new EnumMap<>(R22VisitorKeys.class);
        theMap.put(R22VisitorKeys.REPERE_FONCTIONNEL_REVISION, rf.getName() + SEPARATOR + rf.getRevisionId());
        return theMap;
    }

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

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