package com.capgemini.reports.definition.r07report.data.extractor;

import com.capgemini.framework.teamcenter.authent.TcSession;
import com.capgemini.reports.bomlineholder.BOMLineHolder;
import com.capgemini.reports.bomlineholder.comparison.AbstractDualBomLineFlattener;
import com.capgemini.reports.bomlineholder.flattener.AbstractBomLineFlattener;
import com.capgemini.reports.bomlineholder.flattener.line.*;
import com.capgemini.reports.definition.r07report.data.TransformerR07;
import com.capgemini.reports.definition.r07report.data.extractor.lines.*;
import com.capgemini.reports.releasestatus.EffectivityBehaviourHelper;
import com.capgemini.reports.snecmaobjects.ISnecmaObject;
import com.capgemini.reports.snecmaobjects.part.AbstractPart;
import lombok.AllArgsConstructor;
import lombok.Getter;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;

/**
 * This class analyses two {@link BOMLineHolder} and <i>flattens</i> their tree structure into an array of father-son relationships. <br>
 * The configuration lines are numbered according to the order of the structure, so the structure can be reconstructed after the flattening has been performed.
 */
@Getter
public class BomFlattenerR07 extends AbstractDualBomLineFlattener<String, TransformerR07> {

    /**
     * Compares two {@link ISnecmaObject} by their Identifiers (Name, or ID).
     */
    private static final Comparator<ISnecmaObject> ITEM_COMPARATOR = new ItemComparatorR07();
    /**
     * Compares to {@link BOMLineHolder}s. Uses the {@link ItemComparatorR07} to compare the {@link ISnecmaObject}s inside.
     */
    private static final Comparator<BOMLineHolder> BOM_COMPARATOR = new BomComparatorR07();

    /**
     * This counter increments at every new line.<br>
     * Enables to uniquely identify chronologically every SnecmaLine found on the configuration.<br>
     * After all the filtering is done, the chronological identifier can be used to mimic the original tree structure of the bom.
     */
    private int counter;

    /**
     * Builds an {@link AbstractBomLineFlattener} for the R07 report.
     */
    public BomFlattenerR07() {
        // ***** Spec R07 ****
        // - visit only unit-managed parts
        // - visit parts in pseudo-folder Alternative
        // - Do not retrieve part numbers below RF Generics
        // - Do not investigate Parts wwithout a RF above (do not follow Part->Part links
        // - Unable to provide the pseudo-folder behaviour yet, will be setup after call to super(...)
        // - usual Bom comparator
        // - usual item comparator
        // - Visit brothers below a parent part BEFORE recursing through the brothers' children
        super(EffectivityBehaviourHelper.visitOnlyUnitManagedParts(), true, false, false, null, BOM_COMPARATOR, ITEM_COMPARATOR, true);
        this.setPseudoFolderBehaviour(new R07AltOrDetPseudoFolderBehaviour());
    }

    @Override
    protected AbstractQuad<String, TransformerR07> makeQuad(final TcSession session, final BOMLineHolder receptor, final BOMLineHolder rfReceptor,
                                                            final BOMLineHolder component, final BOMLineHolder rfComponent) {
        return new R07Quad(session, receptor, rfReceptor, component, rfComponent, counter++);
    }

    @Override
    protected AbstractTopLine<String, TransformerR07> maketopline(final BOMLineHolder aTopBomLine) {
        return null; // No need to put the topLine in the report: return null, it will not be put inside the list
    }

    @Override
    protected AbstractProductGeneric<String, TransformerR07> makeProductGeneric(final TcSession session, final BOMLineHolder productReceptor,
                                                                                final BOMLineHolder genericComponent, final BOMLineHolder rfGenericComponent) {
        return new R07ProductGeneric(session, productReceptor, genericComponent, rfGenericComponent, counter++);
    }

    @Override
    protected AbstractPartNumber<String, TransformerR07> makePartNumber(final BOMLineHolder genericReceptor, final BOMLineHolder rfGeneric,
                                                                        final BOMLineHolder partAero) {
        return null; // No need to put part Number in the report: return null, it will not be put inside the list
    }

    @Override
    protected AbstractPartRfPart<String, TransformerR07> makePartRfPart(final TcSession session, final BOMLineHolder partReceptor, final BOMLineHolder rfPartComponent,
                                                                        final BOMLineHolder partComponent) {
        return new R07PartRfPart(session, partReceptor, rfPartComponent, partComponent, counter++);
    }

    @Override
    protected AbstractReceptorLine<String, TransformerR07> makeReceptorLine(final TcSession session, final BOMLineHolder part, final BOMLineHolder rfPart) {
        return new R07ReceptorLine(session, part, rfPart, counter++);
    }

    @Override
    protected AbstractPartPart<String, TransformerR07> makePartPart(final BOMLineHolder partReceptor, final BOMLineHolder partComponent) {
        return null; // No need to cater for this event in R07, nomenclature should be stopped before: return null, it will not be put inside the list
    }

    private static final class ItemComparatorR07 implements Comparator<ISnecmaObject>, Serializable {

        private static final long serialVersionUID = 1212463997223603766L;

        @Override
        public int compare(final ISnecmaObject obj1, final ISnecmaObject obj2) {
            int cmpType = obj1.getType().compareTo(obj2.getType());
            if (cmpType != 0) {
                return cmpType;
            }
            if (obj1.isRF() && obj2.isRF()) {
                return obj1.getName().compareTo(obj2.getName());
            } else {
                return obj1.getItemId().compareTo(obj2.getItemId());
            }
        }
    }

    private static final class BomComparatorR07 implements Comparator<BOMLineHolder>, Serializable {

        private static final long serialVersionUID = 2176721559188935877L;

        @Override
        public int compare(final BOMLineHolder bom1, final BOMLineHolder bom2) {
            final int cmp;
            if (bom1 == null) {
                if (bom2 == null) {
                    cmp = 0;
                } else {
                    cmp = 1;
                }
            } else {
                if (bom2 == null) {
                    cmp = -1;
                } else {
                    cmp = ITEM_COMPARATOR.compare(bom1.getSnecmaObject(), bom2.getSnecmaObject());
                }
            }
            return cmp;
        }
    }

    @AllArgsConstructor
    private class R07AltOrDetPseudoFolderBehaviour implements DealWithAltOrDetPseudoFolder<String, TransformerR07> {
        @Override
        public List<SnecmaLine<String, TransformerR07>> dealWithIt(final BOMLineHolder alt, final AbstractPart partInPseudoFolder) {
            List<SnecmaLine<String, TransformerR07>> contents = new ArrayList<>();
            if (alt != null && alt.getSnecmaObject() != null && partInPseudoFolder != null) {
                contents.add(new R07AltPart(alt, partInPseudoFolder, counter++));
            }
            return contents;
        }
    }
}
