package com.metapace.printer.sample;

import java.util.ArrayList;
import java.util.List;
import java.util.Set;

import com.metapace.thermalprinter.MetapacePrinter;

import android.app.ActionBar;
import android.app.ActivityManager;
import android.app.AlertDialog;
import android.app.ListActivity;
import android.bluetooth.BluetoothDevice;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.hardware.usb.UsbDevice;
import android.hardware.usb.UsbManager;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.ArrayAdapter;
import android.widget.ListView;
import android.widget.ProgressBar;
import android.widget.Toast;

public class MainActivity extends ListActivity {
	
	public static final String TAG = "metapacePrinterSample";
	
	static final String ACTION_GET_DEFINEED_NV_IMAGE_KEY_CODES = "com.metapace.metapacePrinter.anction.GET_DEFINED_NV_IMAGE_KEY_CODES";
	static final String EXTRA_NAME_NV_KEY_CODES = "NvKeyCodes";
	
	static final int REQUEST_CODE_SELECT_FIRMWARE = Integer.MAX_VALUE;
	static final int RESULT_CODE_SELECT_FIRMWARE = Integer.MAX_VALUE - 1;
	static final int MESSAGE_START_WORK = Integer.MAX_VALUE - 2;
	static final int MESSAGE_END_WORK = Integer.MAX_VALUE - 3;
	
	static final String FIRMWARE_FILE_NAME = "FirmwareFileName";

	// Name of the connected device
	private String mConnectedDeviceName = null;
	
	private ListView mListView;
	private ProgressBar mProgressBar;
	
	private AlertDialog mPdf417Dialog;
	private AlertDialog mQrCodeDialog;
	private AlertDialog mCodePageDialog;
	private AlertDialog mPrinterIdDialog;
	private AlertDialog mDirectIoDialog;
	
	static MetapacePrinter metapacePrinter;
	
	private static final String[] FUNCTIONS = {
		"getStatus",
		"enable automatic status back",
		"disable automatic status back",
		"printSelfTest",
		"getPrinterId",
		"setCodePage",
		"set page mode",
		"initialize",
		"printText",
		"print1dBarcode",
		"printPdf417",
		"printQrCode",
		"printBitmap",
		"kickOutDrawer",
		"executeDirectIo",
		"NV image manager (T-3II only)",
		"NV image manager (T-3II, T-4)",
		"updateFirmware",
	};
	
	private boolean mIsConnected;
	
