content: package org.adaway.ui.hosts;
  
  import android.content.Context;
  import android.content.res.Resources;
  import android.view.LayoutInflater;
  import android.view.View;
  import android.view.ViewGroup;
  import android.widget.CheckBox;
  import android.widget.TextView;
  
  import androidx.annotation.NonNull;
  import androidx.recyclerview.widget.DiffUtil;
  import androidx.recyclerview.widget.ListAdapter;
  import androidx.recyclerview.widget.RecyclerView;
  
  import org.adaway.R;
  import org.adaway.db.entity.HostsSource;
  
  import java.time.Duration;
  import java.time.ZonedDateTime;
  
  /**
   * This class is a the {@link RecyclerView.Adapter} for the hosts sources view.
   *
   * @author Bruce BUJON (bruce.bujon(at)gmail(dot)com)
   */
  class HostsSourcesAdapter extends ListAdapter<HostsSource, HostsSourcesAdapter.ViewHolder> {
      /**
       * This callback is use to compare hosts sources.
       */
      private static final DiffUtil.ItemCallback<HostsSource> DIFF_CALLBACK =
              new DiffUtil.ItemCallback<HostsSource>() {
                  @Override
                  public boolean areItemsTheSame(@NonNull HostsSource oldSource, @NonNull HostsSource newSource) {
                      return oldSource.getUrl().equals(newSource.getUrl());
                  }
  
                  @Override
                  public boolean areContentsTheSame(@NonNull HostsSource oldSource, @NonNull HostsSource newSource) {
                      // NOTE: if you use equals, your object must properly override Object#equals()
                      // Incorrectly returning false here will result in too many animations.
                      return oldSource.equals(newSource);
                  }
              };
  
      /**
       * This callback is use to call view actions.
       */
      @NonNull
      private final HostsSourcesViewCallback viewCallback;
      private static final String[] QUANTITY_PREFIXES = new String[]{"k", "M", "G"};
  
      /**
       * Constructor.
       *
       * @param viewCallback The view callback.
       */
      HostsSourcesAdapter(@NonNull HostsSourcesViewCallback viewCallback) {
          super(DIFF_CALLBACK);
          this.viewCallback = viewCallback;
      }
  
      /**
       * Get the approximate delay from a date to now.
       *
       * @param context The application context.
       * @param from    The date from which computes the delay.
       * @return The approximate delay.
       */
      private static String getApproximateDelay(Context context, ZonedDateTime from) {
          // Get resource for plurals
          Resources resources = context.getResources();
          // Get current date in UTC timezone
          ZonedDateTime now = ZonedDateTime.now();
          // Get delay between from and now in minutes
          long delay = Duration.between(from, now).toMinutes();
          // Check if delay is lower than an hour
          if (delay < 60) {
              return resources.getString(R.string.hosts_source_few_minutes);
          }
          // Get delay in hours
          delay /= 60;
          // Check if delay is lower than a day
          if (delay < 24) {
              int hours = (int) delay;
              return resources.getQuantityString(R.plurals.hosts_source_hours, hours, hours);
          }
          // Get delay in days
          delay /= 24;
          // Check if delay is lower than a month
          if (delay < 30) {
              int days = (int) delay;
              return resources.getQuantityString(R.plurals.hosts_source_days, days, days);
          }
          // Get delay in months
          int months = (int) delay / 30;
          return resources.getQuantityString(R.plurals.hosts_source_months, months, months);
      }
  
      @NonNull
      @Override
      public HostsSourcesAdapter.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
          LayoutInflater layoutInflater = LayoutInflater.from(parent.getContext());
          View view = layoutInflater.inflate(R.layout.hosts_sources_card, parent, false);
          return new ViewHolder(view);
      }
  
      @Override
      public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
          HostsSource source = this.getItem(position);
          holder.enabledCheckBox.setChecked(source.isEnabled());
          holder.enabledCheckBox.setOnClickListener(view -> viewCallback.toggleEnabled(source));
          holder.labelTextView.setText(source.getLabel());
          holder.urlTextView.setText(source.getUrl());
          holder.updateTextView.setText(getUpdateText(source));
          holder.sizeTextView.setText(getHostCount(source));
          holder.itemView.setOnClickListener(view -> viewCallback.edit(source));
      }
  
      private String getUpdateText(HostsSource source) {
          // Get context
          Context context = this.viewCallback.getContext();
          // Check if source is enabled
          if (!source.isEnabled()) {
              return context.getString(R.string.hosts_source_disabled);
          }
          // Check modification dates
          boolean lastOnlineModificationDefined = source.getOnlineModificationDate() != null;
          boolean lastLocalModificationDefined = source.getLocalModificationDate() != null;
          // Declare update text
          String updateText;
          // Check if last online modification date is known
          if (lastOnlineModificationDefined) {
              // Get last online modification delay
              String approximateDelay = getApproximateDelay(context, source.getOnlineModificationDate());
              if (!lastLocalModificationDefined) {
                  updateText = context.getString(R.string.hosts_source_last_update, approximateDelay);
              } else if (source.getOnlineModificationDate().isAfter(source.getLocalModificationDate())) {
                  updateText = context.getString(R.string.hosts_source_need_update, approximateDelay);
              } else {
                  updateText = context.getString(R.string.hosts_source_up_to_date, approximateDelay);
              }
          } else {
              if (lastLocalModificationDefined) {
                  String approximateDelay = getApproximateDelay(context, source.getLocalModificationDate());
                  updateText = context.getString(R.string.hosts_source_installed, approximateDelay);
              } else {
                  updateText = context.getString(R.string.hosts_source_unknown_status);
              }
          }
          return updateText;
      }
  
      private String getHostCount(HostsSource source) {
          // Note: NumberFormat.getCompactNumberInstance is Java 12 only
          // Check empty source
          int size = source.getSize();
          if (size <= 0 || !source.isEnabled()) {
              return "";
          }
          // Compute size decimal length
          int length = 1;
          while (size > 10) {
              size /= 10;
              length++;
          }
          // Compute prefix to use
          int prefixIndex = (length - 1) / 3 - 1;
          // Return formatted count
          Context context = this.viewCallback.getContext();
          size = source.getSize();
          if (prefixIndex < 0) {
              return context.getString(R.string.hosts_count, Integer.toString(size));
          } else if (prefixIndex >= QUANTITY_PREFIXES.length) {
              prefixIndex = QUANTITY_PREFIXES.length - 1;
              size = 13;
          }
          size = Math.toIntExact(Math.round(size / Math.pow(10, (prefixIndex + 1) * 3D)));
          return context.getString(R.string.hosts_count, size + QUANTITY_PREFIXES[prefixIndex]);
      }
  
      /**
       * This class is a the {@link RecyclerView.ViewHolder} for the hosts sources view.
       *
       * @author Bruce BUJON (bruce.bujon(at)gmail(dot)com)
       */
      static class ViewHolder extends RecyclerView.ViewHolder {
          final CheckBox enabledCheckBox;
          final TextView labelTextView;
          final TextView urlTextView;
          final TextView updateTextView;
          final TextView sizeTextView;
  
          /**
           * Constructor.
           *
           * @param itemView The hosts sources view.
           */
          ViewHolder(View itemView) {
              super(itemView);
              this.enabledCheckBox = itemView.findViewById(R.id.sourceEnabledCheckBox);
              this.labelTextView = itemView.findViewById(R.id.sourceLabelTextView);
              this.urlTextView = itemView.findViewById(R.id.sourceUrlTextView);
              this.updateTextView = itemView.findViewById(R.id.sourceUpdateTextView);
              this.sizeTextView = itemView.findViewById(R.id.sourceSizeTextView);
          }
      }
  }
  