content: /*
   * Copyright (C) 2015 Actor LLC. <https://actor.im>
   */
  
  package im.actor.runtime.js.mvvm;
  
  import com.google.gwt.core.client.JavaScriptObject;
  import com.google.gwt.core.client.JsArray;
  
  import java.util.ArrayList;
  import java.util.HashMap;
  import java.util.List;
  
  import im.actor.runtime.Log;
  import im.actor.runtime.bser.BserObject;
  import im.actor.runtime.js.storage.JsListEngine;
  import im.actor.runtime.js.storage.JsListEngineCallback;
  import im.actor.runtime.js.utils.JsModernArray;
  import im.actor.runtime.mvvm.PlatformDisplayList;
  import im.actor.runtime.storage.ListEngineItem;
  
  public class JsDisplayList<T extends JavaScriptObject, V extends BserObject & ListEngineItem> implements
          PlatformDisplayList<V> {
  
      private final JsListEngine<V> listEngine;
      private final JsEntityConverter<V, T> entityConverter;
  
      private ArrayList<SubscriberHolder> binds = new ArrayList<SubscriberHolder>();
  
      public JsDisplayList(JsListEngine<V> listEngine, JsEntityConverter<V, T> entityConverter) {
          this.listEngine = listEngine;
          this.entityConverter = entityConverter;
      }
  
      public JsDisplayListBind<T, V> subscribe(JsDisplayListCallback<T> callback, boolean isInverted) {
          unbind(callback);
          JsDisplayListBind<T, V> b = new JsDisplayListBind<T, V>(callback, isInverted, listEngine, entityConverter);
          b.initAll();
          binds.add(new SubscriberHolder(callback, b));
          return b;
      }
  
      public void unsubscribe(JsDisplayListCallback<T> callback) {
          unbind(callback);
      }
  
      private void unbind(JsDisplayListCallback<T> callback) {
          for (SubscriberHolder s : binds) {
              if (s.callback.equals(callback)) {
                  s.bind.dispose();
                  binds.remove(s);
                  break; // Can be only one
              }
          }
      }
  
      public JsDisplayListBind<T, V>[] getActiveBinds() {
          JsDisplayListBind[] res = new JsDisplayListBind[binds.size()];
          for (int i = 0; i < res.length; i++) {
              res[i] = binds.get(i).bind;
          }
          return res;
      }
  
      //
      // Not required methods
      //
  
      @Override
      public void initCenter(long rid) {
          // Nothing to do
      }
  
      @Override
      public void initTop() {
          // Nothing to do
      }
  
      @Override
      public void initEmpty() {
          // Nothing to do
      }
  
      /**
       * Work-around for impossibility of using of hash maps for closures
       */
      private class SubscriberHolder {
  
          private JsDisplayListCallback<T> callback;
          private JsDisplayListBind<T, V> bind;
  
          public SubscriberHolder(JsDisplayListCallback<T> callback, JsDisplayListBind<T, V> bind) {
              this.callback = callback;
              this.bind = bind;
          }
  
          public JsDisplayListCallback<T> getCallback() {
              return callback;
          }
  
          public JsDisplayListBind<T, V> getBind() {
              return bind;
          }
      }
  }