package be.iminds.ilabt.jfed.highlevel.jobs.report;

import be.iminds.ilabt.jfed.highlevel.jobs.AllocateExperimentJob;
import be.iminds.ilabt.jfed.highlevel.stitcher.HopInfo;
import be.iminds.ilabt.jfed.lowlevel.stitching.info.Hop;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.util.Pair;

import java.util.*;

/**
 * User: twalcari
 * Date: 12/9/2015
 * Time: 16:33
 */
public class StitchingJobReport extends JobReport {

    private final Map<String, ObservableList<HopInfo>> hopInfoByLinkName = new HashMap<>();
    private final Map<String, HopInfo> hopInfoByUrn = new HashMap<>();

    public <V> StitchingJobReport(AllocateExperimentJob job) {
        super(job);
    }

    /** update info, or if not known, add all. (called by ParallelStitcher) */
    void updateHopOverview(Map<String, List<Hop>> hopOverview) {
        List<Pair<Hop, HopInfo>> newHopInfo = new ArrayList<>();
        for (Map.Entry<String, List<Hop>> e : hopOverview.entrySet()) {
            String linkName = e.getKey();
            List<Hop> hops = e.getValue();
            ObservableList<HopInfo> hopInfos = hopInfoByLinkName.computeIfAbsent(linkName, c -> FXCollections.observableArrayList());
            for (int i = 0; i < hops.size(); i++) {
                Hop hop = hops.get(i);
                HopInfo hopInfo;
                if (hopInfos.size() <= i) {
                    hopInfo = new HopInfo(hop);
                    newHopInfo.add(new Pair<>(hop, hopInfo));
                    hopInfoByUrn.put(hopInfo.getHopUrn(), hopInfo);
                    //Note: hopInfos.add(hopInfo); would be too early here! First we need to fix the deps.
                } else {
                    hopInfo = hopInfos.get(i);
                }
                assert Objects.equals(hopInfo.getAuthUrn(), hop.getAuthUrn());
            }
        }

        //copy dependencies
        for (Pair<Hop, HopInfo> p : newHopInfo) {
            Hop hop = p.getKey();
            HopInfo hopInfo = p.getValue();
            for (Hop h : hop.getDependsOn()) {
                HopInfo hi = hopInfoByUrn.get(h.getHopUrn());
                assert hi != null;
                hopInfo.getDependsOn().add(hi);
            }
            for (Hop h : hop.getDependingOnThis()) {
                HopInfo hi = hopInfoByUrn.get(h.getHopUrn());
                assert hi != null;
                hopInfo.getDependingOnThis().add(hi);
            }
        }

        //now add new HopInfo and trigger listeners
        for (Pair<Hop, HopInfo> p : newHopInfo) {
            HopInfo hopInfo = p.getValue();
            ObservableList<HopInfo> hopInfos = hopInfoByLinkName.get(hopInfo.getLinkName());
            hopInfos.add(hopInfo);
        }
    }

    public ObservableList<HopInfo> getLinkHopInfo(String linkName) {
        return hopInfoByLinkName.computeIfAbsent(linkName, c -> FXCollections.observableArrayList());
    }
}
