package com.usai.redant.CommonEditor;

import android.app.ProgressDialog;
import android.content.Context;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Color;
import android.support.v7.app.AlertDialog;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.text.Editable;
import android.text.InputFilter;
import android.text.InputType;
import android.text.TextWatcher;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.view.inputmethod.EditorInfo;
import android.widget.AbsListView;
import android.widget.ArrayAdapter;
import android.widget.AutoCompleteTextView;
import android.widget.BaseExpandableListAdapter;
import android.widget.Button;
import android.widget.CompoundButton;
import android.widget.EditText;
import android.widget.ExpandableListView;
import android.widget.Switch;


import com.usai.redant.CommonEditor.CommonEditor.CommonEditorActionCellHolder;
import com.usai.redant.CommonEditor.CommonEditor.CommonEditorAutoCompleteAdapter;
import com.usai.redant.CommonEditor.CommonEditor.CommonEditorCellHolder;
import com.usai.redant.CommonEditor.CommonEditor.CommonEditorDateRangeCellHolder;
import com.usai.redant.CommonEditor.CommonEditor.CommonEditorEditAutoCompleteCellHolder;
import com.usai.redant.CommonEditor.CommonEditor.CommonEditorEditCellHolder;
import com.usai.redant.CommonEditor.CommonEditor.CommonEditorEnumCellHolder;
import com.usai.redant.CommonEditor.CommonEditor.CommonEditorImageCellHolder;
import com.usai.redant.CommonEditor.CommonEditor.CommonEditorLabelCellHolder;
import com.usai.redant.CommonEditor.CommonEditor.CommonEditorModelCellHolder;
import com.usai.redant.CommonEditor.CommonEditor.CommonEditorMultipleActionCellHolder;
import com.usai.redant.CommonEditor.CommonEditor.CommonEditorRangeCellHolder;
import com.usai.redant.CommonEditor.CommonEditor.CommonEditorSectionHeaderHolder;
import com.usai.redant.CommonEditor.CommonEditor.CommonEditorSignatureCellHolder;
import com.usai.redant.CommonEditor.CommonEditor.CommonEditorSwitchCellHolder;
import com.usai.redant.CommonEditor.CommonEditor.CommonEditorTextViewCellHolder;
import com.usai.redant.CommonEditor.EnumSelectAndSort.EnumSelectAndSortActivity;
import com.usai.redant.redantmobile.R;
import com.usai.redant.util.Network;

import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
import java.util.UUID;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import static android.view.Gravity.CENTER_VERTICAL;
import static android.view.Gravity.LEFT;
import static android.view.Gravity.RIGHT;
import static android.view.Gravity.TOP;



public class CommonEditorActivity extends AppCompatActivity implements View.OnLayoutChangeListener{


    public ExpandAdapter adapter;
    public String service_url;

    public boolean hasChildView;
    public ExpandableListView listView;
    public View rootView;

    /**Child Activity Override*/
    public void download_success() {

    }

    public void request_fill() {

    }

    public JSONObject request_editor(String request_url,Bundle params) {
        return null;
    }

    public static class subitem_data {
        public JSONObject params;
        public JSONArray missingfields;
    }

    public ProgressDialog showProgressAlert(String title,String msg) {
        ProgressDialog pd = new ProgressDialog(this);
        pd.setTitle(title);
        pd.setMessage(msg);
        /**
         * false，表示 ProgressDialog 是不能通过 Back 键取消
         * 数据加载完成后必须要调用 ProgressDialog 的 dismiss() 方法来关闭对话框
         * */
        pd.setCancelable(false);
        pd.show();

        return pd;
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        getMenuInflater().inflate(R.menu.action_bar_menu,menu);
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {

        if (item.getItemId() == R.id.save_item) {
            JSONObject obj = check_cancomit(true);
            Log.d("Check Can Commit", "onOptionsItemSelected: ");
        }

        return true;
    }


    @Override
    protected void onSaveInstanceState(Bundle outState) {
        super.onSaveInstanceState(outState);

        if (content_data_control != null) {
            outState.putString("control_content",content_data_control.toString());
        }
        if (content_data_download != null) {
            outState.putString("download_content",content_data_download.toString());
        }

        if (service_url != null) {
            outState.putString("request_url",service_url);
        }

        if (getTitle() != null) {
            outState.putString("title",getTitle().toString());
        }

        outState.putInt("url_type",url_type);
        outState.putBundle("params",selfParams);
    }

    public static Intent build(Context context,Class cls,String title,int URLType,String requestURL,Bundle params) {

        if (context == null || cls == null) {
            return null;
        }

        Intent intent = new Intent(context,cls);

        intent.putExtra("url_type",URLType);

        if (requestURL != null) {
            intent.putExtra("request_url",requestURL);
        }

        if (params != null) {
            intent.putExtra("params",params);
        }


        if (title != null) {
            intent.putExtra("title",title);
        }

        return intent;
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);


        if (!hasChildView) {
            setContentView(R.layout.activity_common_editor);

//            rootView = findViewById(R.id.root_layout);
            listView = (ExpandableListView)findViewById(R.id.list_view);
        }

        rootView = getWindow().getDecorView().findViewById(android.R.id.content);

        if (listView == null) {
            return;
        }

        adapter = new ExpandAdapter(this);

        listView.setOnScrollListener(new AbsListView.OnScrollListener() {
            @Override
            public void onScrollStateChanged(AbsListView view, int scrollState) {
                // 编辑状态下滑动，去掉焦点
                if (lastEditText != null) {
                    lastEditText.clearFocus();
                }
            }

            @Override
            public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {

            }
        });

        listView.setGroupIndicator(null);

        listView.setOnChildClickListener(new ListChildViewClickListener());

        listView.setAdapter(adapter);


        if (savedInstanceState != null) {
            String control_str = savedInstanceState.getString("control_content");
            String download_str = savedInstanceState.getString("download_content");
            try {
                if (control_str != null || !control_str.isEmpty()) {
                    content_data_control = new JSONArray(control_str);
                }
                if (download_str != null || !download_str.isEmpty()) {
                    content_data_download = new JSONObject(download_str);
                }
            } catch (Exception e) {
                e.printStackTrace();
                content_data_control = null;
                content_data_download = null;
            }

            service_url = savedInstanceState.getString("request_url");
            url_type = savedInstanceState.getInt("url_type");
            selfParams = savedInstanceState.getBundle("params");
//            String title = savedInstanceState.getString("title");
//            setTitle(title);

        } else {
            service_url = getIntent().getStringExtra("request_url");
            url_type = getIntent().getIntExtra("url_type",URL_REMOTE);
//            String title = getIntent().getStringExtra("title");
//            setTitle(title);

            Bundle params = getIntent().getBundleExtra("params");
            if (params != null) {
                selfParams = params;
            }



            final ProgressDialog pd = showProgressAlert("Loading","Please wait");
            new Thread(new Runnable() {
                @Override
                public void run() {

                    if (url_type == URL_REMOTE) {
                        final JSONObject obj = request_editor(service_url,selfParams);


                        runOnUiThread(new Runnable() {
                            @Override
                            public void run() {

                                pd.dismiss();

                                if (obj != null) {

                                    int result = obj.optInt("result");
                                    if (result == 2) {

                                        content_data_download = copyDirtyTo(content_data_download,obj);
                                        content_data_control = translateChange(content_data_download,changed_data);


                                        download_success();
                                        defaulExpandSections();
                                        adapter.notifyDataSetChanged();

                                    } else {
                                        Utils.message_alert(mCtx,"Warning","Error");
                                    }

                                } else {
                                    Utils.message_alert(mCtx,"Warning","Error");
                                }

                            }
                        });

                    } else {

                        try {

                            InputStreamReader isr = new InputStreamReader(getAssets().open(service_url + ".json"),"UTF-8");
                            BufferedReader br = new BufferedReader(isr);
                            String line;
                            StringBuilder builder = new StringBuilder();
                            while((line = br.readLine()) != null){
                                builder.append(line);
                            }
                            br.close();
                            isr.close();
                            content_data_download = new JSONObject(builder.toString());//builder读取了JSON中的数据。

                            request_fill();

                            content_data_control = translateChange(content_data_download,changed_data);

                            runOnUiThread(new Runnable() {
                                @Override
                                public void run() {
                                    pd.dismiss();
                                    adapter.notifyDataSetChanged();
                                }
                            });


                        } catch (Exception e) {
                            runOnUiThread(new Runnable() {
                                @Override
                                public void run() {
                                    pd.dismiss();
                                }
                            });
                            e.printStackTrace();
                        }

                    }

                }
            }).start();
        }

        String title = selfParams.getString("title");
        setTitle(title);

    }


    @Override
    protected void onResume() {
        super.onResume();
        if (rootView != null) {
            rootView.addOnLayoutChangeListener(this);
        }
    }

    @Override
    protected void onStop() {
        super.onStop();
        if (lastEditText != null) {
            lastEditText.clearFocus();
        }

    }

