package com.tomastc.anickd;

import static android.view.View.GONE;
import static android.view.View.INVISIBLE;
import static android.view.View.VISIBLE;
import static com.tomastc.anickd.lib.ErrorCode.E110;
import static com.tomastc.anickd.lib.ErrorCode.E111;
import static com.tomastc.anickd.lib.ErrorCode.E112;
import static com.tomastc.anickd.lib.ErrorCode.E113;
import static com.tomastc.anickd.lib.ErrorCode.E115;
import static com.tomastc.anickd.lib.ErrorCode.E116;
import static com.tomastc.anickd.lib.ErrorCode.E117;
import static com.tomastc.anickd.lib.ErrorCode.E120;
import static com.tomastc.anickd.lib.ErrorCode.E121;
import static com.tomastc.anickd.lib.ErrorCode.E122;
import static com.tomastc.anickd.lib.ErrorCode.E123;
import static com.tomastc.anickd.lib.ErrorCode.E124;
import static com.tomastc.anickd.lib.ErrorCode.E203;
import static com.tomastc.anickd.lib.ProductionSchedule.STATUS.CANCELED;
import static com.tomastc.anickd.lib.ProductionSchedule.STATUS.OUTER_PACKED;
import static com.tomastc.anickd.lib.ProductionSchedule.STATUS.STOP_CASE;
import static com.tomastc.anickd.lib.ProductionSchedule.STATUS.WORKING;

import android.annotation.SuppressLint;
import android.content.Context;
import android.graphics.Color;
import android.media.RingtoneManager;
import android.media.ToneGenerator;
import android.os.Bundle;
import android.util.Log;
import android.view.KeyEvent;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.RelativeLayout;
import android.widget.ScrollView;
import android.widget.Spinner;
import android.widget.TableLayout;
import android.widget.TableRow;
import android.widget.TextView;
import android.widget.Toast;

import com.keyence.autoid.sdk.scan.DecodeResult;
import com.tomastc.anickd.lib.ActionListenerCallback;
import com.tomastc.anickd.lib.CkdInterface;
import com.tomastc.anickd.lib.ErrorCode;
import com.tomastc.anickd.lib.KeyMapping;
import com.tomastc.anickd.lib.PendingMaster;
import com.tomastc.anickd.lib.ProductionSchedule;
import com.tomastc.anickd.lib.Scanner;
import com.tomastc.anickd.lib.Settings;
import com.tomastc.anickd.lib.SpinAdapter;
import com.tomastc.anickd.lib.User;
import com.tomastc.anickd.lib.common.CallbackListener;
import com.tomastc.anickd.lib.common.MessageListener;
import com.tomastc.anickd.lib.common.ScrollToTrick;
import com.tomastc.anickd.lib.common.StringConvert;
import com.tomastc.anickd.lib.common.StringUtil;
import com.tomastc.anickd.lib.common.Utils;

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

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.SortedSet;
import java.util.TreeSet;

import okhttp3.WebSocket;

