// Copyright 2012 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package com.google.collide.shared.util;

import com.google.collide.json.shared.JsonArray;

/**
 * A manager to register or unregister listeners.
 */
public interface ListenerRegistrar<T> {

  /**
   * A handle to allow removing the added listener.
   */
  public interface Remover {
    void remove();
  }

  /**
   * An object which helps to simplify management of multiple handlers that need
   * to be removed. This is the recommended approach to managing removers as it
   * guards against null checks and prevents forgetting to remove listeners.
   */
  public static class RemoverManager implements Remover {
    private JsonArray<Remover> handlers;

    /**
     * Tracks a new handler so that it can be removed in bulk.
     */
    public RemoverManager track(Remover remover) {
      if (handlers == null) {
        handlers = JsonCollections.createArray();
      }

      handlers.add(remover);
      return this;
    }

    /**
     * Removes all tracked handlers and clears the stored list of handlers.
     */
    @Override
    public void remove() {
      if (handlers == null) {
        return;
      }

      for (int i = 0; i < handlers.size(); i++) {
        handlers.get(i).remove();
      }

      handlers.clear();
    }
  }

  /**
   * Registers a new listener.
   */
  Remover add(T listener);

  /**
   * Removes a listener. It is strongly preferred you use the {@link Remover}
   * returned by {@link #add(Object)} instead of calling this method directly.
   */
  void remove(T listener);
}
