package be.iminds.ilabt.jfed.rspec.model;

import be.iminds.ilabt.jfed.rspec.rspec_source.ManifestRspecSource;
import be.iminds.ilabt.jfed.util.GeniUrn;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.ByteArrayOutputStream;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

/**
 * ManifestSliverFinder
 *
 * finds sliver URNs in a manifest RSpec
 */
public class ManifestSliverFinder {
    private static final Logger LOG = LoggerFactory.getLogger(ManifestSliverFinder.class);

    private static final int MAX_IP_IN_SLIVERNAME = 3;
    public static final String IP_POOL_PREFIX = "ip-pool-";

    private static String ipsToSliverName(List<? extends IPv4> ip4s) {
        int count = 0;
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        for (IPv4 ip4 : ip4s) {
            try {
                byte[] bytes = InetAddress.getByName(ip4.getAddress()).getAddress();
                baos.write(bytes, 0, bytes.length);
            } catch (UnknownHostException e) {
                LOG.warn("Invalid IP in manifest Rspec AddressPool: " + ip4.getAddress(), e);
                byte[] bytes = {(byte)255, (byte)255, (byte)255, (byte)255};
                baos.write(bytes, 0, bytes.length);
            }
            count++;
            if (count >= MAX_IP_IN_SLIVERNAME)
                break;
        }
        //Base64 uses chars we can't use!
//        return DataConversionUtils.encodeBase64(baos.toByteArray());
        byte[] bytes = baos.toByteArray();
        String res = "";
        for (byte b : bytes) {
            res += String.format("%02X", b);
        }
        return res;
    }

    public static Collection<GeniUrn> findSliversInManifest(String manifestRspecString) {
        ManifestRspecSource manifestRspecSource = new ManifestRspecSource(manifestRspecString, ModelRspecType.BASIC);
        return findSliversInManifest(manifestRspecSource);
    }
    public static Collection<GeniUrn> findSliversInManifest(ManifestRspecSource manifestRspecSource) {
        List<GeniUrn> res = new ArrayList<>();

        ModelRspec rspec = manifestRspecSource.getModelRspec();
        if (rspec == null) return res;

        for (RspecNode node : rspec.getNodes())
            if (node.getSliverId() != null)
                res.add(node.getSliverId());

        for(RspecLink link : rspec.getLinks())
            if(link.getSliverId() != null)
                res.add(link.getSliverId());

        //create fake slivers
        for (AddressPool addressPool: rspec.getAddressPools()) {
            GeniUrn cmUrn = addressPool.getComponentManagerId();
            String ipName = ipsToSliverName(addressPool.getIPv4s());
            String uniqueName = IP_POOL_PREFIX +addressPool.getClientId()+"-"+ipName;
            GeniUrn poolUrn = GeniUrn.createGeniUrnFromEncodedParts(
                    cmUrn.getEncodedTopLevelAuthority(),
                    "sliver",
                    uniqueName
            );
            res.add(poolUrn);
        }

        return res;
    }
}
