// Path: src/main/java/org/sputnikdev/bluetooth/manager/DiscoveredAdapter.java
// public class DiscoveredAdapter implements DiscoveredObject {
// 
//     private static final String COMBINED_ADAPTER_ADDRESS = CombinedGovernor.COMBINED_ADDRESS;
// 
//     private final URL url;
//     private final String name;
//     private final String alias;
// 
//     /**
//      * Creates a new object.
//      * @param url bluetooth object URL
//      * @param name bluetooth object name
//      * @param alias bluetooth object alias
//      */
//     public DiscoveredAdapter(URL url, String name, String alias) {
//         this.url = url;
//         this.name = name;
//         this.alias = alias;
//     }
// 
//     /**
//      * Returns bluetooth object URL.
//      * @return bluetooth object URL
//      */
//     @Override
//     public URL getURL() {
//         return url;
//     }
// 
//     /**
//      * Returns bluetooth object name.
//      * @return bluetooth object name
//      */
//     @Override
//     public String getName() {
//         return name;
//     }
// 
//     /**
//      * Returns bluetooth object alias.
//      * @return bluetooth object alias
//      */
//     @Override
//     public String getAlias() {
//         return alias;
//     }
// 
//     @Override
//     public boolean isCombined() {
//         return COMBINED_ADAPTER_ADDRESS.equalsIgnoreCase(url.getAdapterAddress());
//     }
// 
//     @Override
//     public boolean equals(Object object) {
//         if (this == object) {
//             return true;
//         }
//         if (object == null || getClass() != object.getClass()) {
//             return false;
//         }
// 
//         DiscoveredAdapter that = (DiscoveredAdapter) object;
//         return url.equals(that.url);
// 
//     }
// 
//     @Override
//     public int hashCode() {
//         int result = url.hashCode();
//         result = 31 * result + url.hashCode();
//         return result;
//     }
// 
//     @Override
//     public String toString() {
//         String displayName = getDisplayName();
//         return "[Adapter] " + getURL() + " [" + displayName + "]";
//     }
// 
//     @Override
//     public String getDisplayName() {
//         return alias != null ? alias : name;
//     }
// 
// }
// 
// Path: src/main/java/org/sputnikdev/bluetooth/manager/transport/BluetoothObjectFactory.java
// public interface BluetoothObjectFactory {
// 
// 
//     /**
//      * Returns an adapter by its URl. URL may not contain 'protocol' part.
//      * @param url adapter URL
//      * @return an adapter
//      */
//     Adapter getAdapter(URL url);
// 
//     /**
//      * Returns a device by its URl. URL may not contain 'protocol' part.
//      * @param url device URL
//      * @return a device
//      */
//     Device getDevice(URL url);
// 
//     /**
//      * Returns a characteristic by its URl. URL may not contain 'protocol' part.
//      * @param url characteristic URL
//      * @return a characteristic
//      */
//     Characteristic getCharacteristic(URL url);
// 
//     /**
//      * Returns all discovered adapters by all registered transports.
//      * @return all discovered adapters
//      */
//     Set<DiscoveredAdapter> getDiscoveredAdapters();
// 
//     /**
//      * Returns all discovered devices by all registered transports.
//      * @return all discovered devices
//      */
//     Set<DiscoveredDevice> getDiscoveredDevices();
// 
//     /**
//      * Returns transport protocol name.
//      * @return transport protocol name
//      */
//     String getProtocolName();
// 
//     /**
//      * The bluetooth manager might call this method in order to pass some configuration variables.
//      * @param config configuration
//      */
//     void configure(Map<String, Object> config);
// 
//     /**
//      * Disposes and removes registered object from the transport.
//      * @param url device to remove
//      */
//     void dispose(URL url);
// 
// }


