content: /*
   * Copyright (C) 2014 AChep@xda <artemchep@gmail.com>
   *
   * This program is free software; you can redistribute it and/or
   * modify it under the terms of the GNU General Public License
   * as published by the Free Software Foundation; either version 2
   * of the License, or (at your option) any later version.
   *
   * This program is distributed in the hope that it will be useful,
   * but WITHOUT ANY WARRANTY; without even the implied warranty of
   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   * GNU General Public License for more details.
   *
   * You should have received a copy of the GNU General Public License
   * along with this program; if not, write to the Free Software
   * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
   * MA  02110-1301, USA.
   */
  package com.achep.acdisplay.blacklist;
  
  import android.content.Context;
  import android.support.annotation.NonNull;
  import android.support.annotation.Nullable;
  import android.util.Log;
  
  import com.achep.base.content.SharedList;
  
  /**
   * The blacklist (also known as per-app-features.)
   *
   * @author Artem Chepurnoy
   * @see #saveAppConfig(android.content.Context, AppConfig, SharedList.OnSharedListChangedListener)
   * @see #getAppConfig(String)
   */
  public final class Blacklist extends SharedList<AppConfig, AppConfig.Saver> {
  
      private static final String TAG = "Blacklist";
  
      public static final String PREF_NAME = "blacklist";
  
      private static Blacklist sBlacklist;
  
      /**
       * Interface definition for a callback to be invoked
       * when a blacklist changed.
       *
       * @author Artem Chepurnoy
       */
      public static abstract class OnBlacklistChangedListener
              implements OnSharedListChangedListener<AppConfig> {
  
          /**
           * Called on blacklist changed.
           *
           * @param configNew An instance of new app's config.
           * @param configOld An instance of previous app's config (can not be null.)
           * @param diff      The difference between two configs.
           */
          public abstract void onBlacklistChanged(
                  @NonNull AppConfig configNew,
                  @NonNull AppConfig configOld, int diff);
  
          /**
           * {@inheritDoc}
           */
          @Override
          public final void onPut(@NonNull AppConfig objectNew, AppConfig objectOld, int diff) {
              onBlacklistChanged(objectNew, objectOld, diff);
          }
  
          /**
           * Should never be called.
           *
           * @see #onBlacklistChanged(AppConfig, AppConfig, int)
           */
          @Override
          public final void onRemoved(@NonNull AppConfig objectRemoved) {
              Log.wtf(TAG, "Notified about removing an item from blacklist.");
          }
      }
  
      public static synchronized Blacklist getInstance() {
          if (sBlacklist == null) {
              sBlacklist = new Blacklist();
          }
          return sBlacklist;
      }
  
      private Blacklist() {
          super();
      }
  
      /**
       * This is called on {@link com.achep.acdisplay.App#onCreate() App create}.
       *
       * @see com.achep.base.content.SharedList#init(android.content.Context)
       */
      @Override
      public void init(@NonNull Context context) {
          super.init(context);
      }
  
      /**
       * {@inheritDoc}
       */
      @NonNull
      @Override
      protected String getPreferencesFileName() {
          return PREF_NAME;
      }
  
      /**
       * {@inheritDoc}
       */
      @NonNull
      @Override
      protected AppConfig.Saver onCreateSaver() {
          return new AppConfig.Saver();
      }
  
      /**
       * {@inheritDoc}
       */
      @Override
      protected Comparator onCreateComparator() {
          return new AppConfig.Comparator();
      }
  
      /**
       * {@inheritDoc}
       */
      @Override
      protected boolean isOverwriteAllowed(@NonNull AppConfig object) {
          return true;
      }
  
      //-- MANAGING APP CONFIG --------------------------------------------------
  
      public void saveAppConfig(Context context, AppConfig config,
                                OnSharedListChangedListener listener) {
          if (config.equalsToDefault()) {
  
              // We need to remove defaults to save blacklist's size.
              super.remove(context, config, listener);
              return;
          }
  
          AppConfig clone = new AppConfig(config.packageName);
          AppConfig.copy(config, clone);
          super.put(context, clone, listener); // overwriting is enabled.
      }
  
      /**
       * <b>Creates</b> new instance of {@link com.achep.acdisplay.blacklist.AppConfig} and
       * fills it with present data.
       *
       * @param packageName The package name of need application.
       * @return New instance of app's config filled with present data.
       * @see #fill(AppConfig)
       */
      @NonNull
      public AppConfig getAppConfig(@NonNull String packageName) {
          return fill(new AppConfig(packageName));
      }
  
      @NonNull
      public AppConfig fill(@NonNull AppConfig config) {
          for (AppConfig c : values()) {
              if (c.equals(config)) {
                  AppConfig.copy(c, config);
                  return config;
              }
          }
          AppConfig.reset(config);
          return config;
      }
  
      //-- BULL SHIT PROTECTION -------------------------------------------------
  
      /**
       * This will throw an exception! Please, use
       * {@link #saveAppConfig(Context, AppConfig, SharedList.OnSharedListChangedListener)} instead.
       */
      @Nullable
      @Override
      public AppConfig put(@NonNull Context context, @NonNull AppConfig object,
                           @Nullable OnSharedListChangedListener l) {
          throw new RuntimeException();
      }
  
      /**
       * This will throw an exception! Please, use
       * {@link #saveAppConfig(Context, AppConfig, SharedList.OnSharedListChangedListener)} instead.
       */
      @Override
      public void remove(@NonNull Context context, @NonNull AppConfig object,
                         @Nullable OnSharedListChangedListener l) {
          throw new RuntimeException();
      }
  
      //-- DISMISSING WIDGET ----------------------------------------------------
  
      /**
       * {@inheritDoc}
       */
      @Override
      protected final void notifyOnRemoved(@NonNull AppConfig object, OnSharedListChangedListener l) {
  
          // Change remove-event to event about putting
          // empty config to the list.
          notifyOnPut(new AppConfig(object.packageName), object, l);
      }
  
      /**
       * {@inheritDoc}
       */
      @Override
      protected final void notifyOnPut(AppConfig object, AppConfig old, OnSharedListChangedListener l) {
          if (old == null) {
              // Do not allow nulls.
              old = new AppConfig(object.packageName);
          }
  
          // Notify all listeners
          super.notifyOnPut(object, old, l);
      }
  }
  
  