    @Override
    public void onLayoutChange(View v, int left, int top, int right, int bottom, int oldLeft, int oldTop, int oldRight, int oldBottom) {

        if(oldBottom != 0 && bottom != 0 && oldBottom > bottom){

            Log.d("Keyboard", "show: ");

        }else if(oldBottom != 0 && bottom != 0 && oldBottom < bottom){

            endEditting();
            Log.d("Keyboard", "hide: ");
        }
    }

    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);

        if (data == null || resultCode != RESULT_OK) {
            return;
        }

        // upload image
        if (requestCode == 1) {
            int group = data.getIntExtra("group",0);
            int child = data.getIntExtra("child",0);
            int btn = data.getIntExtra("btn",0);
            String url_down = data.getStringExtra("url_down");
            String url_up = data.getStringExtra("url_up");
            String path = data.getStringExtra("path");
            Utils.cacheLocalImageToURL(path,url_up); // 将图片移动到缓存目录
            // 对应更新数据，然刷新该行
            imgIsChanged(url_down,url_up,group,child,btn,url_up);
        }

        // addr editor
        if (requestCode == 2) {
            String value_str = data.getStringExtra(AddressEditorActivity.RETURN_VALUE);
            JSONObject value = null;
            if (value_str != null) {
                try {
                    value = new JSONObject(value_str);
                } catch (Exception e) {
                    e.printStackTrace();
                    return;
                }
            }
            int group = data.getIntExtra(AddressEditorActivity.GROUP,0);
            int child = data.getIntExtra(AddressEditorActivity.CHILD,0);
            handle_action_return(value,group,child,ACTION_SAVE_DATA);
        }

        // credit card editor
        if (requestCode == 3) {
            String value_str = data.getStringExtra(CreditCardEditorActivity.RETURN_VALUE);
            JSONObject value = null;
            if (value_str != null) {
                try {
                    value = new JSONObject(value_str);
                } catch (Exception e) {
                    e.printStackTrace();
                    return;
                }
            }
            int group = data.getIntExtra(CreditCardEditorActivity.GROUP,0);
            int child = data.getIntExtra(CreditCardEditorActivity.CHILD,0);
            handle_action_return(value,group,child,ACTION_SAVE_DATA);
        }

        // contact list
        if (requestCode == 4 || requestCode == 5 || requestCode == 6 || requestCode == 7 || requestCode == 8 || requestCode == 9) {
            String value_str = data.getStringExtra(ContactListActivity.RETURN_VALUE);
            JSONObject value = null;
            if (value_str != null) {
                try {
                    value = new JSONObject(value_str);
                } catch (Exception e) {
                    e.printStackTrace();
                    return;
                }
            }
            int group = data.getIntExtra(ContactListActivity.GROUP,0);
            int child = data.getIntExtra(ContactListActivity.CHILD,0);
            handle_action_return(value,group,child,ACTION_FILL_SECTION);
        }

        // enum select
        if (requestCode == 10) {

            String cadedate_str = data.getStringExtra(EnumSlectActivity.CADEDATE);
            if (cadedate_str == null || cadedate_str.isEmpty()) {
                return;
            }
            try {
                JSONObject cadedate = new JSONObject(cadedate_str);
                int group = data.getIntExtra(EnumSlectActivity.GROUP_POSITION,0);
                int child = data.getIntExtra(EnumSlectActivity.CHILD_POSITION,0);

                setEnumValue(cadedate,group,child);

            } catch (Exception e) {
                e.printStackTrace();
            }

        }

        // date picker
        if (requestCode == 11) {

        }

        // month picker
        if (requestCode == 12) {

            String date_str = data.getStringExtra("value");
            int group = data.getIntExtra("group",0);
            int child = data.getIntExtra("child",0);
            MPValueChanged(date_str,group,child);

        }

        // signature
        if (requestCode == 13) {

            int group = data.getIntExtra("group",0);
            int child = data.getIntExtra("child",0);
            String url_down = data.getStringExtra("url_down"); // avalue
            String url_up = data.getStringExtra("url_up"); // value
            String path = data.getStringExtra("path");

            Utils.cacheLocalImageToURL(path,url_down);

            signatureIsChanged(url_down,url_up,group,child);
        }

        // date range
        if (requestCode == 14) {
            int group = data.getIntExtra("group",0);
            int child = data.getIntExtra("child",0);
            String min = data.getStringExtra("min");
            String max = data.getStringExtra("max");

            String min_components[] = min.split("/");
            String max_components[] = max.split("/");

            if (min_components.length == max_components.length) {

                int min_year = Integer.valueOf(min_components[2]);
                int min_month = Integer.valueOf(min_components[0]);
                int min_day = Integer.valueOf(min_components[1]);

                int max_year = Integer.valueOf(max_components[2]);
                int max_month = Integer.valueOf(max_components[0]);
                int max_day = Integer.valueOf(max_components[1]);

                if (min_year > max_year) {
                    showWarningAlert("minimum can't larger than maximum");
                    return;
                } else if (min_year == max_year) {

                    if (min_month > max_month) {
                        showWarningAlert("minimum can't larger than maximum");
                        return;
                    } else if (min_month == max_month) {

                        if (min_day > max_day) {
                            showWarningAlert("minimum can't larger than maximum");
                            return;
                        }

                    }

                }


            }

            commonEditorRangeDidChange(min,max,group,child);
        }

    }

    public void showWarningAlert(String msg) {

        new AlertDialog.Builder(mCtx)
                .setTitle("Warning")
                .setMessage(msg)
                .show();

    }

    public void signatureIsChanged(String url_down,String url_up,int group,int child) {

        JSONArray section = content_data_control.optJSONArray(group);
        JSONObject item_json = section.optJSONObject(child);

        try {

            item_json.put("avalue",url_down);
            item_json.put("value",url_up);
            item_json.put("dirty","true");

            JSONObject section_json = content_data_download.optJSONObject("section_" + group);
            section_json.put("item_" + child,item_json);

            content_data_download.put("section_" + group, section_json);
            content_data_control = translateChange(content_data_download,changed_data);

            adapter.notifyDataSetChanged();

        } catch (Exception e) {
            e.printStackTrace();
        }

    }

    public void handle_action_return(JSONObject value,int group,int child,int action_code) {
        if (value == null || value.length() == 0) {
            return;
        }

        JSONObject section_json = null;
        JSONObject item_json = content_data_control.optJSONArray(group).optJSONObject(child);

        boolean is_subaction = value.optBoolean("is_subaction");
        int subaction_tag = value.optInt("subaction_tag");
        value.remove("is_subaction");
        value.remove("subaction_tag");

        if (is_subaction) {

            JSONObject sub_action = item_json.optJSONObject("item_" + subaction_tag);
            int refresh = sub_action.optInt("refresh");
            String refresh_trigger = sub_action.optString("name");
            JSONObject restore_json = sub_action.optJSONObject("restore");

            String subid = sub_action.optString("subid");

            String required = sub_action.optString("required");
            /** Warning
             *   get cell
             *
             * */
            if (required.equals("true") && value.length() == 0) {
                // cell red shadow
            } else {
                // cell clear shadow
            }

            if (value.length() != 0) {

                if (action_code == ACTION_SAVE_DATA) {

                    try {
                        sub_action.put("data",value);
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                    if (subid == null || subid.isEmpty()) {
                        try {

                            sub_action.put("dirty","true");
                            section_json = content_data_download.optJSONObject("section_" + group);
                            int count = 0;
                            count = section_json.optInt("count");
                            for (int i = 0; i < count; i++) {

                                JSONObject olditem = section_json.optJSONObject("item_" + i);
                                if (olditem.optString("name").equals(sub_action.optString("name"))) {
                                    item_json.put("item_" + value.optInt("subaction_tag"),sub_action);
                                    section_json.put("item_" + i,item_json);
                                }

                            } // for

                        } catch (Exception e) {
                            e.printStackTrace();
                        }

                        // subid == null
                    } else {

                        String[] idarr = subid.split("_");
                        int section = Integer.valueOf(idarr[0]);
                        int item = Integer.valueOf(idarr[1]);

                        section_json = content_data_download.optJSONObject("section_" + section);
                        JSONObject olditem = section_json.optJSONObject("item_" + item);
                        sub_action = enum_subitem_changed(olditem,idarr,sub_action,2);

                        try {

                            sub_action.put("dirty","true");
                            item_json.put("item_" + value.optInt("subaction_tag"),sub_action);
                            section_json.put("item_" + item,item_json);

                        } catch (Exception e) {
                            e.printStackTrace();
                        }

                    } // else

                } else if (action_code == ACTION_FILL_SECTION) {
                    if (subid == null || subid.isEmpty()) {

                        JSONObject jsonmap = sub_action.optJSONObject("key_map");
                        section_json = content_data_download.optJSONObject("section_" + group);
                        int icount = section_json .optInt("count");
                        for (int ic = 0; ic < icount; ic++) {
                            JSONObject modify_item = section_json.optJSONObject("item_" + ic);
                            String valuefrom = jsonmap.optString(modify_item.optString("name"));
                            String valuestr = value.optString(valuefrom);
                            if (valuestr != null) {
                                try {

                                    modify_item.put("value",valuestr);
                                    modify_item.put("dirty","true");
                                    section_json.put("item_" + ic,modify_item);

                                } catch (Exception e) {
                                    e.printStackTrace();
                                }
                            }
                        }

                        // subid == null
                    } else {

                        String[] idarr = subid.split("_");
                        int section = Integer.valueOf(idarr[0]);
                        int item = Integer.valueOf(idarr[1]);
                        JSONObject jsonmap = sub_action.optJSONObject("key_map");

                        section_json = content_data_download.optJSONObject("section_" + section);
                        JSONObject olditem = section_json.optJSONObject("item_" + item);
                        JSONObject olditem_sub_action = olditem.optJSONObject("item_" + subaction_tag);

                        olditem_sub_action = fill_switch_subitem_subid_mapping(olditem,null,value,jsonmap);

                        try {

                            olditem_sub_action.put("dirty","true");
                            olditem.put("item_" + value.optInt("subaction_tag"),olditem_sub_action);
                            section_json.put("item_" + item,olditem);

                        } catch (Exception e) {
                            e.printStackTrace();
                        }
                    }
                }

                try {
                    content_data_download.put("section_" + group,section_json);
                } catch (Exception e) {
                    e.printStackTrace();
                }

            } // value.length != 0

            content_data_control = translateChange(content_data_download,changed_data);

            if (refresh == 1) {

                if (restore_json != null) {
                    int rc = restore_json.optInt("count");
                    for (int ir = 0; ir < rc; ir++) {
                        String name = restore_json.optString("item_" + ir);
                        int section_count = content_data_download.optInt("section_count");
                        for (int i = 0; i< section_count; i++) {
                            JSONObject sectionjson = content_data_download.optJSONObject("section_" + i);
                            int item_count = sectionjson.optInt("count");
                            try {
                                for (int j = 0; j < item_count; j++) {
                                    JSONObject itemjson = sectionjson.optJSONObject("item_" + j);
                                    if (itemjson.optString("name").equals(name)) {
                                        itemjson.remove("dirty");
                                        sectionjson.put("item_" + j,itemjson);
                                    }
                                }
                                content_data_download.put("section_" + i,sectionjson);
                            } catch (Exception e) {
                                e.printStackTrace();
                            }
                        }
                    }
                }

                refresh(refresh_trigger);
                return;
            }
            adapter.notifyDataSetChanged();

            // is_subaction
        } else {
            int refresh = item_json.optInt("refresh");
            String refresh_trigger = item_json.optString("name");
            JSONObject restore_json = item_json.optJSONObject("restore");

            String subid = item_json.optString("subid");
            String required = item_json.optString("required");

            /** Warning
             *
             * get cell
             * */
            if (required.equals("true") && value.length() == 0) {
                // cell red shadow
            } else {
                // cell clear shadow
            }

            if (value.length() != 0) {
                if (action_code == ACTION_SAVE_DATA) {

                    try {
                        item_json.put("data",value);
                    } catch (Exception e) {
                        e.printStackTrace();
                    }

                    if (subid == null || subid.isEmpty()) {
                        try {
                            item_json.put("dirty","true");
                            section_json = content_data_download.optJSONObject("section_" + group);
                            int count = 0;
                            count = section_json.optInt("count");
                            for (int i = 0; i < count; i++) {
                                JSONObject olditem = section_json.optJSONObject("item_" + i);
                                if (olditem.optString("name").equals(item_json.optString("name"))) {
                                    section_json.put("item_" + i,item_json);
                                }
                            }

                        } catch (Exception e) {
                            e.printStackTrace();
                        }

                    } else {
                        String[] idarr = subid.split("_");
                        int section = Integer.valueOf(idarr[0]);
                        int item = Integer.valueOf(idarr[1]);

                        section_json = content_data_download.optJSONObject("section_" + section);
                        JSONObject olditem = section_json.optJSONObject("item_" + item);
                        item_json = enum_subitem_changed(olditem,idarr,item_json,2);
                        try {
                            item_json.put("dirty","true");
                            section_json.put("item_" + item,item_json);
                        } catch (Exception e) {
                            e.printStackTrace();
                        }
                    }


                } else if (action_code == ACTION_FILL_SECTION) {

                    if (subid == null || subid.isEmpty()) {

                        JSONObject jsonmap = item_json.optJSONObject("key_map");
                        section_json = content_data_download.optJSONObject("section_" + group);
                        int icount = section_json.optInt("count");
                        for (int ic = 0; ic < icount; ic++) {
                            JSONObject modify_item = section_json.optJSONObject("item_" + ic);
                            String valuefrom = jsonmap.optString(modify_item.optString("name"));
                            String valuestr = value.optString(valuefrom);

                            if (valuestr != null) {
                                try {
                                    modify_item.put("value",valuestr);
                                    modify_item.put("dirty","true");
                                    section_json.put("item_" + ic,modify_item);
                                } catch (Exception e) {
                                    e.printStackTrace();
                                }
                            }
                        }

                    } else {

                        String[] idarr = subid.split("_");
                        int section = Integer.valueOf(idarr[0]);
                        int item = Integer.valueOf(idarr[1]);
                        JSONObject jsonmap = item_json.optJSONObject("key_map");

                        section_json = content_data_download.optJSONObject("section_" + section);
                        JSONObject olditem = section_json.optJSONObject("item_" + item);

                        olditem = fill_switch_subitem_subid_mapping(olditem,null,value,jsonmap);

                        try {
                            olditem.put("dirty","true");
                            section_json.put("item_" + item,olditem);
                        } catch (Exception e) {
                            e.printStackTrace();
                        }

                    }

                }

                try {
                    content_data_download.put("section_" + group,section_json);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }

            content_data_control = translateChange(content_data_download,changed_data);

            if (refresh != 1) {

                if (restore_json != null) {
                    int rc = restore_json.optInt("count");
                    for (int ir = 0; ir < rc; ir++) {
                        String name = restore_json.optString("item_" + ir);
                        int section_count = content_data_download.optInt("section_count");
                        for (int i = 0; i < section_count; i++) {
                            JSONObject sectionjson = content_data_download.optJSONObject("section_" + i);
                            int item_count = sectionjson.optInt("count");
                            try {
                                for (int j = 0; j < item_count; j++) {
                                    JSONObject itemjson = sectionjson.optJSONObject("item_" + j);
                                    if (itemjson.optString("name").equals(name)) {
                                        itemjson.remove("dirty");
                                        sectionjson.put("item_" + j,itemjson);
                                    }
                                }
                                content_data_download.put("section_" + i,sectionjson);
                            } catch (Exception e) {
                                e.printStackTrace();
                            }
                        }

                    }
                }

                refresh(refresh_trigger);
                return;
            }

            adapter.notifyDataSetChanged();
        }

    }

    public JSONObject enum_subitem_changed(JSONObject item,String[] subid,JSONObject value,int step) {

        int index = Integer.valueOf(subid[step]);
        JSONObject cadedate = item.optJSONObject("cadedate");
        JSONObject subitem = item.optJSONObject("sub_item");
        if (cadedate != null) {
            JSONObject valjson = cadedate.optJSONObject("val_" + index);
            valjson = enum_subitem_changed(valjson,subid,value,step+1);

            try {
                cadedate.put("val_" + index,valjson);
                item.put("cadedate",cadedate);
            } catch (Exception e) {
                e.printStackTrace();
            }
            return item;

        } else if (subitem != null) {

            JSONObject itemjson = subitem.optJSONObject("item_" + index);
            if (step == subid.length - 1) {
                itemjson = value;
            } else {
                itemjson = enum_subitem_changed(itemjson,subid,value,step + 1);
            }

            try {

                subitem.put("item_" + index,itemjson);
                item.put("sub_item",subitem);

            } catch (Exception e) {
                e.printStackTrace();
            }
            return item;
        }

        return null;
    }


    JSONObject changed_data;

    public JSONObject copyDirtyTo(JSONObject dirty, JSONObject to) {

        if (dirty == null) {
            return to;
        }

        int section_count = dirty.optInt("section_count");

        try {
            for(int i=0;i<section_count;i++)
            {
                JSONObject sectionjson = dirty.optJSONObject("section_" + i);
                JSONObject to_sectionjson = to.optJSONObject("section_" + i);
                int item_count = sectionjson.optInt("count");
                for(int j=0;j<item_count;j++)
                {
                    JSONObject itemjson = sectionjson.optJSONObject("item_" + j);

                    if(itemjson.optString("dirty").equals("true"))
                    {
                        to_sectionjson.put("item_" + j ,itemjson);
                    }

                }
                to.put("section_" + i,to_sectionjson);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }

        return to;
    }

    public JSONArray translateChange(JSONObject obj, JSONObject change_data) {

        if (obj == null)
            return null;

        JSONArray retarray = new JSONArray();

        int section_count = obj.optInt("section_count");
        for (int i = 0; i < section_count; i++) {
            JSONArray sectionarr = new JSONArray();

            JSONObject sectionjson = obj.optJSONObject("section_" + i);
            int item_count = sectionjson.optInt("count");
            for(int j=0;j<item_count;j++)
            {
                JSONObject itemjson=sectionjson.optJSONObject("item_" + j);

                sectionarr.put(itemjson);

                addSubItemToParent(itemjson,sectionarr,i + "_" + j);

            }

        retarray.put(sectionarr);
        }

        Log.e("Content Data Control", "translateChange: ");
        return retarray;
    }

    public JSONArray addSubItemToParent(JSONObject itemjson,JSONArray sectionarr,String parent) {

        try {

            String control_type = itemjson.optString("control");
            boolean single_select = itemjson.optBoolean("single_select");
            if (control_type.equals("enum") && single_select) {

                JSONObject cadedatejson = itemjson.optJSONObject("cadedate");
                int cade_count = cadedatejson.optInt("count");
                for (int k = 0; k < cade_count; k++) {
                    JSONObject valjson = cadedatejson.optJSONObject("val_" + k);
                    int check = valjson.optInt("check");
                    JSONObject subjson = valjson.optJSONObject("sub_item");
                    boolean active = valjson.optBoolean("active");
                    active = false;
                    if (check == 1 && subjson != null && !active) {
                        int sub_count = subjson.optInt("count");
                        for (int l = 0; l < sub_count; l++) {
                            JSONObject addjson = subjson.optJSONObject("item_" + l);
                            String subself = parent + "_" + k + "_" + l;
                            addjson.put("subid",subself);
                            sectionarr.put(addjson);
                            addSubItemToParent(addjson,sectionarr,subself);

                        }
                        valjson.put("active",true);
                        cadedatejson.put("val_" + k,valjson);
                    }
                }

            } else if (control_type.equals("switch")) {

                String value = itemjson.optString("value");
                JSONObject subjson = null;
                if (value.equals("true")) {
                    JSONObject true_obj = itemjson.optJSONObject("true");
                    if (true_obj != null) {
                        subjson = true_obj.optJSONObject("sub_item");
                    }
                } else {
                    JSONObject false_obj = itemjson.optJSONObject("false");
                    if (false_obj != null) {
                        subjson = false_obj.optJSONObject("sub_item");
                    }
                }

                if (subjson != null) {
                    int sub_count = subjson.optInt("count");
                    for (int l = 0; l < sub_count; l++) {
                        JSONObject addjson = subjson.optJSONObject("item_" + l);
                        String subself = parent + "_" + l;
                        addjson.put("subid",subself);
                        sectionarr.put(addjson);
                        addSubItemToParent(addjson,sectionarr,subself);
                    }
                }

            }

        } catch (Exception e) {
            e.printStackTrace();
        }

        return sectionarr;
    }

    public void defaulExpandSections() {
        int groupCount = 0;
        if (content_data_control != null) {
            groupCount = content_data_control.length();
        } else {
            groupCount = 0;
        }

        if (groupCount <= 0) {
            return;
        }

        for (int i = 0; i < groupCount; i++) {
            JSONObject section_json = content_data_download.optJSONObject("section_" + i);
            boolean hide = section_json.optBoolean("hide");
            if (hide) {
                listView.collapseGroup(i); // 默认关闭
            } else {
                listView.expandGroup(i); // 默认展开
            }
        }

    }

    public int url_type = URL_REMOTE;
    public void refresh(String trigger) {

        if (lastEditText != null) {
            endEditting();
        }

        final ProgressDialog pd = showProgressAlert("Loading","Please wait");

        if (url_type == URL_REMOTE) {

            if (trigger != null) {
                try {
                    selfParams.putString("refresh_trigger",trigger);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
            new Thread(new Runnable() {
                @Override
                public void run() {
                    JSONObject refresh_params = get_refresh_param();
                    Iterator<String> iterator = refresh_params.keys();
                    while (iterator.hasNext()) {
                        String key = iterator.next();
                        String obj_str = "" + refresh_params.optString(key);
                        try {
                            selfParams.putString(key,obj_str);
                        } catch (Exception e) {
                            e.printStackTrace();
                        }
                    }

                    final JSONObject editor_json = request_editor(service_url,selfParams);

                    runOnUiThread(new Runnable() {
                        @Override
                        public void run() {
                            pd.dismiss();
                            if (editor_json == null) {
                                Utils.message_alert(mCtx,"Warning","net error");
                                adapter.notifyDataSetChanged();
                                return;
                            }
                            if (Integer.valueOf(editor_json.optString("result")) == 2) {
                                content_data_download = copyDirtyTo(content_data_download,editor_json);
                                content_data_control = translateChange(content_data_download,changed_data);

                                download_success();
                                adapter.notifyDataSetChanged();

                            } else {
                                Utils.message_alert(mCtx,"Warning",editor_json.optString("err_msg"));
                            }
                        }
                    });
                }
            }).start();


        } // url remote
        else {

            try {

                InputStreamReader isr = new InputStreamReader(getAssets().open(service_url + ".json"),"UTF-8");
                BufferedReader br = new BufferedReader(isr);
                String line;
                StringBuilder builder = new StringBuilder();
                while((line = br.readLine()) != null){
                    builder.append(line);
                }
                br.close();
                isr.close();
                content_data_download = new JSONObject(builder.toString());//builder读取了JSON中的数据。

                request_fill();

                content_data_control = translateChange(content_data_download,changed_data);
                adapter.notifyDataSetChanged();
                pd.dismiss();
            } catch (Exception e) {
                e.printStackTrace();
                pd.dismiss();
            }

        }
    }

    public Bundle selfParams = new Bundle();
    public JSONObject get_refresh_param() {
        try {
            JSONObject params = new JSONObject();
            JSONObject param_names = content_data_download.optJSONObject("up_params");
            int param_count = param_names.optInt("count");
            for (int pc = 0; pc < param_count; pc++) {
                String param_name = param_names.optString("val_" + pc);
                String param_val = getValue(param_name);
                selfParams.putString(param_name,param_val);
            }
            return params;

        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    public  subitem_data subitem_param_addto_alert(JSONObject itemjson,JSONObject upparam,boolean alert) {

        try {

            subitem_data data = new subitem_data();

            JSONArray fields = new JSONArray();
            String control_type = itemjson.optString("control");
            boolean single_select = itemjson.optBoolean("single_select");
            if (control_type.equals("enum") && single_select) {

                JSONObject cadedatejson = itemjson.optJSONObject("cadedate");
                int cade_count = cadedatejson.optInt("count");

                for (int k = 0; k < cade_count; k++) {
                    JSONObject valjson  = cadedatejson.optJSONObject("val_" + k);
                    int check = valjson.optInt("check");

                    JSONObject subjson = valjson.optJSONObject("sub_item");
                    boolean active = valjson.optBoolean("active");
                    if (check == 1 && subjson != null && !active) {

                        int sub_count = subjson.optInt("count");
                        for (int l = 0; l < sub_count; l++) {

                            JSONObject addjson = subjson.optJSONObject("item_" + l);
                            String required = addjson.optString("required");
                            String key = addjson.optString("name");
                            if (key == null || key.isEmpty()) {
                                continue;
                            } //
                            if (addjson.optString("control").equals("enum")) {
                                String add_single_select = addjson.optString("single_select");
                                if (add_single_select.equals("true")) {

                                    JSONObject cadejson = addjson.optJSONObject("cadedate");
                                    int count = cadejson.optInt("count");
                                    boolean setvalue = false;
                                    for (int cc = 0; cc < count; cc++) {
                                        JSONObject cade_valjson = cadejson.optJSONObject("val_" + cc);
                                        if (Integer.valueOf(cade_valjson.optString("check")) == 1) {
                                            upparam.put(addjson.optString("name"),cade_valjson.optString("value_id"));
                                            setvalue = true;
                                            break;
                                        } // check == 1

                                    } // for cc

                                    if (addjson.optString("required").equals("true") && setvalue == false) {
                                        cancommit = false;

                                        String mfield = String.format("%d. %s is missing",fields.length() + 1,addjson.optString("aname"));

                                        fields.put(mfield);

                                        IndexPath indexPath = get_indexpath1(addjson.optString("name"));
                                        if (alert) {
                                            listView.expandGroup(indexPath.section);
                                        }
                                        if (fields.length() == 1) {
                                            first_miss_pos = indexPath;
                                        }

                                    }


                                } else {
                                    // not support multiple selection
                                }

                            } // addjson control enum
                            else if (addjson.optString("control").equals("action")) {

                                JSONObject action_data = addjson.optJSONObject("data");
                                int section_count = action_data.optInt("section_count");

                                if (required.equals("true") && action_data != null) {

                                    cancommit = false;
                                    String mfield = String.format("%d. %@ is missing",fields.length() + 1,addjson.optString("aname"));
                                    fields.put(mfield);

                                    IndexPath indexPath = get_indexpath1(addjson.optString("name"));
                                    if (alert) {
                                        listView.expandGroup(indexPath.section);
                                    }
                                    if (fields.length() == 1) {
                                        first_miss_pos = indexPath;
                                    }

                                } // required true && action_data

                                for (int i = 0; i < section_count; i++) {

                                    JSONObject sectionjson = action_data.optJSONObject("section_" + i);
                                    int item_count = sectionjson.optInt("count");
                                    for (int j = 0; j < item_count; j++) {
                                        JSONObject itemjson_j = sectionjson.optJSONObject("item_" + j);
                                        String key_j = itemjson_j.optString("name");

                                        if (key_j == null || key_j.isEmpty()) {
                                            continue;
                                        }

                                        if (itemjson_j.optString("control").equals("enum")) {

                                            String single_select_j = itemjson_j.optString("single_select");
                                            if (single_select_j.equals("true")) {

                                                JSONObject cadejson = itemjson_j.optJSONObject("cadedate");
                                                int count = cadejson.optInt("count");
                                                boolean setvalue = false;
                                                for (int cc = 0; cc < count; cc++) {
                                                    JSONObject valjson_cc = cadejson.optJSONObject("val_" + cc);
                                                    if (valjson_cc.optInt("check") == 1) {
                                                        upparam.put(itemjson_j.optString("name"),valjson_cc.optString("value_id"));
                                                        setvalue = true;
                                                        break;
                                                    } // check
                                                }

                                                if (itemjson_j.optString("required").equals("true") && setvalue == false) {
                                                    cancommit = false;
                                                    String mfield = String.format("%d. %@ is missing",fields.length() + 1,itemjson_j.optString("aname"));
                                                    fields.put(mfield);

                                                    IndexPath indexPath = get_indexpath1(addjson.optString("name"));
                                                    if (alert) {
                                                        listView.expandGroup(indexPath.section);
                                                    }
                                                    if (fields.length() == 1) {
                                                        first_miss_pos = indexPath;
                                                    }
                                                }

                                            } // single select true
                                            else {
                                                // not support multiple selection
                                            }

                                        } // enum
                                        else {

                                            if (itemjson_j.optString("value") != null && !itemjson_j.optString("value").equals("")) {
                                                upparam.put(itemjson_j.optString("name"),itemjson_j.optString("value"));
                                            } else {

                                                if (itemjson_j.optString("required").equals("true")) {
                                                    cancommit = false;
                                                    String mfield = String.format("%d. %@ is missing",fields.length() + 1,itemjson_j.optString("aname"));
                                                    fields.put(mfield);

                                                    IndexPath indexPath = get_indexpath1(addjson.optString("name"));
                                                    if (alert) {
                                                        listView.expandGroup(indexPath.section);
                                                    }
                                                    if (fields.length() == 1) {
                                                        first_miss_pos = indexPath;
                                                    }
                                                }

                                            } // else

                                        } // else

                                        subitem_data data1 = subitem_param_addto_alert(itemjson_j,upparam,alert);
                                        upparam = data1.params;
                                        for (int fl = 0; fl < data1.missingfields.length(); fl++) {
                                            fields.put(data1.missingfields.opt(fl));
                                        }

                                    } // for j

                                } // for i

                            } // addjson control action
                            else {
                                if (addjson.optString("value") != null && !addjson.optString("value").isEmpty()) {
                                    upparam.put(key,addjson.optString("value"));
                                } else {
                                    if (addjson.optString("required").equals("true")) {
                                        cancommit = false;
                                        String mfield = String.format("%d. %@ is missing",fields.length() + 1,addjson.optString("aname"));
                                        fields.put(mfield);

                                        IndexPath indexPath = get_indexpath1(addjson.optString("name"));
                                        if (alert) {
                                            listView.expandGroup(indexPath.section);
                                        }
                                        if (fields.length() == 1) {
                                            first_miss_pos = indexPath;
                                        }
                                    }
                                }
                            }
                            subitem_data data2 = subitem_param_addto_alert(addjson,upparam,alert);
                            upparam = data2.params;
                            for (int fl = 0; fl < data2.missingfields.length(); fl++) {
                                fields.put(data2.missingfields.opt(fl));
                            }

                        } // for l

                    } // check == 1 && subjson != null && !active

                } // for k

            } // enum single select

            data.params = upparam;
            data.missingfields = fields;

            return data;

        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    public static class IndexPath {
        public int section;
        public int row;
    }

    public IndexPath first_miss_pos;

    public IndexPath get_indexpath1(String name) {
        if (first_miss_pos != null) {
            return first_miss_pos;
        }

        for (int i = 0; i < content_data_control.length();i++) {
            JSONArray items = content_data_control.optJSONArray(i);
            for (int j = 0; j < items.length(); j++) {
                JSONObject item = items.optJSONObject(j);
                String item_name = item.optString("name");
                if (item_name.equals(name)) {
                    IndexPath indexPath = new IndexPath();
                    indexPath.section = i;
                    indexPath.row = j;
                    return indexPath;
                }
            }
        }

        return null;
    }

    public JSONObject check_cancomit(boolean alert) {
        first_miss_pos = null;
        cancommit =  true;

        try {

            JSONArray fields = new JSONArray();
            JSONObject upparams = new JSONObject();

            int section_count = content_data_control.length();
            for (int i = 0; i < section_count; i++) {

                JSONArray sectionjson = content_data_control.optJSONArray(i);
                int item_count = sectionjson.length();
                for (int j = 0; j < item_count; j++) {
                    JSONObject itemjson = sectionjson.optJSONObject(j);
                    String key = itemjson.optString("name");
                    if (key == null || key.length() == 0) {
                        continue;
                    }

                    if (itemjson.optString("control").equals("enum")) {
                        String single_select = itemjson.optString("single_select");
                        if (single_select.equals("true")) {
                            JSONObject cadejson = itemjson.optJSONObject("cadedate");
                            int count = cadejson.optInt("count");
                            boolean setvalue = false;
                            for (int cc = 0; cc < count; cc++) {
                                JSONObject valjson = cadejson.optJSONObject("val_" + cc);
                                if (valjson.optInt("check") == 1) {
                                    upparams.put(itemjson.optString("name"),valjson.optString("value_id"));
                                    setvalue = true;
                                    break;
                                }
                            } // for cc

                            if (itemjson.optString("required").equals("true") && setvalue == false) {
                                cancommit = false;
                                String mfield = String.format("%d. %s is missing",fields.length() + 1,itemjson.optString("aname"));

                                fields.put(mfield);

                                IndexPath indexPath = get_indexpath1(itemjson.optString("name"));
                                if (alert) {
                                    listView.expandGroup(indexPath.section);
                                }
                                if (fields.length() == 1) {
                                    first_miss_pos = indexPath;
                                }
                            }

                        } // single select true
                        else { // multiple selection

                            JSONArray checked = new JSONArray();
                            JSONObject cadejson = itemjson.optJSONObject("cadedate");
                            int count = cadejson.optInt("count");
                            for (int cc = 0; cc < count; cc++) {
                                JSONObject valjson = cadejson.optJSONObject("val_" + cc);
                                if (valjson.optInt("check") == 1) {
                                    checked.put(valjson.optString("value_id"));
                                } // check == 1
                            } // for cc
                            if (itemjson.optString("required").equals("true") && checked.length() == 0) {

                                cancommit = false;
                                String mfield = String.format("%d. %s is missing",fields.length() + 1,itemjson.optString("aname"));

                                fields.put(mfield);

                                IndexPath indexPath = get_indexpath1(itemjson.optString("name"));
                                if (alert) {
                                    listView.expandGroup(indexPath.section);
                                }
                                if (fields.length() == 1) {
                                    first_miss_pos = indexPath;
                                }

                            } // required && checked.length == 0
                            else {
                                String string = checked.join(",");
                                upparams.put(itemjson.optString("name"),string);
                            }

                        }

                    } // enum
                    else if (itemjson.optString("control").equals("action")) {

                        if (itemjson.optString("required").equals("true") && itemjson.opt("data") == null) {
                            cancommit = false;
                            String mfield = String.format("%d. %s is missing",fields.length() + 1,itemjson.optString("aname"));

                            fields.put(mfield);

                            IndexPath indexPath = get_indexpath1(itemjson.optString("name"));
                            if (alert) {
                                listView.expandGroup(indexPath.section);
                            }
                            if (fields.length() == 1) {
                                first_miss_pos = indexPath;
                            }

                        }

                    } // action
                    else if (itemjson.optString("control").equals("signature")) {

                        if (itemjson.optString("required").equals("true") && itemjson.opt("value") == null) {
                            cancommit = false;
                            String mfield = String.format("%d. %s is missing",fields.length() + 1,itemjson.optString("aname"));

                            fields.put(mfield);

                            IndexPath indexPath = get_indexpath1(itemjson.optString("name"));
                            if (alert) {
                                listView.expandGroup(indexPath.section);
                            }
                            if (fields.length() == 1) {
                                first_miss_pos = indexPath;
                            }
                        }

                    } // signature
                    else if (itemjson.optString("control").equals("switch")) {

                        String valuestr = itemjson.optString("value");
                        upparams.put(itemjson.optString("name"),valuestr);

                        String value = itemjson.optString("value");
                        JSONObject boolitem = null;
                        JSONObject subjson = null;
                        if (value.equals("true")) {
                            boolitem = itemjson.optJSONObject("true");
                        } else {
                            boolitem = itemjson.optJSONObject("false");
                        }
                        if (boolitem != null) {
                            subjson = boolitem.optJSONObject("sub_item");
                        }
                        if (subjson != null) {

                            int sub_count = subjson.optInt("count");
                            for (int l = 0; l < sub_count; l++) {
                                JSONObject modify_item = subjson.optJSONObject("item_" + l);
                                if (modify_item.optString("value") != null && !modify_item.optString("value").isEmpty()) {
                                    upparams.put(modify_item.optString("name"),modify_item.optString("value"));
                                }
                                else {
                                    if (modify_item.optString("required").equals("true")) {
                                        cancommit = false;
                                        String mfield = String.format("%d. %s is missing",fields.length() + 1,itemjson.optString("aname"));

                                        fields.put(mfield);

                                        IndexPath indexPath = get_indexpath1(modify_item.optString("name"));
                                        if (alert) {
                                            listView.expandGroup(indexPath.section);
                                        }
                                        if (fields.length() == 1) {
                                            first_miss_pos = indexPath;
                                        }
                                    }
                                }
                            }

                        } // subjson != null

                    } // switch
                    else if (itemjson.optString("control").equals("img")) {

                        if (itemjson.optString("avalue") != null && !itemjson.optString("avalue").isEmpty()) {
                            upparams.put(itemjson.optString("name"),itemjson.optString("avalue"));
                        } else {
                            if (itemjson.optString("required").equals("true")) {
                                cancommit = false;
                                String mfield = String.format("%d. %s is missing",fields.length() + 1,itemjson.optString("aname"));

                                fields.put(mfield);

                                IndexPath indexPath = get_indexpath1(itemjson.optString("name"));
                                if (alert) {
                                    listView.expandGroup(indexPath.section);
                                }
                                if (fields.length() == 1) {
                                    first_miss_pos = indexPath;
                                }
                            }
                        }

                    } // img
                    else if (itemjson.optString("control").equals("edit")) {

                        int min_length = itemjson.optInt("min_length");
                        String check_len_val = itemjson.optString("value");
                        if (check_len_val.length() < min_length) {
                            cancommit = false;
                            String mfield = String.format("%d. %s is too short",fields.length() + 1,itemjson.optString("aname"));
                            if (check_len_val.length() == 0 && itemjson.optString("required").equals("true")) {
                                mfield = String.format("%d. %s is missing",fields.length() + 1,itemjson.optString("aname"));
                            }
                            fields.put(mfield);

                            IndexPath indexPath = get_indexpath1(itemjson.optString("name"));
                            if (alert) {
                                listView.expandGroup(indexPath.section);
                            }
                            if (fields.length() == 1) {
                                first_miss_pos = indexPath;
                            }

                        } // < min_length
                        else if (itemjson.optString("value") != null && !itemjson.optString("value").isEmpty()) {
                            upparams.put(itemjson.optString("name"),itemjson.optString("value"));
                        }
                        else {
                            if (itemjson.optString("required").equals("true")) {
                                cancommit = false;
                                String mfield = String.format("%d. %s is missing",fields.length() + 1,itemjson.optString("aname"));

                                fields.put(mfield);

                                IndexPath indexPath = get_indexpath1(itemjson.optString("name"));
                                if (alert) {
                                    listView.expandGroup(indexPath.section);
                                }
                                if (fields.length() == 1) {
                                    first_miss_pos = indexPath;
                                }
                            }
                        }

                    } // edit
                    else if (itemjson.optString("control").equals("range")) {

                        String min_str = itemjson.optString("min_value","");
                        String max_str = itemjson.optString("max_value","");

                        String required = itemjson.optString("required");
                        if (required != null && required.equals("true") && (min_str.length() < 1 && max_str.length() < 1)) {
                            cancommit = false;
                            String mfield = itemjson.optString("aname") + " is missing";
                            fields.put(mfield);
                        } else {
                            JSONObject range_obj = new JSONObject();
                            range_obj.put("min",min_str);
                            range_obj.put("max",max_str);
                            upparams.put(itemjson.optString("name"),range_obj.toString());
                        }

                    } // range
                    else {

                        if (itemjson.optString("value") != null && !itemjson.optString("value").isEmpty()) {
                            upparams.put(itemjson.optString("name"),itemjson.optString("value"));
                        } else {
                            if (itemjson.optString("required").equals("true")) {
                                cancommit = false;
                                String mfield = String.format("%d. %s is missing",fields.length() + 1,itemjson.optString("aname"));

                                fields.put(mfield);

                                IndexPath indexPath = get_indexpath1(itemjson.optString("name"));
                                if (alert) {
                                    listView.expandGroup(indexPath.section);
                                }
                                if (fields.length() == 1) {
                                    first_miss_pos = indexPath;
                                }
                            }
                        }

                    }

                } // for j

            } // for i

            if (cancommit == false && alert) {

                String missfields = fields.join("\n");
                String msg = missfields;

                new AlertDialog.Builder(mCtx)
                        .setTitle("Warning")
                        .setMessage(msg)
                        .setPositiveButton("OK",null)
                        .show();

                content_data_control = translateChange(content_data_download,changed_data);
                adapter.notifyDataSetChanged();
                listView.setSelectedChild(first_miss_pos.section,first_miss_pos.row,true);
                return upparams;


            } else {
                cancommit = true;
            }
            return upparams;


        } catch (Exception e) {
            e.printStackTrace();
        }

        return null;
    }

    public static int COMMON_EDITOR_CELL_TYPE_ACTION = 0;
    public static int COMMON_EDITOR_CELL_TYPE_EDIT = 1;
    public static int COMMON_EDITOR_CELL_TYPE_ENUM = 2;
    public static int COMMON_EDITOR_CELL_TYPE_IMAGE = 3;
    public static int COMMON_EDITOR_CELL_TYPE_LABLE = 4;
    public static int COMMON_EDITOR_CELL_TYPE_MODEL = 5;
    public static int COMMON_EDITOR_CELL_TYPE_MULTIPLE_ACTION = 6;
    public static int COMMON_EDITOR_CELL_TYPE_SIGNATURE = 7;
    public static int COMMON_EDITOR_CELL_TYPE_SWITCH = 8;
    public static int COMMON_EDITOR_CELL_TYPE_TEXT_VIEW = 9;
    public static int COMMON_EDITOR_CELL_TYPE_SECTION_HEADER = 10;
    public static int COMMON_EDITOR_CELL_TYPE_RANGE = 11;
    public static int COMMON_EDITOR_CELL_TYPE_DATE_RANGE = 12;
    public static int COMMON_EDITOR_CELL_TYPE_AUTO_COMPLETE = 13;

    /**
     * ExpandListView Adapter
     * */
    public JSONArray content_data_control;
    public JSONObject content_data_download;

    public class ExpandAdapter extends BaseExpandableListAdapter {

        private Context mCtx;

        public ExpandAdapter(Context ctx) {
            mCtx = ctx;
        }

        @Override
        public int getGroupCount() {
           if (content_data_control != null) {
               return content_data_control.length();
           } else {
               return 0;
           }
        }

        @Override
        public int getChildrenCount(int groupPosition) {
            if (content_data_download == null) {
                return 0;
            }
            JSONObject section_json = content_data_download.optJSONObject("section_" + groupPosition);
            boolean hide = section_json.optBoolean("hide");
            if (hide) {
                return 0;
            } else {
                JSONArray section = content_data_control.optJSONArray(groupPosition);
                return section.length();
            }
        }

        @Override
        public Object getGroup(int groupPosition) {
            if (content_data_control == null) {
                return null;
            }
            JSONArray section = content_data_control.optJSONArray(groupPosition);
            return section;
        }

        @Override
        public Object getChild(int groupPosition, int childPosition) {
            if (content_data_control == null) {
                return null;
            }
            JSONArray section = content_data_control.optJSONArray(groupPosition);
            JSONObject item = section.optJSONObject(childPosition);
            return item;
        }

        @Override
        public long getGroupId(int groupPosition) {
            return groupPosition;
        }

        @Override
        public long getChildId(int groupPosition, int childPosition) {
            return groupPosition * 1000 + childPosition;
        }

        @Override
        public boolean hasStableIds() {
            return true;
        }

        @Override
        public View getGroupView(int groupPosition, boolean isExpanded, View convertView, ViewGroup parent) {

            JSONObject section_json = content_data_download.optJSONObject("section_" + groupPosition);

            CommonEditorSectionHeaderHolder holder;
            if (convertView == null) {
                convertView = LayoutInflater.from(mCtx).inflate(R.layout.common_editor_section_header,null);
                holder = new CommonEditorSectionHeaderHolder(mCtx,convertView);
            } else {
                holder = (CommonEditorSectionHeaderHolder)convertView.getTag();
            }
            setUpSectionHeaderCellHolder(holder,convertView,section_json,groupPosition,-1);
            holder.clickSectionHeader(isExpanded);


            return convertView;
        }

        @Override
        public View getChildView(int groupPosition, int childPosition, boolean isLastChild, View convertView, ViewGroup parent) {

            JSONObject item_json = (JSONObject) getChild(groupPosition,childPosition);
            String control = null;
            boolean readonly = false;
            try {

                control = item_json.getString("control");

            } catch (Exception e) {
                e.printStackTrace();
            }


            CommonEditorCellHolder holder;
            if (convertView == null) {

                if (control != null) {
                    if (control.equals("text_view")) {
                        convertView = LayoutInflater.from(mCtx).inflate(R.layout.common_editor_text_view_cell_small,null);
                        holder = new CommonEditorTextViewCellHolder(mCtx,convertView);
                        setUpTextViewCellHolder((CommonEditorTextViewCellHolder) holder,convertView,item_json,readonly,groupPosition,childPosition);

                    } else if (control.equals("img")) {
                        convertView = LayoutInflater.from(mCtx).inflate(R.layout.common_editor_image_cell_small,null);
                        holder = new CommonEditorImageCellHolder(mCtx,convertView);
                        setUpImageCellHolder((CommonEditorImageCellHolder)holder,convertView,item_json,readonly,groupPosition,childPosition);

                    } else if (control.equals("edit")) {
                        String autoComplete = item_json.optString("autocomplete");
                        if (autoComplete != null && autoComplete.equals("true")) {
                            convertView = LayoutInflater.from(mCtx).inflate(R.layout.common_editor_edit_auto_complete_cell_small,null);
                            holder = new CommonEditorEditAutoCompleteCellHolder(mCtx,convertView);
                            setUpEditAutoCompleteCellHolder((CommonEditorEditAutoCompleteCellHolder)holder,convertView,item_json,readonly,groupPosition,childPosition);
                        } else {
                            convertView = LayoutInflater.from(mCtx).inflate(R.layout.common_editor_edit_cell_small,null);
                            holder = new CommonEditorEditCellHolder(mCtx,convertView);
                            setUpEditCellHolder((CommonEditorEditCellHolder)holder,convertView,item_json,readonly,groupPosition,childPosition);
                        }

                    } else if (control.equals("text")) {
                        convertView = LayoutInflater.from(mCtx).inflate(R.layout.common_editor_label_cell_small,null);
                        holder = new CommonEditorLabelCellHolder(mCtx,convertView);
                        setUpLabelCellHolder((CommonEditorLabelCellHolder)holder,convertView,item_json,readonly,groupPosition,childPosition);

                    } else if (control.equals("action")) {
                        convertView = LayoutInflater.from(mCtx).inflate(R.layout.common_editor_action_cell,null);
                        holder = new CommonEditorActionCellHolder(mCtx,convertView);
                        setUpActionCellHolder((CommonEditorActionCellHolder)holder,convertView,item_json,readonly,groupPosition,childPosition);

                    } else if (control.equals("multi_action")) {
                        convertView = LayoutInflater.from(mCtx).inflate(R.layout.common_editor_multiple_action_cell,null);
                        holder = new CommonEditorMultipleActionCellHolder(mCtx,convertView);
                        setUpMultipleActionCellHolder((CommonEditorMultipleActionCellHolder)holder,convertView,item_json,readonly,groupPosition,childPosition);

                    } else if (control.equals("switch")) {
                        convertView = LayoutInflater.from(mCtx).inflate(R.layout.common_editor_switch_cell_small,null);
                        holder = new CommonEditorSwitchCellHolder(mCtx,convertView);
                        setUpSwitchCellHolder((CommonEditorSwitchCellHolder)holder,convertView,item_json,readonly,groupPosition,childPosition);

                    } else if (control.equals("enum")) {
                        convertView = LayoutInflater.from(mCtx).inflate(R.layout.common_editor_enum_cell_small,null);
                        holder = new CommonEditorEnumCellHolder(mCtx,convertView);
                        setUpEnumCellHolder((CommonEditorEnumCellHolder)holder,convertView,item_json,readonly,groupPosition,childPosition);

                    } else if (control.equals("model")) {
                        convertView = LayoutInflater.from(mCtx).inflate(R.layout.common_editor_model_cell,null);
                        holder = new CommonEditorModelCellHolder(mCtx,convertView);
                        setUpModelCellHolder((CommonEditorModelCellHolder)holder,convertView,item_json,readonly,groupPosition,childPosition);

                    } else if (control.equals("datepicker")) {
                        convertView = LayoutInflater.from(mCtx).inflate(R.layout.common_editor_enum_cell_small,null);
                        holder = new CommonEditorEnumCellHolder(mCtx,convertView);
                        setUpDatePickerCellHolder((CommonEditorEnumCellHolder)holder,convertView,item_json,readonly,groupPosition,childPosition);

                    } else if (control.equals("monthpicker")) {
                        convertView = LayoutInflater.from(mCtx).inflate(R.layout.common_editor_enum_cell_small,null);
                        holder = new CommonEditorEnumCellHolder(mCtx,convertView);
                        setUpMonthPickerCellHolder((CommonEditorEnumCellHolder)holder,convertView,item_json,readonly,groupPosition,childPosition);

                    } else if (control.equals("signature")) {
                        convertView = LayoutInflater.from(mCtx).inflate(R.layout.common_editor_signature_cell_small,null);
                        holder = new CommonEditorSignatureCellHolder(mCtx,convertView);
                        setUpSignatureCellHolder((CommonEditorSignatureCellHolder)holder,convertView,item_json,readonly,groupPosition,childPosition);

                    }  else if (control.equals("range")) {

                        String type = item_json.optString("type");
                        if (type != null && type.equals("date")) {
                            convertView = LayoutInflater.from(mCtx).inflate(R.layout.common_editor_date_range_cell,null);
                            holder = new CommonEditorDateRangeCellHolder(mCtx,convertView);
                            setUpDateRangeCellHolder((CommonEditorDateRangeCellHolder)holder,convertView,item_json,readonly,groupPosition,childPosition);
                        } else {
                            convertView = LayoutInflater.from(mCtx).inflate(R.layout.common_editor_range_cell,null);
                            holder = new CommonEditorRangeCellHolder(mCtx,convertView);
                            setUpRangeCellHolder((CommonEditorRangeCellHolder)holder,convertView,item_json,readonly,groupPosition,childPosition);
                        }



                    } else {
                        convertView = LayoutInflater.from(mCtx).inflate(R.layout.common_editor_edit_cell_small,null);
                        holder = new CommonEditorEditCellHolder(mCtx,convertView);
                        setUpEditCellHolder((CommonEditorEditCellHolder)holder,convertView,item_json,readonly,groupPosition,childPosition);

                    }
                } else {
                    convertView = LayoutInflater.from(mCtx).inflate(R.layout.common_editor_edit_cell_small,null);
                    holder = new CommonEditorEditCellHolder(mCtx,convertView);
                    setUpEditCellHolder((CommonEditorEditCellHolder)holder,convertView,item_json,readonly,groupPosition,childPosition);
                }

            } else {

                if (control != null) {
                    if (control.equals("text_view")) {
                        holder = (CommonEditorTextViewCellHolder)convertView.getTag();
                        setUpTextViewCellHolder((CommonEditorTextViewCellHolder) holder,convertView,item_json,readonly,groupPosition,childPosition);

                    } else if (control.equals("img")) {
                        holder = (CommonEditorImageCellHolder)convertView.getTag();
                        setUpImageCellHolder((CommonEditorImageCellHolder)holder,convertView,item_json,readonly,groupPosition,childPosition);

                    } else if (control.equals("edit")) {

                        String autoComplete = item_json.optString("autocomplete");
                        if (autoComplete != null && autoComplete.equals("true")) {
                            holder = (CommonEditorEditAutoCompleteCellHolder)convertView.getTag();
                            setUpEditAutoCompleteCellHolder((CommonEditorEditAutoCompleteCellHolder) holder,convertView,item_json,readonly,groupPosition,childPosition);
                        } else {
                            holder = (CommonEditorEditCellHolder)convertView.getTag();
                            setUpEditCellHolder((CommonEditorEditCellHolder)holder,convertView,item_json,readonly,groupPosition,childPosition);
                        }


                    } else if (control.equals("text")) {
                        holder = (CommonEditorLabelCellHolder)convertView.getTag();
                        setUpLabelCellHolder((CommonEditorLabelCellHolder)holder,convertView,item_json,readonly,groupPosition,childPosition);

                    } else if (control.equals("action")) {
                        holder = (CommonEditorActionCellHolder)convertView.getTag();
                        setUpActionCellHolder((CommonEditorActionCellHolder)holder,convertView,item_json,readonly,groupPosition,childPosition);

                    } else if (control.equals("multi_action")) {
                        holder = (CommonEditorMultipleActionCellHolder)convertView.getTag();
                        setUpMultipleActionCellHolder((CommonEditorMultipleActionCellHolder)holder,convertView,item_json,readonly,groupPosition,childPosition);

                    } else if (control.equals("switch")) {
                        holder = (CommonEditorSwitchCellHolder)convertView.getTag();
                        setUpSwitchCellHolder((CommonEditorSwitchCellHolder)holder,convertView,item_json,readonly,groupPosition,childPosition);

                    } else if (control.equals("enum")) {
                        holder = (CommonEditorEnumCellHolder)convertView.getTag();
                        setUpEnumCellHolder((CommonEditorEnumCellHolder)holder,convertView,item_json,readonly,groupPosition,childPosition);

                    } else if (control.equals("model")) {
                        holder = (CommonEditorModelCellHolder)convertView.getTag();
                        setUpModelCellHolder((CommonEditorModelCellHolder)holder,convertView,item_json,readonly,groupPosition,childPosition);

                    } else if (control.equals("datepicker")) {
                        holder = (CommonEditorEnumCellHolder)convertView.getTag();
                        setUpDatePickerCellHolder((CommonEditorEnumCellHolder)holder,convertView,item_json,readonly,groupPosition,childPosition);

                    } else if (control.equals("monthpicker")) {
                        holder = (CommonEditorEnumCellHolder)convertView.getTag();
                        setUpMonthPickerCellHolder((CommonEditorEnumCellHolder)holder,convertView,item_json,readonly,groupPosition,childPosition);

                    } else if (control.equals("signature")) {
                        holder = (CommonEditorSignatureCellHolder)convertView.getTag();
                        setUpSignatureCellHolder((CommonEditorSignatureCellHolder)holder,convertView,item_json,readonly,groupPosition,childPosition);

                    }  else if (control.equals("range")) {

                        String type = item_json.optString("type");
                        if (type != null && type.equals("date")) {
                            holder = (CommonEditorDateRangeCellHolder)convertView.getTag();
                            setUpDateRangeCellHolder((CommonEditorDateRangeCellHolder)holder,convertView,item_json,readonly,groupPosition,childPosition);
                        } else {
                            holder = (CommonEditorRangeCellHolder)convertView.getTag();
                            setUpRangeCellHolder((CommonEditorRangeCellHolder)holder,convertView,item_json,readonly,groupPosition,childPosition);
                        }


                    }  else {
                        holder = (CommonEditorEditCellHolder)convertView.getTag();
                        setUpEditCellHolder((CommonEditorEditCellHolder)holder,convertView,item_json,readonly,groupPosition,childPosition);

                    }
                } else {
                    holder = (CommonEditorEditCellHolder)convertView.getTag();
                    setUpEditCellHolder((CommonEditorEditCellHolder)holder,convertView,item_json,readonly,groupPosition,childPosition);

                }

            }

            return convertView;
        }

        @Override
        public boolean isChildSelectable(int groupPosition, int childPosition) {
            return true;
        }

        @Override
        public int getChildTypeCount() {

            return 14;
        }

        @Override
        public int getChildType(int groupPosition, int childPosition) {
            JSONObject item_json = (JSONObject) getChild(groupPosition,childPosition);
            String control;
            try {
                control = item_json.getString("control");

            } catch (Exception e) {
                e.printStackTrace();
                return COMMON_EDITOR_CELL_TYPE_EDIT;
            }

            if (control != null) {
                if (control.equals("text_view")) {
                    return COMMON_EDITOR_CELL_TYPE_TEXT_VIEW;
                } else if (control.equals("img")) {
                    return COMMON_EDITOR_CELL_TYPE_IMAGE;
                } else if (control.equals("edit")) {
                    String autoComplete = item_json.optString("autocomplete");
                    if (autoComplete != null && autoComplete.equals("true")) {
                        return COMMON_EDITOR_CELL_TYPE_AUTO_COMPLETE;
                    } else {
                        return COMMON_EDITOR_CELL_TYPE_EDIT;
                    }
                } else if (control.equals("text")) {
                    return COMMON_EDITOR_CELL_TYPE_LABLE;
                } else if (control.equals("action")) {
                    return COMMON_EDITOR_CELL_TYPE_ACTION;
                } else if (control.equals("multi_action")) {
                    return COMMON_EDITOR_CELL_TYPE_MULTIPLE_ACTION;
                } else if (control.equals("switch")) {
                    return COMMON_EDITOR_CELL_TYPE_SWITCH;
                } else if (control.equals("enum")) {
                    return COMMON_EDITOR_CELL_TYPE_ENUM;
                } else if (control.equals("model")) {
                    return COMMON_EDITOR_CELL_TYPE_MODEL;
                } else if (control.equals("datepicker")) {
                    return COMMON_EDITOR_CELL_TYPE_ENUM;
                } else if (control.equals("monthpicker")) {
                    return COMMON_EDITOR_CELL_TYPE_ENUM;
                } else if (control.equals("signature")) {
                    return COMMON_EDITOR_CELL_TYPE_SIGNATURE;
                } else if (control.equals("header")){
                    return COMMON_EDITOR_CELL_TYPE_SECTION_HEADER;
                } else if (control.equals("range")){
                    String type = item_json.optString("type");
                    if (type != null && type.equals("date")) {
                        return COMMON_EDITOR_CELL_TYPE_DATE_RANGE;
                    } else {
                        return COMMON_EDITOR_CELL_TYPE_RANGE;
                    }

                } else {
                    return COMMON_EDITOR_CELL_TYPE_EDIT;
                }
            } else {
                return COMMON_EDITOR_CELL_TYPE_EDIT;
            }
        }
    }

    public class ListChildViewClickListener implements ExpandableListView.OnChildClickListener {

        String requesturl = null;
        @Override
        public boolean onChildClick(ExpandableListView parent, View v, int groupPosition, int childPosition, long id) {
            try {

                Intent intent = null;
                int request_code = -1;

                boolean readonly = content_data_download.optBoolean("readonly");

                JSONObject item_json = content_data_control.optJSONArray(groupPosition).optJSONObject(childPosition);
                String control = item_json.optString("control");
                if (control.equals("enum")) {
                    int disable = item_json.optInt("disable");
                    if (disable == 1 || readonly) {
                        return false;
                    }
                    JSONObject cadedate_json = item_json.optJSONObject("cadedate");
                    String single_select = item_json.optString("single_select");
                    String title = item_json.optString("aname");
                    int max_select = item_json.optInt("max");
                    boolean singleSelect = single_select.toLowerCase().equals("true");
                    String cadedate_str = cadedate_json.toString();
                    intent = new EnumSlectActivity.Builder().build(mCtx,title,max_select,groupPosition,childPosition,cadedate_str,singleSelect,true);
                    boolean sort = item_json.getBoolean("sort");
                    if (sort) {
                        intent = new EnumSelectAndSortActivity.Builder().build(mCtx,title,max_select,groupPosition,childPosition,cadedate_str,singleSelect,true);
                    }
                    request_code = 10;

                } // enum
                else if (control.equals("action")) {

                    String value = item_json.optString("value");
                    if (value.equals("new_addr")) {
                        AddressEditorActivity.Builder builder = new AddressEditorActivity.Builder();
                        intent = builder.build(mCtx,URL_REMOTE,requesturl,null,null,groupPosition,childPosition);
                        request_code = 2;

                    } // new addr
                    else if (value.equals("credit_card")) {

                        JSONObject data = item_json.optJSONObject("data");
                        int url_type;
                        JSONObject download_data;
                        if (data != null) {
                            download_data = data;
                            url_type = URL_NONE;
                            requesturl = null;
                        } else {
                            download_data = null;
                            url_type = URL_REMOTE;
                            requesturl = "";
                        }
                        intent = new CreditCardEditorActivity.Builder().build(mCtx,url_type,requesturl,Application.order_code,null,null,download_data,groupPosition,childPosition);
                        request_code = 3;
                    }
                    else if (value.equals("Sales_Order_Freight_Bill_To")) {

                        request_code = 4;
                        intent = new ContactListActivity.Builder().build(mCtx,null,null,value,true,groupPosition,childPosition);

                    }
                    else if (value.equals("Sales_Order_Ship_From")) {

                        request_code = 5;
                        intent = new ContactListActivity.Builder().build(mCtx,null,null,value,true,groupPosition,childPosition);

                    }
                    else if (value.equals("Sales_Order_Customer")) {

                        request_code = 6;
                        intent = new ContactListActivity.Builder().build(mCtx,null,null,value,true,groupPosition,childPosition);

                    }
                    else if (value.equals("Sales_Order_Merchandise_Bill_To")) {

                        request_code = 7;
                        intent = new ContactListActivity.Builder().build(mCtx,null,null,value,true,groupPosition,childPosition);

                    }
                    else if (value.equals("Contact_Return_To")) {

                        request_code = 8;
                        intent = new ContactListActivity.Builder().build(mCtx,null,null,value,true,groupPosition,childPosition);

                    }
                    else if (value.equals("Sales_Order_Ship_To")) {

                        request_code = 9;
                        intent = new ContactListActivity.Builder().build(mCtx,null,null,value,true,groupPosition,childPosition);
                    }

                } // action
                else if (control.equals("datepicker")) {

                    request_code = 11;

                    String value = item_json.optString("value");
                    String type = item_json.optString("type");

                    SimpleDateFormat dateFormatter = new SimpleDateFormat();
                    int pickerMode = 0;
                    if (type.toLowerCase().equals("date")) {
                        pickerMode = 0; // Date
                        dateFormatter.applyPattern("yyyy/MM/dd");
                    }
                    else if (type.toLowerCase().equals("time")) {
                        pickerMode = 1; // time
                        dateFormatter.applyPattern("HH:mm:ss");
                    }
                    else {
                        pickerMode = 2; // date and time
                        dateFormatter.applyPattern("yyyy/MM/dd HH:mm:ss");
                    }

                    Date date = dateFormatter.parse(value);
                    intent = new DatePickerActivity.Builder().build(mCtx,date,dateFormatter,pickerMode,value,groupPosition,childPosition);


                } // date picker
                else if (control.equals("monthpicker")) {

                    request_code = 12;
                    String value = item_json.optString("value");
                    if (value == null || value.isEmpty()) {
                        value = "1/2017";
                    }


                    intent = new MonthPickerActivity.Builder().build(mCtx,value,groupPosition,childPosition);

                } // month picker
                else if (control.equals("signature")) {

                    request_code = 13;
                    intent = new SignatureActivity.Builder().build(mCtx,groupPosition,childPosition);

                }

                if (intent != null) {
                    startActivityForResult(intent,request_code);
                }

            } catch (Exception e) {
                e.printStackTrace();
            }
            return false;
        }
    }

    public boolean cancommit = false;


    public void setUpTextViewCellHolder(CommonEditorTextViewCellHolder holder, View cell, JSONObject item_json, boolean readonly, int group, int child) {
        String control = null;
        String required = null;
        String title = null;
        String value = null;
        String align = "";
        int capital = 0;
        int disable = 0;

        // 重用时先保存
        if (holder.text_view.getText().length() > 0) {
            editTextEndEditing(holder.text_view,false,holder.group,holder.child);
        }

        holder.group = group;
        holder.child = child;
        holder.title_lb.setText(null);
        holder.text_view.setText(null);

        try {
            control = item_json.optString("control");
            required = item_json.optString("required");
            title = item_json.optString("aname");
            value = item_json.optString("value");
            align = item_json.optString("align");
            capital = item_json.optInt("capital");
            disable = item_json.optInt("disable");

        } catch (Exception e) {
            e.printStackTrace();
        }

        if (align.equals("right")) {
            holder.text_view.setGravity(TOP | RIGHT);
        } else {
            holder.text_view.setGravity(TOP | LEFT);
        }

        /**设置大写模式*/
        switch (capital) {
            case 1: {
                holder.text_view.setInputType(InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_FLAG_MULTI_LINE | InputType.TYPE_TEXT_FLAG_IME_MULTI_LINE | InputType.TYPE_TEXT_FLAG_CAP_WORDS);
            }
            break;
            case 2: {
                holder.text_view.setInputType(InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_FLAG_MULTI_LINE | InputType.TYPE_TEXT_FLAG_IME_MULTI_LINE  | InputType.TYPE_TEXT_FLAG_CAP_SENTENCES);
            }
            break;
            case 3: {
                holder.text_view.setInputType(InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_FLAG_MULTI_LINE | InputType.TYPE_TEXT_FLAG_IME_MULTI_LINE  | InputType.TYPE_TEXT_FLAG_CAP_CHARACTERS);
            }
            break;
            default: {
                holder.text_view.setInputType(InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_FLAG_MULTI_LINE | InputType.TYPE_TEXT_FLAG_IME_MULTI_LINE  | InputType.TYPE_TEXT_FLAG_CAP_WORDS);
            }
            break;
        }

        if (disable == 1 || readonly) {
            holder.text_view.setEnabled(false);
            holder.text_view.setTextColor(Color.LTGRAY);
        } else {
            holder.text_view.setEnabled(true);
            holder.text_view.setTextColor(Color.BLACK);
        }

        holder.title_lb.setText(title);

        holder.text_view.setTag(group + "_" + child + "_" + "TextView");
        holder.text_view.setText(value);
        holder.text_view.addTextChangedListener(new TextViewTextWatcher(mCtx,holder.text_view,group,child));
        holder.text_view.setOnFocusChangeListener(new EditTextFocusListener(mCtx,holder.text_view,group,child));


        if (required.equals("true")) {
            holder.startMark.setVisibility(View.VISIBLE);
        } else {
            holder.startMark.setVisibility(View.INVISIBLE);
        }

        if (cancommit == false && required.equals("true") && (value == null || value.length() == 0)) {
            // 阴影 red
            holder.title_lb.setBackground(getResources().getDrawable(R.drawable.red_border));
        } else {
            // 无阴影
            holder.title_lb.setBackground(null);
        }

    }

    public void setUpImageCellHolder(CommonEditorImageCellHolder holder, View cell, JSONObject item_json, boolean readonly, int group, int child) {

        String title = null;
        String value = null;
        String img_url_0 = null;
        String img_url_1 = null;
        String img_url_2 = null;
        String img_url_up_0 = null;
        String img_url_up_1 = null;
        String img_url_up_2 = null;
        int disable = 0;

        holder.group = group;
        holder.child = child;
        holder.title_lb.setText(null);
        holder.desc_lb.setText(null);
        holder.img_btn_0.setImageBitmap(null);
        holder.img_btn_1.setImageBitmap(null);
        holder.img_btn_2.setImageBitmap(null);

//        LinearLayout.LayoutParams layoutParams0 = (LinearLayout.LayoutParams)holder.img_btn_0.getLayoutParams();
//        layoutParams0.height = layoutParams0.width;
//        holder.img_btn_0.setLayoutParams(layoutParams0);
//
//        LinearLayout.LayoutParams layoutParams1 = (LinearLayout.LayoutParams)holder.img_btn_1.getLayoutParams();
//        layoutParams1.height = layoutParams1.width;
//        holder.img_btn_1.setLayoutParams(layoutParams1);
//
//        LinearLayout.LayoutParams layoutParams2 = (LinearLayout.LayoutParams)holder.img_btn_2.getLayoutParams();
//        layoutParams2.height = layoutParams2.width;
//        holder.img_btn_2.setLayoutParams(layoutParams2);

        try {

            title = item_json.optString("aname");
            value = item_json.optString("value");
            disable = item_json.optInt("disable");
            img_url_0 = item_json.optString("img_url_0");
            img_url_up_0 = item_json.optString("img_url_aname_0");
            img_url_1 = item_json.optString("img_url_1");
            img_url_up_1 = item_json.optString("img_url_aname_1");
            img_url_2 = item_json.optString("img_url_2");
            img_url_up_2 = item_json.optString("img_url_aname_2");

        } catch (Exception e) {
            e.printStackTrace();
        }

        if (disable == 1 || readonly) {
            holder.editable = false;
        } else {
            holder.editable = true;
        }

        holder.title_lb.setText(title);
        holder.desc_lb.setText(value);

        Bitmap placeHolder = BitmapFactory.decodeResource(getResources(),R.drawable.not_found);
        if (img_url_0 != null && !img_url_0.isEmpty()) {
            Bitmap bmp0 = Utils.loadCacheImage(img_url_up_0,placeHolder);
            if (bmp0 != null) {
                holder.setImage0(img_url_up_0,bmp0);
            } else {
                // 异步记载数据
                loadImageForPosition(group,child,0,img_url_up_0);
            }
        }

        if (img_url_1 != null && !img_url_1.isEmpty()) {
            Bitmap bmp1 = Utils.loadCacheImage(img_url_up_1,placeHolder);
            if (bmp1 != null) {
                holder.setImage1(img_url_up_1,bmp1);
            } else {
                // 异步记载数据
                loadImageForPosition(group,child,1,img_url_up_1);
            }
        }

        if (img_url_2 != null && !img_url_2.isEmpty()) {
            Bitmap bmp2 = Utils.loadCacheImage(img_url_up_2,placeHolder);
            if (bmp2 != null) {
                holder.setImage2(img_url_up_2,bmp2);
            } else {
                // 异步记载数据
                loadImageForPosition(group,child,2,img_url_up_2);
            }
        }

    }

    private void loadImageForPosition(int group, int child, int item_tag, final String path) {

//        return;

        if (path == null || path.isEmpty()) {
            return;
        }
        new Thread(new Runnable() {
            @Override
            public void run() {
                HttpURLConnection cnn = null;
                Bitmap bitmap = null;


                try {

                    bitmap = Utils.loadCacheImage(path,null);


                    if (bitmap == null) {
                        URL url = new URL(path);
                        cnn = (HttpURLConnection)url.openConnection();
                        cnn.setRequestMethod("GET");
                        cnn.setUseCaches(false);
                        cnn.setConnectTimeout(1500);
                        cnn.setReadTimeout(1500);
                        bitmap = BitmapFactory.decodeStream(cnn.getInputStream());
                        if (bitmap == null) {
                            // 缓存not found
                            bitmap = BitmapFactory.decodeResource(getResources(),R.drawable.not_found);
                        }
                    }


                } catch (IOException e) {
                    e.printStackTrace();

                    bitmap = BitmapFactory.decodeResource(getResources(),R.drawable.not_found);

                } finally {
                    if (cnn != null) {
                        cnn.disconnect();
                    }
                    if (bitmap == null) {
                        bitmap = BitmapFactory.decodeResource(getResources(),R.drawable.not_found);
                    }
                    Utils.cacheImage(path,bitmap);
                    // 更新数据，刷新行
                    runOnUiThread(new Runnable() {
                        @Override
                        public void run() {
                            adapter.notifyDataSetChanged();
                        }
                    });
                }
            }
        }).start();
    }

    public void setUpEditCellHolder(final CommonEditorEditCellHolder holder, View cell, JSONObject item_json, boolean readonly, int group, int child) {
        String title = null;
        String value = null;
        String align = null;
        int capital = 0;
        int disable = 0;
        String keyboard = null;
        String required = null;

       if (holder.textWatcher != null) {
           holder.text_field.removeTextChangedListener(holder.textWatcher);
       }
        // 重用时先保存
        if (holder.text_field.getText().length() > 0) {
            editTextEndEditing(holder.text_field,true,holder.group,holder.child);
        }
        holder.group = group;
        holder.child = child;
        holder.name_lb.setText(null);
        holder.text_field.setText(null);

        try {

            required = item_json.optString("required");
            title = item_json.optString("aname");
            value = item_json.optString("value");
            align = item_json.optString("align");
            capital = item_json.optInt("capital");
            disable = item_json.optInt("disable");
            keyboard = item_json.optString("keyboard");

            if (!keyboard.equals("number") && !keyboard.equals("int")) {
                holder.text_field.setFilters(new InputFilter[]{});
            } else {
                int lenght = item_json.optInt("length");
                holder.text_field.setFilters(new InputFilter[]{new InputFilter.LengthFilter(lenght)});
            }


        } catch (Exception e) {
            e.printStackTrace();
        }

        if (align != null && align.equals("right")) {
            holder.text_field.setGravity(CENTER_VERTICAL | RIGHT);
        } else {
            holder.text_field.setGravity(CENTER_VERTICAL | LEFT);
        }

        int inputType = 0;
        /**设置大写模式*/
        switch (capital) {
            case 1: {
                inputType |= EditorInfo.TYPE_TEXT_FLAG_CAP_WORDS;
            }
            break;
            case 2: {
                inputType |= EditorInfo.TYPE_TEXT_FLAG_CAP_SENTENCES;
            }
            break;
            case 3: {
                inputType |= EditorInfo.TYPE_TEXT_FLAG_CAP_CHARACTERS;
            }
            break;
            default: {
                inputType |= EditorInfo.TYPE_TEXT_FLAG_CAP_WORDS;
            }
            break;
        }

        if (keyboard != null) {
            if (keyboard.equals("number")) {
                inputType |= EditorInfo.TYPE_CLASS_NUMBER;
            } else if (keyboard.equals("email")) {
                inputType |= EditorInfo.TYPE_TEXT_VARIATION_EMAIL_ADDRESS;
            } else if (keyboard.equals("phone")) {
                inputType |= EditorInfo.TYPE_CLASS_PHONE;
            } else {
                inputType |= EditorInfo.TYPE_CLASS_TEXT;
            }
        }

        holder.text_field.setInputType(inputType);

        if (disable == 1 || readonly) {
            holder.text_field.setEnabled(false);
            holder.text_field.setTextColor(Color.LTGRAY);
        } else {
            holder.text_field.setEnabled(true);
            holder.text_field.setTextColor(Color.BLACK);
        }

        holder.name_lb.setText(title);

        holder.text_field.setTag(group + "_" + child + "_" + "TextFiled");
        holder.text_field.setText(value);
        if (holder.textWatcher == null) {
            TextFieldTextWatcher textWatcher = new TextFieldTextWatcher(mCtx,holder.text_field,group,child);
            holder.text_field.addTextChangedListener(textWatcher);
            holder.textWatcher = textWatcher;
        } else {
            TextFieldTextWatcher textWatcher = (TextFieldTextWatcher)holder.textWatcher;
            holder.text_field.addTextChangedListener(textWatcher);
            textWatcher.group = group;
            textWatcher.child = child;
        }
        holder.text_field.setOnFocusChangeListener(new EditTextFocusListener(mCtx,holder.text_field,group,child));




        if (required != null && required.equals("true")) {
            holder.startMark.setVisibility(View.VISIBLE);
        } else {
            holder.startMark.setVisibility(View.INVISIBLE);
        }

        if (cancommit == false && required != null && required.equals("true") && (value == null || value.length() == 0)) {
            // 阴影 red
            holder.name_lb.setBackground(getResources().getDrawable(R.drawable.red_border));
        } else {
            // 无阴影
            holder.name_lb.setBackground(null);
        }




    }


    public void setUpEditAutoCompleteCellHolder(final CommonEditorEditAutoCompleteCellHolder holder, View cell, JSONObject item_json, boolean readonly, int group, int child) {
        setUpEditCellHolder(holder,cell,item_json,readonly,group,child);


        holder.text_field.setThreshold(1);
        if (holder.autoCompleteAdapter == null) {
           int resourceId = R.layout.common_editor_auto_complete_list_cell;
           int textViewId = R.id.auto_complete_value_tv;
           CommonEditorAutoCompleteAdapter autoCompleteAdapter = new CommonEditorAutoCompleteAdapter(mCtx,resourceId, textViewId);
           holder.text_field.setAdapter(autoCompleteAdapter);
           holder.autoCompleteAdapter = autoCompleteAdapter;
        } else {
            ((CommonEditorAutoCompleteAdapter)holder.text_field.getAdapter()).clear();
        }


    }

    private boolean can_see_price = true;
    private boolean price_hidden = false;
    public void setUpLabelCellHolder(CommonEditorLabelCellHolder holder, View cell, JSONObject item_json, boolean readonly, int group, int child) {

        String title = null;
        String value = null;
        String align = null;
        String color = null;
        String type = null;

        holder.group = group;
        holder.child = child;
        holder.title_lb.setText(null);
        holder.value_lb.setText(null);

        try {

            title = item_json.optString("aname");
            value = item_json.optString("value");
            align = item_json.optString("align");
            color = item_json.optString("color");
            type = item_json.optString("type");


        } catch (Exception e) {
            e.printStackTrace();
        }

        if (align.equals("right")) {
            holder.value_lb.setGravity(CENTER_VERTICAL | RIGHT);
        } else {
            holder.value_lb.setGravity(CENTER_VERTICAL | LEFT);
        }

        if (type.equals("price")) {
            if (can_see_price && price_hidden == false) {

            } else {
                value = null;
            }
        }

        if (color.toLowerCase().equals("red")) {
            holder.value_lb.setTextColor(Color.RED);
        } else {
            holder.value_lb.setTextColor(Color.BLACK);
        }

        holder.title_lb.setText(title);
        holder.value_lb.setText(value);

    }


    public void setUpActionCellHolder(CommonEditorActionCellHolder holder, View cell, JSONObject item_json, boolean readonly, int group, int child) {

        String title = null;
        String value = null;
        String required = null;
        JSONObject data = null;

        holder.group = group;
        holder.child = child;
        holder.action_lb.setText(null);

        try {
            title = item_json.optString("aname");
            value = item_json.optString("value");
            required = item_json.optString("required");
            data = item_json.optJSONObject("data");

        } catch (Exception e) {
            e.printStackTrace();
        }

        if (required.equals("true")) {
            title = title + "*";
        }

        holder.action_lb.setText(title);
        holder.action_code = value;

        if (cancommit && required.equals("true") && data == null) {
            // Shadow red
        } else {
            // no shadow
        }

    }

    public void setUpMultipleActionCellHolder(CommonEditorMultipleActionCellHolder holder, View cell, JSONObject item_json, boolean readonly, int group, int child) {

        int count = 0;

        holder.group = group;
        holder.child = child;

        try {
            count = item_json.optInt("count");
            for (int i = 0; i < count; i++) {
                JSONObject sub_action = item_json.optJSONObject("item_" + i);
                String title = sub_action.optString("aname");
                Button btn = null;
                switch (i) {
                    case 0: {
                        btn = holder.btn0;
                    }
                    break;
                    case 1: {
                        btn = holder.btn1;
                    }
                    break;
                    case 2: {
                        btn = holder.btn2;
                    }
                    break;
                    case 3: {
                        btn = holder.btn3;
                    }
                    break;
                }
                if (btn != null) {
                    btn.setText(title);
                    btn.setOnClickListener(multipleActionClickListener);
                    btn.setVisibility(View.VISIBLE);
                    btn.setTag(group + "_" + child + "_" + i);
                }
            }
            if (count < 4) {
                holder.btn3.setVisibility(View.INVISIBLE);
            }
            if (count < 3) {
                holder.btn2.setVisibility(View.INVISIBLE);
            }
            if (count < 2) {
                holder.btn1.setVisibility(View.INVISIBLE);
            }
            if (count < 1) {
                holder.btn0.setVisibility(View.INVISIBLE);
            }

        } catch (Exception e) {
            e.printStackTrace();
        }

    }

    public void setUpSwitchCellHolder(CommonEditorSwitchCellHolder holder, View cell, JSONObject item_json, boolean readonly, int group, int child) {

        String title = null;
        String value = null;
        String required = null;

        holder.group = group;
        holder.child = child;
        holder.title_lb.setText(null);
        holder.aSwitch.setTag(group + "_" + child + "_" + "switch");
        try {

            title = item_json.optString("aname");
            value = item_json.optString("value");
            required = item_json.optString("required");

            holder.title_lb.setText(title);

            if (required.equals("true")) {
                holder.startMark.setVisibility(View.VISIBLE);
            } else {
                holder.startMark.setVisibility(View.INVISIBLE);
            }


            holder.aSwitch.setOnCheckedChangeListener(null);
            if (value.toLowerCase().equals("true")) {
                holder.aSwitch.setChecked(true);
            } else {
                holder.aSwitch.setChecked(false);
            }
            holder.aSwitch.setOnCheckedChangeListener(new SwitchCheckListener());


        } catch (Exception e) {
            e.printStackTrace();
        }

    }

    public void setUpEnumCellHolder(CommonEditorEnumCellHolder holder, View cell, JSONObject item_json, boolean readonly, int group, int child) {
        String title = null;
        String value = "";
        JSONObject cadedate_json = null;
        int disable = 0;
        String align = null;
        String required = null;

        holder.group = group;
        holder.child = child;
        holder.title_lb.setText(null);
        holder.value_lb.setText(null);

        try {

            title = item_json.optString("aname");
            cadedate_json = item_json.optJSONObject("cadedate");
            disable = item_json.optInt("disable");
            align = item_json.optString("align");
            required = item_json.optString("required");

            if (disable == 1 && readonly) {
                holder.value_lb.setTextColor(Color.LTGRAY);
            } else {
                holder.value_lb.setTextColor(Color.BLACK);
            }

            if (align != null && align.equals("right")) {
                holder.value_lb.setGravity(CENTER_VERTICAL | RIGHT);
            } else {
                holder.value_lb.setGravity(CENTER_VERTICAL | LEFT);
            }

            int count = cadedate_json.optInt("count");
            for (int i = 0; i < count; i++) {
                JSONObject val_json = cadedate_json.optJSONObject("val_" + i);
                if (val_json != null) {
                    int check = val_json.optInt("check");
                    if (check == 1) {
                        value += val_json.getString("value") + " | ";
                    }
                }
            }
            if (value.length() > 1) {
                value = value.substring(0,value.length() - 3);
            }

            holder.value_lb.setText(value);
            holder.title_lb.setText(title);

            if (required.equals("true")) {
                holder.startMark.setVisibility(View.VISIBLE);
            } else {
                holder.startMark.setVisibility(View.INVISIBLE);
            }


            if (cancommit == false && required.equals("true") && (value == null || value.length() == 0)) {
                // 阴影 red
                holder.title_lb.setBackground(getResources().getDrawable(R.drawable.red_border));
            } else {
                // 无阴影
                holder.title_lb.setBackground(null);
            }

        } catch (Exception e) {
            e.printStackTrace();
        }

    }

    public void setUpModelCellHolder(CommonEditorModelCellHolder holder, View cell, JSONObject item_json, boolean readonly, int group, int child) {


        holder.group = group;
        holder.child = child;
        holder.model_img_btn.setImageBitmap(null);
        holder.desc_lb.setText(null);
        holder.master_pack_lb.setText(null);
        holder.old_price_lb.setText(null);
        holder.discount_lb.setText(null);
        holder.unit_price_lb.setText(null);
        holder.discount_lb.setText(null);
        holder.bundle_btn.setText(null);
        holder.total_price_lb.setText(null);

        try {
            int count = item_json.optInt("count");
            JSONObject combine_json = item_json.optJSONObject("combine");
            holder.bundle_item = combine_json;
            double dprice = 0.0f;
            if (holder.bundle_item != null) {
                int citem = 0;
                int bcount = holder.bundle_item.optInt("count");
                for (int bc = 0; bc < bcount; bc++) {
                    JSONObject bitem = holder.bundle_item.optJSONObject("item_" + bc);
                    int modulus = bitem.optInt("modulus");
                    citem += modulus;
                    double uprice = bitem.optDouble("unit_price");
                    dprice += uprice * modulus;
                }
                if (citem == 1) {
                    holder.bundle_btn.setText(String.format("%d bundle item with price of $ %.2f",citem,dprice));
                } else {
                    holder.bundle_btn.setText(String.format("%d bundle items with price of $ %.2f",citem,dprice));
                }
                holder.bundle_btn.setVisibility(View.VISIBLE);
            } else {
                holder.bundle_btn.setVisibility(View.INVISIBLE);
            }

            String availability = item_json.optString("quantity_available");
            String available_str = "Available Now";
            if (isNumber(availability) && Integer.valueOf(availability) > 0) {
                available_str = String.format("Available: %s",availability);
            } else {
                available_str = "Available: In Production";
            }
            holder.count_lb.setText(available_str);

            String img_url = item_json.optString("img_url");
            String description = item_json.optString("description");
            double unitprice = item_json.optDouble("unit_price");
            int stockUom = item_json.optInt("stockUom");

            double discount = 0.0;
            String dis_str = item_json.optString("discount");
            if (dis_str == null || dis_str.isEmpty()) {
                discount = 0.0;
            } else {
                discount = Double.valueOf(dis_str);
            }
            String discount_str = String.format("%s%% off",floatFormat(discount));

            String oldprice = String.format("%.2f",unitprice);
            String new_unit_price = "";
            if (dprice > 0) {
                new_unit_price = String.format("%.2f+%.2f",unitprice* (1.0-discount/100),dprice);
            } else {
                new_unit_price = String.format("%.2f",unitprice* (1.0-discount/100));
            }
            String totalprice = String.format("%.2f",(unitprice* (1.0-discount/100)+dprice)*count);

            if (can_see_price ==true && price_hidden == false) {

            } else {
                oldprice = null;
                new_unit_price = null;
                totalprice = null;
            }

            holder.discount_lb.setText(discount_str);
            holder.old_price_lb.setText(oldprice);
            holder.master_pack_lb.setText(String.format("Sold in QTY of:%d", stockUom));

            boolean isfree = item_json.optBoolean("is_free");

            if (isfree) {
                holder.old_price_lb.setVisibility(View.VISIBLE);
                holder.old_price_lb.setTextColor(Color.RED);
                holder.old_price_lb.setText("Free");
                holder.discount_lb.setVisibility(View.INVISIBLE);
                // old_price_lb.hideline = true
            } else {
                holder.old_price_lb.setTextColor(Color.BLACK);
                // old_price_lb.hideline = false
                if (discount == 0) {
                    holder.old_price_lb.setVisibility(View.INVISIBLE);
                    holder.discount_lb.setVisibility(View.INVISIBLE);
                } else {
                    holder.old_price_lb.setVisibility(View.VISIBLE);
                    holder.discount_lb.setVisibility(View.VISIBLE);
                }
            }

            holder.desc_lb.setText(description);
            holder.count_lb.setText(String.format("x %d",count));
            holder.total_price_lb.setText(totalprice);
            holder.unit_price_lb.setText(new_unit_price);

            img_url = "http://img.gank.io/6ade6383-bc8e-40e4-9919-605901ad0ca5?imageView2/0/w/100";
            Bitmap placeHolder = BitmapFactory.decodeResource(getResources(),R.drawable.not_found);
            Bitmap bmp = Utils.loadCacheImage(img_url,placeHolder);
            if (bmp != null) {
                holder.model_img_btn.setImageBitmap(bmp);
            } else {
                // 异步记载数据
                loadImageForPosition(group,child,0,img_url);
            }

        } catch (Exception e) {
            e.printStackTrace();
        }

    }
    /**
     * 利用正则表达式判断字符串是否是数字
     * @param str
     * @return
     */
    public boolean isNumber(String str){
        Pattern pattern = Pattern.compile("[0-9]*");
        Matcher isNum = pattern.matcher(str);
        if( !isNum.matches() ){
            return false;
        }
        return true;
    }

    private String floatFormat(double value) {

        if (Math.IEEEremainder(value, 1)==0)
        {

            return String.format("%.0f",value);

        } else if (Math.IEEEremainder(value*10, 1)==0)
        {

            return String.format("%.1f",value);

        }
        else if (Math.IEEEremainder(value*100, 1)==0)
        {

            return String.format("%.2f",value);

        }
        else if (Math.IEEEremainder(value*1000, 1)==0)
        {

            return String.format("%.3f",value);

        }
        else
        {

            return String.format("%.4f",value);


        }
    }

    public void setUpDatePickerCellHolder(CommonEditorEnumCellHolder holder, View cell, JSONObject item_json, boolean readonly, int group, int child) {

        String title = item_json.optString("aname");
        String value = item_json.optString("value");
        String required = item_json.optString("required");

        holder.group = group;
        holder.child = child;
        holder.title_lb.setText(title);
        holder.value_lb.setText(value);

        if (required.equals("true")) {
            holder.startMark.setVisibility(View.VISIBLE);
        } else {
            holder.startMark.setVisibility(View.INVISIBLE);
        }

        if (cancommit == false && required.equals("true") && (value == null || value.length() == 0)) {
            // red shadow
        } else {
            // no shadow
        }

    }

    public void setUpMonthPickerCellHolder(CommonEditorEnumCellHolder holder, View cell, JSONObject item_json, boolean readonly, int group, int child) {

        String title = item_json.optString("aname");
        String value = item_json.optString("value");
        String required = item_json.optString("required");

        holder.group = group;
        holder.child = child;
        holder.title_lb.setText(title);
        holder.value_lb.setText(value);

        if (required.equals("true")) {
            holder.startMark.setVisibility(View.VISIBLE);
        } else {
            holder.startMark.setVisibility(View.INVISIBLE);
        }

        if (cancommit == false && required.equals("true") && (value == null || value.length() == 0)) {
            // red shadow
        } else {
            // no shadow
        }

    }

    public void setUpSignatureCellHolder(CommonEditorSignatureCellHolder holder, View cell, JSONObject item_json, boolean readonly, int group, int child) {

        String title = item_json.optString("aname");
        String img_url = item_json.optString("avalue");
        String required = item_json.optString("required");

        holder.group = group;
        holder.child = child;
        holder.title_lb.setText(title);

        if (required.equals("true")) {
            holder.startMark.setVisibility(View.VISIBLE);
        } else {
            holder.startMark.setVisibility(View.INVISIBLE);
        }
        Bitmap placeHolder = BitmapFactory.decodeResource(getResources(),R.drawable.not_found);
        if (img_url != null && !img_url.isEmpty()) {
            Bitmap bmp = Utils.loadCacheImage(img_url,placeHolder);
            if (bmp != null) {
                holder.signature_iv.setImageBitmap(bmp);
            } else {
                // 异步记载数据
                loadImageForPosition(group,child,2,img_url);
            }
        }
    }

    public void setUpSectionHeaderCellHolder(CommonEditorSectionHeaderHolder holder, View cell, JSONObject item_json, int group, int child) {
        String title = item_json.optString("title");
        boolean hide = item_json.optBoolean("hide");
        boolean hideControlBtn = item_json.optBoolean("hideControlBtn");

        holder.group = group;
        holder.child = child;
        holder.title_lb.setText(title);
        holder.setShow(!hide);
        holder.hideControlBtn(hideControlBtn);
    }

    public void setUpRangeCellHolder(CommonEditorRangeCellHolder holder, View cell, JSONObject item_json, boolean readonly, int group, int child) {

        holder.clearTextWather();

        String title = item_json.optString("aname");
        holder.group = group;
        holder.child = child;
        holder.title_lb.setText(title);

        String type = item_json.optString("type");
        String keyboard = item_json.optString("keyboard");

        int inputType = 0;
        if (keyboard != null) {
            if (keyboard.equals("number")) {
                inputType = EditorInfo.TYPE_CLASS_NUMBER;
            } else if (keyboard.equals("email")) {
                inputType = EditorInfo.TYPE_TEXT_VARIATION_EMAIL_ADDRESS;
            } else if (keyboard.equals("phone")) {
                inputType = EditorInfo.TYPE_CLASS_PHONE;
            } else {
                inputType = EditorInfo.TYPE_CLASS_TEXT;
            }
        }

        holder.min_et.setInputType(inputType);
        holder.max_et.setInputType(inputType);

        String min_str = item_json.optString("min_value");
        String max_str = item_json.optString("max_value");

        holder.min_et.setText(min_str);
        holder.max_et.setText(max_str);

//        if (disable == 1 || readonly) {
//            holder.text_field.setEnabled(false);
//            holder.text_field.setTextColor(Color.LTGRAY);
//        } else {
//            holder.text_field.setEnabled(true);
//            holder.text_field.setTextColor(Color.BLACK);
//        }


        holder.resetTextWather();

    }

    public void setUpDateRangeCellHolder(CommonEditorDateRangeCellHolder holder, View cell, JSONObject item_json, boolean readonly, int group, int child) {

        String title = item_json.optString("aname");
        holder.group = group;
        holder.child = child;
        holder.title_lb.setText(title);

//        String type = item_json.optString("type");

        String min_str = item_json.optString("min_value");
        String max_str = item_json.optString("max_value");

        holder.min_btn.setText(min_str);
        holder.max_btn.setText(max_str);

    }

    public void commonEditorRangeDidChange(String min, String max, int group, int child) {
        String section_key = "section_" + group;
        String item_key = "item_" + child;

        try {
            JSONObject section_json = content_data_download.getJSONObject(section_key);
            JSONObject item_json = ((JSONArray)content_data_control.getJSONArray(group)).getJSONObject(child);

            item_json.put("max_value",max);
            item_json.put("min_value",min);

            section_json.put(item_key,item_json);
            content_data_download.put(section_key,section_json);
            content_data_control = translateChange(content_data_download,changed_data);

            adapter.notifyDataSetChanged();

        } catch (JSONException e) {
            e.printStackTrace();
        }

    }

    public Context mCtx = this;

    /**Month Picker*/
    public void MPValueChanged(String value,int group,int child) {

        try {

            JSONObject section_json = null;
            JSONObject item_json = content_data_control.optJSONArray(group).optJSONObject(child);

            String subid = item_json.optString("subid");
            item_json.put("value",value);
            if (subid == null || subid.isEmpty()) {

                section_json = content_data_download.optJSONObject("section_" + group);
                int count = 0;
                count = section_json.optInt("count");
                for (int i = 0; i < count; i++) {
                    JSONObject olditem = section_json.optJSONObject("item_" + i);
                    if (olditem.optString("name").equals(item_json.optString("name"))) {
                        section_json.put("item_" + i,item_json);
                    }
                }

            } else {

                String[] idarr = subid.split("_");
                int section = Integer.valueOf(idarr[0]);
                int item = Integer.valueOf(idarr[1]);

                section_json = content_data_download.optJSONObject("section_" + section);
                JSONObject olditem = section_json.optJSONObject("item_" + item);
                String control_type = olditem.optString("control");

                if (control_type.equals("enum")) {
                    item_json = enum_subitem_changed(olditem,idarr,item_json,2);
                } else if (control_type.equals("switch")){
                    item_json = switch_subitem_changed(olditem,idarr,item_json,2);
                }
                item_json.put("dirty","true");
                section_json.put("item_" + item,item_json);
            }

            content_data_download.put("section_" + group,section_json);
            content_data_control = translateChange(content_data_download,changed_data);

            adapter.notifyDataSetChanged();

        } catch (Exception e) {
            e.printStackTrace();
        }

    }

    /**Image Change*/
    public void imgIsChanged(String url_down, String url_up, int group, int child, int index, String url_index) {

        try {

            JSONObject section_json = null;
            JSONObject item_json = content_data_control.optJSONArray(group).optJSONObject(child);
            int refresh = item_json.optInt("refresh");
            String refresh_trigger = item_json.optString("name");
            String subid = item_json.optString("subid");
            item_json.put("img_url_" + index,url_down);
            item_json.put("avalue",url_up);
            item_json.put("img_url_aname_" + index,url_index);
            item_json.put("dirty","true");
            if (subid == null || subid.isEmpty()) {

                section_json = content_data_download.optJSONObject("section_" + group);
                int count = 0;
                count = section_json.optInt("count");
                for (int i = 0; i < count; i++) {
                    JSONObject olditem = section_json.optJSONObject("item_" + i);
                    if (olditem.optString("name").equals(item_json.optString("name"))) {
                        section_json.put("item_" + i,item_json);
                    }
                }

            } else {

                String[] idarr = subid.split("_");
                int section = Integer.valueOf(idarr[0]);
                int item = Integer.valueOf(idarr[1]);

                section_json = content_data_download.optJSONObject("section_" + section);
                JSONObject olditem = section_json.optJSONObject("item_" + item);
                item_json = enum_subitem_changed(olditem,idarr,item_json,2);
                section_json.put("item_" + item,item_json);

            }

            content_data_download.put("section_" + group,section_json);
            content_data_control = translateChange(content_data_download,changed_data);

            if (refresh == 1) {
                refresh(refresh_trigger);
            }

            adapter.notifyDataSetChanged();

        } catch (Exception e) {
            e.printStackTrace();
        }

    }


    /**Switch Check Listener**/
    public class SwitchCheckListener implements CompoundButton.OnCheckedChangeListener {

        @Override
        public void onCheckedChanged(CompoundButton v, boolean isChecked) {
            Switch aSwitch = (Switch)v;

            String[] tag_arr = ((String) v.getTag()).split("_");
            int group =  Integer.valueOf(tag_arr[0]);
            int child = Integer.valueOf(tag_arr[1]);

            JSONObject section_json = null;
            JSONObject item_json = content_data_control.optJSONArray(group).optJSONObject(child);

            int refresh = item_json.optInt("refresh");
            String refresh_trigger = item_json.optString("name");
            String subid = item_json.optString("subid");
            String check = "false";

            if (isChecked) {
                check = "true";
            }

            try {

                item_json.put("dirty","true");
                item_json.put("value",check);

                if (subid == null || subid.isEmpty()) {
                    section_json = content_data_download.optJSONObject("section_" + group);
                    int count = 0;
                    count = section_json.optInt("count");
                    for (int i = 0; i < count; i++) {
                        JSONObject olditem = section_json.optJSONObject("item_" + i);
                        if (olditem.optString("name").equals(item_json.optString("name"))) {
                            section_json.put("item_" + i,item_json);
                        }
                    }
                } else {
                    String[] idarr = subid.split("_");
                    int section = Integer.valueOf(idarr[0]);
                    int item = Integer.valueOf(idarr[1]);

                    section_json = content_data_download.optJSONObject("section_" + section);
                    JSONObject olditem = section_json.optJSONObject("item_" + item);
                    item_json = enum_subitem_changed(olditem,idarr,item_json,2);
                    item_json.put("dirty","true");
                    section_json.put("item_" + item,item_json);
                }

                content_data_download.put("section_" + group,section_json);
                content_data_control = translateChange(content_data_download,changed_data);

                adapter.notifyDataSetChanged();

                if (refresh == 1) {
                    refresh(refresh_trigger);
                }


            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    public static int URL_REMOTE = 1;
    public static int URL_LOCAL = 0;
    public static int URL_NONE = 2;
    public static int URL_RESTORE = 3;
    // 如何处理commoneditor action 类型调用的返回值
    static int ACTION_SAVE_DATA = 0;
    static int ACTION_FILL_SECTION = 1;
    /**Multiple Action**/
    private View.OnClickListener multipleActionClickListener = new View.OnClickListener() {
        @Override
        public void onClick(View v) {

            Button btn = (Button)v;
            String tag = (String) btn.getTag();
            String[] arr = tag.split("_");
            int group = Integer.valueOf(arr[0]);
            int child = Integer.valueOf(arr[1]);
            int i = Integer.valueOf(arr[2]);

            int refresh = 0;
            JSONObject section_json = null;
            JSONObject item_json = content_data_control.optJSONArray(group).optJSONObject(child);
            String subid = item_json.optString("subid");
            String refresh_trigger = item_json.optString("name");
            JSONObject sub_action = item_json.optJSONObject("item_" + i);
            String type = sub_action.optString("type");

            if (type != null && type.equals("pull")) {

                // end edit

                refresh = sub_action.optInt("refresh");
                JSONObject keymap = sub_action.optJSONObject("key_map");
                JSONObject value = create_value_map(keymap);

                if (subid == null || subid.isEmpty()) {
                    JSONObject jsonmap = sub_action.optJSONObject("key_map");
                    section_json = content_data_download.optJSONObject("section_" + group);
                    int icount = section_json.optInt("count");
                    for (int ic = 0; ic < icount; ic++) {
                        JSONObject modity_item = section_json.optJSONObject("item_" + ic);
                        String mapto = modity_item.optString("name");

                        if (mapto.isEmpty()) {
                            continue;
                        }
                        String valuefrom = jsonmap.optString(modity_item.optString("name"));
                        if (valuefrom == null) {
                            continue;
                        }
                        String valuestr = value.optString(valuefrom);

                        try {
                            if (valuestr.isEmpty()) {
                                modity_item.put("value","");
                            } else {
                                modity_item.put("value",valuestr);
                            }
                            modity_item.put("dirty","true");
                            section_json.put("item_" + ic,modity_item);

                        } catch (Exception e) {
                            e.printStackTrace();
                        }

                    }
                } else {
                    String[] idarr = subid.split("_");
                    int section = Integer.valueOf(idarr[0]);
                    int item = Integer.valueOf(idarr[1]);

                    JSONObject jsonmap = sub_action.optJSONObject("key_map");
                    section_json = content_data_download.optJSONObject("section_" + section);
                    JSONObject olditem = section_json.optJSONObject("item_" + item);

                    String control_type = olditem.optString("control");
                    if (control_type.equals("switch")) {
                        olditem = fill_switch_subitem_subid_mapping(olditem,null,value,jsonmap);
                    } else if (control_type.equals("enum")) {
                        olditem = fill_enum_subitem_subid_mapping(olditem,null,value,jsonmap);
                    } else {
                        new AlertDialog.Builder(mCtx)
                                .setMessage("not impl")
                                .setPositiveButton("OK",null)
                                .show();
                    }
                    try {
                        olditem.put("dirty","true");
                        section_json.put("item_" + item,olditem);

                    } catch (Exception e) {
                        e.printStackTrace();
                    }

                }

                try {

                    content_data_download.put("section_" + group,section_json);
                    content_data_control = translateChange(content_data_download,changed_data);

                } catch (Exception e) {
                    e.printStackTrace();
                }

                if (refresh == 1) {
                    refresh(refresh_trigger);
                    return;
                }
                adapter.notifyDataSetChanged();

            } else {
                JSONObject itemjson = sub_action;
                String value = itemjson.optString("value");
                Intent intent = null;
                String requesturl = null;
                int request_code = -1;
                if (value.equals("new_addr")) {

                    AddressEditorActivity.Builder builder = new AddressEditorActivity.Builder(); // 创建内部类实例需要外部类的实例，或者声明内部类为static
                    intent = builder.build(mCtx,URL_REMOTE,requesturl,"true",String.format("%d",i),group,child);
                    request_code = 2;

                } else if (value.equals("credit_card")) {

                    request_code = 3;
                    JSONObject data = item_json.optJSONObject("data");
                    int url_type;
                    JSONObject download_data;
                    if (data != null) {
                        download_data = data;
                        url_type = URL_NONE;
                        requesturl = null;
                    } else {
                        download_data = null;
                        url_type = URL_REMOTE;
                        requesturl = "";
                    }
                    intent = new CreditCardEditorActivity.Builder().build(mCtx,url_type,requesturl,Application.order_code,"true",String.format("%d",i),download_data,group,child);

                } else if (value.equals("Sales_Order_Freight_Bill_To")) {

                    request_code = 4;
                    intent = new ContactListActivity.Builder().build(mCtx,"true",String.format("%d",i),value,true,group,child);

                } else if (value.equals("Sales_Order_Ship_From")) {

                    request_code = 5;
                    intent = new ContactListActivity.Builder().build(mCtx,"true",String.format("%d",i),value,true,group,child);

                } else if (value.equals("Sales_Order_Customer")) {

                    request_code = 6;
                    intent = new ContactListActivity.Builder().build(mCtx,"true",String.format("%d",i),value,true,group,child);

                } else if (value.equals("Sales_Order_Merchandise_Bill_To")) {

                    request_code = 7;
                    intent = new ContactListActivity.Builder().build(mCtx,"true",String.format("%d",i),value,true,group,child);

                } else if (value.equals("Contact_Return_To")) {

                    request_code = 8;
                    intent = new ContactListActivity.Builder().build(mCtx,"true",String.format("%d",i),value,true,group,child);

                } else if (value.equals("Sales_Order_Ship_To")) {

                    request_code = 9;
                    intent = new ContactListActivity.Builder().build(mCtx,"true",String.format("%d",i),value,true,group,child);
                }

               if (intent != null) {
                   startActivityForResult(intent,request_code);
               }
            }

        }
    };

    public JSONObject fill_switch_subitem_subid_mapping(JSONObject switch_item,JSONArray subid,JSONObject source, JSONObject mapping) {

        String value = switch_item.optString("value");
        JSONObject boolitem = null;
        JSONObject subjson = null;
        if (value.equals("true")) {
            boolitem = switch_item.optJSONObject("true");
        } else {
            boolitem = switch_item.optJSONObject("false");
        }
        subjson = boolitem.optJSONObject("sub_item");
        if (subjson != null) {
            int sub_count = subjson.optInt("count");
            for (int l = 0; l <sub_count; l++) {
                JSONObject modify_item = subjson.optJSONObject("item_" + l);
                String mapto = modify_item.optString("name");
                if (mapto == null || mapto.isEmpty()) {
                    continue;
                }
                String valuefrom = mapping.optString(modify_item.optString("name"));
                if (valuefrom == null) {
                    continue;
                }
                String valuestr = source.optString(valuefrom);

                try {
                    if (valuestr.length() > 0) {
                        modify_item.put("value",valuestr);
                    } else {
                        modify_item.put("value","");
                    }

                    modify_item.put("dirty","true");
                    subjson.put("item_" + l,modify_item);

                } catch (Exception e) {
                    e.printStackTrace();
                }
            }

            try {
                boolitem.put("sub_item",subjson);
                if (value.equals("true")) {
                    switch_item.put("true",boolitem);
                } else {
                    switch_item.put("false",boolitem);
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }

        return switch_item;
    }

    public JSONObject fill_enum_subitem_subid_mapping(JSONObject enum_item,JSONArray subid,JSONObject source, JSONObject mapping) {

        JSONObject cadedatejson = enum_item.optJSONObject("cadedate");
        int count = cadedatejson.optInt("count");
        for (int i = 0; i < count; i++) {
            JSONObject val_json = cadedatejson.optJSONObject("val_" + i);
            int check = val_json.optInt("check");
            if (check == 1) {
                JSONObject subjson = val_json.optJSONObject("sub_item");
                if (subjson != null) {
                    int sub_count = subjson.optInt("count");
                    for (int l = 0; l < sub_count; l++) {
                        JSONObject modify_item = subjson.optJSONObject("item_" + l);
                        String control_type = modify_item.optString("control");
                        if (control_type.equals("switch")) {
                            modify_item = fill_switch_subitem_subid_mapping(modify_item,null,source,mapping);
                        } else if (control_type.equals("enum")) {
                            modify_item = fill_enum_subitem_subid_mapping(modify_item,null,source,mapping);
                        } else {
                            String mapto = modify_item.optString("name");
                            if (mapto == null || mapto.isEmpty()) {
                                continue;
                            }
                            String valuefrom = mapping.optString(modify_item.optString("name"));
                            if (valuefrom == null) {
                                continue;
                            }
                            String valuestr = source.optString(valuefrom);

                            try {
                                if (valuefrom != null && valuefrom.length() > 0) {
                                    modify_item.put("value",valuestr);
                                } else {
                                    modify_item.put("value","");
                                }
                            } catch (Exception e) {
                                e.printStackTrace();
                            }
                        }
                        try {
                            modify_item.put("dirty","true");
                            subjson.put("item_" + l,modify_item);
                        } catch (Exception e) {
                            e.printStackTrace();
                        }
                    }
                    try {
                        val_json.put("sub_item",subjson);
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
            }
            try {
                cadedatejson.put("val_" + i,val_json);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        try {
            enum_item.put("cadedate",cadedatejson);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return enum_item;
    }

    public JSONObject create_value_map(JSONObject key_map) {
        JSONObject ret = new JSONObject();

        Iterator<String> keys = key_map.keys();
        try {

            while (keys.hasNext()) {
                String key = keys.next();
                String valuefrom = key_map.optString(key);
                if (valuefrom != null && !valuefrom.isEmpty()) {
                    String value = getValue(valuefrom);
                    ret.put(valuefrom,value);
                }
            }
            JSONObject customerinfo = create_customer_info_from_table();

            String ext = create_customer_ext(customerinfo);
            String first_name = customerinfo.optString("customer_first_name");
            String last_name = customerinfo.optString("customer_last_name");
            if (ext != null) {
                ret.put("customer_contact_ext",ext);
            }
            if (first_name != null) {
                ret.put("customer_first_name",first_name);
            }
            if (last_name != null) {
                ret.put("customer_last_name",last_name);
            }

        } catch (Exception e) {
            e.printStackTrace();
        }

        return ret;
    }

    public String getValue(String name) {

        String ret = "";
        int count = content_data_control.length();
        for (int i = 0; i < count; i++) {
            JSONArray items = content_data_control.optJSONArray(i);
            for (int j = 0; j < items.length(); j++) {
                JSONObject item = items.optJSONObject(j);
                String item_name = item.optString("name");
                if (item_name.equals(name)) {
                    String control = item.optString("control");
                    if (control.equals("enum")) {
                        JSONObject cadedate = item.optJSONObject("cadedate");
                        int cc = cadedate.optInt("count");
                        for (int l = 0; l < cc; l++) {
                            JSONObject val_json = cadedate.optJSONObject("val_" + l);
                            if (val_json.optInt("check") == 1) {
                                return val_json.optString("value_id");
                            }
                        }
                    } else {
                        return item.optString("value");
                    }

                }
            }

        }

        return ret;
    }

    public JSONObject create_customer_info_from_table() {

        JSONObject ret = Application.customerInfo;



        try {

            if (ret == null) {
                ret = new JSONObject();
            }

            ret.put("customer_country",getValue("customer_country"));
            ret.put("customer_phone",getValue("customer_phone"));
            ret.put("customer_email",getValue("customer_email"));
            ret.put("customer_name",getValue("customer_name"));
            ret.put("customer_address4",getValue("customer_address4"));
            ret.put("customer_address3",getValue("customer_address3"));
            ret.put("customer_address2",getValue("customer_address2"));
            ret.put("customer_address1",getValue("customer_address1"));
            ret.put("customer_zipcode",getValue("customer_zipcode"));
            ret.put("customer_city",getValue("customer_city"));
            ret.put("customer_state",getValue("customer_state"));
            ret.put("customer_cid",getValue("customer_cid"));
            ret.put("customer_state",getValue("customer_state"));
            ret.put("customer_contact",getValue("customer_contact"));
            ret.put("customer_fax",getValue("customer_fax"));

            String firstname = "";
            String lastname = "";
            String contact_name = getValue("customer_contact");
            if (contact_name != null) {
                String[] arr = contact_name.split(" ");
                if (arr.length >= 1) {
                    firstname = arr[0];
                    if (arr.length > 1) {
                        lastname = arr[1];
                        int length = arr.length;
                        if (length > 2) {
                            for (int i = 2; i < length; i++) {
                                lastname = lastname + " " + arr[i];
                            }
                        }
                    }
                }
            }
            ret.put("customer_first_name",firstname);
            ret.put("customer_last_name",lastname);

        } catch (Exception e) {
            e.printStackTrace();
        }


        return ret;
    }

    public String create_customer_ext(JSONObject customerinfo) {

        String ret = null;
        String customer_address1 = customerinfo.optString("customer_address1");
        String customer_address2 = customerinfo.optString("customer_address2");
        String customer_address3 = customerinfo.optString("customer_address3");
        String customer_address4 = customerinfo.optString("customer_address4");

        String addr_str = "";
        if (customer_address1 != null && customer_address1.length() > 0) {
            addr_str = addr_str + customer_address1 + "\r\n";
        }
        if (customer_address2 != null && customer_address2.length() > 0) {
            addr_str = addr_str + customer_address2 + "\r\n";
        }
        if (customer_address3 != null && customer_address3.length() > 0) {
            addr_str = addr_str + customer_address3 + "\r\n";
        }
        if (customer_address4 != null && customer_address4.length() > 0) {
            addr_str = addr_str + customer_address4 + "\r\n";
        }
        if (addr_str.length() > 0) {
            addr_str = addr_str.substring(0,addr_str.length() - 3);
        }

        String city = customerinfo.optString("customer_city");
        String country = customerinfo.optString("customer_country");
        String zipcode = customerinfo.optString("customer_zipcode");
        String state = customerinfo.optString("customer_state");

        String cty_str = "";
        if (city != null && city.length() > 0) {
            cty_str = cty_str + city + ", ";
        }
        if (state != null && state.length() > 0) {
            cty_str = cty_str + state + ", ";
        }
        if (zipcode != null && zipcode.length() > 0) {
            cty_str = cty_str + zipcode + ", ";
        }
        if (country != null && country.length() > 0) {
            cty_str = cty_str + country + ", ";
        }
        if (cty_str.length() > 0) {
            cty_str = cty_str.substring(0,cty_str.length() - 3);
        }

        String ext_str = "";
        if (addr_str != null && addr_str.length() > 0) {
            ext_str = ext_str + addr_str + "\r\n";
        }
        if (cty_str != null && cty_str.length() > 0) {
            ext_str = ext_str + cty_str;
        }

        ret = ext_str;

        return ret;
    }

    public void textFieldSetValue(String val,int group,int child) {

        try {

            JSONObject section_json = null;

            val = val.trim();
            JSONObject item_json = content_data_control.optJSONArray(group).optJSONObject(child);

            String subid = item_json.optString("subid");
            String refresh_trigger = item_json.optString("name");

            item_json.put("dirty","true");
            item_json.put("value",val);
            if (item_json.optString("keyboard").equals("number")) {
                float f = Float.valueOf(val);
                item_json.put("value",String.format("%.2f",f));
            }

            if (subid == null || subid.isEmpty()) {

                section_json = content_data_download.optJSONObject("section_" + group);
                int count = 0;

                count = section_json.optInt("count");
                for (int i = 0; i < count; i++) {
                    JSONObject olditem = section_json.optJSONObject("item_" + i);
                    if (olditem.optString("name").equals(item_json.optString("name"))) {
                        section_json.put("item_" + i,item_json);
                    }
                } // for

                content_data_download.put("section_" + group,section_json);
                content_data_control = translateChange(content_data_download,changed_data);

                int refresh = item_json.optInt("refresh");
                JSONObject restore_json = item_json.optJSONObject("restore");
                boolean partial_refresh = item_json.optBoolean("partial_refresh");
                if (refresh == 1) {

                    if (restore_json != null) {
                        int rc = restore_json.optInt("count");
                        for (int ir = 0; ir < rc; ir++) {
                            String name = restore_json.optString("item_" + ir);
                            int section_count = content_data_download.optInt("section_count");
                            for (int i = 0; i < section_count; i++) {
                                JSONObject sectionjson = content_data_download.optJSONObject("section_" + i);
                                int item_count = sectionjson.optInt("count");
                                for (int j = 0; j < item_count; j++) {
                                    JSONObject itemjson = sectionjson.optJSONObject("item_" + j);
                                    if (itemjson.optString("name").equals(name)) {
                                        itemjson.remove("dirty");
                                        sectionjson.put("item_" + j,itemjson);
                                    }
                                }
                                content_data_download.put("section_" + i,sectionjson);
                            }
                        }
                    }
                    refresh(refresh_trigger);

                } // refresh == 1
                else if (partial_refresh) {

                    String name = item_json.optString("name");
                    final String url = item_json.optString("data_interface");

                    JSONObject params = new JSONObject();
                    params.put(name,val);

                    final ProgressDialog pd = Utils.waiting_alert(mCtx,"loading","please wait");
                    final JSONObject final_params = params;
                    new Thread(new Runnable() {
                        @Override
                        public void run() {
                            final JSONObject editor_json = Network.commoneditor_partialrefresh(final_params,url);

                            runOnUiThread(new Runnable() {
                                @Override
                                public void run() {

                                    pd.dismiss();

                                    if (Integer.valueOf(editor_json.optString("result")) == 2) {
                                        int prcount = editor_json.optInt("count");
                                        for (int ipr = 0; ipr < prcount; ipr++) {
                                            JSONObject pr_item = editor_json.optJSONObject("item_" + ipr);
                                            String name = pr_item.optString("name");
                                            String value = pr_item.optString("value");
                                            setValue(name,value);
                                        }
                                    } else {
                                        Utils.message_alert(mCtx,"",editor_json.optString("err_msg"));
                                    }

                                }
                            });
                        }
                    }).start();


                } // partial refresh

                lastEditText = null;
                last_edit_group = -1;
                last_edit_child = -1;

                return;
            } // subid == null
            else
            {

                String[] idarr = subid.split("_");
                int section = Integer.valueOf(idarr[0]);
                int item = Integer.valueOf(idarr[1]);

                section_json = content_data_download.optJSONObject("section_" + section);
                JSONObject olditem = section_json.optJSONObject("item_" + item);

                String control_type = olditem.optString("control");
                JSONObject new_item = null;
                item_json.put("dirty","true");
                if (control_type.equals("enum")) {
                    new_item = enum_subitem_changed(olditem,idarr,item_json,2);
                } else if (control_type.equals("switch")) {
                    new_item = switch_subitem_changed(olditem,idarr,item_json,2);
                }
                section_json.put("item_" + item,new_item);

                content_data_download.put("section_" + group,section_json);
                content_data_control = translateChange(content_data_download,changed_data);

                int refresh = item_json.optInt("refresh");
                JSONObject restore_json = item_json.optJSONObject("restore");
                boolean partial_refresh = item_json.optBoolean("partial_refresh");
                if (refresh == 1) {

                    if (restore_json != null) {
                        int rc = restore_json.optInt("count");
                        for (int ir = 0; ir < rc; ir++) {
                            String name = restore_json.optString("item_" + ir);
                            int section_count = content_data_download.optInt("section_count");
                            for (int i = 0; i < section_count; i++) {
                                JSONObject sectionjson = content_data_download.optJSONObject("section_" + i);
                                int item_count = sectionjson.optInt("count");
                                for (int j = 0; j < item_count; j++) {
                                    JSONObject itemjson = sectionjson.optJSONObject("item_" + j);
                                    if (itemjson.optString("name").equals(name)) {
                                        itemjson.remove("dirty");
                                        sectionjson.put("item_" + j,itemjson);
                                    }
                                }
                                content_data_download.put("section_" + i,sectionjson);
                            }
                        }
                    }
                    refresh(refresh_trigger);

                } // refresh == 1
                else if (partial_refresh) {

                    String name = item_json.getString("name");
                    final String url = item_json.optString("data_interface");

                    JSONObject params = new JSONObject();
                    params.put(name,val);
                    final ProgressDialog pd = Utils.waiting_alert(mCtx,"loading","please wait");
                    final JSONObject final_params = params;
                    new Thread(new Runnable() {
                        @Override
                        public void run() {

                            final JSONObject editor_json = Network.commoneditor_partialrefresh(final_params,url);

                            runOnUiThread(new Runnable() {
                                @Override
                                public void run() {

                                    pd.dismiss();

                                    if (Integer.valueOf(editor_json.optString("result")) == 2) {
                                        int prcount = editor_json.optInt("count");
                                        for (int ipr = 0; ipr < prcount; ipr++) {
                                            JSONObject pr_item = editor_json.optJSONObject("item_" + ipr);
                                            String name = pr_item.optString("name");
                                            String value = pr_item.optString("value");
                                            setValue(name,value);
                                        }
                                    } else {
                                        Utils.message_alert(mCtx,"",editor_json.optString("err_msg"));
                                    }

                                }
                            });

                        }
                    }).start();


                } // partial refresh


                // fix crash when sub item value changed
                adapter.notifyDataSetChanged();

                lastEditText = null;
                // lastedit_from = null
                last_edit_group = -1;
                last_edit_child = -1;

                return;
            }


        } catch (Exception e) {
            e.printStackTrace();
        }

    }

    public JSONObject switch_subitem_changed(JSONObject switch_item,String[] subid,JSONObject valuejson,int step) {

        try {

            int index = Integer.valueOf(subid[step]);
            String value = switch_item.optString("value");

            JSONObject boolitem = null;
            JSONObject subjson = null;
            if (value.equals("true")) {
                boolitem = switch_item.optJSONObject("true");
            } else {
                boolitem = switch_item.optJSONObject("false");
            }
            subjson = boolitem.optJSONObject("sub_item");

            if (subjson != null) {
                JSONObject itemjson = subjson.optJSONObject("item_" + index);
                if (step == subid.length - 1) {
                    itemjson = valuejson;
                }
                subjson.put("item_" + index,itemjson);
                boolitem.put("sub_item",subjson);

                if (value.equals("true")) {
                    switch_item.put("true",boolitem);
                } else {
                    switch_item.put("false",boolitem);
                }

                return switch_item;
            }


        } catch (Exception e) {
            e.printStackTrace();
        }

        return null;

    }

    public void setEnumValue(JSONObject value, int group, int child) {

        try {

            JSONObject section_json = null;
            JSONObject item_json = content_data_control.optJSONArray(group).optJSONObject(child);

            int refresh = item_json.optInt("refresh");
            String refresh_trigger = item_json.optString("name");
            String subid = item_json.optString("subid");

            item_json.put("cadedate",value);

            if (subid == null || subid.isEmpty()) {
                item_json.put("dirty","dirty");
                section_json = content_data_download.optJSONObject("section_" + group);
                int count = 0;
                count = section_json.optInt("count");
                for (int i = 0; i < count; i++) {
                    JSONObject olditem = section_json.optJSONObject("item_" + i);
                    if (olditem.optString("name").equals(item_json.optString("name"))) {
                        section_json.put("item_" + i,item_json);
                    }
                }
            } else {

                String[] idarr = subid.split("_");
                int section = Integer.valueOf(idarr[0]);
                int item = Integer.valueOf(idarr[1]);

                section_json = content_data_download.optJSONObject("section_" + section);
                JSONObject olditem = section_json.optJSONObject("item_" + item);
                item_json = enum_subitem_changed(olditem,idarr,item_json,2);
                item_json.put("dirty","true");
                section_json.put("item_" + item,item_json);

            }

            content_data_download.put("section_" + group,section_json);
            content_data_control = translateChange(content_data_download,changed_data);

            JSONObject restore_json = item_json.optJSONObject("restore");
            if (refresh == 1) {
                if (restore_json != null) {
                    int rc = restore_json.optInt("count");
                    for(int ir=0;ir<rc;ir++) {
                        String name = restore_json.optString("item_" + ir);
                        int section_count = content_data_download.optInt("section_count");

                        for (int i = 0; i < section_count; i++) {
                            JSONObject sectionjson = content_data_download.optJSONObject("section_" + i);
                            int item_count = sectionjson.optInt("count");
                            for (int j = 0; j < item_count; j++) {
                                JSONObject itemjson = sectionjson.optJSONObject("item_" + j);
                                if (itemjson.optString("name").equals(name)) {
                                    itemjson.remove("dirty");
                                    sectionjson.put("item_" + j,itemjson);
                                }
                            }
                            content_data_download.put("section_" + i,sectionjson);
                        }
                    }
                }
                refresh(refresh_trigger);
                return;
            }
            adapter.notifyDataSetChanged();

        } catch (Exception e) {
            e.printStackTrace();
        }



    }

    public void setValue(String key,String val) {


        try {

            for (int i = 0; i < content_data_control.length(); i++) {
                JSONArray items = content_data_control.optJSONArray(i);
                for (int j = 0; j < items.length(); j++) {
                    JSONObject item = items.optJSONObject(j);
                    String item_name = item.optString("name");
                    int group = i;
                    int child = j;
                    if (item_name.equals(key)) {
                        String control = item.optString("control");
                        if (control.equals("enum")) {

                            JSONObject cadedate = item.optJSONObject("cadedate");
                            int cc = cadedate.optInt("count");
                            for (int l = 0; l < cc; l++) {

                                JSONObject val_json = cadedate.optJSONObject("val_" + l);
                                if (val_json.optString("val_id").equals(val)) {
                                    val_json.put("check",1);
                                } else {
                                    val_json.put("check",0);
                                }
                                cadedate.put("val_" + l,val_json);

                            } // for

                            setEnumValue(cadedate,group,child);

                        }// enum
                        else if (control.equals("edit")) {
                            textFieldSetValue(val,group,child);
                        } // edit
                    } // key

                }
            }
            adapter.notifyDataSetChanged();

        } catch (Exception e) {
            e.printStackTrace();
        }

    }

    public JSONArray sync_loadCadidate(String keyword,JSONObject item_json) {

        if (keyword == null || keyword.isEmpty()) {
            return null;
        }

        Bundle params = new Bundle();
        params.putString("query_id",selfParams.getString("query_id"));
        params.putString("name",item_json.optString("name"));
        params.putString("keyword",keyword);

        JSONObject json = Network.queryAutoComplete(params);

        if (json != null) {
            return json.optJSONArray("cadedate");
        } else {
            return null;
        }
    }

    /**Text Field Change*/
    public class TextFieldTextWatcher implements TextWatcher {

        Context mCtx;
        int group;
        int child;
        EditText textView;
        boolean autoComplete = false;

        public TextFieldTextWatcher(Context ctx,EditText textView,int group,int child) {
            this.mCtx = ctx;
            this.textView = textView;
            this.group = group;
            this.child = child;

        }

        String origin_text;
        String string;
        int start_position;
        int change_length; // 修改原文长度
        int new_string_length;


        /**
         * s        改变前的内容
         * start    增加内容前光标位置，删除内容后光标位置 （起始位置）
         * count    选中s中的内容长度（发生改变的原内容长度），未选中为0
         * after    新添加的内容长度，删除为0
         * */
        @Override
        public void beforeTextChanged(CharSequence s, int start, int count, int after) {
//            Log.d("TextChange", "before Text Changed: " + s + " Start: " + start + " Count: " + count + " After: " + after);

            origin_text = s.toString();
            start_position = start;
            change_length = count;
            new_string_length = after;

        }

        /**
         * s        改变后的内容
         * start    增加内容前光标位置，删除内容后光标位置 （起始位置）
         * before   选中s中的内容长度（发生改变的原内容长度），未选中为0
         * count    增加内容长度，删除内容为0
         * */
        @Override
        public void onTextChanged(CharSequence s, int start, int before, int count) {
//            Log.d("TextChange", "on Text Changed: " + s + " Start: " + start + " Before: " + before + " Count: " + count);
        }

        @Override
        public void afterTextChanged(final Editable s) {

            /**
             * 文本处理
             * */
            if (new_string_length == 0) {
                string = "";
            } else {
                string = s.toString().substring(start_position,start_position + new_string_length);
            }

            if (change_length == 0) { // 新加内容

            } else { // 替换原文或删除原文

            }

            /**
             * 业务逻辑
             * */
            final JSONObject item_json = content_data_control.optJSONArray(group).optJSONObject(child);
            if (item_json == null) {
                return;
            }
            String required = item_json.optString("required");

            if (required.equals("true") && string.length() == 0 && (origin_text == null || origin_text.length() < 1)) {

                // cell red shadow

            } else {
                // cell clear shadow
            }

            if (textView instanceof AutoCompleteTextView) {

                final CommonEditorEditAutoCompleteCellHolder holder = (CommonEditorEditAutoCompleteCellHolder) ((View)textView.getParent().getParent()).getTag();

                holder.autoCompleteAdapter.clear();

                final String threadIdentifier = UUID.randomUUID().toString();
                holder.thread_identifier = threadIdentifier;

                new Thread(new Runnable() {
                    @Override
                    public void run() {

                        // 延迟0.8s 请求
                        try {

                            Thread.sleep(800);

                        } catch (Exception e) {
                            e.printStackTrace();
                        }
                        if (threadIdentifier.equals(holder.thread_identifier)) {

                            if (s == null || s.toString().length() < 1) {

                            } else  {

                                // 请求
                                JSONArray cadedate = sync_loadCadidate(s.toString(),item_json);

                                List<String> list = new ArrayList<>();
                                for (int i = 0; i < cadedate.length(); i++) {
                                    JSONObject object = cadedate.optJSONObject(i);
                                    if (object != null) {
                                        String str = object.optString("value");
                                        if (str != null || !str.isEmpty()) {
                                            list.add(str);
                                        }
                                    }

                                }

                                if (threadIdentifier.equals(holder.thread_identifier)) {
                                    final String[] arr = (String[]) list.toArray(new String[list.size()]);

                                    runOnUiThread(new Runnable() {
                                        @Override
                                        public void run() {

                                            holder.autoCompleteAdapter.addObjects(arr);
                                        }
                                    });
                                }
                            }

                        }


                    }
                }).start();
            }

            String keyboard = item_json.optString("keyboard");
            if (!keyboard.equals("number") && !keyboard.equals("int")) {

                return;
            }
            String filterStr;
            if (keyboard.equals("number")) {
                filterStr = string.replaceAll("[^(0-9/.)]", "");
            } else {
                filterStr = string.replaceAll("[^(0-9)]", "");
            }
            boolean canChange = string.equals(filterStr);
            int lenght = item_json.optInt("length");

            // 长度控制在textView初始化时
            if (lenght == 0) {

                if (!canChange) {
                    textView.setText(origin_text);
                } else {

                }

            } else {
                if (canChange) {

                } else {
                    textView.setText(origin_text);
                }
            }

        }
    }

    /**EditText Focus Listener**/
    public class EditTextFocusListener implements View.OnFocusChangeListener {

        Context mCtx;
        int group;
        int child;
        EditText et;
        boolean is_text_field;

        public EditTextFocusListener(Context ctx,EditText textView,int group,int child) {
            this.mCtx = ctx;
            this.et = textView;
            this.group = group;
            this.child = child;

            String[] tag_arr = ((String) textView.getTag()).split("_");
            String tag_identifier = tag_arr[2];
            if (tag_identifier.equals("TextFiled")) {
                is_text_field = true;
            } else {
                is_text_field = false;
            }
        }

        @Override
        public void onFocusChange(View v, boolean hasFocus) {

            if (hasFocus) {

                editTextBeginEditing(et,is_text_field,group,child);

            } else {

                editTextEndEditing(et,is_text_field,group,child);
                endEditting();
                lastEditText = null;
                last_edit_group = -1;
                last_edit_child = -1;
            }


        }
    }

    public EditText lastEditText;
    public int last_edit_group;
    public int last_edit_child;
    public String last_edit_str;

    public void endEditting() {
        if (lastEditText != null) {
            lastEditText.clearFocus(); // 辞去焦点
            lastEditText = null;
        }
    }

    public void editTextEndEditing(EditText et,boolean is_text_field,int group,int child) {
        Log.d("Edit", "end editing");
        if (is_text_field) {

            JSONObject item_json = content_data_control.optJSONArray(group).optJSONObject(child);
            if (item_json == null) {
                return;
            }
            String fillText = item_json.optString("fill");

            // 没有判断fillText empty会导致重复不断的调用focusChange，并且不能输入
            if (fillText != null && et.getText().length() == 0 && !fillText.isEmpty()) {
                et.setText(fillText);
            }
            textFieldSetValue(et.getText().toString(),group,child);

        } else {

            try {
                JSONObject section_json = null;
                JSONObject item_json = content_data_control.optJSONArray(group).optJSONObject(child);
                String subid = item_json.optString("subid");
                item_json.put("dirty","true");
                item_json.put("value",et.getText().toString());
                if (subid == null || subid.isEmpty()) {
                    section_json = content_data_download.optJSONObject("section_" + group);
                    int count = 0;
                    count = section_json.optInt("count");
                    for (int i = 0; i < count;i++) {
                        JSONObject olditem = section_json.optJSONObject("item_" + i);
                        if (olditem.optString("name").equals(item_json.optString("name"))) {
                            section_json.put("item_" + i,item_json);
                        }
                    }
                } else {
                    String[] idarr = subid.split("_");
                    int section = Integer.valueOf(idarr[0]);
                    int item = Integer.valueOf(idarr[1]);

                    section_json = content_data_download.optJSONObject("section_" + section);
                    JSONObject olditem = section_json.optJSONObject("item_" + item);
                    String control_type = olditem.optString("control");
                    if (control_type.equals("enum")) {
                        item_json = enum_subitem_changed(olditem,idarr,item_json,2);
                    } else if (control_type.equals("switch")) {
                        item_json = switch_subitem_changed(olditem,idarr,item_json,2);
                    }
                    item_json.put("dirty","true");
                    section_json.put("item_" + item,item_json);

                }

                content_data_download.put("section_" + group, section_json);
                content_data_control = translateChange(content_data_download,changed_data);


            } catch (Exception e) {
                e.printStackTrace();
            }

        }

    }

    public void editTextBeginEditing(EditText et,boolean is_text_field,int group,int child) {
        Log.d("Edit", "begin editing");

        lastEditText = et;
        last_edit_group = group;
        last_edit_child = child;

        et.setSelection(et.getText().length());
        if (is_text_field) {

            JSONObject item_json = content_data_control.optJSONArray(group).optJSONObject(child);
            String clear_str = item_json.optString("clear");
            String et_str = et.getText().toString();
            if (clear_str != null && !clear_str.isEmpty() && et_str != null && !et_str.isEmpty()) {
                double clear_double = Double.valueOf(clear_str);
                double et_double = Double.valueOf(et_str);
                boolean clear = clear_double == et_double;
                if (clear == true) {
                    et.setText(null);
                }
            }


        } else {
            // Text View

        }
    }


    /**Text View Change**/
    public class TextViewTextWatcher implements TextWatcher {

        Context mCtx;
        int group;
        int child;
        EditText textView;

        public TextViewTextWatcher(Context ctx,EditText textView,int group,int child) {
            this.mCtx = ctx;
            this.textView = textView;
            this.group = group;
            this.child = child;
        }

        String origin_text;
        String string;
        int start_position;
        int change_length; // 修改原文长度
        int new_string_length;

        @Override
        public void beforeTextChanged(CharSequence s, int start, int count, int after) {

            origin_text = s.toString();
            start_position = start;
            change_length = count;
            new_string_length = after;
        }

        @Override
        public void onTextChanged(CharSequence s, int start, int before, int count) {

        }

        @Override
        public void afterTextChanged(Editable s) {

            /**
             * 文本处理
             * */
            if (new_string_length == 0) {
                string = "";
            } else {
                string = s.toString().substring(start_position,start_position + new_string_length);
            }

            if (change_length == 0) { // 新加内容

            } else { // 替换原文或删除原文

            }

            /**
             * 业务逻辑
             * */

            JSONObject item_json = content_data_control.optJSONArray(group).optJSONObject(child);
            if (item_json == null) {
                return;
            }
            String required = item_json.optString("required");
            if (required.equals("true") && string.length() == 0 && (origin_text == null || origin_text.length() < 1)) {
                // cell red shadow
            } else {
                // cell clear shadow
            }

        }
    }
}
