package hu.akarnokd.rxjava2;

import java.util.Collections;

import org.junit.Test;

import hu.akarnokd.rxjava2.operators.Flowables;
import io.reactivex.Flowable;

public class JoinPairwise {

    static abstract class Pair implements Comparable<Pair> { 
        int value;

        @Override
        public int compareTo(Pair o) {
            return Integer.compare(value, o.value);
        }
    }
    
    static final class Left extends Pair {
        Left(int value) {
            this.value = value;
        }

        @Override
        public String toString() {
            return "[" + value + ", _]";
        }
    }
    
    static final class Right extends Pair {
        Right(int value) {
            this.value = value;
        }

        @Override
        public String toString() {
            return "[_, " + value + "]";
        }
    }
    
    static final class Both extends Pair {
        Both(int value) {
            this.value = value;
        }
        
        @Override
        public int hashCode() {
            return value;
        }

        @Override
        public boolean equals(Object obj) {
            if (obj instanceof Both) {
                return ((Both)obj).value == value;
            }
            return false;
        }

        @Override
        public String toString() {
            return "[" + value + ", " + value + "]";
        }
    }
    
    @SuppressWarnings("unchecked")
    @Test
    public void test() {
        Flowable<Integer> a = Flowable.just(0, 2, 3, 6);
        Flowable<Integer> b = Flowable.just(1, 2, 3, 4, 5, 6);

        Flowable.defer(() -> {
            boolean[] skip = { false };
            return Flowables.<Pair>orderedMerge(
                    a.<Pair>map(Left::new), b.<Pair>map(Right::new)
                )
                .distinctUntilChanged()
                .buffer(2, 1)
                .flatMapIterable(buf -> {
                    if (skip[0]) {
                        skip[0] = false;
                        return Collections.emptyList();
                    }
                    if (buf.size() == 2) {
                        if (buf.get(0).value == buf.get(1).value) {
                            skip[0] = true;
                            return Collections.singletonList(new Both(buf.get(0).value));
                        }
                        return buf.subList(0, 1);
                    }
                    return buf;
                });
        })
        .subscribe(System.out::println);
    }
}