package ru.kirillius.pf.sdn.core.Networking;

import ru.kirillius.pf.sdn.core.AppService;
import ru.kirillius.pf.sdn.core.Context;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;

/**
 * Delegates asynchronous retrieval of BGP prefix data through a configurable provider.
 */
public class BGPInfoService extends AppService {
    private final ExecutorService executor = Executors.newSingleThreadExecutor();

    public void addProvider(ASInfoProvider provider) {
        synchronized (providers) {
            providers.add(provider);
        }
    }

    public void fallbackNextProvider() {
        synchronized (providers) {
            if (provider == null) {
                provider = providers.getFirst();
                return;
            }
            for (var i = 0; i < providers.size(); i++) {
                var provider = providers.get(i);
                if (provider == this.provider) {
                    var nextIndex = i + 1;
                    if (nextIndex >= providers.size()) {
                        nextIndex = 0;
                    }
                    this.provider = providers.get(nextIndex);
                    return;
                }
            }
        }
    }

    private final List<ASInfoProvider> providers = new ArrayList<>();

    public ASInfoProvider getProvider() {
        if (provider == null) {
            if (providers.isEmpty()) {
                return null;
            }
            fallbackNextProvider();
        }
        return provider;
    }

    private ASInfoProvider provider;

    /**
     * Creates the service tied to the shared context.
     */
    public BGPInfoService(Context context) {
        super(context);
    }

    /**
     * Submits a request to obtain prefixes for the provided autonomous system number.
     */
    public Future<List<IPv4Subnet>> getPrefixes(int as) {
        return executor.submit(() -> getProvider().getPrefixes(as));
    }

    public Future<ASInfoProvider.IPQueryInfo> getAddressInfo(String address) {
        return executor.submit(() -> getProvider().queryAddress(address));
    }

    /**
     * Shuts down the background executor.
     */
    @Override
    public void close() throws IOException {
        executor.shutdown();
    }

}
