package com.atid.app.atx.ble.inventory.barcode;

import android.Manifest;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.app.Application.ActivityLifecycleCallbacks;
import android.bluetooth.BluetoothAdapter;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.os.Build;
import android.os.Bundle;
import android.os.PowerManager;
import android.support.v4.app.ActivityCompat;
import android.support.v4.content.ContextCompat;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.Toast;

import com.atid.app.atx.ble.inventory.barcode.adapter.DataListAdapter;
import com.atid.app.atx.ble.inventory.barcode.data.DeviceItem;
import com.atid.app.atx.ble.inventory.barcode.data.GlobalData;
import com.atid.app.atx.ble.inventory.barcode.device.ReaderManager;
import com.atid.app.atx.ble.inventory.barcode.dialog.MessageBox;
import com.atid.app.atx.ble.inventory.barcode.dialog.WaitDialog;
import com.atid.lib.diagnostics.ATException;
import com.atid.lib.module.barcode.ATBarcode;
import com.atid.lib.module.barcode.event.IATBarcodeEventListener;
import com.atid.lib.module.barcode.types.BarcodeType;
import com.atid.lib.reader.ATEAReader;
import com.atid.lib.reader.event.IATEAReaderEventListener;
import com.atid.lib.reader.types.KeyState;
import com.atid.lib.reader.types.KeyType;
import com.atid.lib.reader.types.OperationMode;
import com.atid.lib.reader.types.UsbChargerState;
import com.atid.lib.reader.types.UsbChargerType;
import com.atid.lib.transport.types.ConnectState;
import com.atid.lib.transport.types.ConnectType;
import com.atid.lib.types.ActionState;
import com.atid.lib.types.DeviceType;
import com.atid.lib.types.ResultCode;
import com.atid.lib.util.SysUtil;
import com.atid.lib.util.diagnotics.ATLog;

import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.Locale;

public class MainActivity extends Activity implements OnClickListener, IATEAReaderEventListener, IATBarcodeEventListener {

	private static final String TAG = MainActivity.class.getSimpleName();
	private static final int INFO = ATLog.L1;

	private static final int REQUEST_PERMISSION_CODE = 1000;
	private static final int REQUEST_ENABLE_BLUETOOTH = 1;

	// ------------------------------------------------------------------------
	// Member Variable
	// ------------------------------------------------------------------------
	private TextView txtVersion;
	private TextView txtDevice;
	private TextView txtAddress;

	private ListView lstData;

	private TextView txtTagCount;
	private TextView txtTotalTagCount;

	private Button btnAction;
	private Button btnSetting;
	private Button btnClear;

	private DataListAdapter mDataListAdapter;

	private ATEAReader mReader;

	private volatile int mTotalTagCount;
	private volatile boolean mIsInitialize;
	private volatile boolean mIsConnected;

	private boolean mIsRunAppHomeButton = true;
	OperationMode mOperationMode;

	private PowerManager.WakeLock mWakeLock;
	private ActivityLifecycleManager mActivityLifecycleCallbacks;

	private BluetoothAdapter mBluetooth;
	private volatile boolean mIsCheckEnableBluetooth;
	private volatile boolean mIsSelectBluetooth;

	@Override
	protected void onCreate(Bundle savedInstanceState) {

		mActivityLifecycleCallbacks = new ActivityLifecycleManager();
		getApplication().registerActivityLifecycleCallbacks(mActivityLifecycleCallbacks);

		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);

		SysUtil.setContext(this);        // must used the ble device

		checkPermission();

