package com.easternedgerobotics.rov.io;

import net.java.games.input.Component;
import net.java.games.input.Controller;
import net.java.games.input.ControllerEnvironment;
import net.java.games.input.Event;
import net.java.games.input.EventQueue;
import rx.Observable;
import rx.schedulers.Schedulers;

import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;

public final class Joysticks {
    private Joysticks() {

    }

    public static Observable<Joystick> logitechExtreme3dPro() {
        final String name = "Logitech Logitech Extreme 3D";
        final Observable<Controller> joystick = availableControllers()
            .first(controller -> controller.getName().equals(name));

        return joystick.map(js -> new LogitechExtremeJoystick(
            events(js),
            axes(js),
            buttons(js)
        ));
    }

    public static Observable<Event> events(final Controller controller) {
        final Observable<Event> events = Observable.create(subscriber -> {
            final EventQueue eventQueue = controller.getEventQueue();
            while (!subscriber.isUnsubscribed()) {
                if (!controller.poll()) {
                    subscriber.onError(new JoystickDisconnectedException());
                    return;
                }

                final Event event = new Event();
                if (!eventQueue.getNextEvent(event)) {
                    continue;
                }
                subscriber.onNext(event);
            }
        });

        return events.subscribeOn(Schedulers.io()).share();
    }

    public static List<Component> axes(final Controller controller) {
        return Stream.of(controller.getComponents())
            .filter(component -> component.getIdentifier() instanceof Component.Identifier.Axis)
            .collect(Collectors.toList());
    }

    public static List<Component> buttons(final Controller controller) {
        return Stream.of(controller.getComponents())
            .filter(component -> component.getIdentifier() instanceof Component.Identifier.Button)
            .collect(Collectors.toList());
    }

    public static Observable<Controller> availableControllers() {
        final Observable<Controller> controllers = Observable.create(subscriber -> {
            Stream.of(ControllerEnvironment.getDefaultEnvironment().getControllers()).forEach(subscriber::onNext);
            subscriber.onCompleted();
        });

        return controllers;
    }
}

@@ -311,118 +311,1371 @@
 ava.
-util.List;%0Aimport java.util.stream.Collectors;%0Aimport java.util.stream.Stream;%0A%0Apublic final class Joysticks %7B
+io.IOException;%0Aimport java.nio.file.Files;%0Aimport java.nio.file.Path;%0Aimport java.nio.file.StandardCopyOption;%0Aimport java.util.Arrays;%0Aimport java.util.List;%0Aimport java.util.stream.Collectors;%0Aimport java.util.stream.Stream;%0A%0Apublic final class Joysticks %7B%0A    static void load(final Path directory, final String resource) %7B%0A        try %7B%0A            final ClassLoader loader = Joysticks.class.getClassLoader();%0A            Files.copy(%0A                loader.getResourceAsStream(resource),%0A                directory.resolve(resource),%0A                StandardCopyOption.REPLACE_EXISTING);%0A        %7D catch (final IOException e) %7B%0A            throw new RuntimeException(e);%0A        %7D%0A    %7D%0A%0A    static %7B%0A        final Iterable%3CString%3E natives = Arrays.asList(%0A            %22jinput-dx8_64.dll%22,%0A            %22jinput-dx8.dll%22,%0A            %22jinput-raw_64.dll%22,%0A            %22jinput-raw.dll%22,%0A            %22jinput-wintab.dll%22,%0A            %22libjinput-linux64.so%22,%0A            %22libjinput-linux.so%22,%0A            %22libjinput-osx.jnilib%22);%0A%0A        try %7B%0A            final Path tmpdir = Files.createTempDirectory(%22jinput%22);%0A%0A            natives.forEach(lib -%3E Joysticks.load(tmpdir, lib));%0A            System.setProperty(%22net.java.games.input.librarypath%22, tmpdir.toString());%0A        %7D catch (final IOException e) %7B%0A            throw new RuntimeException(e);%0A        %7D%0A    %7D%0A
 %0A   

Load JInput native libraries at runtime