package chat.rocket.android.realm_helper;

import io.realm.Realm;
import io.realm.RealmChangeListener;
import io.realm.RealmObject;
import io.realm.RealmQuery;
import io.realm.RealmResults;

public class RealmObjectObserver<T extends RealmObject> extends AbstractRealmResultsObserver<T> {

  public interface Query<T extends RealmObject> {
    RealmQuery<T> query(Realm realm);
  }

  public interface OnUpdateListener<T extends RealmObject> {
    void onUpdateObject(T element);
  }

  public static class Impl<T extends RealmObject> {
    protected T extractObjectFromResults(RealmResults<T> results) {
      return results.isEmpty() ? null : results.last();
    }

    protected boolean isSame(T element1, T element2) {
      return element1.equals(element2);
    }
  }

  private final Query<T> query;
  private OnUpdateListener<T> onUpdateListener;
  private Impl<T> impl;

  /*package*/ RealmObjectObserver(RealmHelper helper, Query<T> query) {
    super(helper);
    this.query = query;
    setImpl(new Impl<T>());
  }

  public void setImpl(Impl<T> impl) {
    this.impl = impl;
  }

  public RealmObjectObserver<T> setOnUpdateListener(OnUpdateListener<T> onUpdateListener) {
    this.onUpdateListener = onUpdateListener;
    return this;
  }

  private T previousResult;

  @Override
  protected final RealmResults<T> queryItems(Realm realm) {
    return query.query(realm).findAll();
  }

  @Override
  protected final RealmChangeListener<RealmResults<T>> getListener() {
    return new RealmChangeListener<RealmResults<T>>() {
      @Override
      public void onChange(RealmResults<T> element) {
        T currentResult = impl.extractObjectFromResults(element);
        if (previousResult != null && impl.isSame(previousResult, currentResult)) {
          return;
        }
        previousResult = currentResult;
        if (onUpdateListener != null) {
          onUpdateListener.onUpdateObject(
              currentResult != null ? realm.copyFromRealm(currentResult) : null);
        }
      }
    };
  }

  public void sub() {
    previousResult = null;
    super.sub();
  }
}

@@ -663,110 +663,8 @@
    %7D
-%0A%0A    protected boolean isSame(T element1, T element2) %7B%0A      return element1.equals(element2);%0A    %7D
 %0A  %7D
@@ -1153,17 +1153,22 @@
 private 
-T
+String
  previou
@@ -1174,16 +1174,22 @@
 usResult
+String
 ;%0A%0A  @Ov
@@ -1186,34 +1186,32 @@
 ng;%0A%0A  @Override
-%0A 
  protected final
@@ -1310,18 +1310,16 @@
 Override
-%0A 
  protect
@@ -1451,22 +1451,16 @@
 Override
-%0A     
  public 
@@ -1566,16 +1566,110 @@
 ement);%0A
+        String currentResultString = currentResult != null ? currentResult.toString() : null;%0A
         
@@ -1682,24 +1682,30 @@
 eviousResult
+String
  != null && 
@@ -1708,20 +1708,8 @@
  && 
-impl.isSame(
 prev
@@ -1718,18 +1718,30 @@
 usResult
-, 
+String.equals(
 currentR
@@ -1745,16 +1745,22 @@
 ntResult
+String
 )) %7B%0A   
@@ -1806,16 +1806,22 @@
 usResult
+String
  = curre
@@ -1828,16 +1828,22 @@
 ntResult
+String
 ;%0A      
@@ -2027,24 +2027,25 @@
     %7D;%0A  %7D%0A%0A
+%0A
   public voi
@@ -2072,16 +2072,22 @@
 usResult
+String
  = null;
@@ -2109,9 +2109,8 @@
 );%0A  %7D%0A%7D
-%0A

improve "Stops the same object from been propagated over and over as if updated"