package net.lr.osgibp.app;

import static org.junit.Assert.assertNotNull;

import java.io.Closeable;
import java.io.IOException;
import java.util.HashSet;
import java.util.Set;

import org.junit.rules.TestRule;
import org.junit.runner.Description;
import org.junit.runners.model.Statement;
import org.osgi.framework.Bundle;
import org.osgi.framework.FrameworkUtil;
import org.osgi.util.tracker.ServiceTracker;

public class ServiceRule implements TestRule {
    private final Bundle bundle = FrameworkUtil.getBundle(this.getClass());
    private Set<Closeable> trackers = new HashSet<>();

    @Override
    public Statement apply(Statement base, Description description) {
        assertNotNull("OSGi Bundle tests must be run inside an OSGi framework", bundle);
        return new Statement() {
            
            @Override
            public void evaluate() throws Throwable {
                
                try {
                    base.evaluate();
                } finally {
                    trackers.stream().forEach(ServiceRule::silentClose);
                }
            }
        };
    }
    
    public <T> T require(Class<T> serviceClass) {
        ServiceTracker<T, T> tracker = new ServiceTracker<T, T>(bundle.getBundleContext(), serviceClass, null);
        tracker.open();
        trackers.add(()->tracker.close());
        try {
            return tracker.waitForService(10000);
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
            throw new IllegalStateException("Timeout waiting for service " + serviceClass.getName());
        }
    }
    
    private static void silentClose(Closeable closeable) {
        try {
            closeable.close();
        } catch (IOException e) {
            // Ignore
        }
    }

}