import org.sputnikdev.bluetooth.URL;
import org.sputnikdev.bluetooth.manager.DiscoveredAdapter;
import org.sputnikdev.bluetooth.manager.transport.BluetoothObjectFactory;
import java.util.HashMap;
import java.util.Map;
import java.util.Random;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.stream.Collectors;
import static org.mockito.Matchers.any;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
        when(objectFactory.getProtocolName()).thenReturn(factoryName);
        when(objectFactory.getDiscoveredAdapters()).thenAnswer(answer -> adapters.keySet());

        when(objectFactory.getDiscoveredDevices()).thenAnswer(answer -> adapters.values().stream()
                .flatMap(adapter -> adapter.getDeviceEmulators().stream())
                .map(DeviceEmulator::getDiscoveredDevice).collect(Collectors.toSet()));

        when(objectFactory.getAdapter(any(URL.class))).thenAnswer(answer -> adapters.values().stream()
                .filter(adapter -> adapter.getAdapter().getURL().equals(answer.getArgumentAt(0, URL.class)))
                .findFirst().map(AdapterEmulator::getAdapter).orElse(null));

        when(objectFactory.getDevice(any(URL.class))).thenAnswer(answer -> adapters.values().stream()
                .flatMap(adapter -> adapter.getAdapter().getDevices().stream())
                .filter(device -> device.getURL().equals((answer.getArgumentAt(0, URL.class))))
                .findFirst().orElse(null));

        when(objectFactory.getCharacteristic(any(URL.class))).thenAnswer(answer -> adapters.values().stream()
                .flatMap(adapter -> adapter.getAdapter().getDevices().stream())
                .flatMap(device -> device.getServices().stream())
                .flatMap(service -> service.getCharacteristics().stream())
                .filter(characteristic -> characteristic.getURL().equals((answer.getArgumentAt(0, URL.class))))
                .findFirst().orElse(null));
    }

    public AdapterEmulator addAdapter(URL url) {
        return addAdapter(url, url.getAdapterAddress());
    }

    public AdapterEmulator addAdapter(URL url, String name) {
        AdapterEmulator adapterEmulator = new AdapterEmulator(url, name);
// Path: src/main/java/org/sputnikdev/bluetooth/manager/DiscoveredAdapter.java
// public class DiscoveredAdapter implements DiscoveredObject {
// 
//     private static final String COMBINED_ADAPTER_ADDRESS = CombinedGovernor.COMBINED_ADDRESS;
// 
//     private final URL url;
//     private final String name;
//     private final String alias;
// 
//     /**
//      * Creates a new object.
//      * @param url bluetooth object URL
//      * @param name bluetooth object name
//      * @param alias bluetooth object alias
//      */
//     public DiscoveredAdapter(URL url, String name, String alias) {
//         this.url = url;
//         this.name = name;
//         this.alias = alias;
//     }
// 
//     /**
//      * Returns bluetooth object URL.
//      * @return bluetooth object URL
//      */
//     @Override
//     public URL getURL() {
//         return url;
//     }
// 
//     /**
//      * Returns bluetooth object name.
//      * @return bluetooth object name
//      */
//     @Override
//     public String getName() {
//         return name;
//     }
// 
//     /**
//      * Returns bluetooth object alias.
//      * @return bluetooth object alias
//      */
//     @Override
//     public String getAlias() {
//         return alias;
//     }
// 
//     @Override
//     public boolean isCombined() {
//         return COMBINED_ADAPTER_ADDRESS.equalsIgnoreCase(url.getAdapterAddress());
//     }
// 
//     @Override
//     public boolean equals(Object object) {
//         if (this == object) {
//             return true;
//         }
//         if (object == null || getClass() != object.getClass()) {
//             return false;
//         }
// 
//         DiscoveredAdapter that = (DiscoveredAdapter) object;
//         return url.equals(that.url);
// 
//     }
// 
//     @Override
//     public int hashCode() {
//         int result = url.hashCode();
//         result = 31 * result + url.hashCode();
//         return result;
//     }
// 
//     @Override
//     public String toString() {
//         String displayName = getDisplayName();
//         return "[Adapter] " + getURL() + " [" + displayName + "]";
//     }
// 
//     @Override
//     public String getDisplayName() {
//         return alias != null ? alias : name;
//     }
// 
// }
// 
// Path: src/main/java/org/sputnikdev/bluetooth/manager/transport/BluetoothObjectFactory.java
// public interface BluetoothObjectFactory {
// 
// 
//     /**
//      * Returns an adapter by its URl. URL may not contain 'protocol' part.
//      * @param url adapter URL
//      * @return an adapter
//      */
//     Adapter getAdapter(URL url);
// 
//     /**
//      * Returns a device by its URl. URL may not contain 'protocol' part.
//      * @param url device URL
//      * @return a device
//      */
//     Device getDevice(URL url);
// 
//     /**
//      * Returns a characteristic by its URl. URL may not contain 'protocol' part.
//      * @param url characteristic URL
//      * @return a characteristic
//      */
//     Characteristic getCharacteristic(URL url);
// 
//     /**
//      * Returns all discovered adapters by all registered transports.
//      * @return all discovered adapters
//      */
//     Set<DiscoveredAdapter> getDiscoveredAdapters();
// 
//     /**
//      * Returns all discovered devices by all registered transports.
//      * @return all discovered devices
//      */
//     Set<DiscoveredDevice> getDiscoveredDevices();
// 
//     /**
//      * Returns transport protocol name.
//      * @return transport protocol name
//      */
//     String getProtocolName();
// 
//     /**
//      * The bluetooth manager might call this method in order to pass some configuration variables.
//      * @param config configuration
//      */
//     void configure(Map<String, Object> config);
// 
//     /**
//      * Disposes and removes registered object from the transport.
//      * @param url device to remove
//      */
//     void dispose(URL url);
// 
// }


// Path: src/test/java/org/sputnikdev/bluetooth/manager/util/BluetoothFactoryEmulator.java
import org.sputnikdev.bluetooth.URL;
import org.sputnikdev.bluetooth.manager.DiscoveredAdapter;
import org.sputnikdev.bluetooth.manager.transport.BluetoothObjectFactory;
import java.util.HashMap;
import java.util.Map;
import java.util.Random;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.stream.Collectors;
import static org.mockito.Matchers.any;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;

        when(objectFactory.getProtocolName()).thenReturn(factoryName);
        when(objectFactory.getDiscoveredAdapters()).thenAnswer(answer -> adapters.keySet());

        when(objectFactory.getDiscoveredDevices()).thenAnswer(answer -> adapters.values().stream()
                .flatMap(adapter -> adapter.getDeviceEmulators().stream())
                .map(DeviceEmulator::getDiscoveredDevice).collect(Collectors.toSet()));

        when(objectFactory.getAdapter(any(URL.class))).thenAnswer(answer -> adapters.values().stream()
                .filter(adapter -> adapter.getAdapter().getURL().equals(answer.getArgumentAt(0, URL.class)))
                .findFirst().map(AdapterEmulator::getAdapter).orElse(null));

        when(objectFactory.getDevice(any(URL.class))).thenAnswer(answer -> adapters.values().stream()
                .flatMap(adapter -> adapter.getAdapter().getDevices().stream())
                .filter(device -> device.getURL().equals((answer.getArgumentAt(0, URL.class))))
                .findFirst().orElse(null));

        when(objectFactory.getCharacteristic(any(URL.class))).thenAnswer(answer -> adapters.values().stream()
                .flatMap(adapter -> adapter.getAdapter().getDevices().stream())
                .flatMap(device -> device.getServices().stream())
                .flatMap(service -> service.getCharacteristics().stream())
                .filter(characteristic -> characteristic.getURL().equals((answer.getArgumentAt(0, URL.class))))
                .findFirst().orElse(null));
    }

    public AdapterEmulator addAdapter(URL url) {
        return addAdapter(url, url.getAdapterAddress());
    }

    public AdapterEmulator addAdapter(URL url, String name) {
        AdapterEmulator adapterEmulator = new AdapterEmulator(url, name);
        DiscoveredAdapter discoveredAdapter = new DiscoveredAdapter(url, name, null);