// Path: java/core/src/main/java/eu/mais_h/mathsync/serialize/Deserializer.java
// public interface Deserializer<T> {
// 
//   /**
//    * Deserializes an array of bytes back to an object.
//    *
//    * <p>Any array of bytes should lead to either a non <code>null</code> value or throw an
//    * {@link IllegalArgumentException}.</p>
//    *
//    * <p>The output must be consistent, an identical output should be returned if called twice
//    * on the identical arrays: for any valid <code>a1</code> and <code>a2</code>,
//    * <code>Arrays.equals(a1, a2)</code> implies
//    * <code>deserialize(a1).equals(deserialize(a2))</code>.</p>
//    *
//    * @param content the array of bytes representing an object.
//    * @return the object deserialized from the array of bytes.
//    * @throws IllegalArgumentException if the input array does not denote a valid object.
//    */
//   T deserialize(byte[] content) throws IllegalArgumentException;
// }
// 
// Path: java/core/src/main/java/eu/mais_h/mathsync/serialize/Serializer.java
// public interface Serializer<T> {
// 
//   /**
//    * Serializes an object to an array of byte.
//    *
//    * <p>Any instance of <code>T</code> must be accepted and have a non <code>null</code> return value:
//    * for any <code>o</code>, <code>o instanceof T</code> implies <code>serialize(o) != null</code>.</p>
//    *
//    * <p>The output must be consistent, an identical output should be returned if called twice on the equal
//    * objects: for any <code>o1</code> and <code>o2</code>, <code>o1.equals(o2)</code> implies
//    * <code>Arrays.equals(serialize(o1), serialize(o2))</code>.</p>
//    *
//    * @param item the object to serialize.
//    * @return the array of bytes representing the input object on the wire.
//    */
//   byte[] serialize(T item);
// }


import java.util.Set;
import eu.mais_h.mathsync.serialize.Deserializer;
import eu.mais_h.mathsync.serialize.Serializer;
package eu.mais_h.mathsync;



/**
 * Resolver using a remote summarizer to compute the delta.
 *
 * @param <T> the type of compared items.
 */
public class ResolverFromItems<T> implements Resolver<T> {

  private final Iterable<byte[]> items;
  private final Summarizer remote;
  private final Deserializer<T> deserializer;

  ResolverFromItems(Iterable<byte[]> items, Summarizer remote, Deserializer<T> deserializer) {
    this.items = items;
    this.remote = remote;
    this.deserializer = deserializer;
  }

  @Override
  public Difference<T> difference() {
    int level = 0;
    Difference<byte[]> difference = null;
    while (difference == null) {
      level++;
      Summary remoteIbf = remote.summarize(level);
      Summary minusLocal = remoteIbf.minus(items.iterator());
      difference = minusLocal.toDifference();
    }
    return new DeserializedDifference<T>(difference, deserializer);
  }

  /**
   * Builds a simple resolver.
   *
   * @param items the set containing all items in the current state.
   * @param serializer the serializer to use to serialize items.
   * @param remote the retriever of remote state.
   * @param deserializer the deserializer to use to deserialize items.
   * @return a summarizer with SHA-1 digester and default spread.
   */
// Path: java/core/src/main/java/eu/mais_h/mathsync/serialize/Deserializer.java
// public interface Deserializer<T> {
// 
//   /**
//    * Deserializes an array of bytes back to an object.
//    *
//    * <p>Any array of bytes should lead to either a non <code>null</code> value or throw an
//    * {@link IllegalArgumentException}.</p>
//    *
//    * <p>The output must be consistent, an identical output should be returned if called twice
//    * on the identical arrays: for any valid <code>a1</code> and <code>a2</code>,
//    * <code>Arrays.equals(a1, a2)</code> implies
//    * <code>deserialize(a1).equals(deserialize(a2))</code>.</p>
//    *
//    * @param content the array of bytes representing an object.
//    * @return the object deserialized from the array of bytes.
//    * @throws IllegalArgumentException if the input array does not denote a valid object.
//    */
//   T deserialize(byte[] content) throws IllegalArgumentException;
// }
// 
// Path: java/core/src/main/java/eu/mais_h/mathsync/serialize/Serializer.java
// public interface Serializer<T> {
// 
//   /**
//    * Serializes an object to an array of byte.
//    *
//    * <p>Any instance of <code>T</code> must be accepted and have a non <code>null</code> return value:
//    * for any <code>o</code>, <code>o instanceof T</code> implies <code>serialize(o) != null</code>.</p>
//    *
//    * <p>The output must be consistent, an identical output should be returned if called twice on the equal
//    * objects: for any <code>o1</code> and <code>o2</code>, <code>o1.equals(o2)</code> implies
//    * <code>Arrays.equals(serialize(o1), serialize(o2))</code>.</p>
//    *
//    * @param item the object to serialize.
//    * @return the array of bytes representing the input object on the wire.
//    */
//   byte[] serialize(T item);
// }


// Path: java/core/src/main/java/eu/mais_h/mathsync/ResolverFromItems.java
import java.util.Set;
import eu.mais_h.mathsync.serialize.Deserializer;
import eu.mais_h.mathsync.serialize.Serializer;

package eu.mais_h.mathsync;



/**
 * Resolver using a remote summarizer to compute the delta.
 *
 * @param <T> the type of compared items.
 */
public class ResolverFromItems<T> implements Resolver<T> {

  private final Iterable<byte[]> items;
  private final Summarizer remote;
  private final Deserializer<T> deserializer;

  ResolverFromItems(Iterable<byte[]> items, Summarizer remote, Deserializer<T> deserializer) {
    this.items = items;
    this.remote = remote;
    this.deserializer = deserializer;
  }

  @Override
  public Difference<T> difference() {
    int level = 0;
    Difference<byte[]> difference = null;
    while (difference == null) {
      level++;
      Summary remoteIbf = remote.summarize(level);
      Summary minusLocal = remoteIbf.minus(items.iterator());
      difference = minusLocal.toDifference();
    }
    return new DeserializedDifference<T>(difference, deserializer);
  }

  /**
   * Builds a simple resolver.
   *
   * @param items the set containing all items in the current state.
   * @param serializer the serializer to use to serialize items.
   * @param remote the retriever of remote state.
   * @param deserializer the deserializer to use to deserialize items.
   * @return a summarizer with SHA-1 digester and default spread.
   */
  public static <T> Resolver<T> from(Set<? extends T> items, Serializer<? super T> serializer, Summarizer remote, Deserializer<T> deserializer) {