		ATLog.i(TAG, INFO, "INFO. onCreate()");
	}

	@SuppressLint("NewApi")
	private void checkPermission() {
		if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {

			final String[] permissionList = new String[]{
					Manifest.permission.WAKE_LOCK,
					Manifest.permission.BLUETOOTH_ADMIN,
					Manifest.permission.BLUETOOTH,
					Manifest.permission.ACCESS_FINE_LOCATION,
					Manifest.permission.ACCESS_COARSE_LOCATION,
					Manifest.permission.BLUETOOTH_SCAN,
					Manifest.permission.BLUETOOTH_CONNECT,
			};

			ArrayList<String> permissions = new ArrayList<String>();
			int grantResult = PackageManager.PERMISSION_GRANTED;
			for (int i = 0; i < permissionList.length; i++) {
				grantResult = ContextCompat.checkSelfPermission(MainActivity.this, permissionList[i]);
				if (grantResult == PackageManager.PERMISSION_DENIED) {
					permissions.add(permissionList[i]);
				}
			}

			if (permissions.size() <= 0) {
				onPermissionResult(true);
			} else {
				String[] requestPermissions = new String[permissions.size()];
				//permissions.toArray(requestPermissions);
				ActivityCompat.requestPermissions(this, permissions.toArray(requestPermissions), REQUEST_PERMISSION_CODE);

			}
		} else {
			onPermissionResult(true);
		}
	}

	@Override
	protected void onDestroy() {

		closeActivity();

		if (mReader != null) {
			GlobalData.saveConfig(this, mReader.getDeviceType(), mReader.getAddress());

			mReader.removeListener(this);
			mReader.destroy();
		}
		super.onDestroy();
		getApplication().unregisterActivityLifecycleCallbacks(mActivityLifecycleCallbacks);
		ATLog.i(TAG, INFO, "INFO. onDestroy()");
	}

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

	@Override
	public boolean onPrepareOptionsMenu(Menu menu) {
		ATLog.i(TAG, INFO, "INFO. onPrepareOptionsMenu()");

		MenuItem menuAction = menu.findItem(R.id.menu_action);
		MenuItem menuSearh = menu.findItem(R.id.menu_search);

		if (mReader != null) {
			if (mReader.getState() == ConnectState.Connected) {
				menuAction.setTitle(R.string.action_disconnect);
			} else {
				menuAction.setTitle(R.string.action_connect);
			}

		}

		if (isAvailableBluetoothState()) {
			if (mIsSelectBluetooth)
				menuAction.setEnabled(true);
			else
				menuAction.setEnabled(false);

			if (mReader != null) {
				if (mReader.getState() == ConnectState.Connected) {
					menuSearh.setEnabled(false);
				} else {
					menuSearh.setEnabled(true);
				}
			} else {
				menuSearh.setEnabled(true);
			}

		} else {
			Toast.makeText(this, "Current state of the local Bluetooth adapter is not ON", Toast.LENGTH_SHORT).show();
			menuAction.setEnabled(false);
			menuSearh.setEnabled(false);
		}

		return super.onPrepareOptionsMenu(menu);
	}

	@Override
	public boolean onOptionsItemSelected(MenuItem item) {

		int id = item.getItemId();
		switch (id) {
			case R.id.menu_action:
				if (null != mReader) {
					if (mReader.getState() == ConnectState.Connected) {
						mReader.disconnect();
					} else {
						if (!mReader.connect()) {
							ATLog.e(TAG, "ERROR. onOptionsItemSelected - Failed to connect reader");
							MessageBox.show(this, getString(R.string.msg_not_connect_ble),
									getString(R.string.title_error));
						} else {
							DeviceItem deviceItem = new DeviceItem(ConnectType.BluetoothLe, mReader.getDeviceName(), mReader.getAddress());
							GlobalData.saveDeviceInfo(this, deviceItem);
						}
					}
				}
				return true;

			case R.id.menu_search:
				selectDevice();
				return true;
			default:
				break;
		}

		return super.onOptionsItemSelected(item);
	}

	@Override
	public void onUserLeaveHint() {

		if (!mIsRunAppHomeButton) {
			if (mReader != null) {
				closeActivity();
			}
		}
		ATLog.i(TAG, INFO, "INFO. onUserLeaveHint()");
		super.onUserLeaveHint();
	}

	@Override
	public void onClick(View v) {

		if (!mIsConnected) {
			ATLog.e(TAG, "ERROR - onClick(%d) - Device is not connected !!", v.getId());
			return;
		}

		switch (v.getId()) {
			case R.id.action:
				action();
				break;
			case R.id.setting:
				btnAction.setEnabled(false);
				btnClear.setEnabled(false);
				btnSetting.setEnabled(false);

				setting();

				btnAction.setEnabled(true);
				btnClear.setEnabled(true);
				btnSetting.setEnabled(true);
				break;

			case R.id.clear:
				btnAction.setEnabled(false);
				btnSetting.setEnabled(false);
				btnClear.setEnabled(false);

				clear();

				btnAction.setEnabled(true);
				btnSetting.setEnabled(true);
				btnClear.setEnabled(true);
				break;
		}

	}

	@Override
	public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
		if (requestCode != REQUEST_PERMISSION_CODE) {
			return;
		}

		boolean result = true;
		for (int i = 0; i < grantResults.length; i++) {
			result &= (grantResults[i] != PackageManager.PERMISSION_DENIED);
		}
		onPermissionResult(result);
	}

	@Override
	public void onActivityResult(int requestCode, int resultCode, Intent data) {
		if (requestCode == BarcodeOptionActivity.ID) {
			switch (resultCode) {
				case Activity.RESULT_FIRST_USER:
					mIsConnected = false;
					enableWidgets(false);
					closeActivity();
					break;
				case Activity.RESULT_OK:
				case Activity.RESULT_CANCELED:

					try {
						mReader.setUseActionKey(true);
					} catch (ATException e) {
						ATLog.e(TAG, "ERROR. onActivityResult() - Failed to enable key action");
					}
					enableWidgets(true);
					break;
			}
			ATLog.i(TAG, INFO, "INFO. onActivityResult() - RfidOptionActivity [%d]", resultCode);
		} else if (requestCode == SelectDeviceActivity.ID) {
			if (resultCode == Activity.RESULT_OK) {

				DeviceItem item = data.getParcelableExtra(SelectDeviceActivity.ITEM);

				if (null != mReader)
					mReader.removeListener(this);

				mReader = ReaderManager.getReader(item.getConnectType(), item.getName(), item.getAddress(), false);
				if (mReader == null) {
					ATLog.e(TAG, "ERROR. onActivityResult(SelectDeviceActivity, [%s]) - %s",
							getString(R.string.msg_fail_load_reader_instance));
					MessageBox.show(this, R.string.msg_fail_load_reader_instance,
							R.string.title_error, android.R.drawable.ic_dialog_alert,
							new DialogInterface.OnClickListener() {

								@Override
								public void onClick(DialogInterface dialog, int which) {
									MainActivity.this.finish();
									return;
								}
							});
					return;
				}
				// Set Reader Event Listener
				mReader.addListener(this);

				mIsSelectBluetooth = true;

				txtDevice.setText(item.getType().toString());
				txtAddress.setText(item.getAddress());

				ATLog.i(TAG, INFO, "INFO. onActivityResult(SelectDeviceActivity, [%s])", item.toString());
			}
		} else if (requestCode == REQUEST_ENABLE_BLUETOOTH) {
			if (resultCode == Activity.RESULT_OK) {

				checkSystem();

				ATLog.i(TAG, INFO, "INFO. onActivityResult(REQUEST_ENABLE_BLUETOOTH)");
				return;
			}
			GlobalData.isEnableBluetooth = false;
			return;
		}
		super.onActivityResult(requestCode, resultCode, data);
	}

	private void onPermissionResult(boolean result) {

		if (!result) {
			MessageBox.show(this, R.string.msg_fail_permission, R.string.title_error,
					android.R.drawable.ic_dialog_alert, new DialogInterface.OnClickListener() {

						@Override
						public void onClick(DialogInterface dialog, int which) {
							MainActivity.this.finish();
							return;
						}
					});
		}

		mReader = null;

		mTotalTagCount = 0;
		mIsInitialize = false;
		mIsConnected = false;

		mIsCheckEnableBluetooth = false;
		mIsSelectBluetooth = false;

		initActivity();

		enableWidgets(false);

		// Initialize Bluetooth
		mBluetooth = BluetoothAdapter.getDefaultAdapter();

		checkSystem();

		DeviceItem item = GlobalData.loadDeviceInfo(this, ConnectType.BluetoothLe);
		if (null != item) {
			mReader = ReaderManager.getReader(item.getConnectType(), item.getName(), item.getAddress(), false);
			if (mReader == null) {
				ATLog.e(TAG, "ERROR. onActivityResult(SelectDeviceActivity, [%s]) - %s",
						getString(R.string.msg_fail_load_reader_instance));
				MessageBox.show(this, R.string.msg_fail_load_reader_instance,
						R.string.title_error, android.R.drawable.ic_dialog_alert,
						new DialogInterface.OnClickListener() {

							@Override
							public void onClick(DialogInterface dialog, int which) {
								MainActivity.this.finish();
								return;
							}
						});
				return;
			}
			// Set Reader Event Listener
			mReader.addListener(this);

			mIsSelectBluetooth = true;

			txtDevice.setText(item.getType().toString());
			txtAddress.setText(item.getAddress());
		}
	}

	// ------------------------------------------------------------------------
	// Reader Event Handler Methods
	// ------------------------------------------------------------------------

	@Override
	public void onReaderStateChanged(ATEAReader reader, ConnectState state, Object params) {

		switch (state) {
			case Connected:
				WaitDialog.hide();
				mIsConnected = true;
				loadProperties();
				break;
			case Connecting:
				WaitDialog.show(this, R.string.msg_connecting_ble);
				break;
			case Disconnected:
				WaitDialog.hide();
				mIsConnected = false;
				enableWidgets(false);
				closeActivity();
				break;
			default:
				break;
		}
		ATLog.i(TAG, INFO, "EVENT. onReaderStateChanged([%s], %s)", reader, state);
	}

	@Override
	public void onReaderActionChanged(ATEAReader reader, ResultCode code, ActionState action, Object params) {

		switch (mOperationMode) {
			case Barcode:
				if (code != ResultCode.NoError) {
					ATLog.e(TAG, "ERROR. onReaderActionChanged([%s], %s, %s) - Failed to action changed [%s]", reader, code,
							action, code);

					showErrorMessage(String.format(Locale.US, "%s\r\nError[%s]",
							getString(R.string.msg_fail_changed_action), code));

					enableWidgets(true);
					return;
				}

				if (action == ActionState.Stop) {

					txtTagCount.setText(String.format(Locale.US, "%d", mDataListAdapter.getCount()));
					txtTotalTagCount.setText(String.format(Locale.US, "%d", mTotalTagCount));

					btnAction.setText(R.string.action_start);
					enableWidgets(true);
				} else {
					btnAction.setText(R.string.action_stop);
					enableWidgets(true);
				}

				break;
			case Normal:
			case KeyEventOnly:
			default:
				enableWidgets(false);
				break;
		}

		ATLog.i(TAG, INFO, "EVENT. onReaderActionChanged([%s], %s, %s)", reader, code, action);
	}

	@Override
	public void onReaderOperationModeChanged(ATEAReader reader, OperationMode mode, Object params) {

		mOperationMode = mode;

		switch (mode) {
			case Barcode:
				enableWidgets(true);
				break;
			case Normal:
			case KeyEventOnly:
			default:
				enableWidgets(false);
				break;
		}
		ATLog.i(TAG, INFO, "EVENT. onReaderOperationModeChanged([%s], %s)", reader, mode);
	}

	@Override
	public void onReaderBatteryState(ATEAReader reader, int batteryState, Object params) {

		ATLog.i(TAG, INFO, "EVENT. onReaderBatteryState([%s], %d)", reader, batteryState);
	}

	@Override
	public void onReaderKeyChanged(ATEAReader reader, KeyType type, KeyState state, Object params) {

		ATLog.i(TAG, INFO, "EVENT. onReaderKeyChanged([%s], %s, %s)", reader, type, state);
	}

	@Override
	public void onReaderUsbChargerChanged(ATEAReader reader, UsbChargerType type, UsbChargerState state, Object params) {

		ATLog.i(TAG, INFO, "EVENT. onReaderUsbChargerChanged([%s], %s, %s)", reader, type, state);
	}

	// ------------------------------------------------------------------------
	// Barcode Event Handler Methods
	// ------------------------------------------------------------------------

	@Override
	public void onBarcodeReadData(ATBarcode barcode, BarcodeType type, String codeId, String data, Object params) {

		mDataListAdapter.add(type, codeId, data);
		mTotalTagCount++;

		txtTagCount.setText(String.format(Locale.US, "%d", mDataListAdapter.getCount()));
		txtTotalTagCount.setText(String.format(Locale.US, "%d", mTotalTagCount));

		ATLog.i(TAG, INFO, "EVENT. onReaderReadBarcode([%s], %s, [%s], [%s])", mReader, type, codeId, data);
	}

	// ------------------------------------------------------------------------
	// Internal Widget Control Methods
	// ------------------------------------------------------------------------
	private void initActivity() {
		txtVersion = (TextView) findViewById(R.id.app_version);
		txtVersion.setText(SysUtil.getVersion(this));
		txtDevice = (TextView) findViewById(R.id.bluetooth_device);
		txtAddress = (TextView) findViewById(R.id.bluetooth_address);

		lstData = (ListView) findViewById(R.id.data_list);
		mDataListAdapter = new DataListAdapter(this);
		lstData.setAdapter(mDataListAdapter);

		txtTagCount = (TextView) findViewById(R.id.tag_count);
		txtTotalTagCount = (TextView) findViewById(R.id.total_tag_count);

		btnAction = (Button) findViewById(R.id.action);
		btnAction.setOnClickListener(this);
		btnSetting = (Button) findViewById(R.id.setting);
		btnSetting.setOnClickListener(this);
		btnClear = (Button) findViewById(R.id.clear);
		btnClear.setOnClickListener(this);
	}

	private void closeActivity() {
		WaitDialog.hide();

		if (mReader != null) {
			if (mReader.getBarcode() != null) {

				if (mReader.getAction() != ActionState.Stop) {
					mReader.getBarcode().stop();
					while (mReader.getAction() != ActionState.Stop &&
							mReader.getState() == ConnectState.Connected) {

						try {
							ATLog.i(TAG, INFO, "closeActivity() - wait for action stop.");
							Thread.sleep(50);
						} catch (InterruptedException e) {
							ATLog.e(TAG, e, "closeActivity() - Falied to sleep for thread");
						}
					}
				}
				btnAction.setText(R.string.action_start);
				mReader.getBarcode().removeListener(this);
			}
		}

		ATLog.i(TAG, INFO, "INFO. closeActivity()");
	}

	private void enableWidgets(boolean enabled) {

		lstData.setEnabled(enabled && mReader.getAction() == ActionState.Stop);

		btnAction.setEnabled(enabled);
		btnSetting.setEnabled(enabled && mReader.getAction() == ActionState.Stop);
		btnClear.setEnabled(enabled && mReader.getAction() == ActionState.Stop);

		txtDevice.setEnabled(enabled || mIsConnected);
		txtAddress.setEnabled(enabled || mIsConnected);

		ATLog.i(TAG, INFO, "INFO. enableWidgets(%s)", enabled);
	}

	// ------------------------------------------------------------------------
	// Internal Helper Methods
	// ------------------------------------------------------------------------
	private void action() {
		ResultCode res = ResultCode.NoError;
		enableWidgets(false);

		if (mReader.getAction() == ActionState.Stop) {

			if ((res = mReader.getBarcode().startDecode()) != ResultCode.NoError) {
				ATLog.e(TAG, "ERROR. action() - Failed to start decode [%s] for barcode", res);
				MessageBox.show(
						this, String.format(Locale.US, "%s. [%s]",
								getString(R.string.msg_fail_start_decode), res),
						getString(R.string.title_error));
				mReader.getBarcode().stop();
				enableWidgets(true);
				return;
			} else
				ATLog.i(TAG, INFO, "INFO. action() - inventory");
		} else {
			if ((res = mReader.getBarcode().stop()) != ResultCode.NoError) {
				ATLog.e(TAG, "ERROR. action() - Failed to stop operation [%s] for barcode", res);
				MessageBox.show(
						this, String.format(Locale.US, "%s. [%s]",
								getString(R.string.msg_fail_stop_action), res),
						getString(R.string.title_error));
				enableWidgets(true);
				return;
			} else
				ATLog.i(TAG, INFO, "INFO. action() - stop");
		}

	}

	private void clear() {
		mDataListAdapter.clear();
		mTotalTagCount = 0;

		txtTagCount.setText(String.format(Locale.US, "%d", mDataListAdapter.getCount()));
		txtTotalTagCount.setText(String.format(Locale.US, "%d", mTotalTagCount));

		ATLog.i(TAG, INFO, "INFO. clear()");
	}

	private void setting() {
		Intent intent = new Intent(this, BarcodeOptionActivity.class);
		intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);

		startActivityForResult(intent, BarcodeOptionActivity.ID);

		ATLog.i(TAG, INFO, "INFO. setting()");
	}

	private void showErrorMessage(final String message) {
		runOnUiThread(new Runnable() {
			@Override
			public void run() {
				MessageBox.show(MainActivity.this, message, getString(R.string.title_error));
			}
		});
	}

	private void selectDevice() {
		Intent intent = new Intent(this, SelectDeviceActivity.class);
		intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);

		startActivityForResult(intent, SelectDeviceActivity.ID);

		ATLog.i(TAG, INFO, "INFO. setting()");
	}

	private boolean isAvailableBluetoothState() {
		boolean available = false;

		if (mBluetooth == null)
			return available;

		int state = BluetoothAdapter.STATE_TURNING_ON;

		while (state == BluetoothAdapter.STATE_TURNING_OFF || state == BluetoothAdapter.STATE_TURNING_ON) {
			state = mBluetooth.getState();
		}

		if (state == BluetoothAdapter.STATE_ON) {
			available = true;
		} else {
			ATLog.i(TAG, INFO, "INFO. current state of the local Bluetooth adapter : " + state);
		}

		return available;
	}

	private synchronized void checkSystem() {

		// Check Bluetooth
		if (mBluetooth == null) {
			// Not Support Bluetooth...
			GlobalData.isSupportBluetooth = false;
			ATLog.e(TAG, "INFO. checkSystem() - Not suppored bluetooth");
		} else {
			GlobalData.isSupportBluetooth = true;
			// Suppoted Bluetooth
			if (!mBluetooth.isEnabled() && !mIsCheckEnableBluetooth) {
				mIsCheckEnableBluetooth = true;
				// Disabled Bluetotoh
				GlobalData.isEnableBluetooth = false;
				Intent intent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
				if (ActivityCompat.checkSelfPermission(this, Manifest.permission.BLUETOOTH_CONNECT) != PackageManager.PERMISSION_GRANTED) {
					// TODO: Consider calling
					//    ActivityCompat#requestPermissions
					// here to request the missing permissions, and then overriding
					//   public void onRequestPermissionsResult(int requestCode, String[] permissions,
					//                                          int[] grantResults)
					// to handle the case where the user grants the permission. See the documentation
					// for ActivityCompat#requestPermissions for more details.
					return;
				}
				startActivityForResult(intent, REQUEST_ENABLE_BLUETOOTH);
				ATLog.i(TAG, INFO, "INFO. checkSystem() - Request Enable Bluetooth");
				return;
			} else {
				GlobalData.isEnableBluetooth = true;
			}
		}

		
		if (!GlobalData.isSupportBluetooth) {
			MessageBox.show(this, R.string.msg_not_support_ble, R.string.title_bt);
		}

		ATLog.i(TAG, INFO, "INFO. checkSystem()");
	}
	
	private void showMessage(final String message) {
		runOnUiThread( new Runnable() {
			@Override
			public void run() {
				MessageBox.show(MainActivity.this, message);
			}
		});
		
	}
	
	// ------------------------------------------------------------------------
	// Load RFID Reader Properties
	// ------------------------------------------------------------------------
	private void loadProperties() {
		WaitDialog.show(this, R.string.msg_initialize_view);
		
		Thread thread = new Thread(mLoadingProperties);
		thread.start();
	}
	
	private Runnable mLoadingProperties = new Runnable() {
		@Override
		public void run() {
			mIsInitialize = loadingProperties();
			runOnUiThread(mLoadedProperties);
		}
	};
	
	private Runnable mLoadedProperties = new Runnable() {
		@Override
		public void run() {
			loadedProperties(mIsInitialize);
			WaitDialog.hide();
		}
	};		
	
	private boolean loadingProperties() {
		
		if (mIsConnected) {
			if (mReader.getDeviceType() == DeviceType.ATD100) {
				
				runOnUiThread(new Runnable(){
					@Override
					public void run() {
						MessageBox.show(MainActivity.this, getString(R.string.msg_not_support_function),
								getString(R.string.title_error));
					}
				});
				ATLog.e(TAG, "ERROR. loadingProperties() - %s", getString(R.string.msg_not_support_function));
				return false;
			}

		} else {
			ATLog.e(TAG, "ERROR. loadingProperties() - disconnected the bluetooth ");
			return false;
		}
		
		OperationMode mode = OperationMode.Barcode;
		
		if (mIsConnected) {
			try {
				mode = mReader.getOperationMode();
			} catch (ATException e) {
				ATLog.e(TAG, e, "ERROR. loadingProperties() - Failed to load operation mode");
				return false;
			}
		} else {
			ATLog.e(TAG, "ERROR. loadingProperties() - disconnected the bluetooth ");
			return false;
		}
		
		if (mIsConnected) {
			switch(mode) {
			case Barcode:
				break;
			case Normal:
			case KeyEventOnly:
				try {
					mReader.setOperationMode(OperationMode.Barcode);
				} catch (ATException e) {
					ATLog.e(TAG, e, "ERROR. loadingProperties() - Failed to set operation mode");
					return false;
				}
				break;
			default:
				ATLog.e(TAG, "ERROR. loadingProperties() - Unknown operation mode");
				return false;
			}
		} else {
			ATLog.e(TAG, "ERROR. loadingProperties() - disconnected the bluetooth ");
			return false;
		}
		
		mOperationMode = OperationMode.Barcode;
		
		if (mIsConnected) {
			if (mReader.getBarcode() == null) {
				ATLog.e(TAG, "ERROR. loadingProperties() - Failed to get barcode instance");
				return false;
			}
		} else {
			ATLog.e(TAG, "ERROR. loadingProperties() - disconnected the bluetooth ");
			return false;
		}
		
		// Set Barcode Event Listener
		mReader.getBarcode().addListener(this);
		
		GlobalData.loadConfig(this, mReader.getDeviceType(), mReader.getAddress());
		
		if (mIsConnected) {
			try {
				if(mReader.getBarcode() != null)
					mReader.getBarcode().setCharset((Charset)
							GlobalData.getConfig(this, mReader.getDeviceType(), mReader.getAddress(), 
									GlobalData.KEY_BARCODE_CHARSET)); 
									
			} catch (ATException e) {
				ATLog.e(TAG, e, "EVENT. loadingProperties() - Failed to set Character Set");
				return false;
			} catch (Exception e) {
				ATLog.e(TAG, e, "EVENT. loadingProperties() - Failed to get global data(%s)", GlobalData.KEY_BARCODE_CHARSET);
				return false;
			}
		} else {
			ATLog.e(TAG, "ERROR. loadingProperties() - disconnected the bluetooth ");
			return false;
		}
			
		// Enabled Use Key Action
		if (mIsConnected) {
			try {
				mReader.setUseActionKey(true);
			} catch (ATException e) {
				ATLog.e(TAG, e, "ERROR. loadingProperties() - Failed to enabled key action");
				return false;
			}
		} else {
			ATLog.e(TAG, "ERROR. loadingProperties() - disconnected the bluetooth ");
			return false;
		}
		
		ATLog.i(TAG, INFO, "INFO. loadingProperties()");
		return true;
	}
	
	private void loadedProperties(boolean isInitialize) {
		
		if (isInitialize) {
			
			txtTagCount.setText(String.format(Locale.US, "%d", mDataListAdapter.getCount()));
			txtTotalTagCount.setText(String.format(Locale.US, "%d", mTotalTagCount));
			
			enableWidgets(true);
		} else {
			enableWidgets(false);
		}
		
		ATLog.i(TAG, INFO, "INFO. loadedProperties(%s)", isInitialize);
	}	

	// ------------------------------------------------------------------------
	// Activity Life cycle
	// ------------------------------------------------------------------------
	public class ActivityLifecycleManager implements ActivityLifecycleCallbacks {

		private int mRefCount = 0;
		private String _tag = ActivityLifecycleManager.class.getSimpleName();
		
		@SuppressWarnings("deprecation")
		@Override
		public void onActivityStarted(Activity activity) {
			mRefCount++;
			ATLog.i(TAG, INFO, "INFO. ActivityLifecycleManager.onActivityStarted : " + mRefCount);
			
			if(mRefCount == 1) {
				// Setup always wake up
				Context context = activity.getApplicationContext();
				//SysUtil.wakeLock(activity.getApplicationContext(), SysUtil.getAppName(context));
				
				if(mWakeLock != null) {
					ATLog.i(TAG, INFO, "INFO. Already exist wake lock");
				}
				
				PowerManager powerManager = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
				mWakeLock = powerManager.newWakeLock(PowerManager.FULL_WAKE_LOCK, _tag);
				//mWakeLock = powerManager.newWakeLock(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON, TAG);
				mWakeLock.acquire();
				ATLog.i(TAG, INFO, "INFO. Acquires the wake lock.");
			}
		}
		
		@Override
		public void onActivityStopped(Activity activity) {
			mRefCount--;
			ATLog.i(TAG, INFO, "INFO. ActivityLifecycleManager.onActivityStopped : " + mRefCount);
			
			if(mRefCount == 0) {
				// release WakeLock.
				//SysUtil.wakeUnlock();
				
				if (mWakeLock == null)
					return;

				mWakeLock.release();
				mWakeLock = null;
				ATLog.i(TAG, INFO, "INFO. Releases the wake lock.");
			}
		}

		@Override
		public void onActivityCreated(Activity activity, Bundle savedInstanceState) {}
		@Override
		public void onActivityResumed(Activity activity) {}
		@Override
		public void onActivityPaused(Activity activity) {}
		@Override
		public void onActivitySaveInstanceState(Activity activity, Bundle outState) {}
		@Override
		public void onActivityDestroyed(Activity activity) {}
		
	}

}
