content: /*
   * MIT License
   *
   * Copyright (c) 2016 Alibaba Group
   *
   * Permission is hereby granted, free of charge, to any person obtaining a copy
   * of this software and associated documentation files (the "Software"), to deal
   * in the Software without restriction, including without limitation the rights
   * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
   * copies of the Software, and to permit persons to whom the Software is
   * furnished to do so, subject to the following conditions:
   *
   * The above copyright notice and this permission notice shall be included in all
   * copies or substantial portions of the Software.
   *
   * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
   * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
   * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
   * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
   * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
   * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
   * SOFTWARE.
   */
  
  package com.alibaba.android.vlayout;
  
  import android.graphics.Rect;
  import android.os.Bundle;
  import android.support.annotation.NonNull;
  import android.support.annotation.Nullable;
  import android.support.v7.widget.RecyclerView;
  import android.view.View;
  
  import com.alibaba.android.vlayout.layout.LayoutChunkResult;
  
  import java.util.LinkedList;
  import java.util.List;
  
  import static com.alibaba.android.vlayout.VirtualLayoutManager.LayoutStateWrapper;
  
  /**
   * Helper class to handle different layouts in {@link VirtualLayoutManager}
   *
   * @author villadora
   * @date 2015-8-14
   * @since 1.0.0
   */
  
  public abstract class LayoutHelper {
  
      public static final Range<Integer> RANGE_ALL = Range.create(Integer.MIN_VALUE, Integer.MAX_VALUE);
      public static final Range<Integer> RANGE_EMPTY = Range.create(-1, -1);
  
      /**
       * Range for this layoutHelper, intialize with EMPTY
       */
      @NonNull
      Range<Integer> mRange = RANGE_EMPTY;
  
      int mZIndex = 0;
  
  
      /**
       * Is the position should be handle by this {@link LayoutHelper}
       *
       * @param position position without offset, which is the true index in {@link VirtualLayoutManager}
       * @return true if position in range returned by {@link #getRange()}
       */
      public boolean isOutOfRange(int position) {
          return !mRange.contains(position);
      }
  
  
      /**
       * Set range of items, which will be handled by this layoutHelper
       * start position must be greater than end position, otherwise {@link IllegalArgumentException}
       * will be thrown
       *
       * @param start start position of items handled by this layoutHelper
       * @param end   end position of items handled by this layoutHelper, if end < start, it will throw {@link IllegalArgumentException}
       * @throws MismatchChildCountException when the (start - end) doesn't equal to itemCount
       */
      public void setRange(int start, int end) {
          if (end < start) {
              throw new IllegalArgumentException("end should be larger or equeal then start position");
          }
  
          if (start == -1 && end == -1) {
              this.mRange = RANGE_EMPTY;
              onRangeChange(start, end);
              return;
          }
  
          if ((end - start + 1) != getItemCount()) {
              throw new MismatchChildCountException("ItemCount mismatch when range: " + mRange.toString() + " childCount: " + getItemCount());
          }
  
          if (start == mRange.getUpper() && end == mRange.getLower()) {
              // no change
              return;
          }
  
          this.mRange = Range.create(start, end);
          onRangeChange(start, end);
      }
  
      /**
       * This method will be called when range changes
       *
       * @param start start position of items handled by this layoutHelper
       * @param end   end position of items handled by this layoutHelper, if end < start, it will throw {@link IllegalArgumentException}
       */
      public void onRangeChange(final int start, final int end) {
  
      }
  
      /**
       * Return current range
       *
       * @return Range of integer
       */
      @NonNull
      public final Range<Integer> getRange() {
          return mRange;
      }
  
  
      /**
       * Given a chance to check and change the chosen anchorInfo
       *
       * @param state      current {@link }RecyclerView} 's state
       * @param anchorInfo the chosen anchorInfo
       * @param helper
       */
      public void checkAnchorInfo(RecyclerView.State state, VirtualLayoutManager.AnchorInfoWrapper anchorInfo, LayoutManagerHelper helper) {
  
      }
  
      /**
       * This method is called when scroll state is changed
       *
       * @param state         The new scroll state for RecyclerView
       * @param startPosition
       * @param endPosition
       */
      public void onScrollStateChanged(int state, int startPosition, int endPosition, LayoutManagerHelper helper) {
  
      }
  
  
      /**
       * Offset all child views attached to the parent RecyclerView by dx pixels along
       * the horizontal axis.
       *
       * @param dx Pixels to offset by
       */
      public void onOffsetChildrenHorizontal(int dx, LayoutManagerHelper helper) {
  
      }
  
      /**
       * Offset all child views attached to the parent RecyclerView by dy pixels along
       * the vertical axis.
       *
       * @param dy Pixels to offset by
       */
      public void onOffsetChildrenVertical(int dy, LayoutManagerHelper helper) {
  
      }
  
      /**
       * Get zIndex of this {@link LayoutHelper}
       *
       * @return zIndex of current layoutHelper
       */
      public int getZIndex() {
          return mZIndex;
      }
  
      /**
       * Experimental attribute, set zIndex of this {@link LayoutHelper}，it does not mean the z-index of view. It just reorder the layoutHelpers in linear flow.
       * Do not use it currently.
       * @param zIndex
       */
      public void setZIndex(int zIndex) {
          this.mZIndex = zIndex;
      }
  
      /**
       * Get View that fixed in some position
       *
       * @return
       */
      @Nullable
      public View getFixedView() {
          return null;
      }
  
  
      @NonNull
      protected final List<View> mOffFlowViews = new LinkedList<>();
  
      /**
       * Get Views that out of normal flow layout
       *
       * @return list of views
       */
      @NonNull
      public List<View> getOffFlowViews() {
          return mOffFlowViews;
      }
  
      /**
       * Tell LayoutManager whether the child can be recycled, the recycleChild range is (startIndex, endIndex)
       *
       * @param childPos   recycled child index
       * @param startIndex start index of child will be recycled
       * @param endIndex   end index of child will be recycled
       * @param helper     a helper of type {@link LayoutManagerHelper}
       * @param fromStart  whether is recycleChildren from start
       * @return whether the child in <code>childPos</code> can be recycled
       */
      public boolean isRecyclable(int childPos, int startIndex, int endIndex, LayoutManagerHelper helper, boolean fromStart) {
          return true;
      }
  
      /**
       * Return children count
       *
       * @return the number of children
       */
      public abstract int getItemCount();
  
      /**
       * Set items' count
       *
       * @param itemCount how many children in this layoutHelper
       */
      public abstract void setItemCount(int itemCount);
  
      public abstract void doLayout(RecyclerView.Recycler recycler, RecyclerView.State state,
                                    LayoutStateWrapper layoutState, LayoutChunkResult result,
                                    LayoutManagerHelper helper);
  
      public void onRefreshLayout(RecyclerView.State state, VirtualLayoutManager.AnchorInfoWrapper anchorInfo, LayoutManagerHelper helper) {
  
      }
  
      /**
       * Called before <code>doLayout</code>
       *
       * @param recycler recycler
       * @param state    RecyclerView's State
       * @param helper   LayoutManagerHelper to handle views
       */
      public abstract void beforeLayout(RecyclerView.Recycler recycler, RecyclerView.State state,
                                        LayoutManagerHelper helper);
  
      /**
       * Called after <code>doLayout</code>
       *
       * @param recycler      recycler
       * @param state         RecyclerView's State
       * @param startPosition firstVisiblePosition in {@link RecyclerView}
       * @param endPosition   lastVisiblePosition in {@link RecyclerView}
       * @param scrolled      how many offset scrolled if layout is happened in a scrolling process
       * @param helper        LayoutManagerHelper
       */
      public abstract void afterLayout(RecyclerView.Recycler recycler, RecyclerView.State state,
                                       int startPosition, int endPosition, int scrolled,
                                       LayoutManagerHelper helper);
  
      /**
       * Run to adjust layoutHelper's background area
       * @param startPosition
       * @param endPosition
       * @param helper
       */
      public abstract void adjustLayout(int startPosition, int endPosition, LayoutManagerHelper helper);
  
      public void onItemsChanged(LayoutManagerHelper helper) {
  
      }
  
      /**
       * Called when this layoutHelper will be removed from LayoutManager, please release views and other resources here
       *
       * @param helper LayoutManagerHelper
       */
      public abstract void clear(LayoutManagerHelper helper);
  
      /**
       * Whether a background layoutView is required
       *
       * @return true if require a layoutView
       */
      public abstract boolean requireLayoutView();
  
      /**
       * Bind properties to <code>layoutView</code>
       *
       * @param layoutView generated layoutView as backgroundView
       */
      public abstract void bindLayoutView(View layoutView);
  
      public abstract boolean isFixLayout();
  
      /**
       * Get margins between layout when layout child at <code>offset</code>
       * Or compute offset for align line during scrolling
       *
       * @param offset      anchor child's offset in current layoutHelper, for example, 0 means first item
       * @param isLayoutEnd is the layout process will do to end or start, true means it will lay views from start to end
       * @param useAnchor   whether offset is computed for scrolling or for anchor reset
       * @param helper      view layout helper
       * @return extra offset must be calculated in {@link VirtualLayoutManager}
       */
      public abstract int computeAlignOffset(int offset, boolean isLayoutEnd, boolean useAnchor,
          LayoutManagerHelper helper);
  
      public abstract int computeMarginStart(int offset, boolean isLayoutEnd, boolean useAnchor,
          LayoutManagerHelper helper);
  
      public abstract int computeMarginEnd(int offset, boolean isLayoutEnd, boolean useAnchor,
          LayoutManagerHelper helper);
  
      public abstract int computePaddingStart(int offset, boolean isLayoutEnd, boolean useAnchor,
          LayoutManagerHelper helper);
  
      public abstract int computePaddingEnd(int offset, boolean isLayoutEnd, boolean useAnchor,
          LayoutManagerHelper helper);
  
      public void onSaveState(final Bundle bundle) {
  
      }
  
      public void onRestoreInstanceState(final Bundle bundle) {
  
      }
  
  }
  