package com.capgemini.framework.teamcenter.resolution.structureservice;

import com.capgemini.framework.teamcenter.ServiceDataHelper;
import com.capgemini.framework.teamcenter.authent.TcSession;
import com.capgemini.framework.teamcenter.exceptions.EmptyNomenclatureException;
import com.capgemini.framework.teamcenter.resolution.filtering.ITcTypeFilter;
import com.capgemini.reports.bomlineholder.BOMLineHolder;
import com.teamcenter.services.strong.cad._2008_06.StructureManagement.*;
import com.teamcenter.soa.client.model.strong.BOMLine;
import com.teamcenter.soa.client.model.strong.ItemRevision;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;


/**
 * Helper dedicated to multi levels resolution of configurations.
 **/
public class MultiStructureServiceCallerRaw implements StructureServiceRaw {
    private static final Logger LOGGER = LoggerFactory.getLogger(MultiStructureServiceCallerRaw.class);
    private static final String NO_FILTER = "None2";

    private final TcSession session;

    public MultiStructureServiceCallerRaw(final TcSession session) {
        this.session = session;
    }

    @Override
    public BOMLineHolder resolve(final BOMLine topBomLine, final ITcTypeFilter filter) throws EmptyNomenclatureException {
        LOGGER.debug("Top line: {}", topBomLine.getUid());
        LOGGER.debug("Start Multi-level BOMLine expansion");
        ExpandPSAllLevelsResponse2 response = session.getStructureManagementService().expandPSAllLevels(expandInfo(topBomLine), expandPref());
        LOGGER.debug("End expand all levels");
        if (ServiceDataHelper.hasErrors(response.serviceData)) {
            ServiceDataHelper.displayErrors(response.serviceData);
        }

        Map<BOMLine, ExpandPSAllLevelsOutput> dataByBomLine = new HashMap<>();
        for (ExpandPSAllLevelsOutput output : response.output) {
            BOMLine parentBomLine = output.parent.bomLine;
            if (parentBomLine != null && output.parent.objectOfBOMLine != null) {
                dataByBomLine.put(parentBomLine, output);
            }
        }

        return toTreeBom(dataByBomLine, topBomLine, filter);
    }

    private ExpandPSAllLevelsInfo expandInfo(BOMLine topBomLine) {
        ExpandPSAllLevelsInfo info = new ExpandPSAllLevelsInfo();
        info.parentBomLines = new BOMLine[]{topBomLine};
        info.excludeFilter = NO_FILTER;
        return info;
    }

    private ExpandPSAllLevelsPref expandPref() {
        ExpandPSAllLevelsPref pref = new ExpandPSAllLevelsPref();
        pref.expItemRev = false;
        return pref;
    }

    private BOMLineHolder toTreeBom(final Map<BOMLine, ExpandPSAllLevelsOutput> dataByBomLine, final BOMLine parentBomLine, final ITcTypeFilter filter) {
        ExpandPSAllLevelsOutput parentOutput = dataByBomLine.get(parentBomLine);
        List<BOMLineHolder> childs = new ArrayList<>();
        for (ExpandPSData currentChildData : parentOutput.children) {
            if (currentChildData.objectOfBOMLine != null && filter.isIncluded(currentChildData.objectOfBOMLine.getTypeObject().getName())) {
                if (hasChilds(dataByBomLine, currentChildData)) {
                    childs.add(toTreeBom(dataByBomLine, currentChildData.bomLine, filter));
                } else {
                    childs.add(new BOMLineHolder(session, currentChildData.bomLine, (ItemRevision) currentChildData.objectOfBOMLine, new ArrayList<BOMLineHolder>()));
                }
            }
        }
        return new BOMLineHolder(session, parentOutput.parent.bomLine, (ItemRevision) parentOutput.parent.objectOfBOMLine, childs);
    }

    private boolean hasChilds(Map<BOMLine, ExpandPSAllLevelsOutput> dataByBomLine, ExpandPSData currentChildData) {
        return dataByBomLine.get(currentChildData.bomLine) != null;
    }
}
