/*
 * Copyright (C) 2011 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 android.support.appcompat.view.menu;

import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;

import java.util.ArrayList;

/**
 * Base class for MenuPresenters that have a consistent container view and item
 * views. Behaves similarly to an AdapterView in that existing item views will
 * be reused if possible when items change.
 */
public abstract class BaseMenuPresenter implements MenuPresenter {
  protected Context mSystemContext;
  protected Context mContext;
  protected MenuBuilder mMenu;
  protected LayoutInflater mSystemInflater;
  protected LayoutInflater mInflater;
  private Callback mCallback;

  private int mMenuLayoutRes;
  private int mItemLayoutRes;

  protected MenuView mMenuView;

  private int mId;

  /**
   * Construct a new BaseMenuPresenter.
   *
   * @param context Context for generating system-supplied views
   * @param menuLayoutRes Layout resource ID for the menu container view
   * @param itemLayoutRes Layout resource ID for a single item view
   */
  public BaseMenuPresenter(Context context, int menuLayoutRes, int itemLayoutRes) {
    mSystemContext = context;
    mSystemInflater = LayoutInflater.from(context);
    mMenuLayoutRes = menuLayoutRes;
    mItemLayoutRes = itemLayoutRes;
  }

  @Override
  public void initForMenu(Context context, MenuBuilder menu) {
    mContext = context;
    mInflater = LayoutInflater.from(mContext);
    mMenu = menu;
  }

  public MenuView getMenuView(ViewGroup root) {
    if (mMenuView == null) {
      mMenuView = (MenuView) mSystemInflater.inflate(mMenuLayoutRes, root, false);
      mMenuView.initialize(mMenu);
      updateMenuView(true);
    }

    return mMenuView;
  }

  /**
   * Reuses item views when it can
   */
  public void updateMenuView(boolean cleared) {
    final ViewGroup parent = (ViewGroup) mMenuView;
    if (parent == null) return;

    int childIndex = 0;
    if (mMenu != null) {
      mMenu.flagActionItems();
      ArrayList<MenuItemImpl> visibleItems = mMenu.getVisibleItems();
      final int itemCount = visibleItems.size();
      for (int i = 0; i < itemCount; i++) {
        MenuItemImpl item = visibleItems.get(i);
        if (shouldIncludeItem(childIndex, item)) {
          final View convertView = parent.getChildAt(childIndex);
          final MenuItemImpl oldItem = convertView instanceof MenuView.ItemView ?
              ((MenuView.ItemView) convertView).getItemData() : null;
          final View itemView = getItemView(item, convertView, parent);
          if (item != oldItem) {
            // Don't let old states linger with new data.
            itemView.setPressed(false);
            itemView.jumpDrawablesToCurrentState();
          }
          if (itemView != convertView) {
            addItemView(itemView, childIndex);
          }
          childIndex++;
        }
      }
    }

    // Remove leftover views.
    while (childIndex < parent.getChildCount()) {
      if (!filterLeftoverView(parent, childIndex)) {
        childIndex++;
      }
    }
  }

  /**
   * Add an item view at the given index.
   *
   * @param itemView View to add
   * @param childIndex Index within the parent to insert at
   */
  protected void addItemView(View itemView, int childIndex) {
    final ViewGroup currentParent = (ViewGroup) itemView.getParent();
    if (currentParent != null) {
      currentParent.removeView(itemView);
    }
    ((ViewGroup) mMenuView).addView(itemView, childIndex);
  }

  /**
   * Filter the child view at index and remove it if appropriate.
   * @param parent Parent to filter from
   * @param childIndex Index to filter
   * @return true if the child view at index was removed
   */
  protected boolean filterLeftoverView(ViewGroup parent, int childIndex) {
    parent.removeViewAt(childIndex);
    return true;
  }

  public void setCallback(Callback cb) {
    mCallback = cb;
  }

  /**
   * Create a new item view that can be re-bound to other item data later.
   *
   * @return The new item view
   */
  public MenuView.ItemView createItemView(ViewGroup parent) {
    return (MenuView.ItemView) mSystemInflater.inflate(mItemLayoutRes, parent, false);
  }

  /**
   * Prepare an item view for use. See AdapterView for the basic idea at work here.
   * This may require creating a new item view, but well-behaved implementations will
   * re-use the view passed as convertView if present. The returned view will be populated
   * with data from the item parameter.
   *
   * @param item Item to present
   * @param convertView Existing view to reuse
   * @param parent Intended parent view - use for inflation.
   * @return View that presents the requested menu item
   */
  public View getItemView(MenuItemImpl item, View convertView, ViewGroup parent) {
    MenuView.ItemView itemView;
    if (convertView instanceof MenuView.ItemView) {
      itemView = (MenuView.ItemView) convertView;
    } else {
      itemView = createItemView(parent);
    }
    bindItemView(item, itemView);
    return (View) itemView;
  }

  /**
   * Bind item data to an existing item view.
   *
   * @param item Item to bind
   * @param itemView View to populate with item data
   */
  public abstract void bindItemView(MenuItemImpl item, MenuView.ItemView itemView);

  /**
   * Filter item by child index and item data.
   *
   * @param childIndex Indended presentation index of this item
   * @param item Item to present
   * @return true if this item should be included in this menu presentation; false otherwise
   */
  public boolean shouldIncludeItem(int childIndex, MenuItemImpl item) {
    return true;
  }

  public void onCloseMenu(MenuBuilder menu, boolean allMenusAreClosing) {
    if (mCallback != null) {
      mCallback.onCloseMenu(menu, allMenusAreClosing);
    }
  }

  public boolean onSubMenuSelected(SubMenuBuilder menu) {
    if (mCallback != null) {
      return mCallback.onOpenSubMenu(menu);
    }
    return false;
  }

  public boolean flagActionItems() {
    return false;
  }

  public boolean expandItemActionView(MenuBuilder menu, MenuItemImpl item) {
    return false;
  }

  public boolean collapseItemActionView(MenuBuilder menu, MenuItemImpl item) {
    return false;
  }

  public int getId() {
    return mId;
  }

  public void setId(int id) {
    mId = id;
  }
}

@@ -3296,32 +3296,35 @@
 se);%0A           
+ //
  itemView.jumpDr
@@ -3344,24 +3344,80 @@
 entState();%0A
+            // Animation API: Not available on API %3C 11%0A
           %7D%0A

Remove non-implemented APIs in BaseMenuPresenter