public class OuterActivity extends Scanner implements
        CallbackListener, MessageListener, CkdInterface {

    private String job_id; // Random hash 32
    private Button btn_main_menu, btn_clear, btn_pending, btn_ng;
    private EditText txt_pc_no, txt_module_code, txt_case_no
            , txt_packing_ttl_qty, txt_packing_ttl_qty_packed, txt_ttl_qty, txt_ttl_qty_packed
            , txt_ttl_seq, txt_ttl_seq_packed;
    private TextView lbl_tablet_no;

    private SpinAdapter pendingSpinAdapter=null, ngSpinAdapter=null;
    private RelativeLayout popupLayout1, popupLayout2;
    private ScrollView scr_contents;
    private TableLayout tbl_contents_label_scan;

    private Map<String, JSONObject> mapItems = new LinkedHashMap<>();

    private int scan_step = 0;
    private boolean waiting_ws_response = false;
    private boolean screen_locked = false;

    private int outer_act_qty = 0;

    private ProductionSchedule.STAGE stage = ProductionSchedule.STAGE.OUTER_PACKING;

    private String pc_no, module_code, control_no, first_3_mtoc, s_case_no;
    private int case_no;

    private int prevent_duplicate_check = 0; // v1.4.6

    /**
     * Variables to keep buffering for step 3 scan
     */
//    String contents_label_scan;
    Map<String, Object> keymap_label_scan = new LinkedHashMap<>();

    private JSONArray j_schedules;
    private JSONObject matched_schedule, j_ext;

    private void redrawContentsLabelScanList() {
        redrawContentsLabelScanList(null);
    }

    /**
     * Function redrawContentsLabelScanList
     * @param scroll_to_schedule_id - Scroll to schedule ID (null for not focus)
     */
    private void redrawContentsLabelScanList(String scroll_to_schedule_id) {

        Log.d(getString(R.string.tag), "redrawContentsLabelScanList() called");

        TableRow scroll_to_row = null;

        try {
            Context context = getApplicationContext();

            // clear tbl_serial_scan
            tbl_contents_label_scan.removeAllViews();

            int i = 0;
            Comparator<JSONObject> comparator = (JSONObject o1, JSONObject o2) -> {
                try {
                    if (o1.getString("model_no").equalsIgnoreCase("PPP"))
                        return o1.getInt("item_no") - o2.getInt("item_no");
                    else
                        return o1.getInt("case_packing_seq") - o2.getInt("case_packing_seq");
                } catch (Exception e) {
                    return 0;
                }
            };

            int colorYellow = Color.argb(0xff, 0xff, 0xff, 0x00);
            int colorGreen = Color.argb(0xff, 0x00, 0xff, 0x00);
            int colorRed = Color.argb(0xff, 0xff, 0x00, 0x00);
            int colorBlack = Color.argb(0xff, 0x00, 0x00, 0x00);
            int colorWhite = Color.argb(0xff, 0xff, 0xff, 0xff);

            SortedSet<JSONObject> items = new TreeSet<>(comparator);
            items.addAll(mapItems.values());
            for (JSONObject item : items) {

                int bgColor = Color.argb((++i%2) == 0 ? 0x30 : 0x10, 0xaa, 0xaa, 0xaa);
                int bgColorStatus = bgColor;
                int textColor = colorBlack;

                //JSONObject item = mapItems.get(key);
                String seq_no = item.getString(
                        item.getString("model_no").equalsIgnoreCase("PPP") ? "packing_no" : "case_packing_seq");
                //String item_no = item.getString("item_no");
                String part_no = item.getString("part_no");
                //String qty_in_case = item.getString("outer_act_packing_in_case") + "/" +
                //        item.getInt("packing_qty_in_case");
                String qty_in_case;


                //Supported multiple cases packing
                int outer_act_packing_in_case = item.getInt("outer_act_packing_in_case");
                qty_in_case = String.format("%d/%d", outer_act_packing_in_case, item.getInt("packing_qty_in_case"));

                if (outer_act_packing_in_case >= item.getInt("packing_qty_in_case")) {
                    bgColorStatus = colorGreen;
                } else if (item.getInt("outer_act_packing_in_case") > 0) {
                    bgColorStatus = colorYellow;
                }

                if (item.getString("status").equalsIgnoreCase(ProductionSchedule.STATUS.CANCELED.toString())) {
                    bgColorStatus = colorRed;
                    bgColor = colorRed;
                    textColor = colorWhite;
                    qty_in_case = "C/P";
                }

                TableRow tableRow = new TableRow(context);
                TableRow.LayoutParams layoutParams = new TableRow.LayoutParams(
                        TableLayout.LayoutParams.MATCH_PARENT, TableRow.LayoutParams.WRAP_CONTENT);
                layoutParams.setMargins(1,1,1,1);
                tableRow.setLayoutParams(layoutParams);

                TextView textView = new TextView(context);
                textView.setText(seq_no);
                textView.setWidth(45);
                textView.setHeight(30);
                textView.setTextAlignment(View.TEXT_ALIGNMENT_CENTER);
                textView.setBackgroundColor(bgColor);
                textView.setTextColor(textColor);
                textView.setPadding(1,5,0,0);
                textView.setLayoutParams(layoutParams);
                tableRow.addView(textView);

                /*

                textView = new TextView(context);
                textView.setText(item_no);
                textView.setWidth(45);
                textView.setHeight(30);
                textView.setTextAlignment(View.TEXT_ALIGNMENT_CENTER);
                textView.setBackgroundColor(bgColor);
                textView.setPadding(1,5,0,0);
                textView.setLayoutParams(layoutParams);
                tableRow.addView(textView);


                 */

                textView = new TextView(context);
                textView.setText(part_no);
                textView.setHeight(30);
                textView.setBackgroundColor(bgColor);
                textView.setTextColor(textColor);
                textView.setPadding(1,5,0,0);
                textView.setLayoutParams(layoutParams);
                tableRow.addView(textView);

                textView = new TextView(context);
                textView.setText(qty_in_case);
                textView.setWidth(60);
                textView.setHeight(30);
                textView.setBackgroundColor(bgColorStatus);
                textView.setTextColor(textColor);
                textView.setTextAlignment(View.TEXT_ALIGNMENT_CENTER);
                textView.setPadding(1,5,0,0);
                textView.setLayoutParams(layoutParams);
                tableRow.addView(textView);

                tbl_contents_label_scan.addView(tableRow);

                if (scroll_to_schedule_id == null) { // latest schedule is auto focus
                    scroll_to_row = tableRow;
                } else if (item.getString("id").equalsIgnoreCase(scroll_to_schedule_id)) {
                    scroll_to_row = tableRow;
                }

            }

            // scroll to last item added
            if (scroll_to_row != null)
                scr_contents.post(new ScrollToTrick(scr_contents, scroll_to_row));
        } catch (Exception e) {
            Log.e(getString(R.string.tag), e.getMessage());
            e.printStackTrace();
        }

    }

    @Override
    public void processData(String data, DecodeResult.Result result, String codeType) {

        if (waiting_ws_response
            && Settings.getMgmtList().get("HT_WAIT_SERVER_RESPONSE").equals("1")
        ) {
            alertOk("Please waiting for server response.", new ActionListenerCallback() {
                @Override
                public void onActionSuccess(String successMessage) {
                }

                @Override
                public void onActionFailure(Throwable throwableError) {

                }
            });
            return;
        }

        if (screen_locked) {
            EditText txt_leader_password = (EditText) findViewById(R.id.txt_leader_password);
            txt_leader_password.setEnabled(false);
            txt_leader_password.setText(data);
            Button btn = (Button) findViewById(R.id.popupLayout2_btn1);
            btn.performClick();
            return;
        }

        try {

            Log.d(getString(R.string.tag), String.format("data read[%d bytes]: %s", data.length(), data));

            /**
             * SCAN STEP
             * 1 : scan pc_no on check sheet
             * 2 : scan module code on check sheet
             * 3 : scan pc_no on case mark --> match to check sheet
             * 4 : scan module code on case mark --> match to check sheet
             * 5...n : scan contents label to finish job -- match pc_no to check sheet
             */
            switch (scan_step) {
                case 0:
                    // Format: PC_NO[12]
                    // Length: 12
                    // Other:

                    if (data.length()!=12) {
                        // Send HT_OUTER_PACKING_SCAN_STEP1_FAILED
                        WsClient.sendWsEventLog(this,
                                new HashMap<String, Object>() {{
                                    put("event_det", data);
                                    put("error_code", E110.getId());
                                    put("error_det", E110.getDet());
                                }}
                                , WsProtocol.EVENT.HT_OUTER_PACKING_SCAN_STEP1_FAILED
                                , ProductionSchedule.STATUS.WORKING
                        );
                        alertError(E110.toString(), new ActionListenerCallback() {
                            @Override
                            public void onActionSuccess(String successMessage) throws Exception {

                            }

                            @Override
                            public void onActionFailure(Throwable throwableError) {
                                ErrorCode errorCode = ErrorCode.fromId(Integer.parseInt(throwableError.getMessage()));
                                Toast.makeText(OuterActivity.this, errorCode.toString(), Toast.LENGTH_LONG)
                                        .show();
                                try {
                                    WsClient.sendWsEventLog(OuterActivity.this,
                                            new HashMap<String, Object>() {{
                                                put("event_det", WsProtocol.EVENT.HT_OUTER_PACKING_SCAN_STEP1_FAILED);
                                                put("error_code", errorCode.getId());
                                                put("error_det", errorCode.getDet());
                                            }}
                                            , WsProtocol.EVENT.HT_UNLOCK_SCREEN_FAILED
                                            , ProductionSchedule.STATUS.NG
                                    );
                                } catch (Exception e) {
                                    Log.e(getString(R.string.tag), e.getMessage());
                                }
                            }
                        }, screen_locked=true);
                        return;
                    }

                    pc_no = data.trim();

                    // Update display
                    txt_pc_no.setText(pc_no);

                    scan_step++;

                    break;

                case 1:
                    // Format: MODULE_CODE => CONTROL_NO[4]+MTOC[4]+[ ]...+CASE_NO[...]
                    // Length: -
                    // Other:
                    String p = "([\\d\\w]{8,})\\s+([\\w\\d\\-]{5,})";
                    String[] tmp_ = StringUtil.doScanner(data, p);

                    if (tmp_.length != 2) {
                        // Send HT_OUTER_PACKING_SCAN_STEP1_FAILED
                        WsClient.sendWsEventLog(this,
                                new HashMap<String, Object>() {{
                                    put("event_det", data);
                                    put("error_code", E110.getId());
                                    put("error_det", E110.getDet());
                                }}
                                , WsProtocol.EVENT.HT_OUTER_PACKING_SCAN_STEP1_FAILED
                                , ProductionSchedule.STATUS.NG
                        );
                        alertError(E110.toString(), new ActionListenerCallback() {
                            @Override
                            public void onActionSuccess(String successMessage) throws Exception {

                            }

                            @Override
                            public void onActionFailure(Throwable throwableError) {
                                ErrorCode errorCode = ErrorCode.fromId(Integer.parseInt(throwableError.getMessage()));
                                Toast.makeText(OuterActivity.this, errorCode.toString(), Toast.LENGTH_LONG)
                                        .show();
                                try {
                                    WsClient.sendWsEventLog(OuterActivity.this,
                                            new HashMap<String, Object>() {{
                                                put("event_det", WsProtocol.EVENT.HT_OUTER_PACKING_SCAN_STEP1_FAILED);
                                                put("error_code", errorCode.getId());
                                                put("error_det", errorCode.getDet());
                                            }}
                                            , WsProtocol.EVENT.HT_UNLOCK_SCREEN_FAILED
                                            , ProductionSchedule.STATUS.NG
                                    );
                                } catch (Exception e) {
                                    Log.e(getString(R.string.tag), e.getMessage());
                                }
                            }
                        }, screen_locked=true);
                        return;
                    }

                    // Extract module code
                    module_code = data.trim();
                    control_no = module_code.substring(0,4);
                    first_3_mtoc = module_code.substring(5,8);
                    s_case_no = tmp_[1]; // 2nd token of read data
                    case_no = Integer.parseInt(s_case_no.replaceFirst("^[\\s0]+(?!$)", ""));

                    // Update display
                    txt_module_code.setText(control_no);
                    txt_case_no.setText(String.valueOf(case_no));

                    // Send HT_OUTER_PACKING_SCAN_STEP1
                    // WS should return all schedule related to pass arguments
                    try {
                        waiting_ws_response = true;
                        WsClient.sendWsEventLog(this,
                                new HashMap<String, Object>() {{
                                    put("pc_no", pc_no);
                                    put("control_no", control_no);
                                    put("mtoc", first_3_mtoc);
                                    put("case_no", String.valueOf(case_no));
                                }}
                                , WsProtocol.EVENT.HT_OUTER_PACKING_SCAN_STEP1
                                , ProductionSchedule.STATUS.WORKING
                        );
                    } catch (Exception e) {
                        Log.e(getString(R.string.tag), e.getMessage());
                        e.printStackTrace();
                    }

                    break;

                case 2:
                    // Format: PC_NO[12]
                    // Length: 12
                    // Other: Check packing case

                    if (data.length()!=12) {
                        // Send HT_OUTER_PACKING_SCAN_STEP2_FAILED
                        WsClient.sendWsEventLog(this,
                                new HashMap<String, Object>() {{
                                    put("event_det", data);
                                    put("error_code", E110.getId());
                                    put("error_det", E110.getDet());
                                }}
                                , WsProtocol.EVENT.HT_OUTER_PACKING_SCAN_STEP2_FAILED
                                , ProductionSchedule.STATUS.NG
                        );
                        alertError(E110.toString(), new ActionListenerCallback() {
                            @Override
                            public void onActionSuccess(String successMessage) throws Exception {

                            }

                            @Override
                            public void onActionFailure(Throwable throwableError) {
                                ErrorCode errorCode = ErrorCode.fromId(Integer.parseInt(throwableError.getMessage()));
                                Toast.makeText(OuterActivity.this, errorCode.toString(), Toast.LENGTH_LONG)
                                        .show();
                                try {
                                    WsClient.sendWsEventLog(OuterActivity.this,
                                            new HashMap<String, Object>() {{
                                                put("event_det", WsProtocol.EVENT.HT_OUTER_PACKING_SCAN_STEP2_FAILED);
                                                put("error_code", errorCode.getId());
                                                put("error_det", errorCode.getDet());
                                            }}
                                            , WsProtocol.EVENT.HT_UNLOCK_SCREEN_FAILED
                                            , ProductionSchedule.STATUS.NG
                                    );
                                } catch (Exception e) {
                                    Log.e(getString(R.string.tag), e.getMessage());
                                }
                            }
                        }, screen_locked=true);
                        return;
                    }

                    if (!pc_no.equalsIgnoreCase(data)) {
                        // Send HT_OUTER_PACKING_SCAN_STEP2_FAILED
                        WsClient.sendWsEventLog(this,
                                new HashMap<String, Object>() {{
                                    put("event_det", data);
                                    put("error_code", E117.getId());
                                    put("error_det", E117.getDet());
                                }}
                                , WsProtocol.EVENT.HT_OUTER_PACKING_SCAN_STEP2_FAILED
                                , ProductionSchedule.STATUS.NG
                        );
                        alertError(E117.toString(), new ActionListenerCallback() {
                            @Override
                            public void onActionSuccess(String successMessage) throws Exception {

                            }

                            @Override
                            public void onActionFailure(Throwable throwableError) {
                                ErrorCode errorCode = ErrorCode.fromId(Integer.parseInt(throwableError.getMessage()));
                                Toast.makeText(OuterActivity.this, errorCode.toString(), Toast.LENGTH_LONG)
                                        .show();
                                try {
                                    WsClient.sendWsEventLog(OuterActivity.this,
                                            new HashMap<String, Object>() {{
                                                put("event_det", WsProtocol.EVENT.HT_OUTER_PACKING_SCAN_STEP2_FAILED);
                                                put("error_code", errorCode.getId());
                                                put("error_det", errorCode.getDet());
                                            }}
                                            , WsProtocol.EVENT.HT_UNLOCK_SCREEN_FAILED
                                            , ProductionSchedule.STATUS.NG
                                    );
                                } catch (Exception e) {
                                    Log.e(getString(R.string.tag), e.getMessage());
                                }
                            }
                        }, screen_locked=true);
                        return;

                    }
                    Toast.makeText(OuterActivity.this, "PC No matched.", Toast.LENGTH_LONG)
                            .show();
                    scan_step++;

                    break;

                case 3:
                    // Format: MODULE_CODE[17] => CONTROL_NO[4]+MTOC[4]+CASE_NO[...]
                    // Length: 17
                    // Other:

                    Log.d(getString(R.string.tag), "data read len => " + data.length());

                    if (data.length()!=17
                        || (
                                data.trim().contains(" ") // Version 1.4.11
                            && !data.contains("PPP") // Version 1.4.12
                        )
                    ) {
                        // Send HT_OUTER_PACKING_SCAN_STEP2_FAILED
                        WsClient.sendWsEventLog(this,
                                new HashMap<String, Object>() {{
                                    put("event_det", data);
                                    put("error_code", E110.getId());
                                    put("error_det", E110.getDet());
                                }}
                                , WsProtocol.EVENT.HT_OUTER_PACKING_SCAN_STEP2_FAILED
                                , ProductionSchedule.STATUS.NG
                        );
                        alertError(E110.toString(), new ActionListenerCallback() {
                            @Override
                            public void onActionSuccess(String successMessage) throws Exception {

                            }

                            @Override
                            public void onActionFailure(Throwable throwableError) {
                                ErrorCode errorCode = ErrorCode.fromId(Integer.parseInt(throwableError.getMessage()));
                                Toast.makeText(OuterActivity.this, errorCode.toString(), Toast.LENGTH_LONG)
                                        .show();
                                try {
                                    WsClient.sendWsEventLog(OuterActivity.this,
                                            new HashMap<String, Object>() {{
                                                put("event_det", WsProtocol.EVENT.HT_OUTER_PACKING_SCAN_STEP2_FAILED);
                                                put("error_code", errorCode.getId());
                                                put("error_det", errorCode.getDet());
                                            }}
                                            , WsProtocol.EVENT.HT_UNLOCK_SCREEN_FAILED
                                            , ProductionSchedule.STATUS.NG
                                    );
                                } catch (Exception e) {
                                    Log.e(getString(R.string.tag), e.getMessage());
                                }
                            }
                        }, screen_locked=true);
                        return;
                    }

                    String _module_code = data.trim();
                    String _control_no = _module_code.substring(0,4);
                    String _first_3_mtoc = _module_code.substring(5,8);
                    String _s_case_no = _module_code.substring(8);

                    // Add supported for PPP
                    Log.d(getString(R.string.tag), "read _first_3_mtoc => " + _first_3_mtoc);
                    if (_first_3_mtoc.equals("PPP")) {
                        String tokens[] = _module_code.split(" ");
                        _s_case_no = tokens[1];
                    }

                    int _case_no = Integer.parseInt(_s_case_no.replaceFirst("^[\\s0]+(?!$)", ""));

                    Log.d(getString(R.string.tag), "compare Case mark.");
                    Log.d(getString(R.string.tag), _control_no + "<=>" + control_no);
                    Log.d(getString(R.string.tag), _first_3_mtoc + "<=>" + first_3_mtoc);
                    Log.d(getString(R.string.tag), _case_no + "<=>" + case_no);

                    if (!(
                            _control_no.equalsIgnoreCase(control_no)
                            && _first_3_mtoc.equalsIgnoreCase(first_3_mtoc)
                            && _case_no == case_no
                            )) {

                        // Send HT_OUTER_PACKING_SCAN_STEP2_FAILED
                        WsClient.sendWsEventLog(this,
                                new HashMap<String, Object>() {{
                                    put("event_det", data);
                                    put("error_code", E117.getId());
                                    put("error_det", E117.getDet());
                                }}
                                , WsProtocol.EVENT.HT_OUTER_PACKING_SCAN_STEP2_FAILED
                                , ProductionSchedule.STATUS.NG
                        );
                        alertError(E117.toString(), new ActionListenerCallback() {
                            @Override
                            public void onActionSuccess(String successMessage) throws Exception {

                            }

                            @Override
                            public void onActionFailure(Throwable throwableError) {
                                ErrorCode errorCode = ErrorCode.fromId(Integer.parseInt(throwableError.getMessage()));
                                Toast.makeText(OuterActivity.this, errorCode.toString(), Toast.LENGTH_LONG)
                                        .show();
                                try {
                                    WsClient.sendWsEventLog(OuterActivity.this,
                                            new HashMap<String, Object>() {{
                                                put("event_det", WsProtocol.EVENT.HT_OUTER_PACKING_SCAN_STEP2_FAILED);
                                                put("error_code", errorCode.getId());
                                                put("error_det", errorCode.getDet());
                                            }}
                                            , WsProtocol.EVENT.HT_UNLOCK_SCREEN_FAILED
                                            , ProductionSchedule.STATUS.NG
                                    );
                                } catch (Exception e) {
                                    Log.e(getString(R.string.tag), e.getMessage());
                                }
                            }
                        }, screen_locked=true);
                        return;

                    }

                    Toast.makeText(OuterActivity.this, "Module code matched.", Toast.LENGTH_LONG)
                            .show();

                    // Send HT_OUTER_PACKING_SCAN_STEP2_SUCCESS
                    WsClient.sendWsEventLog(this,
                            null
                            , WsProtocol.EVENT.HT_OUTER_PACKING_SCAN_STEP2_SUCCESS
                            , ProductionSchedule.STATUS.WORKING
                    );

                    // find total of qty and packing
                    /*
                    int ttl_qty = 0;
                    int ttl_qty_packed = 0;
                    int ttl_packing_qty = 0;
                    int ttl_packing_qty_packed = 0;
                    for (int i=0;i<j_schedules.length();i++) {
                        ttl_qty += j_schedules.getJSONObject(i).getInt("outer_plan_qty");
                        ttl_packing_qty += j_schedules.getJSONObject(i).getInt("packing_qty_in_case");
                        ttl_qty_packed += j_schedules.getJSONObject(i).getInt("outer_act_qty");
                        ttl_packing_qty_packed += j_schedules.getJSONObject(i).getInt("outer_act_packing_in_case");
                    }

                    txt_ttl_qty.setText(String.valueOf(ttl_qty));
                    txt_ttl_qty_packed.setText(String.valueOf(ttl_qty_packed));
                    txt_packing_ttl_qty.setText(String.valueOf(ttl_packing_qty));
                    txt_packing_ttl_qty_packed.setText(String.valueOf(ttl_packing_qty_packed));

                     */

                    txt_case_no.setBackgroundColor(getColor(R.color.green));
                    scan_step++;
                    break;

                case 4:
                    if (data.length() < 140) {
                        // Send HT_OUTER_PACKING_SCAN_STEP3_FAILED
                        WsClient.sendWsEventLog(this,
                                new HashMap<String, Object>() {{
                                    put("event_det", data);
                                    put("error_code", E110.getId());
                                    put("error_det", E110.getDet());
                                }}
                                , WsProtocol.EVENT.HT_OUTER_PACKING_SCAN_STEP3_FAILED
                                , ProductionSchedule.STATUS.NG
                        );
                        alertError(E110.toString(), new ActionListenerCallback() {
                            @Override
                            public void onActionSuccess(String successMessage) throws Exception {

                            }

                            @Override
                            public void onActionFailure(Throwable throwableError) {
                                ErrorCode errorCode = ErrorCode.fromId(Integer.parseInt(throwableError.getMessage()));
                                Toast.makeText(OuterActivity.this, errorCode.toString(), Toast.LENGTH_LONG)
                                        .show();
                                try {
                                    WsClient.sendWsEventLog(OuterActivity.this,
                                            new HashMap<String, Object>() {{
                                                put("event_det", WsProtocol.EVENT.HT_OUTER_PACKING_SCAN_STEP3_FAILED);
                                                put("error_code", errorCode.getId());
                                                put("error_det", errorCode.getDet());
                                            }}
                                            , WsProtocol.EVENT.HT_UNLOCK_SCREEN_FAILED
                                            , ProductionSchedule.STATUS.NG
                                    );
                                } catch (Exception e) {
                                    Log.e(getString(R.string.tag), e.getMessage());
                                }
                            }
                        }, screen_locked=true);
                        return;
                    }

                    if (j_schedules == null) {// Send HT_OUTER_PACKING_SCAN_STEP3_FAILED
                        WsClient.sendWsEventLog(this,
                                new HashMap<String, Object>() {{
                                    put("event_det", data);
                                    put("error_code", E113.getId());
                                    put("error_det", E113.getDet());
                                }}
                                , WsProtocol.EVENT.HT_OUTER_PACKING_SCAN_STEP3_FAILED
                                , ProductionSchedule.STATUS.NG
                        );
                        alertError(E113.toString(), new ActionListenerCallback() {
                            @Override
                            public void onActionSuccess(String successMessage) throws Exception {

                            }

                            @Override
                            public void onActionFailure(Throwable throwableError) {
                                ErrorCode errorCode = ErrorCode.fromId(Integer.parseInt(throwableError.getMessage()));
                                Toast.makeText(OuterActivity.this, errorCode.toString(), Toast.LENGTH_LONG)
                                        .show();
                                try {
                                    WsClient.sendWsEventLog(OuterActivity.this,
                                            new HashMap<String, Object>() {{
                                                put("event_det", WsProtocol.EVENT.HT_OUTER_PACKING_SCAN_STEP3_FAILED);
                                                put("error_code", errorCode.getId());
                                                put("error_det", errorCode.getDet());
                                            }}
                                            , WsProtocol.EVENT.HT_UNLOCK_SCREEN_FAILED
                                            , ProductionSchedule.STATUS.NG
                                    );
                                } catch (Exception e) {
                                    Log.e(getString(R.string.tag), e.getMessage());
                                }
                            }
                        }, screen_locked=true);
                        return;
                    }

                    // v1.4.6
                    // Reset prevent_check_duplicate if the current label scan isn't the same as old
//                    if (!data.equalsIgnoreCase(contents_label_scan) && prevent_duplicate_check==1) {
//                        Log.d(getString(R.string.tag), "Reset prevent_duplicate_check flag coz it isn't the same as old.");
//                        prevent_duplicate_check = 0;
//                    }

                    // Extract and label validation
                    HashMap<String, Object> map = extractContentsLable(data);


                    Log.d(getString(R.string.tag), "compare Case mark.");
                    Log.d(getString(R.string.tag), "Control no : " + map.get("control_no") + "<=>" + control_no);
                    //Log.d(getString(R.string.tag), "MTOC : " + map.get("mtoc") + "<=>" + first_3_mtoc);
                    Log.d(getString(R.string.tag), "PC no : " + map.get("pc_no") + "<=>" + pc_no);
                    Log.d(getString(R.string.tag), "Case no : " + map.get("case_no") + "<=>" + String.valueOf(case_no));

                    // Matching with case mark
                    if (!(
                            // Add supported for PPP
                            // map.get("control_no").toString().equalsIgnoreCase(control_no)
                            map.get("control_no").toString().startsWith(control_no)
                            //&& map.get("mtoc").toString().substring(0,3).equalsIgnoreCase(first_3_mtoc)
                            && map.get("pc_no").toString().equalsIgnoreCase(pc_no)
                            && map.get("case_no").toString().equalsIgnoreCase(String.valueOf(case_no))
                    )) {

                        // Send HT_OUTER_PACKING_SCAN_STEP3_FAILED
                        WsClient.sendWsEventLog(this,
                                new HashMap<String, Object>() {{
                                    put("event_det", data);
                                    put("error_code", E117.getId());
                                    put("error_det", E117.getDet());
                                }}
                                , WsProtocol.EVENT.HT_OUTER_PACKING_SCAN_STEP3_FAILED
                                , ProductionSchedule.STATUS.NG
                        );
                        alertError(E117.toString(), new ActionListenerCallback() {
                            @Override
                            public void onActionSuccess(String successMessage) throws Exception {

                            }

                            @Override
                            public void onActionFailure(Throwable throwableError) {
                                ErrorCode errorCode = ErrorCode.fromId(Integer.parseInt(throwableError.getMessage()));
                                Toast.makeText(OuterActivity.this, errorCode.toString(), Toast.LENGTH_LONG)
                                        .show();
                                try {
                                    WsClient.sendWsEventLog(OuterActivity.this,
                                            new HashMap<String, Object>() {{
                                                put("event_det", WsProtocol.EVENT.HT_OUTER_PACKING_SCAN_STEP3_FAILED);
                                                put("error_code", errorCode.getId());
                                                put("error_det", errorCode.getDet());
                                            }}
                                            , WsProtocol.EVENT.HT_UNLOCK_SCREEN_FAILED
                                            , ProductionSchedule.STATUS.NG
                                    );
                                } catch (Exception e) {
                                    Log.e(getString(R.string.tag), e.getMessage());
                                }
                            }
                        }, screen_locked=true);
                        return;

                    }

                    // Validating part_no/part_item
                    boolean isFound = false;
                    for (int i=0; i<j_schedules.length(); i++) {
                        JSONObject j_schedule = j_schedules.getJSONObject(i);
                        if (
                                j_schedule.getString("part_no").equalsIgnoreCase(map.get("part_no").toString())
                                && j_schedule.getString("part_color").equalsIgnoreCase(map.get("part_color").toString())
                        ) {
                            isFound = true;
                            break;
                        }
                    }
                    if (!isFound) {

                        // Send HT_OUTER_PACKING_SCAN_STEP3_FAILED
                        WsClient.sendWsEventLog(this,
                                new HashMap<String, Object>() {{
                                    put("event_det", data);
                                    put("error_code", E123.getId());
                                    put("error_det", E123.getDet());
                                }}
                                , WsProtocol.EVENT.HT_OUTER_PACKING_SCAN_STEP3_FAILED
                                , ProductionSchedule.STATUS.NG
                        );
                        alertError(E123.toString(), new ActionListenerCallback() {
                            @Override
                            public void onActionSuccess(String successMessage) throws Exception {

                            }

                            @Override
                            public void onActionFailure(Throwable throwableError) {
                                ErrorCode errorCode = ErrorCode.fromId(Integer.parseInt(throwableError.getMessage()));
                                Toast.makeText(OuterActivity.this, errorCode.toString(), Toast.LENGTH_LONG)
                                        .show();
                                try {
                                    WsClient.sendWsEventLog(OuterActivity.this,
                                            new HashMap<String, Object>() {{
                                                put("event_det", WsProtocol.EVENT.HT_OUTER_PACKING_SCAN_STEP3_FAILED);
                                                put("error_code", errorCode.getId());
                                                put("error_det", errorCode.getDet());
                                            }}
                                            , WsProtocol.EVENT.HT_UNLOCK_SCREEN_FAILED
                                            , ProductionSchedule.STATUS.NG
                                    );
                                } catch (Exception e) {
                                    Log.e(getString(R.string.tag), e.getMessage());
                                }
                            }
                        }, screen_locked=true);
                        return;

                    }

                    // v1.4.6 - Check cut part scan
                    boolean isCutpart = false;
                    for (int i=0; i<j_schedules.length(); i++) {
                        JSONObject j_schedule = j_schedules.getJSONObject(i);
                        Log.d(getString(R.string.tag), j_schedule.getString("part_no") + " <==> " + map.get("part_no").toString());
                        Log.d(getString(R.string.tag), j_schedule.getString("part_color") + " <==> " + map.get("part_color").toString());
                        Log.d(getString(R.string.tag), j_schedule.getString("packing_no") + " <==> " + map.get("seq_no").toString());
                        Log.d(getString(R.string.tag), j_schedule.getString("status") + " <==> " + CANCELED.toString());
                        if (
                                j_schedule.getString("part_no").equalsIgnoreCase(map.get("part_no").toString())
                                        && j_schedule.getString("part_color").equalsIgnoreCase(map.get("part_color").toString())
                                        && j_schedule.getInt("packing_no") == Integer.parseInt(map.get("seq_no").toString())
                                        && j_schedule.getString("status").equalsIgnoreCase(CANCELED.toString())
                        ) {
                            isCutpart = true;
                            break;
                        }
                    }
                    if (isCutpart) {

                        // Send HT_OUTER_PACKING_SCAN_STEP3_FAILED
                        WsClient.sendWsEventLog(this,
                                new HashMap<String, Object>() {{
                                    put("event_det", data);
                                    put("error_code", E124.getId());
                                    put("error_det", E124.getDet());
                                }}
                                , WsProtocol.EVENT.HT_OUTER_PACKING_SCAN_STEP3_FAILED
                                , ProductionSchedule.STATUS.NG
                        );
                        alertError(E124.toString(), new ActionListenerCallback() {
                            @Override
                            public void onActionSuccess(String successMessage) throws Exception {

                            }

                            @Override
                            public void onActionFailure(Throwable throwableError) {
                                ErrorCode errorCode = ErrorCode.fromId(Integer.parseInt(throwableError.getMessage()));
                                Toast.makeText(OuterActivity.this, errorCode.toString(), Toast.LENGTH_LONG)
                                        .show();
                                try {
                                    WsClient.sendWsEventLog(OuterActivity.this,
                                            new HashMap<String, Object>() {{
                                                put("event_det", WsProtocol.EVENT.HT_OUTER_PACKING_SCAN_STEP3_FAILED);
                                                put("error_code", errorCode.getId());
                                                put("error_det", errorCode.getDet());
                                            }}
                                            , WsProtocol.EVENT.HT_UNLOCK_SCREEN_FAILED
                                            , ProductionSchedule.STATUS.NG
                                    );
                                } catch (Exception e) {
                                    Log.e(getString(R.string.tag), e.getMessage());
                                }
                            }
                        }, screen_locked=true);
                        return;

                    }

                    // Send HT_OUTER_PACKING_SCAN_STEP3
                    // WS will check the duplicated and record the scan contents lable
                    // It will return the participated schedule
                    map.put("payload", data);
                    if (prevent_duplicate_check==1) {
                        Log.d(getString(R.string.tag), "Found previous duplicated error, temporary prevent duplicate check has been set.");
                        map.put("prevent_duplicate_check", prevent_duplicate_check);
                        prevent_duplicate_check = 0;
                    }
                    waiting_ws_response = true;
                    WsClient.sendWsEventLog(this,
                            map
                            , WsProtocol.EVENT.HT_OUTER_PACKING_SCAN_STEP3
                            , ProductionSchedule.STATUS.WORKING
                    );


                    String Key = String.format("%s%s%s%s%s%s%s",
                                map.get("pc_no").toString().trim(),
                                map.get("part_no").toString().trim(),
                                map.get("part_color").toString().trim(),
                                map.get("control_no").toString().substring(0,4),
                                map.get("case_no").toString().trim(),
                                map.get("item_no").toString().trim(),
                                map.get("serial_no").toString().trim());

                    keymap_label_scan.put(Key, map);
                    Log.d(getString(R.string.tag), "keymap_label_scan : "+Key);
                    Log.d(getString(R.string.tag), "keymap_label_scan Size : "+keymap_label_scan.size());

                    break;
            }

            // always hide keyboard after scan
            //Utils.hideKeyboardFrom(getApplicationContext(), default_view);

        } catch (Exception e) {
            Log.e(getString(R.string.tag), "ERROR: " + e.getMessage());
            alertError("Please try again!!", new ActionListenerCallback() {
                @Override
                public void onActionSuccess(String successMessage) throws Exception {

                }

                @Override
                public void onActionFailure(Throwable throwableError) {

                }
            }, screen_locked=false);
        }
    }

    @SuppressLint("MissingInflatedId")
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_outer);

        default_view = (EditText) findViewById(R.id.txt_tmp);

        // update MessageListener class
        WsClient.getInstance().setOnMessageListener(this);

        btn_main_menu = (Button) findViewById(R.id.btn_main_menu);
        btn_clear = (Button) findViewById(R.id.btn_clear);
        btn_pending = (Button) findViewById(R.id.btn_pending);
        btn_ng = (Button) findViewById(R.id.btn_ng);

        tbl_contents_label_scan = (TableLayout)findViewById(R.id.tbl_contents_label_scan);

        txt_pc_no = (EditText) findViewById(R.id.txt_pc_no);
        txt_module_code = (EditText) findViewById(R.id.txt_module_code);
        txt_case_no = (EditText) findViewById(R.id.txt_case_no);
        txt_packing_ttl_qty = (EditText) findViewById(R.id.txt_packing_ttl_qty);
        txt_packing_ttl_qty_packed = (EditText) findViewById(R.id.txt_packing_ttl_qty_packed);
        txt_ttl_qty = (EditText) findViewById(R.id.txt_ttl_qty);
        txt_ttl_qty_packed = (EditText) findViewById(R.id.txt_ttl_qty_packed);
        txt_ttl_seq = (EditText) findViewById(R.id.txt_ttl_seq);
        txt_ttl_seq_packed = (EditText) findViewById(R.id.txt_ttl_seq_packed);
        lbl_tablet_no = (TextView) findViewById(R.id.lbl_tablet_no);

        popupLayout1 = (RelativeLayout) findViewById(R.id.popupLayout1);
        popupLayout2 = (RelativeLayout) findViewById(R.id.popupLayout2);
        scr_contents = (ScrollView) findViewById(R.id.scr_contents);

        reset();

        try {
            // Set AREA
            WsClient.sendWs(OuterActivity.this,
                new HashMap<String, Object>() {{
                    put("area", ProductionSchedule.AREA.OUTER_PACKING);
                }}
                , WsProtocol.COMMAND.SET_AREA_REQUEST
            );

            // Get paired tablet device id
            WsClient.sendWs(OuterActivity.this,
                new HashMap<String, Object>() {{
                    put("area", ProductionSchedule.AREA.OUTER_PACKING);
                }}
                , WsProtocol.COMMAND.GET_PAIRED_DEVICE_REQUEST
            );
        } catch (Exception e) {
            Log.e(getString(R.string.tag), "ERROR: " + e.getMessage());
        }

        btn_main_menu.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                // stop activity
                finish();
            }
        });
        btn_clear.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                reset();
            }
        });

        // Set the remaining uncompleted schedules to pending status
        btn_pending.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                // It need to be loaded the all schedules list
                if (scan_step < 2) {
                    alertError("Please scan check sheet first.", new ActionListenerCallback() {
                        @Override
                        public void onActionSuccess(String successMessage) throws Exception {

                        }

                        @Override
                        public void onActionFailure(Throwable throwableError) {

                        }
                    }, screen_locked=false);
                }

                // Open pending dialog
                if (pendingSpinAdapter == null) {
                    JSONArray jArray = MainActivity.pendingMasterJsonArray;
                    if (jArray!=null) {

                        try {
                            if (jArray.length() == 0)
                                return;

                            List<PendingMaster> list = new ArrayList<>();
                            for (int i=0;i<jArray.length();i++) {
                                if (jArray.getJSONObject(i).getString("sec").equalsIgnoreCase("pending")) {
                                    String id = jArray.getJSONObject(i).getString("id");
                                    String name = jArray.getJSONObject(i).getString("mesg");

                                    list.add(new PendingMaster(id, name));
                                }
                            }
                            PendingMaster[] pendingMasters = list.toArray(new PendingMaster[0]);

                            Log.d(getString(R.string.tag), Arrays.deepToString(pendingMasters));

                            pendingSpinAdapter = new SpinAdapter(
                                    getApplicationContext(), R.layout.spinner_usr_list, pendingMasters);

                        } catch (Exception e) {
                            Log.e(getString(R.string.tag), "ERROR: " + e.getMessage());
                            alertError(e.getMessage(), new ActionListenerCallback() {
                                @Override
                                public void onActionSuccess(String successMessage) throws Exception {

                                }

                                @Override
                                public void onActionFailure(Throwable throwableError) {

                                }
                            }, screen_locked=false);
                        }
                    }
                }

                if (pendingSpinAdapter.getCount() == 0) {
                    alertError(E115.toString(), new ActionListenerCallback() {
                        @Override
                        public void onActionSuccess(String successMessage) throws Exception {

                        }

                        @Override
                        public void onActionFailure(Throwable throwableError) {
                            ErrorCode errorCode = ErrorCode.fromId(Integer.parseInt(throwableError.getMessage()));
                            Toast.makeText(OuterActivity.this, errorCode.toString(), Toast.LENGTH_LONG)
                                    .show();
                            try {
                                WsClient.sendWsEventLog(OuterActivity.this,
                                        new HashMap<String, Object>() {{
                                            put("event_det", WsProtocol.EVENT.HT_OUTER_PACKING_PENDING);
                                            put("error_code", errorCode.getId());
                                            put("error_det", errorCode.getDet());
                                        }}
                                        , WsProtocol.EVENT.HT_UNLOCK_SCREEN_FAILED
                                        , ProductionSchedule.STATUS.NG
                                );
                            } catch (Exception e) {
                                Log.e(getString(R.string.tag), e.getMessage());
                            }

                        }
                    }, screen_locked=true);

                    return;
                }

                // get uncompleted list
                JSONArray uncompleted_list = new JSONArray();
                try {
                    for (int i=0;i<j_schedules.length();i++) {
                        // Skip CANCELED records
                        if (j_schedules.getJSONObject(i).getString("status")
                                .equalsIgnoreCase(ProductionSchedule.STATUS.CANCELED.toString())) {
                            continue;
                        }

                        if (!mapItems.containsKey(j_schedules.getJSONObject(i).getString("id"))) {
                            uncompleted_list.put(j_schedules.getJSONObject(i));
                        } else {
                            JSONObject item = mapItems.get(j_schedules.getJSONObject(i).getString("id"));
                            if (item.getInt("outer_act_qty") < item.getInt("outer_plan_qty")) {
                                uncompleted_list.put(j_schedules.getJSONObject(i));
                            }
                        }
                    }

                    confirmation("Please select the reason for pending "
                                    + uncompleted_list.length() + " content(s).\n"
                            , getColor(R.color.red)
                            , true
                            , new ActionListenerCallback() {
                                @Override
                                public void onActionSuccess(String successMessage) throws Exception {
                                    WsClient.sendWsEventLog(OuterActivity.this,
                                            new HashMap<String, Object>() {{
                                                put("event_det", successMessage);
                                                put("schedules", uncompleted_list);
                                            }}
                                            , WsProtocol.EVENT.HT_OUTER_PACKING_PENDING
                                            , ProductionSchedule.STATUS.PENDING
                                    );
                                }

                                @Override
                                public void onActionFailure(Throwable throwableError) {

                                }
                            }, pendingSpinAdapter);


                } catch (Exception e) {
                    Log.e(getString(R.string.tag), "ERROR: " + e.getMessage());
                    alertError(e.getMessage(), new ActionListenerCallback() {
                        @Override
                        public void onActionSuccess(String successMessage) throws Exception {

                        }

                        @Override
                        public void onActionFailure(Throwable throwableError) {

                        }
                    }, screen_locked=false);
                }

            }
        });
        btn_ng.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                // It need to be loaded the all schedules list
                if (scan_step < 2) {
                    alertError("Please scan check sheet first.", new ActionListenerCallback() {
                        @Override
                        public void onActionSuccess(String successMessage) throws Exception {

                        }

                        @Override
                        public void onActionFailure(Throwable throwableError) {

                        }
                    }, screen_locked=false);
                }

                // Open NG dialog
                if (ngSpinAdapter == null) {
                    JSONArray jArray = MainActivity.pendingMasterJsonArray;
                    if (jArray!=null) {

                        try {
                            if (jArray.length() == 0)
                                return;

                            List<PendingMaster> list = new ArrayList<>();
                            for (int i=0;i<jArray.length();i++) {
                                if (jArray.getJSONObject(i).getString("sec").equalsIgnoreCase("ng")) {
                                    String id = jArray.getJSONObject(i).getString("id");
                                    String name = jArray.getJSONObject(i).getString("mesg");

                                    list.add(new PendingMaster(id, name));
                                }
                            }
                            PendingMaster[] pendingMasters = list.toArray(new PendingMaster[0]);

                            Log.d(getString(R.string.tag), Arrays.deepToString(pendingMasters));

                            ngSpinAdapter = new SpinAdapter(
                                    getApplicationContext(), R.layout.spinner_usr_list, pendingMasters);

                        } catch (Exception e) {
                            Log.e(getString(R.string.tag), "ERROR: " + e.getMessage());
                            alertError(e.getMessage(), new ActionListenerCallback() {
                                @Override
                                public void onActionSuccess(String successMessage) throws Exception {

                                }

                                @Override
                                public void onActionFailure(Throwable throwableError) {

                                }
                            }, screen_locked=false);
                        }
                    }
                }

                if (ngSpinAdapter.getCount() == 0) {
                    alertError(E116.toString(), new ActionListenerCallback() {
                        @Override
                        public void onActionSuccess(String successMessage) throws Exception {

                        }

                        @Override
                        public void onActionFailure(Throwable throwableError) {
                            ErrorCode errorCode = ErrorCode.fromId(Integer.parseInt(throwableError.getMessage()));
                            Toast.makeText(OuterActivity.this, errorCode.toString(), Toast.LENGTH_LONG)
                                    .show();
                            try {
                                WsClient.sendWsEventLog(OuterActivity.this,
                                        new HashMap<String, Object>() {{
                                            put("event_det", WsProtocol.EVENT.HT_OUTER_PACKING_NG);
                                            put("error_code", errorCode.getId());
                                            put("error_det", errorCode.getDet());
                                        }}
                                        , WsProtocol.EVENT.HT_UNLOCK_SCREEN_FAILED
                                        , ProductionSchedule.STATUS.NG
                                );
                            } catch (Exception e) {
                                Log.e(getString(R.string.tag), e.getMessage());
                            }

                        }
                    }, screen_locked=true);

                    return;
                }

                // get uncompleted list
                JSONArray uncompleted_list = new JSONArray();
                try {
                    for (int i=0;i<j_schedules.length();i++) {
                        // Skip CANCELED records
                        if (j_schedules.getJSONObject(i).getString("status")
                                .equalsIgnoreCase(ProductionSchedule.STATUS.CANCELED.toString())) {
                            continue;
                        }

                        if (!mapItems.containsKey(j_schedules.getJSONObject(i).getString("id"))) {
                            uncompleted_list.put(j_schedules.getJSONObject(i));
                        } else {
                            JSONObject item = mapItems.get(j_schedules.getJSONObject(i).getString("id"));
                            if (item.getInt("outer_act_qty") < item.getInt("outer_plan_qty")) {
                                uncompleted_list.put(j_schedules.getJSONObject(i));
                            }
                        }
                    }

                    confirmation("Please select the reason for NG "
                                    + uncompleted_list.length() + " content(s).\n"
                            , getColor(R.color.red)
                            , true
                            , new ActionListenerCallback() {
                                @Override
                                public void onActionSuccess(String successMessage) throws Exception {
                                    WsClient.sendWsEventLog(OuterActivity.this,
                                            new HashMap<String, Object>() {{
                                                put("event_det", successMessage);
                                                put("schedules", uncompleted_list);
                                            }}
                                            , WsProtocol.EVENT.HT_OUTER_PACKING_NG
                                            , ProductionSchedule.STATUS.NG
                                    );
                                }

                                @Override
                                public void onActionFailure(Throwable throwableError) {

                                }
                            }, ngSpinAdapter);


                } catch (Exception e) {
                    Log.e(getString(R.string.tag), "ERROR: " + e.getMessage());
                    alertError(e.getMessage(), new ActionListenerCallback() {
                        @Override
                        public void onActionSuccess(String successMessage) throws Exception {

                        }

                        @Override
                        public void onActionFailure(Throwable throwableError) {

                        }
                    }, screen_locked=false);
                }
            }
        });
    }

    private HashMap<String, Object> extractContentsLable(String data) {
        HashMap<String, Object> map = new HashMap<String, Object>(){{
            put("pc_no", data.substring(0,12).trim().replace("-",""));
            put("part_no", data.substring(69,84).trim().replace("-",""));
            put("part_color", data.substring(119,130).trim()); // also supported part color 11 digits
            put("control_no", data.substring(130,145).trim());
            put("mtoc", data.substring(31,54).trim().replace("-",""));
            put("case_no", data.substring(152,157).trim().replaceFirst("^0+", ""));
            put("item_no", data.substring(84,89).trim());
            put("qty_in_case", data.substring(157,164).trim().replaceFirst("^0+", ""));
            put("qty_in_bag", data.substring(164,178).trim().replaceFirst("^0+", ""));
            put("seq_no", data.substring(178,181).trim().replaceFirst("^0+", ""));
            put("serial_no", data.substring(213,216).trim());

        }};

        return map;
    }

    private void reset() {
        job_id = StringConvert.randomHex(32);
        scan_step = 0;
        j_schedules = null;
        matched_schedule = null;

        waiting_ws_response = false;

//        contents_label_scan = "";

        txt_pc_no.setText("");
        txt_module_code.setText("");
        txt_case_no.setText("");
        txt_case_no.setBackgroundColor(getColor(R.color.silver));
        txt_packing_ttl_qty.setText("0");
        txt_packing_ttl_qty_packed.setText("0");
        txt_ttl_qty.setText("0");
        txt_ttl_qty_packed.setText("0");
        txt_ttl_seq.setText("0");
        txt_ttl_seq_packed.setText("0");
        tbl_contents_label_scan.removeAllViews();
        mapItems.clear();
        keymap_label_scan.clear();

        // Send HT_OUTER_PACKING_OPEN
        try {
            WsClient.sendWsEventLog(OuterActivity.this,
                    null
                    , WsProtocol.EVENT.HT_OUTER_PACKING_OPEN
                    , ProductionSchedule.STATUS.WORKING
            );
        } catch (Exception e) {
            Log.e(getString(R.string.tag), e.getMessage());
        }
    }

    @Override
    public void onFinished(String result) {

    }

    @Override
    public void onMessage(WebSocket webSocket, String text) {
        waiting_ws_response = false;

        Log.d(getString(R.string.tag), String.format("%s : received[len=%d] -> \"%s\"", this.getLocalClassName(),
                text.length(), text));

        runOnUiThread(new Runnable() {

            @Override
            public void run() {

                try {
                    JSONObject jsonObject = new JSONObject(text);
                    JSONObject j_ext;

                    Log.d(getString(R.string.tag), "cmd=>" + jsonObject.getString("cmd"));

                    switch (WsProtocol.COMMAND.valueOf(jsonObject.getString("cmd"))) {

                        case HELLO:
                            j_ext = new JSONObject(jsonObject.getString("ext"));
                            WsClient.getInstance().client_id = j_ext.getInt("id");

                            WsClient.sendWs(OuterActivity.this, null, WsProtocol.COMMAND.REGISTER_REQUEST);
                            break;

                        case DEVICE_PAIRING_NOTIFY_REQUEST:
                            lbl_tablet_no.setText(jsonObject.getJSONObject("ext").getString("device_id"));

                            WsClient.sendWs(OuterActivity.this, null, WsProtocol.COMMAND.DEVICE_PAIRING_NOTIFY_ACK);
                            break;

                        case GET_PAIRED_DEVICE_ACK:
                            lbl_tablet_no.setText("");
                            JSONArray jarry = new JSONArray(jsonObject.getString("ext"));
                            if (jarry.length() > 0) {
                                String tmp = "";
                                for (int i=0; i<jarry.length(); i++) {
                                    tmp = String.format("%s%s%s", tmp, (i>0?",":""), jarry.getJSONObject(i).getString("device_id"));
                                }
                                lbl_tablet_no.setText(tmp);
                            }

                            break;

                        case EVENT_LOG_ACK:
                            Log.d(getString(R.string.tag), jsonObject.has("ext") ? "has ext" : "don't have ext");
                            if (jsonObject.has("ext") && jsonObject.getJSONObject("ext").has("event")) {
                                Log.d(getString(R.string.tag), "event=>" + jsonObject.getJSONObject("ext").getString("event"));
                                switch (WsProtocol.EVENT.valueOf(
                                        jsonObject.getJSONObject("ext").getString("event"))) {
                                    case HT_OUTER_PACKING_SCAN_STEP1_SUCCESS:

                                        Log.d(getString(R.string.tag), jsonObject.getJSONObject("ext").has("event_det") ? "has event_det" : "don't have event_det");
                                        if (jsonObject.getJSONObject("ext").has("event_det")) {
                                            j_schedules = jsonObject.getJSONObject("ext").getJSONArray("event_det");

                                            Log.d(getString(R.string.tag), String.format("Size of packing list : %d", j_schedules.length()));

                                            // Put packed items to table list
                                            boolean isUpdate = false;
                                            int ttl_qty=0, ttl_packing_qty=0, ttl_seq_packed=0, ttl_qty_packed=0, ttl_packing_qty_packed=0;
                                            for (int i=0;i<j_schedules.length();i++) {
                                                JSONObject schedule = j_schedules.getJSONObject(i);

                                                if (!schedule.getString("status")
                                                        .equalsIgnoreCase(ProductionSchedule.STATUS.CANCELED.toString())) {

                                                    ttl_qty += schedule.getInt("packing_qty_in_case")
                                                            * (schedule.getInt("parts_qty_in_bag")==0?1:schedule.getInt("parts_qty_in_bag"))
                                                            * (schedule.getInt("bag_qty_in_packing")==0?1:schedule.getInt("bag_qty_in_packing"))
                                                    ;
                                                    ttl_packing_qty += schedule.getInt("packing_qty_in_case");
                                                    ttl_seq_packed += schedule.getInt("outer_plan_qty") == schedule.getInt("outer_act_qty")
                                                            && schedule.getInt("outer_act_qty")>0 ? 1 : 0;
                                                    ttl_qty_packed += schedule.getInt("outer_act_qty");
                                                    ttl_packing_qty_packed += schedule.getInt("outer_act_packing_in_case");

                                                }

                                                isUpdate = true;
                                                mapItems.put(schedule.getString("id"), schedule);
                                            }

                                            // Version 1.3.13
                                            if (ttl_qty_packed > ttl_qty) ttl_qty_packed = ttl_qty;
                                            if (ttl_packing_qty_packed > ttl_packing_qty) ttl_packing_qty_packed = ttl_packing_qty;
                                            if (ttl_seq_packed > j_schedules.length()) ttl_seq_packed = j_schedules.length();

                                            txt_ttl_seq.setText(String.valueOf(j_schedules.length()));
                                            txt_ttl_qty.setText(String.valueOf(ttl_qty));
                                            txt_packing_ttl_qty.setText(String.valueOf(ttl_packing_qty));

                                            txt_ttl_qty_packed.setText(String.valueOf(ttl_qty_packed));
                                            txt_ttl_seq_packed.setText(String.valueOf(ttl_seq_packed));
                                            txt_packing_ttl_qty_packed.setText(String.valueOf(ttl_packing_qty_packed));

                                                /**
                                                 *
                                                Version 1.3.13: fix exceed the qty
                                            if (txt_packing_ttl_qty.getText().toString().equals(txt_packing_ttl_qty_packed.getText().toString())
                                                    && txt_ttl_qty.getText().toString().equals(txt_ttl_qty_packed.getText().toString())
                                            ) {
                                            */
                                            if (ttl_qty_packed >= ttl_qty) {
                                                alertOk("All items packing finished.", new ActionListenerCallback() {
                                                    @Override
                                                    public void onActionSuccess(String successMessage) throws Exception {
                                                        reset();
                                                    }

                                                    @Override
                                                    public void onActionFailure(Throwable throwableError) {

                                                    }
                                                });
                                            }

                                            if (isUpdate)
                                                redrawContentsLabelScanList();
                                        }

                                        // Response
                                        WsClient.sendWsEventLog(OuterActivity.this,
                                                null
                                                , WsProtocol.EVENT.HT_OUTER_PACKING_SCAN_STEP1_SUCCESS
                                                , ProductionSchedule.STATUS.WORKING
                                        );

                                        waiting_ws_response = false;
                                        scan_step++;

                                        break;

                                    case HT_OUTER_PACKING_SCAN_STEP1_FAILED:
                                        String str_event_det = jsonObject.getJSONObject("ext").getString("event_det");
                                        //waiting_ws_response = false;
                                        //scan_step = 0;
                                        reset();
                                        // Response
                                        WsClient.sendWsEventLog(OuterActivity.this,
                                                null
                                                , WsProtocol.EVENT.HT_OUTER_PACKING_SCAN_STEP1_FAILED
                                                , ProductionSchedule.STATUS.NG
                                        );

                                        alertError(str_event_det, new ActionListenerCallback() {
                                            @Override
                                            public void onActionSuccess(String successMessage) throws Exception {
                                            }

                                            @Override
                                            public void onActionFailure(Throwable throwableError) {
                                                ErrorCode errorCode = ErrorCode.fromId(Integer.parseInt(throwableError.getMessage()));
                                                Toast.makeText(OuterActivity.this, errorCode.toString(), Toast.LENGTH_LONG)
                                                        .show();
                                                try {
                                                    WsClient.sendWsEventLog(OuterActivity.this,
                                                            new HashMap<String, Object>() {{
                                                                put("event_det", WsProtocol.EVENT.HT_OUTER_PACKING_SCAN_STEP1_FAILED);
                                                                put("error_code", errorCode.getId());
                                                                put("error_det", errorCode.getDet());
                                                            }}
                                                            , WsProtocol.EVENT.HT_UNLOCK_SCREEN_FAILED
                                                            , ProductionSchedule.STATUS.NG
                                                    );
                                                } catch (Exception e) {
                                                    Log.e(getString(R.string.tag), e.getMessage());
                                                }
                                            }
                                        }, screen_locked=true);
                                        break;

                                    case HT_OUTER_PACKING_SCAN_STEP3_SUCCESS:


                                        // it will return this if not duplicated scan
                                        // Able to get JSONObject schedule from response
                                        waiting_ws_response = false;

//                                        Map<String, Object> map_label_scan = null;

                                        // Retrieve schedule
                                        matched_schedule = jsonObject.getJSONObject("ext").getJSONObject("event_det");

                                        //check key map data


                                        String Key = String.format("%s%s%s%s%d%05d%s",
                                                matched_schedule.getString("pc_no").trim(),
                                                matched_schedule.getString("part_no").trim(),
                                                matched_schedule.getString("part_color").trim(),
                                                matched_schedule.getString("control_no").trim(),
                                                matched_schedule.getInt("case_no"),
                                                matched_schedule.getInt("item_no"),
                                                matched_schedule.getString("serial_no").toString().trim());
                                        Log.d(getString(R.string.tag), "keymap_label_scan : "+Key);


                                        if (!keymap_label_scan.containsKey(Key))
                                            return;

                                        HashMap<String, Object> last_scan = (HashMap<String, Object>) keymap_label_scan.get(Key);

                                        // version 1.3.10 : supported multiple cases packing
                                        int packing_case_plan = matched_schedule.getInt("packing_qty_in_case");
                                        int packing_case_act = matched_schedule.getInt("outer_act_packing_in_case");
                                        // Check is it finished or on currently packing
                                        /*
                                        * Supported multiple cases packing, version 1.3.10
                                        *
                                        if (matched_schedule.getInt("outer_plan_qty")
                                                <= matched_schedule.getInt("outer_act_qty") ) {

                                         */
                                        if (packing_case_act >= packing_case_plan) {

                                            // It is finished job.
                                            // Remove current scan data
//                                            contents_label_scan = "";
                                            // It has already finished job, just inform leader and ignore the last scan
                                            alertError(E121.toString(), new ActionListenerCallback() {
                                                @Override
                                                public void onActionSuccess(String successMessage) throws Exception {
                                                }

                                                @Override
                                                public void onActionFailure(Throwable throwableError) {
                                                    ErrorCode errorCode = ErrorCode.fromId(Integer.parseInt(throwableError.getMessage()));
                                                    Toast.makeText(OuterActivity.this, errorCode.toString(), Toast.LENGTH_LONG)
                                                            .show();
                                                    try {
                                                        WsClient.sendWsEventLog(OuterActivity.this,
                                                                new HashMap<String, Object>() {{
                                                                    put("event_det", WsProtocol.EVENT.HT_OUTER_PACKING_SCAN_STEP3_FAILED);
                                                                    put("error_code", errorCode.getId());
                                                                    put("error_det", errorCode.getDet());
                                                                }}
                                                                , WsProtocol.EVENT.HT_UNLOCK_SCREEN_FAILED
                                                                , ProductionSchedule.STATUS.NG
                                                        );
                                                    } catch (Exception e) {
                                                        Log.e(getString(R.string.tag), e.getMessage());
                                                    }

                                                }
                                            }, screen_locked = true);
                                        /*
                                        * Supported multiple cases packing, version 1.3.10
                                        *
                                        } else if (matched_schedule.getInt("outer_plan_qty")
                                                > matched_schedule.getInt("outer_act_qty")) {

                                         */
                                        } else {
                                            // It is absolutely new contents label, let add it to mapItems
                                            // Also check is it the same schedule
                                            JSONObject j_obj;
                                            if (mapItems.containsKey(matched_schedule.getString("id"))) {
                                                j_obj = mapItems.remove(matched_schedule.getString("id"));
                                            } else {
                                                j_obj = matched_schedule;
                                            }

                                            Log.d(getString(R.string.tag), matched_schedule.toString());

                                            // Update qty before put to mapItem
                                            int outer_act_qty = j_obj.getInt("outer_act_qty")
                                                    + ( (matched_schedule.getInt("parts_qty_in_bag")==0?1:matched_schedule.getInt("parts_qty_in_bag"))
                                                        * (matched_schedule.getInt("bag_qty_in_packing")==0?1:matched_schedule.getInt("bag_qty_in_packing"))
                                                        )
                                                    ;
                                            int outer_act_packing_in_case = j_obj.getInt("outer_act_packing_in_case")
                                                    + 1;

                                            // version 1.3.13 : Fix exceed the amount error
                                            int outer_plan_qty = j_obj.getInt("outer_plan_qty");
                                            int outer_plan_packing_in_case = j_obj.getInt("packing_qty_in_case");
                                            if (outer_act_qty > outer_plan_qty
                                                || outer_act_packing_in_case > outer_plan_packing_in_case
                                            ) {
                                                outer_act_qty = outer_plan_qty;
                                                outer_act_packing_in_case = outer_plan_packing_in_case;
                                            }

                                            j_obj.remove("outer_act_qty");
                                            j_obj.remove("outer_act_packing_in_case");
                                            j_obj.put("outer_act_qty", outer_act_qty);
                                            j_obj.put("outer_act_packing_in_case", outer_act_packing_in_case);

                                            Log.d(getString(R.string.tag), j_obj.toString());
                                            mapItems.put(matched_schedule.getString("id"), j_obj);

                                            // Redraw
                                            redrawContentsLabelScanList(matched_schedule.getString("id"));

                                            /**
                                             *
                                             Update current contents label qty to the totally display
                                             total_packing
                                             total_qty
                                             total_seq
                                              */
                                            // Fixed version 1.3.13
                                            int total_packing_plan = Integer.valueOf(txt_packing_ttl_qty.getText().toString());
                                            int total_qty_plan = Integer.valueOf(txt_ttl_qty.getText().toString());
                                            int total_seq_plan = Integer.valueOf(txt_ttl_seq.getText().toString());
                                            int total_packing_act = Integer.parseInt(txt_packing_ttl_qty_packed.getText().toString()) + 1;
                                            int total_qty_act = ( (matched_schedule.getInt("parts_qty_in_bag")==0?1:matched_schedule.getInt("parts_qty_in_bag"))
                                                        * (matched_schedule.getInt("bag_qty_in_packing")==0?1:matched_schedule.getInt("bag_qty_in_packing")) )
                                                    + Integer.parseInt(txt_ttl_qty_packed.getText().toString());

                                            // check exceed
                                            if (total_packing_act > total_packing_plan) {
                                                total_packing_act = total_packing_plan;
                                            }
                                            if (total_qty_act > total_qty_plan) {
                                                total_qty_act = total_qty_plan;
                                            }

                                            txt_ttl_qty_packed.setText(String.valueOf( total_qty_act ));
                                            txt_packing_ttl_qty_packed.setText(String.valueOf( total_packing_act ));

                                            // Increase the total seq number if finished the current item
                                            if (outer_act_packing_in_case >= outer_plan_packing_in_case) {
                                                int total_seq_act = Integer.parseInt(txt_ttl_seq_packed.getText().toString()) + 1;
                                                // check exceed
                                                if (total_seq_act > total_seq_plan) {
                                                    total_seq_act = total_seq_plan;
                                                }
                                                txt_ttl_seq_packed.setText(String.valueOf( total_seq_act ));
                                            }

                                            // Send HT_OUTER_PACKING_SCAN_STEP3_SUCCESS
                                            String id = matched_schedule.getString("id");
                                            /*
                                            // Fixed version 1.3.13
                                            outer_act_qty = mapItems.get(id).getInt("outer_act_qty")
                                                            + mapItems.get(id).getInt("parts_qty_in_packing");
                                            if (outer_act_qty >= mapItems.get(id).getInt("outer_plan_qty")) outer_act_qty = mapItems.get(id).getInt("outer_plan_qty");
                                            outer_act_packing_in_case = outer_act_qty / mapItems.get(id).getInt("parts_qty_in_packing");
                                             */

                                            last_scan.put("event_det", last_scan.get("payload"));
                                            last_scan.put("schedule_id", id);
                                            last_scan.put("outer_act_qty", outer_act_qty);
                                            last_scan.put("outer_act_packing_in_case", outer_act_packing_in_case);

                                            ProductionSchedule.STATUS status = mapItems.get(id).getInt("outer_act_qty")
                                                    >= mapItems.get(id).getInt("outer_plan_qty")
                                                    ? OUTER_PACKED : WORKING;
                                            WsClient.sendWsEventLog(OuterActivity.this,
                                                    last_scan
                                                    , WsProtocol.EVENT.HT_OUTER_PACKING_SCAN_STEP3_SUCCESS
                                                    , status);

                                            keymap_label_scan.remove(Key);
                                            Log.d(getString(R.string.tag), "keymap_label_scan Size : "+keymap_label_scan.size());

//                                            }

                                            /**
                                             * Version 1.3.13: Fix exceed error
                                             *
                                            if (txt_packing_ttl_qty.getText().toString().equals(txt_packing_ttl_qty_packed.getText().toString())
                                                    && txt_ttl_qty.getText().toString().equals(txt_ttl_qty_packed.getText().toString())
                                            ) {
                                             */
                                            Log.d(getString(R.string.tag), String.format("total_qty_act=%d, total_qty_plan=%d", total_qty_act, total_qty_plan));
                                            if (total_qty_act >= total_qty_plan) {
                                                alertOk("All items packing finished.", new ActionListenerCallback() {
                                                    @Override
                                                    public void onActionSuccess(String successMessage) throws Exception {
                                                        reset();
                                                    }

                                                    @Override
                                                    public void onActionFailure(Throwable throwableError) {

                                                    }
                                                });
                                                Utils.playNotification(getApplicationContext(), RingtoneManager.TYPE_NOTIFICATION);
                                            }
                                        }

                                        break;

                                    case HT_OUTER_PACKING_SCAN_STEP3_FAILED:

                                        // Response
                                        WsClient.sendWsEventLog(OuterActivity.this,
                                                null
                                                , WsProtocol.EVENT.HT_OUTER_PACKING_SCAN_STEP3_FAILED
                                                , ProductionSchedule.STATUS.NG
                                        );

                                        alertError(E120.toString(), new ActionListenerCallback() {
                                            @Override
                                            public void onActionSuccess(String successMessage) throws Exception {
                                                waiting_ws_response = false;

                                                prevent_duplicate_check = 1; // temporary prevent check on the same scan

                                               //leader confirm --> do step HT_OUTER_PACKING_SCAN_STEP3_SUCCESS??
                                            }

                                            @Override
                                            public void onActionFailure(Throwable throwableError) {
                                                ErrorCode errorCode = ErrorCode.fromId(Integer.parseInt(throwableError.getMessage()));
                                                Toast.makeText(OuterActivity.this, errorCode.toString(), Toast.LENGTH_LONG)
                                                        .show();
                                                try {
                                                    WsClient.sendWsEventLog(OuterActivity.this,
                                                            new HashMap<String, Object>() {{
                                                                put("event_det", WsProtocol.EVENT.HT_OUTER_PACKING_SCAN_STEP3_FAILED);
                                                                put("error_code", errorCode.getId());
                                                                put("error_det", errorCode.getDet());
                                                            }}
                                                            , WsProtocol.EVENT.HT_UNLOCK_SCREEN_FAILED
                                                            , ProductionSchedule.STATUS.NG
                                                    );
                                                } catch (Exception e) {
                                                    Log.e(getString(R.string.tag), e.getMessage());
                                                }
                                            }
                                        }, screen_locked=true);
                                        break;


                                    case HT_OUTER_PACKING_PENDING:
                                        Toast.makeText(OuterActivity.this, "Pending successfully.", Toast.LENGTH_LONG)
                                                .show();
                                        break;

                                    case HT_OUTER_PACKING_NG:
                                        Toast.makeText(OuterActivity.this, "NG successfully.", Toast.LENGTH_LONG)
                                                .show();
                                        break;

                                    case TB_OUTER_PACKING_SUB_LEADER_CONFIRM_OPEN:

                                        alertError("Please scan sub leader ID to confirm.", new ActionListenerCallback() {
                                            @Override
                                            public void onActionSuccess(String successMessage) throws Exception {
                                                Toast.makeText(OuterActivity.this, "confirm success", Toast.LENGTH_LONG)
                                                        .show();
                                                WsClient.sendWsEventLog(OuterActivity.this,
                                                        new HashMap<String, Object>() {{
                                                            put("user_id", successMessage);
                                                            put("pc_no", jsonObject.getJSONObject("ext").getString("pc_no"));
                                                            put("control_no", jsonObject.getJSONObject("ext").getString("control_no"));
                                                            put("case_no", jsonObject.getJSONObject("ext").getString("case_no"));
                                                        }}
                                                        , WsProtocol.EVENT.HT_OUTER_PACKING_SUB_LEADER_CONFIRM_SUCCESS
                                                        , ProductionSchedule.STATUS.WORKING
                                                );
                                            }

                                            @Override
                                            public void onActionFailure(Throwable throwableError) {
                                                ErrorCode errorCode = ErrorCode.fromId(Integer.parseInt(throwableError.getMessage()));
                                                Toast.makeText(OuterActivity.this, errorCode.toString(), Toast.LENGTH_LONG)
                                                        .show();
                                                try {
                                                    WsClient.sendWsEventLog(OuterActivity.this,
                                                            new HashMap<String, Object>() {{
                                                                put("error_code", errorCode.getId());
                                                                put("error_det", errorCode.getDet());
                                                            }}
                                                            , WsProtocol.EVENT.HT_OUTER_PACKING_SUB_LEADER_CONFIRM_FAILED
                                                            , ProductionSchedule.STATUS.NG
                                                    );
                                                } catch (Exception e) {
                                                    Log.e(getString(R.string.tag), e.getMessage());
                                                }
                                            }
                                        }, screen_locked=true, R.string.LEVEL_PERMIT_SUB_LEADER_CONFIRM,
                                                R.color.black, R.color.green, R.color.white, "OK");

                                        break;

                                    case TB_OUTER_PACKING_LEADER_CONFIRM_OPEN:

                                        alertError("Please scan leader ID to confirm.", new ActionListenerCallback() {
                                            @Override
                                            public void onActionSuccess(String successMessage) throws Exception {
                                                Toast.makeText(OuterActivity.this, "confirm success", Toast.LENGTH_LONG)
                                                        .show();
                                                WsClient.sendWsEventLog(OuterActivity.this,
                                                        new HashMap<String, Object>() {{
                                                            put("user_id", successMessage);
                                                            put("pc_no", jsonObject.getJSONObject("ext").getString("pc_no"));
                                                            put("control_no", jsonObject.getJSONObject("ext").getString("control_no"));
                                                            put("case_no", jsonObject.getJSONObject("ext").getString("case_no"));
                                                        }}
                                                        , WsProtocol.EVENT.HT_OUTER_PACKING_LEADER_CONFIRM_SUCCESS
                                                        , OUTER_PACKED
                                                );
                                            }

                                            @Override
                                            public void onActionFailure(Throwable throwableError) {
                                                ErrorCode errorCode = ErrorCode.fromId(Integer.parseInt(throwableError.getMessage()));
                                                Toast.makeText(OuterActivity.this, errorCode.toString(), Toast.LENGTH_LONG)
                                                        .show();
                                                try {
                                                    WsClient.sendWsEventLog(OuterActivity.this,
                                                            new HashMap<String, Object>() {{
                                                                put("error_code", errorCode.getId());
                                                                put("error_det", errorCode.getDet());
                                                            }}
                                                            , WsProtocol.EVENT.HT_OUTER_PACKING_LEADER_CONFIRM_FAILED
                                                            , ProductionSchedule.STATUS.NG
                                                    );
                                                } catch (Exception e) {
                                                    Log.e(getString(R.string.tag), e.getMessage());
                                                }
                                            }
                                        }, screen_locked=true, R.string.LEVEL_PERMIT_LEADER_CONFIRM,
                                                R.color.black, R.color.green, R.color.white, "OK");

                                        break;

                                    case TB_OUTER_PACKING_STOP_CASE_OPEN:

                                        alertError("Please scan ID to stop case.", new ActionListenerCallback() {
                                            @Override
                                            public void onActionSuccess(String successMessage) throws Exception {
                                                Toast.makeText(OuterActivity.this, "stop case success", Toast.LENGTH_LONG)
                                                        .show();
                                                WsClient.sendWsEventLog(OuterActivity.this,
                                                        new HashMap<String, Object>() {{
                                                            put("user_id", successMessage);
                                                            put("pc_no", jsonObject.getJSONObject("ext").getString("pc_no"));
                                                            put("control_no", jsonObject.getJSONObject("ext").getString("control_no"));
                                                            put("case_no", jsonObject.getJSONObject("ext").getString("case_no"));
                                                        }}
                                                        , WsProtocol.EVENT.HT_OUTER_PACKING_STOP_CASE_SUCCESS
                                                        , STOP_CASE
                                                );
                                            }

                                            @Override
                                            public void onActionFailure(Throwable throwableError) {
                                                ErrorCode errorCode = ErrorCode.fromId(Integer.parseInt(throwableError.getMessage()));
                                                Toast.makeText(OuterActivity.this, errorCode.toString(), Toast.LENGTH_LONG)
                                                        .show();
                                                try {
                                                    WsClient.sendWsEventLog(OuterActivity.this,
                                                            new HashMap<String, Object>() {{
                                                                put("error_code", errorCode.getId());
                                                                put("error_det", errorCode.getDet());
                                                            }}
                                                            , WsProtocol.EVENT.HT_OUTER_PACKING_STOP_CASE_FAILED
                                                            , ProductionSchedule.STATUS.NG
                                                    );
                                                } catch (Exception e) {
                                                    Log.e(getString(R.string.tag), e.getMessage());
                                                }
                                            }
                                        }, screen_locked=true, R.string.LEVEL_PERMIT_STOP_CASE,
                                                R.color.black, R.color.green, R.color.white, "OK");

                                        break;

                                    case HT_OUTER_PACKING_SUB_LEADER_CONFIRM_FAILED:
                                    case HT_OUTER_PACKING_LEADER_CONFIRM_FAILED:
                                    case HT_OUTER_PACKING_STOP_CASE_FAILED:
                                        alertError("There are some error on action!", new ActionListenerCallback() {
                                            @Override
                                            public void onActionSuccess(String successMessage) throws Exception {

                                            }

                                            @Override
                                            public void onActionFailure(Throwable throwableError) {

                                            }
                                        }, screen_locked=false);
                                        break;

                                    // v1.4.7 : Support invalid working step alert
                                    case WB_INVALID_WORKING_STEP:
                                        alertError(E203.toString(), new ActionListenerCallback() {
                                            @Override
                                            public void onActionSuccess(String successMessage) throws Exception {

                                            }

                                            @Override
                                            public void onActionFailure(Throwable throwableError) {
                                                // Just alarm to user
                                            }
                                        }, screen_locked=true);
                                        break;

                                    default:
                                        throw new Exception("Unsupported command : " + jsonObject.getString("cmd"));
                                }
                            }

                            break;

                        default:
                            throw new Exception("Unsupported command : " + jsonObject.getString("cmd"));
                    }
                } catch (Exception e) {
                    Log.e(getString(R.string.tag), "ERROR: " + e.getMessage());
                }

            }
        });

    }

    @Override
    public boolean onKeyUp(int keyCode, KeyEvent event) {
        Log.d(getString(R.string.tag), String.format("keyCode: %d", keyCode) );
        if (keyCode >= KeyMapping.P1.getId()
                && keyCode <= KeyMapping.P4.getId())
        {
            if (popupLayout1.getVisibility() == VISIBLE) {
                Button btnOk = (Button) findViewById(R.id.popupLayout1_btn1);
                Button btnConfirm = (Button) findViewById(R.id.popupLayout1_btn2);
                switch (KeyMapping.fromId(keyCode)) {
                    case P1:
                        btnOk.performClick();
                        break;

                    case P2:
                        btnConfirm.performClick();
                        break;

                }
            } else {
                switch (KeyMapping.fromId(keyCode)) {
                    case P1:
                        btn_main_menu.performClick();
                        break;

                    case P2:
                        btn_clear.performClick();
                        break;

                    case P3:
                        btn_pending.performClick();
                        break;

                    case P4:
                        btn_ng.performClick();
                        break;

                }
            }
        } else if (keyCode == KeyMapping.ENT.getId()) {
            if (popupLayout2.getVisibility() == VISIBLE) {
                Button btn = (Button) findViewById(R.id.popupLayout2_btn1);
                btn.requestFocus();
                btn.performClick();
            }
            return false;
        }

        return super.onKeyUp(keyCode, event);
    }


    private void confirmation(String msg, int color, boolean isBtnOkShow
            , ActionListenerCallback callback, SpinAdapter spinAdapter) {


        Log.d(getString(R.string.tag), "confirmation() " + msg);

        RelativeLayout layout = popupLayout1;
        TextView lbl_msg = (TextView) findViewById(R.id.popupLayout1_txt);
        Button btnOk = (Button) findViewById(R.id.popupLayout1_btn1);
        Button btnConfirm = (Button) findViewById(R.id.popupLayout1_btn2);
        Spinner ddl_options = (Spinner) findViewById(R.id.ddl_options);

        ddl_options.setVisibility (spinAdapter == null ? GONE : VISIBLE);

        if (spinAdapter != null) {
            ddl_options.setAdapter(spinAdapter);
        }

        lbl_msg.setText(msg);
        lbl_msg.setTextColor(color);
        btnOk.setVisibility(isBtnOkShow ? VISIBLE : INVISIBLE);
        layout.setVisibility(VISIBLE);
        btnOk.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                try {
                    layout.setVisibility(GONE);
                    callback.onActionFailure(null);
                } catch (Exception e) {
                    // In case if item is the top most view
                };
            }
        });
        btnConfirm.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                try {
                    layout.setVisibility(GONE);
                    callback.onActionSuccess(
                            spinAdapter.getItem(
                                    ddl_options.getSelectedItemPosition()
                            ).getName()
                    );
                } catch (Exception e) {
                    // In case if item is the top most view
                };
            }
        });

    }

    private void alertOk(String msg, ActionListenerCallback callback) {
        // Enable the ENT key down, it must current focus on multiline text input
        default_view.requestFocus();

        RelativeLayout layout = popupLayout2;
        TextView lbl_msg = (TextView) findViewById(R.id.popupLayout2_txt);
        Button btn = (Button) findViewById(R.id.popupLayout2_btn1);
        EditText txt_leader_password = (EditText) findViewById(R.id.txt_leader_password);
        txt_leader_password.setEnabled(false);

        lbl_msg.setText(msg);
        lbl_msg.setTextColor(getColor(R.color.black));
        layout.setVisibility(VISIBLE);
        txt_leader_password.setVisibility(GONE);
        btn.setBackgroundColor(getColor(R.color.green));
        btn.setTextColor(getColor(R.color.white));
        btn.setText("OK [ENT]");
        btn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                // stop activity
                try {
                    layout.setVisibility(GONE);
                    callback.onActionSuccess("");
                } catch (Exception e) {
                    // In case if item is the top most view
                };
            }
        });

    }

    private void alertError(String msg, ActionListenerCallback callback, Boolean isLockScreen) {
        alertError(msg, callback, isLockScreen, R.string.LEVEL_PERMIT_UNLOCK_SCREEN,
                R.color.red, R.color.red, R.color.white, "NG");
    }

    private void alertError(String msg, ActionListenerCallback callback, Boolean isLockScreen
            , int level_permit, int txt_color, int btn_bg_color, int btn_txt_color, String btn_prefix) {
        // Enable the ENT key down, it must current focus on multiline text input
        default_view.requestFocus();

        RelativeLayout layout = popupLayout2;
        TextView lbl_msg = (TextView) findViewById(R.id.popupLayout2_txt);
        Button btn = (Button) findViewById(R.id.popupLayout2_btn1);
        EditText txt_leader_password = (EditText) findViewById(R.id.txt_leader_password);
        txt_leader_password.setEnabled(false);


        if (isLockScreen) {
            txt_leader_password.setVisibility(VISIBLE);
            txt_leader_password.setText("");

            if (btn_prefix.equalsIgnoreCase("NG"))
                Utils.playMedia(getApplicationContext(), R.raw.ship_siren);
        } else {
            txt_leader_password.setVisibility(GONE);

            Utils.playTones(ToneGenerator.TONE_CDMA_ABBR_ALERT, 10000, 900);
        }

        lbl_msg.setText(msg);
        lbl_msg.setTextColor(getColor(txt_color));
        layout.setVisibility(VISIBLE);
        btn.setBackgroundColor(getColor(btn_bg_color));
        btn.setTextColor(getColor(btn_txt_color));
        btn.setText(btn_prefix + " [" + (isLockScreen?"scan":"ENT") + "]");
        btn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                // stop activity
                try {
                    if (!isLockScreen) {
                        layout.setVisibility(GONE);
                        callback.onActionSuccess("");
                    } else {
                        // check password
                        if (!Settings.getMgmtList().containsKey(getString(level_permit))) {
                            callback.onActionFailure(new Exception(String.valueOf(E111.getId())));
                            return;
                        }

                        List<String> levelTokens = Arrays.asList(Settings.getMgmtList().get(getString(level_permit))
                                .split(getString(R.string.DELIMITER_SETTINGS)));
                        EditText txt_leader_password = (EditText) findViewById(R.id.txt_leader_password);
                        txt_leader_password.setEnabled(false);
                        if (!MainActivity.instance.userHashMap.containsKey(txt_leader_password.getText().toString())) {
                            callback.onActionFailure(new Exception(String.valueOf(E112.getId())));
                            return;
                        }

                        User user = MainActivity.instance.userHashMap.get(txt_leader_password.getText().toString());
                        if (levelTokens.contains(user.getLevel())) {
                            screen_locked = false;
                            layout.setVisibility(GONE);
                            callback.onActionSuccess(txt_leader_password.getText().toString());
                        } else {
                            callback.onActionFailure(new Exception(String.valueOf(E122.getId())));
                        }
                    }



                } catch (Exception e) {
                    // In case if item is the top most view
                };
            }
        });

    }

    @Override
    public String getJobId() {
        return job_id;
    }

    @Override
    public String getStage() {
        return stage.toString();
    }

    @Override
    public void onBackPressed() {

    }
}