content: /**
   * Licensed to the Apache Software Foundation (ASF) under one
   * or more contributor license agreements.  See the NOTICE file
   * distributed with this work for additional information
   * regarding copyright ownership.  The ASF licenses this file
   * to you 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 org.apache.weex.ui.component.binding;
  
  import android.os.Looper;
  import android.support.v4.util.ArrayMap;
  import android.text.TextUtils;
  
  import com.alibaba.fastjson.JSONArray;
  import com.alibaba.fastjson.JSONObject;
  import org.apache.weex.WXEnvironment;
  import org.apache.weex.bridge.EventResult;
  import org.apache.weex.bridge.WXBridgeManager;
  import org.apache.weex.common.Constants;
  import org.apache.weex.dom.WXAttr;
  import org.apache.weex.dom.WXEvent;
  import org.apache.weex.dom.WXStyle;
  import org.apache.weex.dom.binding.ELUtils;
  import org.apache.weex.dom.binding.JSONUtils;
  import org.apache.weex.dom.binding.WXStatement;
  import org.apache.weex.el.parse.ArrayStack;
  import org.apache.weex.el.parse.Operators;
  import org.apache.weex.el.parse.Token;
  import org.apache.weex.ui.action.BasicComponentData;
  import org.apache.weex.ui.action.GraphicPosition;
  import org.apache.weex.ui.action.GraphicSize;
  import org.apache.weex.ui.component.WXComponent;
  import org.apache.weex.ui.component.WXComponentFactory;
  import org.apache.weex.ui.component.WXImage;
  import org.apache.weex.ui.component.WXVContainer;
  import org.apache.weex.ui.component.list.WXCell;
  import org.apache.weex.ui.component.list.template.CellDataManager;
  import org.apache.weex.ui.component.list.template.CellRenderContext;
  import org.apache.weex.ui.component.list.template.TemplateDom;
  import org.apache.weex.ui.component.list.template.VirtualComponentLifecycle;
  import org.apache.weex.ui.component.list.template.WXRecyclerTemplateList;
  import org.apache.weex.ui.component.list.template.jni.NativeRenderObjectUtils;
  import org.apache.weex.utils.WXLogUtils;
  import org.apache.weex.utils.WXUtils;
  
  import java.util.ArrayList;
  import java.util.Collection;
  import java.util.HashMap;
  import java.util.Iterator;
  import java.util.List;
  import java.util.Map;
  import java.util.Set;
  
  /**
   * Created by jianbai.gbj on 2017/8/17.
   * simple statement execute, render component for template list
   */
  public class Statements {
  
  
      /**
       * parse statements token from attrs and style and event
       * */
      public static void  parseStatementsToken(WXComponent component){
          if(component.getBasicComponentData().isRenderPtrEmpty()){
             component.getBasicComponentData().setRenderObjectPr(component.getRenderObjectPtr());
          }
          if(component.getBasicComponentData() != null){
              BasicComponentData basicComponentData =  component.getBasicComponentData();
              basicComponentData.getAttrs().parseStatements();
              basicComponentData.getStyles().parseStatements();
              basicComponentData.getEvents().parseStatements();
          }
          if(component instanceof WXVContainer){
              WXVContainer container = (WXVContainer) component;
              int count = container.getChildCount();
              for (int i = 0; i < count; ++i) {
                  parseStatementsToken(container.getChild(i));
              }
          }
      }
  
  
  
      /**
       * init component  if component is lazy,
       * if component is not lazy, do nothing
       * */
      public static void initLazyComponent(WXComponent component, WXVContainer mParent){
          if(component.isLazy() || component.getHostView() == null){
              component.lazy(false);
              if(mParent != null){
                  int index = mParent.indexOf(component);
                  mParent.createChildViewAt(index);
              }else {
                  component.createView();
              }
              component.applyLayoutAndEvent(component);
              component.bindData(component);
          }
      }
  
  
  
      /**
       * recursive copy component, none parent connect
       * */
      public static WXComponent copyComponentTree(WXComponent component){
          WXComponent copy =  copyComponentTree(component, component.getParent());
          return copy;
      }
  
      /**
       * recursive copy component,
       * */
      private static final WXComponent copyComponentTree(WXComponent source, WXVContainer parent){
          BasicComponentData basicComponentData = null;
          try {
              basicComponentData = source.getBasicComponentData().clone();
          } catch (CloneNotSupportedException e) {
              e.printStackTrace();
          }
          WXComponent component = WXComponentFactory
              .newInstance(source.getInstance(), parent, basicComponentData);
          GraphicPosition graphicPosition = source.getLayoutPosition();
          GraphicSize graphicSize = source.getLayoutSize();
          component.updateDemission(graphicPosition.getTop(), graphicPosition.getBottom(), graphicPosition.getLeft(), graphicPosition.getRight(),
                   graphicSize.getHeight(), graphicSize.getWidth());
          component.updateExtra(source.getExtra());
          if(source instanceof WXVContainer){
              WXVContainer container = (WXVContainer) source;
              WXVContainer childParent = (WXVContainer) component;
              int count = container.getChildCount();
              for (int i = 0; i < count; ++i) {
                  WXComponent sourceChild = container.getChild(i);
                  if (sourceChild != null) {
                      WXComponent targetChild = copyComponentTree(sourceChild,  childParent);childParent.addChild(targetChild);
                      NativeRenderObjectUtils.nativeAddChildRenderObject(childParent.getRenderObjectPtr(),
                              targetChild.getRenderObjectPtr());
                  }
              }
          }
          //copy info need be sync
          if(source.isWaste()){
              component.setWaste(true);
          }
          return  component;
      }
  
      /**
       *  @param component component with v-for statement, v-if statement and bind attrs
       *  @param stack  execute context
       *  render component in context, the function do the following  work.
       *  execute component's v-for statement, v-if statement in context,
       *  and rebuild component's tree with the statement, v-for reuse component execute by pre render.
       *  if executed, component will be removed, don't remove, just mark it waste;
       *  may be next render it can be used.
       *  after statement has executed, render component's binding attrs in context and bind it to component.
       * */
      public static final List<WXComponent> doRender(WXComponent component, CellRenderContext stack){
          List<WXComponent> updates = new ArrayList<>(4);
          try{
              doRenderComponent(component, stack, updates);
          }catch (Exception e){
              WXLogUtils.e("WeexStatementRender", e);
          }
          return updates;
      }
  
      public static final void doInitCompontent(List<WXComponent> updates) {
          if(updates == null || updates.size() == 0){
              return;
          }
          for(WXComponent renderNode : updates){
              if(renderNode.getParent() == null){
                  throw new IllegalArgumentException("render node parent cann't find");
              }
              WXVContainer parent = renderNode.getParent();
              int renderIndex = parent.indexOf(renderNode);
              if(renderIndex < 0){
                  throw new IllegalArgumentException("render node cann't find");
              }
              parent.createChildViewAt(renderIndex);
              renderNode.applyLayoutAndEvent(renderNode);
              renderNode.bindData(renderNode);
          }
      }
  
          /**
           *  @param component component with v-for statement, v-if statement and bind attrs
           *  @param context   execute context
           *  render component in context, the function do the following  work.
           *  execute component's v-for statement, v-if statement in context,
           *  and rebuild component's tree with the statement, v-for reuse component execute by pre render.
           *  if executed, component will be removed, don't remove, just mark it waste;
           *  may be next render it can be used.
           *  after statement has executed, render component's binding attrs in context and bind it to component.
           * */
      private static final int doRenderComponent(WXComponent component, CellRenderContext context,
                                                 List<WXComponent> updates){
          WXVContainer parent = component.getParent();
          WXAttr attrs = component.getAttrs();
          WXStatement statement =  attrs.getStatement();
          if(statement != null){
              Token vif =  null;
              JSONObject vfor = null;
              if(statement.get(WXStatement.WX_IF) instanceof Token){
                  vif = (Token) statement.get(WXStatement.WX_IF);
              }
              if(statement.get(WXStatement.WX_FOR) instanceof  JSONObject){
                  vfor = (JSONObject) statement.get(WXStatement.WX_FOR);
              }
              // execute v-for content
              if(vfor != null){
                  int    renderIndex = parent.indexOf(component);
                  if(vfor.get(WXStatement.WX_FOR_LIST) instanceof Token){
                      Token listBlock = (Token) vfor.get(WXStatement.WX_FOR_LIST);
                      String indexKey = vfor.getString(WXStatement.WX_FOR_INDEX);
                      String itemKey = vfor.getString(WXStatement.WX_FOR_ITEM);
                      Object data = null;
                      if(listBlock != null) {
                          data = listBlock.execute(context.stack);
                      }
                      if((data instanceof List || data instanceof  Map)){
  
                          Collection collection = null;
                          Map  map = null;
                          if(data instanceof  List){
                              collection = (List)data;
                          }else{
                              map = (Map)data;
                              collection = map.keySet();
                          }
                          Map<String, Object> loop = new HashMap<>();
                          int index = 0;
                          for(Object item : collection){
                              Object key = null;
                              Object value = item;
                              if(map == null){
                                  key = index;
                                  value = item;
                                  index ++;
                              }else{
                                  key = item;
                                  value = map.get(item);
                              }
                              if(indexKey != null){
                                  loop.put(indexKey, key);
                              }
  
                              if(itemKey != null){
                                  loop.put(itemKey, value);
                              }else{
                                  context.stack.push(value);
                              }
                              if(loop.size() > 0){
                                  context.stack.push(loop);
                              }
  
  
                              if(vif != null){
                                  if(!Operators.isTrue(vif.execute(context.stack))){
                                      continue;
                                  }
                              }
                              //find resuable renderNode
                              WXComponent renderNode = null;
                              if(renderIndex < parent.getChildCount()){
                                  renderNode = parent.getChild(renderIndex);
                                  //check is same statment, if true, it is usabled.
                                  if(!isCreateFromNodeStatement(renderNode, component)){
                                      renderNode = null;
                                  }
                                  if(renderNode != null){
                                      if(renderNode.isWaste()){
                                          renderNode.setWaste(false);
                                      }
                                  }
                              }
                              //none resuable render node, create node, add to parent, but clear node's statement
                              if(renderNode == null){
                                  long start = System.currentTimeMillis();
                                  renderNode = copyComponentTree(component, parent);
                                  renderNode.setWaste(false);
                                  if(renderNode.getAttrs().getStatement() != null) {
                                      renderNode.getAttrs().getStatement().remove(WXStatement.WX_FOR);
                                      renderNode.getAttrs().getStatement().remove(WXStatement.WX_IF); //clear node's statement
                                  }
                                  parent.addChild(renderNode, renderIndex);
                                  NativeRenderObjectUtils.nativeAddChildRenderObject(parent.getRenderObjectPtr(),
                                          renderNode.getRenderObjectPtr());
                                  updates.add(renderNode);
                                  if(WXEnvironment.isApkDebugable()){
                                      WXLogUtils.d(WXRecyclerTemplateList.TAG, Thread.currentThread().getName() +  renderNode.getRef() + renderNode.getComponentType() + "statements copy component tree used " + (System.currentTimeMillis() - start));
                                  }
                              }
                              doBindingAttrsEventAndRenderChildNode(renderNode, context, updates);
                              renderIndex++;
                              if(loop.size() > 0){
                                  context.stack.push(loop);
                              }
                              if(itemKey == null) {
                                  context.stack.pop();
                              }
                          }
                      }
                  }else{
                      WXLogUtils.e(WXRecyclerTemplateList.TAG,  vfor.toJSONString() + " not call vfor block, for pre compile");
                  }
                  //after v-for execute, remove component created pre v-for.
                  for(;renderIndex<parent.getChildCount(); renderIndex++){
                      WXComponent wasteNode = parent.getChild(renderIndex);
                      if(!isCreateFromNodeStatement(wasteNode, component)){
                          break;
                      }
                      wasteNode.setWaste(true);
                  }
                  return renderIndex - parent.indexOf(component);
              }
  
              //execute v-if context
              if(vif != null){
                  if(!Operators.isTrue(vif.execute(context.stack))){
                      component.setWaste(true);
                      return 1;
                  }else{
                      component.setWaste(false);
                  }
  
              }
          }
          doBindingAttrsEventAndRenderChildNode(component, context, updates);
          return  1;
      }
  
  
      /**
       * bind attrs and doRender component child
       * */
      private static void doBindingAttrsEventAndRenderChildNode(WXComponent component, CellRenderContext context,
                                                                List<WXComponent> updates){
          WXAttr attr = component.getAttrs();
  
          /**
           * sub component supported, sub component new stack
           * */
          ArrayStack stack = context.stack;
  
  
          String virtualComponentId = null;
          boolean callVirtualComponentAttach = false;
          if(attr.get(ELUtils.IS_COMPONENT_ROOT) != null
                  && WXUtils.getBoolean(attr.get(ELUtils.IS_COMPONENT_ROOT), false)){
              if(attr.get(ELUtils.COMPONENT_PROPS) != null
                      && JSONUtils.isJSON(attr.get(ELUtils.COMPONENT_PROPS))){
                   String compoentId = (String) attr.get(CellDataManager.SUB_COMPONENT_TEMPLATE_ID);
                  Object compoentData = null;
                  if(!TextUtils.isEmpty(compoentId)){
                     virtualComponentId =  context.getRenderState().getVirtualComponentIds().get(component.getViewTreeKey());
                     if(virtualComponentId == null){ //none virtualComponentId, create and do attach
                          virtualComponentId =  CellDataManager.createVirtualComponentId(context.templateList.getRef(),
                                  component.getViewTreeKey(), context.templateList.getItemId(context.position));
                          Map<String, Object>  props  = renderProps(JSONUtils.toJSON(attr.get(ELUtils.COMPONENT_PROPS)), context.stack);
                          EventResult result = WXBridgeManager.getInstance().syncCallJSEventWithResult(WXBridgeManager.METHD_COMPONENT_HOOK_SYNC, component.getInstanceId(), null, compoentId, VirtualComponentLifecycle.LIFECYCLE, VirtualComponentLifecycle.CREATE,  new Object[]{
                                  virtualComponentId,
                                  props
                          }, null);
                          if(result != null
                                  && result.getResult() != null
                                  && result.getResult() instanceof Map){
                              props.putAll((Map<? extends String, ?>) result.getResult());
                          }
                          compoentData  =  props;
                          context.getRenderState().getVirtualComponentIds().put(component.getViewTreeKey(), virtualComponentId);
                          context.templateList.getCellDataManager().createVirtualComponentData(context.position, virtualComponentId, compoentData);
                           callVirtualComponentAttach = true; // when first create virtual compoent, call create
                       }else{ // get virtual component data check has dirty's update
                         compoentData = context.getRenderState().getVirtualComponentDatas().get(virtualComponentId);
                         if(context.getRenderState().isHasDataUpdate()){
                             Map<String, Object>  props  = renderProps((JSONObject) attr.get(ELUtils.COMPONENT_PROPS), context.stack);
                             EventResult result = WXBridgeManager.getInstance().syncCallJSEventWithResult(WXBridgeManager.METHD_COMPONENT_HOOK_SYNC, component.getInstanceId(), null, virtualComponentId, VirtualComponentLifecycle.LIFECYCLE, VirtualComponentLifecycle.SYNSTATE,  new Object[]{
                                     virtualComponentId,
                                     props
                             }, null);
  
                             if(result != null
                                     && result.getResult() != null
                                     && result.getResult() instanceof Map){
                                 props.putAll((Map<? extends String, ?>) result.getResult());
                                 context.templateList.getCellDataManager().updateVirtualComponentData(virtualComponentId, props);
                                 compoentData = props;
                             }
                         }
                      }
                      component.getAttrs().put(CellDataManager.VIRTUAL_COMPONENT_ID, virtualComponentId);
                  }else{ //stateless component
                      Map<String, Object>  props  = renderProps((JSONObject) attr.get(ELUtils.COMPONENT_PROPS), context.stack);
                      compoentData = props;
                  }
                  //virtual component is new context
                  context.stack = new ArrayStack();
                  if(compoentData != null){
                      context.stack.push(compoentData);
                  }
              }
          }
  
          /**
           * check node is render only once, if render once, and has rendered, just return
           * */
          Object vonce = null;
          if(attr.getStatement() != null){
              vonce = attr.getStatement().get(WXStatement.WX_ONCE);
          }
          if(vonce != null){
              ArrayStack onceStack = context.getRenderState().getOnceComponentStates().get(component.getViewTreeKey());
              if(onceStack == null){
                  onceStack = context.templateList.copyStack(context, stack);
                  context.getRenderState().getOnceComponentStates().put(component.getViewTreeKey(), onceStack);
              }
              context.stack = onceStack;
          }
  
          doRenderBindingAttrsAndEvent(component, context);
          if(component instanceof WXVContainer){
              if(component.isWaste()){
                  if(!(component instanceof WXCell)){
                       return;
                  }
              }
              WXVContainer container = (WXVContainer) component;
              for(int k=0; k<container.getChildCount();){
                  WXComponent next = container.getChild(k);
                  k += doRenderComponent(next, context, updates);
              }
          }
          if(stack != context.stack){
              context.stack = stack;
          }
          //create virtual componentId
          if(callVirtualComponentAttach && virtualComponentId != null){
              WXBridgeManager.getInstance().asyncCallJSEventVoidResult(WXBridgeManager.METHD_COMPONENT_HOOK_SYNC, component.getInstanceId(), null, virtualComponentId, VirtualComponentLifecycle.LIFECYCLE, VirtualComponentLifecycle.ATTACH, new Object[]{
                      TemplateDom.findAllComponentRefs(context.templateList.getRef(),context.position, component)
              });
          }
       }
  
  
      /**
       * check whether render node is create from component node statement.
       * */
      private static boolean isCreateFromNodeStatement(WXComponent renderNode, WXComponent component){
          return (renderNode.getRef() != null && renderNode.getRef().equals(component.getRef()));
      }
  
  
      /**
       * render dynamic binding attrs and bind them to component node.
       * */
      private static void doRenderBindingAttrsAndEvent(WXComponent component, CellRenderContext context){
          ArrayStack stack  = context.stack;
          component.setWaste(false);
          WXAttr attr = component.getAttrs();
          if(attr != null
                  && attr.getBindingAttrs() != null
                  && attr.getBindingAttrs().size() > 0){
              ArrayMap<String, Object> bindAttrs = component.getAttrs().getBindingAttrs();
              Map<String, Object> dynamic =  renderBindingAttrs(bindAttrs, stack);
              Set<Map.Entry<String, Object>> entries = dynamic.entrySet();
              /**
               * diff attrs, see attrs has update, remove none update attrs
               * */
              Iterator<Map.Entry<String, Object>> iterator = entries.iterator();
              while (iterator.hasNext()){
                  Map.Entry<String, Object> entry = iterator.next();
                  String key = entry.getKey();
                  Object value = entry.getValue();
                  Object oldValue = attr.get(key);
                  if(value == null){
                      if(oldValue == null){
                          iterator.remove();
                          continue;
                      }
                  }else{
                      if(value.equals(oldValue)){
                          iterator.remove();
                      }
                  }
              }
  
              if(dynamic.size() > 0) {
                  if(dynamic.size() == 1
                          && dynamic.get(Constants.Name.SRC) != null
                          && component instanceof WXImage){
                      //for image avoid dirty layout, only update src attrs
                      component.getAttrs().put(Constants.Name.SRC, dynamic.get(Constants.Name.SRC));
                  }else {
                      component.nativeUpdateAttrs(dynamic);
                  }
                  if(isMainThread()) {
                      component.updateProperties(dynamic);
                  }
                  dynamic.clear();
              }
          }
  
  
          WXStyle style = component.getStyles();
          if(style != null && style.getBindingStyle() != null){
              ArrayMap<String, Object> bindStyle = style.getBindingStyle();
              Map<String, Object> dynamic =  renderBindingAttrs(bindStyle, stack);
              Set<Map.Entry<String, Object>> entries = dynamic.entrySet();
              /**
               * diff attrs, see attrs has update, remove none update attrs
               * */
              Iterator<Map.Entry<String, Object>> iterator = entries.iterator();
              while (iterator.hasNext()){
                  Map.Entry<String, Object> entry = iterator.next();
                  String key = entry.getKey();
                  Object value = entry.getValue();
                  Object oldValue = style.get(key);
                  if(value == null){
                      if(oldValue == null){
                          iterator.remove();
                          continue;
                      }
                  }else{
                      if(value.equals(oldValue)){
                          iterator.remove();
                      }
                  }
              }
              if(dynamic.size() > 0) {
                    component.updateNativeStyles(dynamic);
                   if(isMainThread()) {
                      component.updateProperties(dynamic);
                   }
              }
          }
  
          WXEvent event = component.getEvents();
          if(event == null || event.getEventBindingArgs() == null){
              return;
          }
          Set<Map.Entry<String, Object>> eventBindArgsEntrySet = event.getEventBindingArgs().entrySet();
          for(Map.Entry<String, Object> eventBindArgsEntry : eventBindArgsEntrySet){
               List<Object> values = getBindingEventArgs(stack, eventBindArgsEntry.getValue());
               if(values != null){
                   event.putEventBindingArgsValue(eventBindArgsEntry.getKey(), values);
               }
          }
  
      }
  
  
      /**
       * @param  bindAttrs  none null,
       * @param  context  context
       * return binding attrs rended value in context
       * */
      private static final  ThreadLocal<Map<String, Object>> dynamicLocal = new ThreadLocal<>();
      public static Map<String, Object> renderBindingAttrs(ArrayMap bindAttrs, ArrayStack stack){
          Set<Map.Entry<String, Object>> entrySet = bindAttrs.entrySet();
          Map<String, Object> dynamic = dynamicLocal.get();
          if(dynamic == null) {
              dynamic = new HashMap<>();
              dynamicLocal.set(dynamic);
          }
          if(dynamic.size() > 0){
              dynamic.clear();
          }
          for(Map.Entry<String, Object> entry : entrySet){
              Object value = entry.getValue();
              String key = entry.getKey();
              if(value instanceof  JSONObject
                      && (((JSONObject) value).get(ELUtils.BINDING)  instanceof Token)){
                  JSONObject binding = (JSONObject) value;
                  Token block = (Token) (binding.get(ELUtils.BINDING));
                  Object blockValue = block.execute(stack);
                  dynamic.put(key, blockValue);
              }else if(value instanceof JSONArray){
                  JSONArray array = (JSONArray) value;
                  StringBuilder builder = new StringBuilder();
                  for(int i=0; i<array.size(); i++){
                      Object element = array.get(i);
                      if(element instanceof  CharSequence){
                          builder.append(element);
                          continue;
                      }
                      if(element instanceof JSONObject
                              && (((JSONObject) element).get(ELUtils.BINDING) instanceof Token)){
                          JSONObject binding = (JSONObject) element;
                          Token block = (Token) (binding.get(ELUtils.BINDING));
                          Object blockValue = block.execute(stack);
                          if(blockValue == null){
                              blockValue = "";
                          }
                          builder.append(blockValue);
                      }
                  }
                  String builderString = builder.toString();
                  if(builderString.length() > 256){
                      if(WXEnvironment.isApkDebugable()){
                          WXLogUtils.w(WXRecyclerTemplateList.TAG, " warn too big string " + builderString);
                      }
                  }
                  dynamic.put(key, builderString);
              }
          }
          return  dynamic;
      }
  
  
      public static Map<String, Object> renderProps(JSONObject props, ArrayStack stack){
          Set<Map.Entry<String, Object>> entrySet = props.entrySet();
          Map<String, Object> renderProps = new ArrayMap<>(4);
          for(Map.Entry<String, Object> entry : entrySet){
              Object value = entry.getValue();
              String key = entry.getKey();
              if(value instanceof  JSONObject
                      && (((JSONObject) value).get(ELUtils.BINDING)  instanceof Token)){
                  JSONObject binding = (JSONObject) value;
                  Token block = (Token) (binding.get(ELUtils.BINDING));
                  Object blockValue = block.execute(stack);
                  renderProps.put(key, blockValue);
              }else{
                  renderProps.put(key, value);
              }
          }
          return  renderProps;
      }
  
      public static List<Object> getBindingEventArgs(ArrayStack stack, Object bindings){
            List<Object>  params = new ArrayList<>(4);
            if(bindings instanceof  JSONArray){
                JSONArray array = (JSONArray) bindings;
                for(int i=0; i<array.size(); i++){
                    Object value = array.get(i);
                    if(value instanceof  JSONObject
                            && (((JSONObject) value).get(ELUtils.BINDING) instanceof Token)){
                        Token block = (Token)(((JSONObject) value).get(ELUtils.BINDING));
                        Object blockValue = block.execute(stack);
                        params.add(blockValue);
                    }else{
                        params.add(value);
                    }
                }
            }else if(bindings instanceof  JSONObject){
                JSONObject binding = (JSONObject) bindings;
                 if(binding.get(ELUtils.BINDING) instanceof Token){
                     Token block = (Token) binding.get(ELUtils.BINDING);
                     Object blockValue = block.execute(stack);
                     params.add(blockValue);
                 }else{
                     params.add(bindings.toString());
                 }
            }else{
                params.add(bindings.toString());
            }
            return  params;
      }
  
  
      private static boolean isMainThread(){
          return  Thread.currentThread() == Looper.getMainLooper().getThread();
      }
  
  
  
      public static String getComponentId(WXComponent component){
          if(component instanceof WXCell || component == null){
              return  null;
          }
          WXAttr attr = component.getAttrs();
          if(attr.get(ELUtils.IS_COMPONENT_ROOT) != null
                  && WXUtils.getBoolean(attr.get(ELUtils.IS_COMPONENT_ROOT), false)){
              if(attr.get(ELUtils.COMPONENT_PROPS) != null
                      && attr.get(ELUtils.COMPONENT_PROPS) instanceof  JSONObject){
                  Object componentId = attr.get(CellDataManager.VIRTUAL_COMPONENT_ID);
                  if(componentId == null){
                      return null;
                  }
                  return componentId.toString();
              }
          }
          return getComponentId(component.getParent());
      }
  
  
  
  }
  