	@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);

		ArrayList<String> list = new ArrayList<String>();
		for (int i = 0; i < FUNCTIONS.length; i++) {
			list.add(FUNCTIONS[i]);
		}

		ArrayAdapter<String> adapter = new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, list);
		mListView = (ListView) findViewById(android.R.id.list);
		mListView.setAdapter(adapter);
		mListView.setEnabled(false);
		
		mProgressBar = (ProgressBar) findViewById(R.id.progressBar1);
		
		metapacePrinter = new MetapacePrinter(this, mHandler, null);
	}

	@Override
	public void onDestroy() {
		super.onDestroy();
		
		try {
			unregisterReceiver(mUsbReceiver);
		} catch (IllegalArgumentException e) {
			e.printStackTrace();
		}
		
		metapacePrinter.disconnect();
	}

	@Override
	public boolean onCreateOptionsMenu(Menu menu) {
		getMenuInflater().inflate(R.menu.activity_main, menu);
		return true;
	}
	
	@Override
	public boolean onPrepareOptionsMenu(Menu menu) {
		if (mIsConnected) {
			menu.getItem(0).setEnabled(false);
			menu.getItem(1).setEnabled(false);
			menu.getItem(2).setEnabled(false);
			menu.getItem(3).setEnabled(true);
		} else {
			menu.getItem(0).setEnabled(true);
			menu.getItem(1).setEnabled(true);
			menu.getItem(2).setEnabled(true);
			menu.getItem(3).setEnabled(false);
		}
		return true;
	}

	@Override
	public boolean onOptionsItemSelected(MenuItem item) {
		switch (item.getItemId()) {
		case R.id.item1:
			metapacePrinter.findBluetoothPrinters();
			break;

		case R.id.item2:
			metapacePrinter.findNetworkPrinters(3000);
			return true;

		case R.id.item3:
			if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB_MR1) {
				metapacePrinter.findUsbPrinters();
			}
			return true;
			
		case R.id.item4:
			metapacePrinter.disconnect();
			return true;
		}
		return false;
	}

	@Override
	protected void onListItemClick(ListView l, View v, int position, long id) {
		switch (position) {
		case 0:	// getStatus
			metapacePrinter.getStatus();
			break;
			
		case 1: // enable automatic status back
			metapacePrinter.automateStatusBack(true);
			break;
			
		case 2: // disable automatic status back
			metapacePrinter.automateStatusBack(false);
			break;
			
		case 3: // printSelfTest
			metapacePrinter.printSelfTest(true);
			break;
			
		case 4: // getPrinterId
			DialogManager.showPrinterIdDialog(mPrinterIdDialog, MainActivity.this);
			break;
			
		case 5: // setCodePage
			DialogManager.showCodePageDialog(mCodePageDialog, MainActivity.this, mHandler);
			break;		
			
		case 6: // set page mode
			Intent intent = new Intent(MainActivity.this, PageModeActivity.class);
			startActivity(intent);
			break;
			
		case 7:	// initialize
			metapacePrinter.initialize();
			break;
			
		case 8:	// printText
			intent = new Intent(MainActivity.this, PrintTextActivity.class);
			startActivity(intent);
			break;

		case 9:	// print1dBarcode
			intent = new Intent(MainActivity.this, Print1dBarcodeActivity.class);
			startActivity(intent);
			break;

		case 10:	// printPdf417
			DialogManager.showPdf417Dialog(mPdf417Dialog, MainActivity.this);
			break;

		case 11:	// printQrCode
			DialogManager.showQrCodeDialog(mQrCodeDialog, MainActivity.this);
			break;

		case 12: // printBitmap
			intent = new Intent(MainActivity.this, PrintBitmapAcitivity.class);
			startActivity(intent);
			break;
			
		case 13: // kickOutDrawer
			metapacePrinter.kickOutDrawer(MetapacePrinter.DRAWER_CONNECTOR_PIN2);
			metapacePrinter.kickOutDrawer(MetapacePrinter.DRAWER_CONNECTOR_PIN5);
			break;
			
		case 14: // directIo
			DialogManager.showDirectIoDialog(mDirectIoDialog, MainActivity.this);
			break;
			
		case 15: // NV image manager (T-3II)
			intent = new Intent(MainActivity.this, NvImageT_3iiActivity.class);
			startActivity(intent);
			break;
			
		case 16: // NV image manager (T-4)
			intent = new Intent(MainActivity.this, NvImageActivity.class);
			startActivity(intent);
			break;
			
		case 17: // updateFirmware
			intent = new Intent(MainActivity.this, FileExplorerActivity.class);
			startActivityForResult(intent, REQUEST_CODE_SELECT_FIRMWARE);
			break;
		}
	}
	
	@Override
	public void onActivityResult(int requestCode, int resultCode, Intent data) {
		if (requestCode == REQUEST_CODE_SELECT_FIRMWARE && resultCode == RESULT_CODE_SELECT_FIRMWARE) {
			final String binaryFilePath = data.getStringExtra(FIRMWARE_FILE_NAME);
			mHandler.obtainMessage(MESSAGE_START_WORK).sendToTarget();
			new Thread(new Runnable() {
				
				public void run() {
					metapacePrinter.updateFirmware(binaryFilePath);
					try {
						Thread.sleep(5000);
					} catch (InterruptedException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}
					mHandler.obtainMessage(MESSAGE_END_WORK).sendToTarget();
				}
			}).start();
		} else {
			super.onActivityResult(requestCode, resultCode, data);
		}
	}
	
	private final void setStatus(int resId) {
		final ActionBar actionBar = getActionBar();
		actionBar.setSubtitle(resId);
	}

	private final void setStatus(CharSequence subtitle) {
		final ActionBar actionBar = getActionBar();
		actionBar.setSubtitle(subtitle);
	}

	private void dispatchMessage(Message msg) {
		switch (msg.arg1) {
		case MetapacePrinter.PROCESS_GET_STATUS:
			if (msg.arg2 == MetapacePrinter.STATUS_NORMAL) {
				Toast.makeText(getApplicationContext(), "No error", Toast.LENGTH_SHORT).show();
			} else {
				StringBuffer buffer = new StringBuffer();
				if ((msg.arg2 & MetapacePrinter.STATUS_COVER_OPEN) == MetapacePrinter.STATUS_COVER_OPEN) {
					buffer.append("Cover is open.\n");
				}
				if ((msg.arg2 & MetapacePrinter.STATUS_PAPER_NOT_PRESENT) == MetapacePrinter.STATUS_PAPER_NOT_PRESENT) {
					buffer.append("Paper end sensor: paper not present.\n");
				}

				Toast.makeText(getApplicationContext(), buffer.toString(), Toast.LENGTH_SHORT).show();
			}
			break;
			
		case MetapacePrinter.PROCESS_GET_PRINTER_ID:
			Bundle data = msg.getData();
			Toast.makeText(getApplicationContext(), data.getString(MetapacePrinter.KEY_STRING_PRINTER_ID), Toast.LENGTH_SHORT).show();
			break;
			
		case MetapacePrinter.PROCESS_AUTO_STATUS_BACK:
			StringBuffer buffer = new StringBuffer(0);
			if ((msg.arg2 & MetapacePrinter.AUTO_STATUS_COVER_OPEN) == MetapacePrinter.AUTO_STATUS_COVER_OPEN) {
				buffer.append("Cover is open.\n");
			}
			if ((msg.arg2 & MetapacePrinter.AUTO_STATUS_NO_PAPER) == MetapacePrinter.AUTO_STATUS_NO_PAPER) {
				buffer.append("Paper end sensor: no paper present.\n");
			}
			
			if (buffer.capacity() > 0) {
				Toast.makeText(getApplicationContext(), buffer.toString(), Toast.LENGTH_SHORT).show();
			} else {
				Toast.makeText(getApplicationContext(), "No error.", Toast.LENGTH_SHORT).show();
			}
			break;
			
		case MetapacePrinter.PROCESS_GET_NV_IMAGE_KEY_CODES:
			data = msg.getData();
			int[] value = data.getIntArray(MetapacePrinter.NV_IMAGE_KEY_CODES);
			
			Intent intent = new Intent();
			intent.setAction(ACTION_GET_DEFINEED_NV_IMAGE_KEY_CODES);
			intent.putExtra(EXTRA_NAME_NV_KEY_CODES, value);
			sendBroadcast(intent);
			break;
			
		case MetapacePrinter.PROCESS_EXECUTE_DIRECT_IO:
			buffer = new StringBuffer();
			data = msg.getData();
			byte[] response = data.getByteArray(MetapacePrinter.KEY_STRING_DIRECT_IO);
			for (int i = 0; i < response.length && response[i] != 0; i++) {
				buffer.append(Integer.toHexString(response[i]) + " ");
			}
			
			Toast.makeText(getApplicationContext(), buffer.toString(), Toast.LENGTH_SHORT).show();
			break;
		}
	}

	private final Handler mHandler = new Handler(new Handler.Callback() {
		
		@SuppressWarnings("unchecked")
		@Override
		public boolean handleMessage(Message msg) {
			Log.d(TAG, "mHandler.handleMessage(" + msg + ")");
			
			switch (msg.what) {
			case MetapacePrinter.MESSAGE_STATE_CHANGE:
				switch (msg.arg1) {
				case MetapacePrinter.STATE_CONNECTED:
					setStatus(getString(R.string.title_connected_to, mConnectedDeviceName));
					mListView.setEnabled(true);
					mIsConnected = true;
					invalidateOptionsMenu();
					break;

				case MetapacePrinter.STATE_CONNECTING:
					setStatus(R.string.title_connecting);
					break;

				case MetapacePrinter.STATE_NONE:
					setStatus(R.string.title_not_connected);
					mListView.setEnabled(false);
					mIsConnected = false;
					invalidateOptionsMenu();
					mProgressBar.setVisibility(View.INVISIBLE);
					break;
				}
				return true;
				
			case MetapacePrinter.MESSAGE_WRITE:
				switch (msg.arg1) {
				case MetapacePrinter.PROCESS_DEFINE_NV_IMAGE:
					ActivityManager activityManager = (ActivityManager) getSystemService(ACTIVITY_SERVICE);
					List<ActivityManager.RunningTaskInfo> runningTaskInfos = activityManager.getRunningTasks(1);
					ComponentName componentName = runningTaskInfos.get(0).topActivity;
					String topActivityName = componentName.getPackageName();
					Log.d(TAG, "topActivityName: " + topActivityName);
					if (topActivityName.equals("com.metapace.printer.sample.NvImageT_3iiActivity")) {
						metapacePrinter.getDefinedNvImageKeyCodes();
					}
					Toast.makeText(getApplicationContext(), "Complete to define NV image", Toast.LENGTH_LONG).show();
					break;
					
				case MetapacePrinter.PROCESS_REMOVE_NV_IMAGE:
					metapacePrinter.getDefinedNvImageKeyCodes();
					Toast.makeText(getApplicationContext(), "Complete to remove NV image", Toast.LENGTH_LONG).show();
					break;
					
				case MetapacePrinter.PROCESS_UPDATE_FIRMWARE:
					metapacePrinter.disconnect();
					Toast.makeText(getApplicationContext(), "Complete to download firmware.\nPlease reboot the printer.", Toast.LENGTH_SHORT).show();
					break;
				}
				return true;

			case MetapacePrinter.MESSAGE_READ:
				MainActivity.this.dispatchMessage(msg);
				return true;

			case MetapacePrinter.MESSAGE_DEVICE_NAME:
				mConnectedDeviceName = msg.getData().getString(MetapacePrinter.KEY_STRING_DEVICE_NAME);
				Toast.makeText(getApplicationContext(), mConnectedDeviceName, Toast.LENGTH_LONG).show();
				return true;

			case MetapacePrinter.MESSAGE_TOAST:
				mListView.setEnabled(false);
				Toast.makeText(getApplicationContext(), msg.getData().getString(MetapacePrinter.KEY_STRING_TOAST), Toast.LENGTH_SHORT).show();
				return true;
				
			case MetapacePrinter.MESSAGE_PRINT_COMPLETE:
				Toast.makeText(getApplicationContext(), "Complete to print", Toast.LENGTH_SHORT).show();
				return true;
				
			case MetapacePrinter.MESSAGE_ERROR_INVALID_ARGUMENT:
				Toast.makeText(getApplicationContext(), "Invalid argument", Toast.LENGTH_SHORT).show();
				return true;
				
			case MetapacePrinter.MESSAGE_ERROR_NV_MEMORY_CAPACITY:
				Toast.makeText(getApplicationContext(), "NV memory capacity error", Toast.LENGTH_SHORT).show();
				return true;
				
			case MetapacePrinter.MESSAGE_ERROR_OUT_OF_MEMORY:
				Toast.makeText(getApplicationContext(), "Out of memory", Toast.LENGTH_SHORT).show();
				return true;
				
			case MESSAGE_START_WORK:
				mListView.setEnabled(false);
				mProgressBar.setVisibility(View.VISIBLE);
				return true;
				
			case MESSAGE_END_WORK:
				mListView.setEnabled(true);
				mProgressBar.setVisibility(View.INVISIBLE);
				return true;
				
			case MetapacePrinter.MESSAGE_BLUETOOTH_DEVICE_SET:
				if (msg.obj == null) {
					Toast.makeText(getApplicationContext(), "No paired device", Toast.LENGTH_SHORT).show();
				} else {
					DialogManager.showBluetoothDialog(MainActivity.this, (Set<BluetoothDevice>) msg.obj);
				}
				return true;
				
			case MetapacePrinter.MESSAGE_USB_DEVICE_SET:
				if (msg.obj == null) {
					Toast.makeText(getApplicationContext(), "No connected device", Toast.LENGTH_SHORT).show();
				} else {
					DialogManager.showUsbDialog(MainActivity.this, (Set<UsbDevice>) msg.obj, mUsbReceiver);
				}
				return true;
				
			case MetapacePrinter.MESSAGE_NETWORK_DEVICE_SET:
				if (msg.obj == null) {
					Toast.makeText(getApplicationContext(), "No connectable device", Toast.LENGTH_SHORT).show();
				}
				DialogManager.showNetworkDialog(MainActivity.this, (Set<String>) msg.obj);
				return true;
			}
			return false;
		}
	});

	private BroadcastReceiver mUsbReceiver = new BroadcastReceiver() {

		@Override
		public void onReceive(Context context, Intent intent) {
			Log.d(TAG, "mUsbReceiver.onReceive(" + context + ", " + intent + ")");
			String action = intent.getAction();

			if (UsbManager.ACTION_USB_DEVICE_ATTACHED.equals(action)) {
				metapacePrinter.connect();
				Toast.makeText(getApplicationContext(), "Found USB device", Toast.LENGTH_SHORT).show();
			} else if (UsbManager.ACTION_USB_DEVICE_DETACHED.equals(action)) {
				metapacePrinter.disconnect();
				Toast.makeText(getApplicationContext(), "USB device removed", Toast.LENGTH_SHORT).show();
			}

		}
	};
}
