package com.easternedgerobotics.rov;

import com.easternedgerobotics.rov.event.BroadcastEventPublisher;
import com.easternedgerobotics.rov.event.EventPublisher;
import com.easternedgerobotics.rov.measure.Depth;
import com.easternedgerobotics.rov.value.ExternalPressureValueA;
import com.easternedgerobotics.rov.value.ExternalPressureValueB;
import com.easternedgerobotics.rov.value.VideoFlipValueA;
import com.easternedgerobotics.rov.value.VideoValueA;
import com.easternedgerobotics.rov.video.PicameraVideo;

import org.apache.commons.cli.CommandLine;
import org.apache.commons.cli.CommandLineParser;
import org.apache.commons.cli.DefaultParser;
import org.apache.commons.cli.HelpFormatter;
import org.apache.commons.cli.Option;
import org.apache.commons.cli.Options;
import org.apache.commons.cli.ParseException;
import org.pmw.tinylog.Logger;
import rx.broadcast.BasicOrder;
import rx.broadcast.UdpBroadcast;
import rx.schedulers.Schedulers;
import rx.subscriptions.CompositeSubscription;

import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.SocketException;
import java.net.UnknownHostException;
import java.util.concurrent.TimeUnit;

final class PicameraA {
    private final EventPublisher eventPublisher;

    private final CompositeSubscription subscriptions;

    private final CompositeSubscription flips;

    private PicameraA(final EventPublisher eventPublisher) {
        this.eventPublisher = eventPublisher;
        this.subscriptions = new CompositeSubscription();
        this.flips = new CompositeSubscription();
    }

    private void initCameraA() {
        subscriptions.add(
            eventPublisher.valuesOfType(VideoValueA.class)
                .map(value -> new PicameraVideo(value.getHost(), value.getPort()))
                .scan((old, event) -> {
                    flips.clear();
                    old.stop();
                    return event;
                })
                .delay(1, TimeUnit.SECONDS)
                .subscribe(video -> {
                    video.start();
                    flips.add(eventPublisher.valuesOfType(VideoFlipValueA.class).subscribe(f -> video.flip()));
                }));
    }

    public static void main(final String[] args) throws InterruptedException, SocketException, UnknownHostException {
        final String app = "picamera-a";
        final HelpFormatter formatter = new HelpFormatter();
        final Option broadcast = Option.builder("b")
            .longOpt("broadcast")
            .hasArg()
            .argName("ADDRESS")
            .desc("use ADDRESS to broadcast messages")
            .required()
            .build();

        final Options options = new Options();
        options.addOption(broadcast);

        try {
            final CommandLineParser parser = new DefaultParser();
            final CommandLine arguments = parser.parse(options, args);

            final InetAddress broadcastAddress = InetAddress.getByName(arguments.getOptionValue("b"));
            final int broadcastPort = BroadcastEventPublisher.DEFAULT_BROADCAST_PORT;
            final DatagramSocket socket = new DatagramSocket(broadcastPort);
            final EventPublisher eventPublisher = new BroadcastEventPublisher(new UdpBroadcast<>(
                socket, broadcastAddress, broadcastPort, new BasicOrder<>()));
            final PicameraA picamera = new PicameraA(eventPublisher);

            eventPublisher.valuesOfType(ExternalPressureValueA.class)
                .observeOn(Schedulers.computation())
                .map(Depth::fromPressure)
                .observeOn(Schedulers.io())
                .subscribe(eventPublisher::emit, Logger::error);
            eventPublisher.valuesOfType(ExternalPressureValueB.class)
                .observeOn(Schedulers.computation())
                .map(Depth::fromPressure)
                .observeOn(Schedulers.io())
                .subscribe(eventPublisher::emit, Logger::error);

            picamera.initCameraA();
            Logger.info("Started");
            eventPublisher.await();
        } catch (final ParseException e) {
            formatter.printHelp(app, options, true);
            System.exit(1);
        }
    }
}

@@ -158,188 +158,8 @@
 er;%0A
-import com.easternedgerobotics.rov.measure.Depth;%0Aimport com.easternedgerobotics.rov.value.ExternalPressureValueA;%0Aimport com.easternedgerobotics.rov.value.ExternalPressureValueB;%0A
 impo
@@ -729,41 +729,8 @@
 st;%0A
-import rx.schedulers.Schedulers;%0A
 impo
@@ -3182,557 +3182,8 @@
 );%0A%0A
-            eventPublisher.valuesOfType(ExternalPressureValueA.class)%0A                .observeOn(Schedulers.computation())%0A                .map(Depth::fromPressure)%0A                .observeOn(Schedulers.io())%0A                .subscribe(eventPublisher::emit, Logger::error);%0A            eventPublisher.valuesOfType(ExternalPressureValueB.class)%0A                .observeOn(Schedulers.computation())%0A                .map(Depth::fromPressure)%0A                .observeOn(Schedulers.io())%0A                .subscribe(eventPublisher::emit, Logger::error);%0A%0A
     

Revert "Calculate depth{A,B} from ext. pressure{A,B}"