/**
 * 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());
    }



}
