package be.iminds.ilabt.jfed.experimenter_gui.util;

import be.iminds.ilabt.jfed.experimenter_gui.editor.properties.map.ImageMap;
import be.iminds.ilabt.jfed.jaxb.testbed_nodes_map.BoundsType;
import be.iminds.ilabt.jfed.jaxb.testbed_nodes_map.TestbedNodeType;
import be.iminds.ilabt.jfed.jaxb.testbed_nodes_map.TestbedNodesMap;
import be.iminds.ilabt.jfed.jaxb.testbed_nodes_maps.TestbedNodesMaps;
import be.iminds.ilabt.jfed.util.GeniUrn;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.inject.Inject;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Unmarshaller;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.Callable;

/**
 * User: twalcari
 * Date: 8/20/2015
 * Time: 11:50
 */
public class TestbedNodesMapFetcher implements Callable<Map<GeniUrn, ImageMap<GeniUrn>>> {
    private static final Logger LOG = LoggerFactory.getLogger(TestbedNodesMapFetcher.class);

    private static final String DEFAULT_MAPS_LOCATION = "https://flsmonitor.fed4fire.eu/maps/testbed_nodes_maps.xml";

    private final ConnectivityDetector connectivityDetector;

    @Inject
    public TestbedNodesMapFetcher(ConnectivityDetector connectivityDetector) {
        this.connectivityDetector = connectivityDetector;
    }

    @Override
    public Map<GeniUrn, ImageMap<GeniUrn>> call()  {
        if (connectivityDetector.isNoInternet())
            return Collections.emptyMap();

        try {
            Map<GeniUrn, ImageMap<GeniUrn>> imageMaps = new HashMap<>();

            JAXBContext contextMaps = JAXBContext.newInstance(TestbedNodesMaps.class);
            JAXBContext contextMap = JAXBContext.newInstance("be.iminds.ilabt.jfed.jaxb.testbed_nodes_map");
            Unmarshaller unmarshaller = contextMaps.createUnmarshaller();

            URL mapsUrl = new URL(DEFAULT_MAPS_LOCATION);

            TestbedNodesMaps testbedNodesMaps =
                    (TestbedNodesMaps) unmarshaller.unmarshal(mapsUrl);

            unmarshaller = contextMap.createUnmarshaller();
            for (TestbedNodesMaps.TestbedNodeMap tnmRef : testbedNodesMaps.getTestbedNodeMap()) {

                final URL mapUrl = new URL(mapsUrl, tnmRef.getUrl());
                TestbedNodesMap testbedNodesMap =
                        (TestbedNodesMap) unmarshaller.unmarshal(mapUrl);

                final URL imageUrl = new URL(mapUrl, testbedNodesMap.getMapUrl());

                ImageMap<GeniUrn> testbedImageMap = new ImageMap<>(imageUrl);
                for (TestbedNodeType testbedNode : testbedNodesMap.getTestbedNode()) {
                    BoundsType b = testbedNode.getBounds();
                    testbedImageMap.addSelectableRegion(
                            new ImageMap.Bounds(b.getMinX(), b.getMaxX(), b.getMinY(), b.getMaxY()),
                            GeniUrn.parse(testbedNode.getComponentId()));
                }

                imageMaps.put(GeniUrn.parse(tnmRef.getComponentManagerId()), testbedImageMap);
            }

            return imageMaps;
        } catch (JAXBException | MalformedURLException e) {
            LOG.debug("Could not initialize testbed nodes maps", e);
            return Collections.emptyMap();
        }
    }
}
