content: /*
   * Copyright (C) 2013 The Android Open Source Project
   *
   * 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.android.timezonepicker;
  
  import android.content.Context;
  import android.content.SharedPreferences;
  import android.text.TextUtils;
  import android.util.Log;
  import android.view.LayoutInflater;
  import android.view.View;
  import android.view.ViewGroup;
  import android.widget.AdapterView;
  import android.widget.AdapterView.OnItemClickListener;
  import android.widget.BaseAdapter;
  import android.widget.TextView;
  
  import com.android.timezonepicker.TimeZoneFilterTypeAdapter.OnSetFilterListener;
  import com.android.timezonepicker.TimeZonePickerView.OnTimeZoneSetListener;
  
  import java.util.ArrayList;
  import java.util.Iterator;
  import java.util.LinkedHashSet;
  
  public class TimeZoneResultAdapter extends BaseAdapter implements OnItemClickListener,
          OnSetFilterListener {
      private static final String TAG = "TimeZoneResultAdapter";
      private static final boolean DEBUG = false;
      private static final int VIEW_TAG_TIME_ZONE = R.id.time_zone;
      private static final int EMPTY_INDEX = -100;
  
      /** SharedPref name and key for recent time zones */
      private static final String SHARED_PREFS_NAME = "com.android.calendar_preferences";
      private static final String KEY_RECENT_TIMEZONES = "preferences_recent_timezones";
  
      private int mLastFilterType;
      private String mLastFilterString;
      private int mLastFilterTime;
  
      private boolean mHasResults = false;
  
      /**
       * The delimiter we use when serializing recent timezones to shared
       * preferences
       */
      private static final String RECENT_TIMEZONES_DELIMITER = ",";
  
      /** The maximum number of recent timezones to save */
      private static final int MAX_RECENT_TIMEZONES = 3;
  
      static class ViewHolder {
          TextView timeZone;
          TextView timeOffset;
          TextView location;
  
          static void setupViewHolder(View v) {
              ViewHolder vh = new ViewHolder();
              vh.timeZone = (TextView) v.findViewById(R.id.time_zone);
              vh.timeOffset = (TextView) v.findViewById(R.id.time_offset);
              vh.location = (TextView) v.findViewById(R.id.location);
              v.setTag(vh);
          }
      }
  
      private Context mContext;
      private LayoutInflater mInflater;
  
      private OnTimeZoneSetListener mTimeZoneSetListener;
      private TimeZoneData mTimeZoneData;
  
      private int[] mFilteredTimeZoneIndices;
      private int mFilteredTimeZoneLength = 0;
  
      public TimeZoneResultAdapter(Context context, TimeZoneData tzd,
              com.android.timezonepicker.TimeZonePickerView.OnTimeZoneSetListener l) {
          super();
  
          mContext = context;
          mTimeZoneData = tzd;
          mTimeZoneSetListener = l;
  
          mInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
  
          mFilteredTimeZoneIndices = new int[mTimeZoneData.size()];
  
          onSetFilter(TimeZoneFilterTypeAdapter.FILTER_TYPE_NONE, null, 0);
      }
  
      public boolean hasResults() {
          return mHasResults;
      }
  
      public int getLastFilterType() {
          return mLastFilterType;
      }
  
      public String getLastFilterString() {
          return mLastFilterString;
      }
  
      public int getLastFilterTime() {
          return mLastFilterTime;
      }
  
      // Implements OnSetFilterListener
      @Override
      public void onSetFilter(int filterType, String str, int time) {
          if (DEBUG) {
              Log.d(TAG, "onSetFilter: " + filterType + " [" + str + "] " + time);
          }
  
          mLastFilterType = filterType;
          mLastFilterString = str;
          mLastFilterTime = time;
  
          mFilteredTimeZoneLength = 0;
          int idx = 0;
  
          switch (filterType) {
              case TimeZoneFilterTypeAdapter.FILTER_TYPE_EMPTY:
                  mFilteredTimeZoneIndices[mFilteredTimeZoneLength++] = EMPTY_INDEX;
                  break;
              case TimeZoneFilterTypeAdapter.FILTER_TYPE_NONE:
                  // Show the default/current value first
                  int defaultTzIndex = mTimeZoneData.getDefaultTimeZoneIndex();
                  if (defaultTzIndex != -1) {
                      mFilteredTimeZoneIndices[mFilteredTimeZoneLength++] = defaultTzIndex;
                  }
  
                  // Show the recent selections
                  SharedPreferences prefs = mContext.getSharedPreferences(SHARED_PREFS_NAME,
                          Context.MODE_PRIVATE);
                  String recentsString = prefs.getString(KEY_RECENT_TIMEZONES, null);
                  if (!TextUtils.isEmpty(recentsString)) {
                      String[] recents = recentsString.split(RECENT_TIMEZONES_DELIMITER);
                      for (int i = recents.length - 1; i >= 0; i--) {
                          if (!TextUtils.isEmpty(recents[i])
                                  && !recents[i].equals(mTimeZoneData.mDefaultTimeZoneId)) {
                              int index = mTimeZoneData.findIndexByTimeZoneIdSlow(recents[i]);
                              if (index != -1) {
                                  mFilteredTimeZoneIndices[mFilteredTimeZoneLength++] = index;
                              }
                          }
                      }
                  }
  
                  break;
              case TimeZoneFilterTypeAdapter.FILTER_TYPE_GMT:
                  ArrayList<Integer> indices = mTimeZoneData.getTimeZonesByOffset(time);
                  if (indices != null) {
                      for (Integer i : indices) {
                          mFilteredTimeZoneIndices[mFilteredTimeZoneLength++] = i;
                      }
                  }
                  break;
              case TimeZoneFilterTypeAdapter.FILTER_TYPE_COUNTRY:
                  ArrayList<Integer> tzIds = mTimeZoneData.mTimeZonesByCountry.get(str);
                  if (tzIds != null) {
                      for (Integer tzi : tzIds) {
                          mFilteredTimeZoneIndices[mFilteredTimeZoneLength++] = tzi;
                      }
                  }
                  break;
              case TimeZoneFilterTypeAdapter.FILTER_TYPE_STATE:
                  // TODO Filter by state
                  break;
              default:
                  throw new IllegalArgumentException();
          }
          mHasResults = mFilteredTimeZoneLength > 0;
  
          notifyDataSetChanged();
      }
  
      /**
       * Saves the given timezone ID as a recent timezone under shared
       * preferences. If there are already the maximum number of recent timezones
       * saved, it will remove the oldest and append this one.
       *
       * @param id the ID of the timezone to save
       * @see {@link #MAX_RECENT_TIMEZONES}
       */
      public void saveRecentTimezone(String id) {
          SharedPreferences prefs = mContext.getSharedPreferences(SHARED_PREFS_NAME,
                  Context.MODE_PRIVATE);
          String recentsString = prefs.getString(KEY_RECENT_TIMEZONES, null);
          if (recentsString == null) {
              recentsString = id;
          } else {
              // De-dup
              LinkedHashSet<String> recents = new LinkedHashSet<String>();
              for(String tzId : recentsString.split(RECENT_TIMEZONES_DELIMITER)) {
                  if (!recents.contains(tzId) && !id.equals(tzId)) {
                      recents.add(tzId);
                  }
              }
  
              Iterator<String> it = recents.iterator();
              while (recents.size() >= MAX_RECENT_TIMEZONES) {
                  if (!it.hasNext()) {
                      break;
                  }
                  it.next();
                  it.remove();
              }
              recents.add(id);
  
              StringBuilder builder = new StringBuilder();
              boolean first = true;
              for (String recent : recents) {
                  if (first) {
                      first = false;
                  } else {
                      builder.append(RECENT_TIMEZONES_DELIMITER);
                  }
                  builder.append(recent);
              }
              recentsString = builder.toString();
          }
  
          prefs.edit().putString(KEY_RECENT_TIMEZONES, recentsString).apply();
      }
  
      @Override
      public int getCount() {
          return mFilteredTimeZoneLength;
      }
  
      @Override
      public Object getItem(int position) {
          if (position < 0 || position >= mFilteredTimeZoneLength) {
              return null;
          }
  
          return mTimeZoneData.get(mFilteredTimeZoneIndices[position]);
      }
  
      @Override
      public boolean areAllItemsEnabled() {
          return false;
      }
  
      @Override
      public boolean isEnabled(int position) {
          return mFilteredTimeZoneIndices[position] >= 0;
      }
  
      @Override
      public long getItemId(int position) {
          return mFilteredTimeZoneIndices[position];
      }
  
      @Override
      public View getView(int position, View convertView, ViewGroup parent) {
          View v = convertView;
  
          if (mFilteredTimeZoneIndices[position] == EMPTY_INDEX) {
              v = mInflater.inflate(R.layout.empty_time_zone_item, null);
              return v;
          }
  
          // We'll need to re-inflate the view if it was null, or if it was used as an empty item.
          if (v == null || v.findViewById(R.id.empty_item) != null) {
              v = mInflater.inflate(R.layout.time_zone_item, null);
              ViewHolder.setupViewHolder(v);
          }
  
          ViewHolder vh = (ViewHolder) v.getTag();
  
          TimeZoneInfo tzi = mTimeZoneData.get(mFilteredTimeZoneIndices[position]);
          v.setTag(VIEW_TAG_TIME_ZONE, tzi);
  
          vh.timeZone.setText(tzi.mDisplayName);
  
          vh.timeOffset.setText(tzi.getGmtDisplayName(mContext));
  
          String location = tzi.mCountry;
          if (location == null) {
              vh.location.setVisibility(View.INVISIBLE);
          } else {
              vh.location.setText(location);
              vh.location.setVisibility(View.VISIBLE);
          }
  
          return v;
      }
  
      @Override
      public boolean hasStableIds() {
          return true;
      }
  
      // Implements OnItemClickListener
      @Override
      public void onItemClick(AdapterView<?> parent, View v, int position, long id) {
          if (mTimeZoneSetListener != null) {
              TimeZoneInfo tzi = (TimeZoneInfo) v.getTag(VIEW_TAG_TIME_ZONE);
              if (tzi != null) {
                mTimeZoneSetListener.onTimeZoneSet(tzi);
                saveRecentTimezone(tzi.mTzId);
              }
          }
      }
  }
  