content: /*
   * Created by LuaView.
   * Copyright (c) 2017, Alibaba Group. All rights reserved.
   *
   * This source code is licensed under the MIT.
   * For the full copyright and license information,please view the LICENSE file in the root directory of this source tree.
   */
  
  package com.taobao.luaview.userdata.list;
  
  import android.graphics.Point;
  import android.view.ViewGroup;
  import android.widget.AbsListView;
  
  import com.taobao.luaview.cache.SparseCache;
  import com.taobao.luaview.global.LuaView;
  import com.taobao.luaview.provider.ImageProvider;
  import com.taobao.luaview.userdata.ui.UDViewGroup;
  import com.taobao.luaview.util.AndroidUtil;
  import com.taobao.luaview.util.DimenUtil;
  import com.taobao.luaview.util.LuaUtil;
  
  import org.luaj.vm2.Globals;
  import org.luaj.vm2.LuaValue;
  import org.luaj.vm2.Varargs;
  
  import java.util.HashMap;
  import java.util.concurrent.atomic.AtomicBoolean;
  
  /**
   * UDBaseListView or RecyclerView
   *
   * @author song
   * @date 15/10/23
   */
  public abstract class UDBaseListOrRecyclerView<T extends ViewGroup> extends UDViewGroup<T> {
      //初始化数据
      private LuaValue mSectionDelegate;
      protected LuaValue mCellDelegate;
  
      //view type map
      private AtomicBoolean isSectionLengthInit = new AtomicBoolean(false);
      private Point[] mSectionLength;//长度数组，每个point的x为开始位置(包含)，y为结束位置(不包含)，(y-x)为该组长度
      protected HashMap<String, Integer> mViewTypeMap = new HashMap<String, Integer>();//view类型集合，从0开始，不能放到init中初始化
      protected HashMap<Integer, String> mViewTypeNameMap = new HashMap<Integer, String>();//View类型名称集合，不能放到init中初始化
  
      //id
      protected SparseCache<String> mIdCache;
  
      //延迟加载
      protected boolean mLazyLoad = true;
  
      public UDBaseListOrRecyclerView(T view, Globals globals, LuaValue metaTable, Varargs initParams) {
          super(view, globals, metaTable, initParams);
          init();
      }
  
      /**
       * 初始化数据
       */
      public void init() {
          if (this.initParams != null) {
              this.mIdCache = new SparseCache<String>();
  
              this.mSectionDelegate = LuaUtil.getValue(initParams, "Section");
              this.mCellDelegate = LuaUtil.getValue(initParams, "Cell");
              this.mCallback = LuaUtil.getValue(initParams, "Callback");
              initSectionLength();
          }
      }
  
      /**
       * 初始化section的长度
       */
      private void initSectionLength() {
          isSectionLengthInit.set(false);
          final int numOfSections = getSectionCount();
          if (numOfSections > 0) {
              mSectionLength = new Point[numOfSections];
              int left = 0, right = 0;
              for (int i = 0; i < numOfSections; i++) {
                  left = right;
                  right = right + getRowCount(i);
                  mSectionLength[i] = new Point(left, right);
              }
          }
          isSectionLengthInit.set(true);
      }
  
      //-----------------------------------------section----------------------------------------------
  
      /**
       * 获取新的总数跟老的总数差别
       *
       * @return
       */
      public int getDiffTotalCount() {
          int oldCount = (isSectionLengthInit.get() && mSectionLength != null) ? mSectionLength[mSectionLength.length - 1].y : 0;
          int newCount = getRawTotalCount();
          return newCount - oldCount;
      }
  
      /**
       * 获取总的个数
       *
       * @return
       */
      public int getTotalCount() {
          if (isSectionLengthInit.get()) {
              return mSectionLength != null ? mSectionLength[mSectionLength.length - 1].y : 0;
          } else {
              final int totalSections = getSectionCount();
              int totalCount = 0;
              for (int i = 0; i < totalSections; i++) {
                  totalCount += getRowCount(i);
              }
              return totalCount;
          }
      }
  
      /**
       * 获取原始总个数
       *
       * @return
       */
      protected int getRawTotalCount() {
          final int totalSections = getRawSectionCount();
          int totalCount = 0;
          for (int i = 0; i < totalSections; i++) {
              totalCount += getRawRowCount(i);
          }
          return totalCount;
      }
  
      /**
       * 返回新count 跟 老count的差距
       *
       * @return
       */
      protected int getDiffSectionCount() {
          int oldCount = (isSectionLengthInit.get() && mSectionLength != null) ? mSectionLength.length : 0;
          int newCount = getRawSectionCount();
          return newCount - oldCount;
      }
  
      /**
       * 分区个数，android的totalCount=分区个数*每个分区的数目
       *
       * @return
       */
      protected int getSectionCount() {
          if (isSectionLengthInit.get()) {
              return mSectionLength != null ? mSectionLength.length : 0;
          } else {
              return getRawSectionCount();
          }
      }
  
      /**
       * 获取原始的SectionCount
       *
       * @return
       */
      protected int getRawSectionCount() {
          if (this.mSectionDelegate == null) {
              return 0;
          }
  
          return LuaUtil.getOrCallFunction(this.mSectionDelegate.get("SectionCount")).optint(1);
      }
  
      /**
       * 获取diff of new RowCount and old RowCount of Section
       *
       * @param section
       * @return
       */
      protected int diffRowCount(int section) {
          int oldCount = (isSectionLengthInit.get() && mSectionLength != null) ? (this.mSectionLength[section].y - this.mSectionLength[section].x) : 0;
          int newCount = getRawRowCount(section);
          return newCount - oldCount;
      }
  
      /**
       * 每个分区的行数，section从0开始
       *
       * @param section
       * @return
       */
      protected int getRowCount(int section) {
          if (isSectionLengthInit.get()) {
              return mSectionLength != null ? (this.mSectionLength[section].y - this.mSectionLength[section].x) : 0;
          } else {
              return getRawRowCount(section);
          }
      }
  
      /**
       * 读取RowCount，获取原始count
       *
       * @param section
       * @return
       */
      protected int getRawRowCount(int section) {
          return LuaUtil.callFunction(this.mSectionDelegate.get("RowCount"), LuaUtil.toLuaInt(section)).optint(0);
      }
      //------------------------------------------cell------------------------------------------------
  
      /**
       * get position by section and rowInSection
       *
       * @param section
       * @param rowInSection
       * @return
       */
      protected int getPositionBySectionAndRow(int section, int rowInSection) {
          if (mSectionLength != null) {
              if (section >= 0 && section < mSectionLength.length) {
                  return mSectionLength[section].x + rowInSection;
              } else {
                  return 0;
              }
          }
          return rowInSection;
      }
  
      /**
       * 根据position来判断该位置属于哪个position
       *
       * @param position
       * @return
       */
      protected int getSectionByPosition(int position) {
          if (mSectionLength != null) {
              for (int i = 0; i < mSectionLength.length; i++) {
                  if (position >= mSectionLength[i].x && position < mSectionLength[i].y) {
                      return i;
                  }
              }
          }
          return 0;
      }
  
      /**
       * 根据position来判断该位置位于section的第几个位置
       *
       * @param position
       * @return
       */
      protected int getRowInSectionByPosition(int position) {
          if (mSectionLength != null) {
              final int section = getSectionByPosition(position);
              return position - mSectionLength[section].x;
          } else {
              return 0;
          }
      }
  
      /**
       * 根据position获取某个cell的类型
       *
       * @param position
       * @return
       */
      public String getId(int position) {
          return getId(position, getSectionByPosition(position), getRowInSectionByPosition(position));
      }
  
      /**
       * 根据section, row获取cell的Id
       *
       * @param position
       * @param section
       * @param row
       * @return
       */
      protected String getId(int position, int section, int row) {
          final String cacheId = mIdCache != null ? mIdCache.get(position) : null;
          if (cacheId != null) {
              return cacheId;
          } else {
              final String id = LuaUtil.callFunction(mCellDelegate.get("Id"), LuaUtil.toLuaInt(section), LuaUtil.toLuaInt(row)).optjstring("");
              if (mIdCache != null) {
                  mIdCache.put(position, id);
              }
              return id;
          }
      }
  
  
      /**
       * 根据id获取某个cell
       *
       * @param id
       * @return
       */
      public LuaValue getCell(String id) {
          return mCellDelegate.get(id);
      }
  
  
      /**
       * 是否有size的定义
       *
       * @param position
       * @return
       */
      public boolean hasCellSize(int position) {
          return hasCellFunction(position, "Size");
      }
  
      /**
       * return width, height
       *
       * @param cell
       * @param position
       * @return
       */
      public int[] callCellSize(LuaValue cell, int position, int... defaultSize) {
          final Varargs size = invokeCellSize(cell, position);
          int defaultWidth = (defaultSize != null && defaultSize.length > 1) ? defaultSize[0] : AndroidUtil.getScreenWidth(getContext());
          int width = 0, height = 0;
          if (size != null) {
              if (size.narg() > 1) {//width & height
                  width = DimenUtil.dpiToPx(size.arg(1), defaultWidth);
                  height = DimenUtil.dpiToPx(size.arg(2));
              } else {
                  width = defaultWidth;
                  height = DimenUtil.dpiToPx(size.arg(1));
              }
          }
          return new int[]{width, height};
      }
  
      /**
       * 调用 Size 方法 （返回多个值)
       *
       * @param cell
       * @param position
       * @return
       */
      public Varargs invokeCellSize(LuaValue cell, int position) {
  //        return invokeCellFunction("Size", cell, position);
          return invokeCellFunction("Size", position);//不带cell
      }
  
      /**
       * 调用 Init 方法
       *
       * @param cell
       * @param position
       * @return
       */
      public LuaValue callCellInit(LuaValue cell, int position) {
          return callCellFunction("Init", cell, position);//Lua从1开始
      }
  
      /**
       * 调用 Layout 方法
       *
       * @param cell
       * @param position
       * @return
       */
      public LuaValue callCellLayout(LuaValue cell, int position) {
          return callCellFunction("Layout", cell, position);
      }
  
      /**
       * 调用 Callback 方法
       *
       * @param cell
       * @param position
       * @return
       */
      public LuaValue onCellClicked(LuaValue cell, int position) {
          final int section = getSectionByPosition(position);
          final int row = getRowInSectionByPosition(position);
          final String id = getId(position, section, row);
          final LuaValue cellData = getCell(id);
          if (cellData != null) {
              final LuaValue callback = cellData.get("Callback");
              if (callback.isfunction()) {
                  return LuaUtil.callFunction(callback, cell, LuaUtil.toLuaInt(section), LuaUtil.toLuaInt(row));
              } else if (callback.istable()) {
                  return LuaUtil.callFunction(LuaUtil.getFunction(callback, "Click", "click"), cell, LuaUtil.toLuaInt(section), LuaUtil.toLuaInt(row));
              }
          }
          return NIL;
      }
  
      /**
       * 调用 Callback 方法
       *
       * @param cell
       * @param position
       * @return
       */
      public boolean onCellLongClicked(LuaValue cell, int position) {
          final int section = getSectionByPosition(position);
          final int row = getRowInSectionByPosition(position);
          final String id = getId(position, section, row);
          final LuaValue cellData = getCell(id);
          if (cellData != null) {
              final LuaValue callback = cellData.get("Callback");
              if (callback != null && callback.istable()) {
                  return LuaUtil.callFunction(LuaUtil.getFunction(callback, "LongClick", "longClick"), cell, LuaUtil.toLuaInt(section), LuaUtil.toLuaInt(row)).optboolean(false);
              }
          }
          return false;
      }
  
      /**
       * 调用cell的某个方法
       *
       * @param method
       * @param cell
       * @param position
       * @return
       */
      private LuaValue callCellFunction(String method, LuaValue cell, int position) {
          final int section = getSectionByPosition(position);
          final int row = getRowInSectionByPosition(position);
          return callCellFunction(getId(position, section, row), method, cell, section, row);
      }
  
      /**
       * 调用cell的某个方法，返回多个值
       *
       * @param method
       * @param cell
       * @param position
       * @return
       */
      private Varargs invokeCellFunction(String method, LuaValue cell, int position) {
          final int section = getSectionByPosition(position);
          final int row = getRowInSectionByPosition(position);
          return invokeCellFunction(getId(position, section, row), method, cell, section, row);
      }
  
      /**
       * 调用cell的某个方法，返回多个值
       *
       * @param method
       * @param position
       * @return
       */
      private Varargs invokeCellFunction(String method, int position) {
          final int section = getSectionByPosition(position);
          final int row = getRowInSectionByPosition(position);
          return invokeCellFunction(getId(position, section, row), method, section, row);
      }
  
      /**
       * 调用cell的某个方法
       *
       * @param id
       * @param method
       * @param cell
       * @param section
       * @param row
       * @return
       */
      private LuaValue callCellFunction(String id, String method, LuaValue cell, int section, int row) {
          final LuaValue methodData = getCell(id);
          if (!methodData.isnil()) {
              return LuaUtil.callFunction(methodData.get(method), cell, LuaUtil.toLuaInt(section), LuaUtil.toLuaInt(row));
          }
          return NIL;
      }
  
      /**
       * 调用cell的某个方法 (返回多个值)
       *
       * @param id
       * @param method
       * @param cell
       * @param section
       * @param row
       * @return
       */
      private Varargs invokeCellFunction(String id, String method, LuaValue cell, int section, int row) {
          final LuaValue methodData = getCell(id);
          if (!methodData.isnil()) {
              return LuaUtil.invokeFunction(methodData.get(method), cell, LuaUtil.toLuaInt(section), LuaUtil.toLuaInt(row));
          }
          return NIL;
      }
  
      /**
       * 调用cell的某个方法 (返回多个值)
       *
       * @param id
       * @param method
       * @param section
       * @param row
       * @return
       */
      private Varargs invokeCellFunction(String id, String method, int section, int row) {
          final LuaValue methodData = getCell(id);
          if (!methodData.isnil()) {
              return LuaUtil.invokeFunction(methodData.get(method), LuaUtil.toLuaInt(section), LuaUtil.toLuaInt(row));
          }
          return NIL;
      }
  
      /**
       * 是否有某个函数
       *
       * @param method
       * @param position
       * @return
       */
      private boolean hasCellFunction(int position, String method) {
          final int section = getSectionByPosition(position);
          final int row = getRowInSectionByPosition(position);
          final String id = getId(position, section, row);
          return hasCellFunction(id, method);
      }
  
      /**
       * 是否有某个函数
       *
       * @param cellId
       * @param method
       * @return
       */
      public boolean hasCellFunction(String cellId, String method) {
          final LuaValue methodData = getCell(cellId);
          return !methodData.isnil() && methodData.get(method) != null && methodData.get(method).isfunction();
      }
  
      /**
       * 获取key map
       *
       * @return
       */
      public HashMap<String, Integer> getCellKeyMap() {
          HashMap<String, Integer> result = new HashMap<String, Integer>();
          if (mCellDelegate != null) {
              LuaValue[] keys = this.mCellDelegate.checktable().keys();
              if (keys != null) {
                  for (int i = 0; i < keys.length; i++) {
                      result.put(keys[i].toString(), i);
                  }
              }
          }
          return result;
      }
  
      /**
       * 根据位置获取 item 的type id
       *
       * @param position
       * @return
       */
      public int getItemViewType(int position) {
          final String viewTypeName = getId(position);//得到坑位类型名称
          if (this.mViewTypeMap != null) {
              if (!this.mViewTypeMap.containsKey(viewTypeName)) {
                  final int index = this.mViewTypeMap.size();
                  this.mViewTypeMap.put(viewTypeName, index);
                  this.mViewTypeNameMap.put(index, viewTypeName);
                  return index;
              }
              return this.mViewTypeMap.get(viewTypeName);
          }
          return 0;
      }
  
      /**
       * 获取ViewType的name
       *
       * @param viewType
       * @return
       */
      public String getItemViewTypeName(int viewType) {
          if (this.mViewTypeNameMap != null) {
              return this.mViewTypeNameMap.get(viewType);
          }
          return null;
      }
  
      /**
       * 这里不是真实的viewType的数字，只是获取Cell中的属性数目（该属性数目一定比cell种数多)
       * TODO 这里通过读取ID的方式获取所有的count
       *
       * @return
       */
      public int getViewTypeCount() {
          return getCellKeyMap().size();
      }
  
  
      public UDBaseListOrRecyclerView setLazyLoad(boolean mLazyLoad) {
          this.mLazyLoad = mLazyLoad;
          return this;
      }
  
      //-----------------------------------------lazy load--------------------------------------------
  
      /**
       * 更新所有子view的ScrollState，用于延迟加载
       *
       * @param view
       * @param scrollState
       */
      protected void updateAllChildScrollState(ViewGroup view, int scrollState) {
          if (this.mLazyLoad && view != null) {
              if (scrollState >= AbsListView.OnScrollListener.SCROLL_STATE_FLING) {//手滑动的时候
                  final ImageProvider provider = LuaView.getImageProvider();
                  if (provider != null) {
                      provider.pauseRequests(view, getContext());
                  }
              } else {
                  final ImageProvider provider = LuaView.getImageProvider();
                  if (provider != null) {
                      provider.resumeRequests(view, getContext());
                  }
              }
          }
      }
  
      //------------------------------------------Scroll----------------------------------------------
  
      /**
       * 初始化滚动回调
       */
      public abstract void initOnScrollCallback(final T view);
  
      //------------------------------------------功能------------------------------------------------
  
      /**
       * 重新加载
       *
       * @return
       */
      public abstract UDBaseListOrRecyclerView reload(Integer section, Integer row);
  
      /**
       * listview滚动到顶部
       *
       * @param animate 是否动画
       * @return
       */
      public abstract UDBaseListOrRecyclerView scrollToTop(final int offset, final boolean animate);
  
      /**
       * listview滚动到某个位置
       *
       * @param section
       * @param rowInSection
       * @param offset
       * @return
       */
      public abstract UDBaseListOrRecyclerView scrollToItem(final int section, final int rowInSection, final int offset, final boolean animate);
  
  
      /**
       * 设置item最小间隔
       *
       * @param spacing
       * @return
       */
      public abstract UDBaseListOrRecyclerView setMiniSpacing(final int spacing);
  
      /**
       * 获取item最小间隔
       *
       * @return
       */
      public abstract int getMiniSpacing();
  }