protected View getHeaderView(int position, View convertView, ViewGroup parent) {
    if (mDelegate.getNumHeaders() == 0) {
      return null;
    }

    return mDelegate.getHeaderView(translatePosition(position).mHeader, convertView, parent);
  }
  protected void updateCount() {
    mCount = 0;
    int numHeaders = mDelegate.getNumHeaders();
    if (numHeaders == 0) {
      mCount = mDelegate.getCount();
      mCounted = true;
      return;
    }

    for (int i = 0; i < numHeaders; i++) {
      mCount += mDelegate.getCountForHeader(i) + mNumColumns;
    }
    mCounted = true;
  }
  protected Position translatePosition(int position) {
    int numHeaders = mDelegate.getNumHeaders();
    if (numHeaders == 0) {
      if (position >= mDelegate.getCount()) {
        return new Position(POSITION_FILLER, 0);
      }
      return new Position(position, 0);
    }

    // Translate GridView position to Adapter position.
    int adapterPosition = position;
    int place = position;
    int i;

    for (i = 0; i < numHeaders; i++) {
      int sectionCount = mDelegate.getCountForHeader(i);

      // Skip past fake items making space for header in front of
      // sections.
      if (place == 0) {
        // Position is first column where header will be.
        return new Position(POSITION_HEADER, i);
      }
      place -= mNumColumns;
      if (place < 0) {
        // Position is a fake so return null.
        return new Position(POSITION_HEADER_FILLER, i);
      }
      adapterPosition -= mNumColumns;

      if (place < sectionCount) {
        return new Position(adapterPosition, i);
      }

      // Skip past section end of section row filler;
      int filler = unFilledSpacesInHeaderGroup(i);
      adapterPosition -= filler;
      place -= sectionCount + filler;

      if (place < 0) {
        // Position is a fake so return null.
        return new Position(POSITION_FILLER, i);
      }
    }

    // Position is a fake.
    return new Position(POSITION_FILLER, i);
  }
 public StickyGridHeadersBaseAdapterWrapper(
     Context context, StickyGridHeadersGridView gridView, StickyGridHeadersBaseAdapter delegate) {
   mContext = context;
   mDelegate = delegate;
   mGridView = gridView;
   delegate.registerDataSetObserver(mDataSetObserver);
 }
  /**
   * Counts the number of items that would be need to fill out the last row in the group of items
   * with the given header.
   *
   * @param header Header set of items are grouped by.
   * @return The count of unfilled spaces in the last row.
   */
  private int unFilledSpacesInHeaderGroup(int header) {
    // If mNumColumns is equal to zero we will have a divide by 0 exception
    if (mNumColumns == 0) {
      return 0;
    }

    int remainder = mDelegate.getCountForHeader(header) % mNumColumns;
    return remainder == 0 ? 0 : mNumColumns - remainder;
  }
  @Override
  public boolean isEnabled(int position) {
    Position adapterPosition = translatePosition(position);
    if (adapterPosition.mPosition == POSITION_FILLER
        || adapterPosition.mPosition == POSITION_HEADER) {
      return false;
    }

    return mDelegate.isEnabled(adapterPosition.mPosition);
  }
  /**
   * Get the data item associated with the specified position in the data set.
   *
   * <p>Since this wrapper inserts fake entries to fill out items grouped by header and also spaces
   * to insert headers into some positions will return null.
   *
   * @param position Position of the item whose data we want within the adapter's data set.
   * @return The data at the specified position.
   */
  @Override
  public Object getItem(int position) throws ArrayIndexOutOfBoundsException {
    Position adapterPosition = translatePosition(position);
    if (adapterPosition.mPosition == POSITION_FILLER
        || adapterPosition.mPosition == POSITION_HEADER) {
      // Fake entry in view.
      return null;
    }

    return mDelegate.getItem(adapterPosition.mPosition);
  }
  @Override
  public int getCount() {
    if (mCounted) {
      return mCount;
    }
    mCount = 0;
    int numHeaders = mDelegate.getNumHeaders();
    if (numHeaders == 0) {
      mCount = mDelegate.getCount();
      mCounted = true;
      return mCount;
    }

    for (int i = 0; i < numHeaders; i++) {
      // Pad count with space for header and trailing filler in header
      // group.
      mCount += mDelegate.getCountForHeader(i) + unFilledSpacesInHeaderGroup(i) + mNumColumns;
    }
    mCounted = true;
    return mCount;
  }
 @Override
 public long getItemId(int position) {
   Position adapterPosition = translatePosition(position);
   if (adapterPosition.mPosition == POSITION_HEADER) {
     return ID_HEADER;
   }
   if (adapterPosition.mPosition == POSITION_FILLER) {
     return ID_FILLER;
   }
   if (adapterPosition.mPosition == POSITION_HEADER_FILLER) {
     return ID_HEADER_FILLER;
   }
   return mDelegate.getItemId(adapterPosition.mPosition);
 }
  @Override
  public View getView(int position, View convertView, ViewGroup parent) {
    Position adapterPosition = translatePosition(position);
    if (adapterPosition.mPosition == POSITION_HEADER) {
      HeaderFillerView v = getHeaderFillerView(adapterPosition.mHeader, convertView, parent);
      View view = mDelegate.getHeaderView(adapterPosition.mHeader, (View) v.getTag(), parent);
      mGridView.detachHeader((View) v.getTag());
      v.setTag(view);
      mGridView.attachHeader(view);
      convertView = v;
      mLastHeaderViewSeen = v;
      v.forceLayout();
    } else if (adapterPosition.mPosition == POSITION_HEADER_FILLER) {
      convertView = getFillerView(convertView, parent, mLastHeaderViewSeen);
      convertView.forceLayout();
    } else if (adapterPosition.mPosition == POSITION_FILLER) {
      convertView = getFillerView(convertView, parent, mLastViewSeen);
    } else {
      convertView = mDelegate.getView(adapterPosition.mPosition, convertView, parent);
      mLastViewSeen = convertView;
    }

    return convertView;
  }
 @Override
 public int getItemViewType(int position) {
   Position adapterPosition = translatePosition(position);
   if (adapterPosition.mPosition == POSITION_HEADER) {
     return VIEW_TYPE_HEADER;
   }
   if (adapterPosition.mPosition == POSITION_FILLER) {
     return VIEW_TYPE_FILLER;
   }
   if (adapterPosition.mPosition == POSITION_HEADER_FILLER) {
     return VIEW_TYPE_HEADER_FILLER;
   }
   int itemViewType = mDelegate.getItemViewType(adapterPosition.mPosition);
   if (itemViewType == IGNORE_ITEM_VIEW_TYPE) {
     return itemViewType;
   }
   return itemViewType + sNumViewTypes;
 }
 @Override
 public void unregisterDataSetObserver(DataSetObserver observer) {
   super.unregisterDataSetObserver(observer);
   mDelegate.unregisterDataSetObserver(observer);
 }
 @Override
 public boolean isEmpty() {
   return mDelegate.isEmpty();
 }
 @Override
 public boolean hasStableIds() {
   return mDelegate.hasStableIds();
 }
 @Override
 public int getViewTypeCount() {
   return mDelegate.getViewTypeCount() + sNumViewTypes;
 }