package emv.controllers;

import java.io.IOException;
import java.text.Format;
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Calendar;
import java.util.Date;

import android.util.Log;

import controllers.PinpadHelper;
import controllers.PinpadManager;
import emv.EmvCardData;
import emv.EmvRequest;
import emv.EmvResponse;
import emv._0200Type;
import emv.utils.BerTlv;
import emv.utils.Tag;
import exceptions.TransactionAbortedException;
import exceptions.TransactionCanceledException;
import exceptions.TransactionDeniedException;
import exceptions.TransactionException;
import extras.ReferenceList;
import facade.PayPadManager;
import models.messaging.nibss.BalanceRequest;
import models.messaging.nibss.BalanceResponse;
import models.messaging.nibss.CashAdvanceRequest;
import models.messaging.nibss.CashAdvanceResponse;
import models.messaging.nibss.CashBackRequest;
import models.messaging.nibss.CashBackResponse;
import models.messaging.nibss.Globals;
import models.messaging.nibss.NibssIsoProcessor;
import models.messaging.nibss.NibssIsoProcessorVas;
import models.messaging.nibss.PurchaseRequest;
import models.messaging.nibss.PurchaseResponse;
import models.messaging.nibss.RePowerRequest;
import models.messaging.nibss.RePowerResponse;
import models.messaging.nibss.RefundRequest;
import models.messaging.nibss.RefundResponse;
import utils.HexUtil;

import com.datecs.pinpad.Pinpad;
import com.datecs.pinpad.PinpadException;
import com.datecs.pinpad.emv.EMVApplication;
import com.datecs.pinpad.emv.EMVCommonApplications;
import com.datecs.pinpad.emv.EMVStatusCodes;
import com.datecs.pinpad.emv.EMVTags;
import utils.CryptoUtil;
import org.json.JSONObject;
import org.json.JSONException;
import com.esl.lib.PaypadFacade;
import org.apache.cordova.*;


public class EmvTransactionProcesssorVas {

	public String track = "";

	private static final int KEY_DATA_INDEX = 0;
	// Specify if default processing is permit.
	private final boolean OFFLINE_PROCESSING = true;
	// Simulate communication failure
	private final boolean COMMUNICATION_FAILURE = false;

	private String stan;
	private PinpadManager pinPadManager = null;
	private _0200Type _0200type;

	private Long amount = (long) 000000000000;
	private static String TAG = "EMVTransactionProcessor";
	private boolean webServiceSuccess = false;
	byte[] sessionKey = null;
	byte[] pinKey = null;
	private String dbDate;
	private String processingCode;
	private String unitPrices;
	private String quantities;
	private String items;
	private String bdk;
	private String CAID;
	private String sequenceNo;

	public EmvTransactionProcesssorVas(PinpadManager pinPadManager,
			_0200Type _0200type) {

		this.pinPadManager = pinPadManager;

		this._0200type = _0200type;

		bdk = ReferenceList.config.getString(Globals.BDKKey,"");

		String tsk = ReferenceList.config.getString(Globals.TSKVasKey, "none");

		// PaypadFacade.showStaticToast("tsk: "+tsk);

		if (!tsk.equals("none")) {
			sessionKey = HexUtil.hexStringToByteArray(tsk,' ');
		}

		String tpk = ReferenceList.config.getString(Globals.TPKVasKey, "none");

		// PaypadFacade.showStaticToast("tpk: "+tpk);

		if (!tpk.equals("none")) {
			pinKey = HexUtil.hexStringToByteArray(tpk,' ');
		}
	}

	public EmvResponse doEmv(EmvRequest request) throws IOException,
			InterruptedException, PinpadException,
			TransactionCanceledException, TransactionException,
			TransactionAbortedException, TransactionDeniedException {

		if (pinPadManager == null) {
			return null;
		}

		Pinpad pinpad = pinPadManager.getPinpad();

		if (pinpad == null) {
			return null;
		}
		/*
		 * if(request == null){ return null; }
		 */
		EmvResponse response = new EmvResponse();

		try{
		try {
			boolean completed = false;

			do {
				// Wait to present card on Pinpad.
				Log.i("EMVPROCESSOR", "� Wait to insert card\n");
				Globals.state = "payment";
				JSONObject presentCardObj = new JSONObject();
				presentCardObj.put("operation",Globals.state);
				// presentCardObj.put("status","inserting_card");

				int cardType = PinpadHelper.presentCard(pinpad);

	            presentCardObj.put("status","processing");

	            PluginResult pr = new PluginResult(PluginResult.Status.OK, presentCardObj );
	            pr.setKeepCallback(true);
				PaypadFacade.callbackContext.sendPluginResult(pr);

				// First try to process smart card transaction.
				if ((cardType & PinpadHelper.CARD_SC) != 0) {

//					Intent v1 = new Intent();
//					v1.setAction("com.firstpad");
//					v1.putExtra("response", "stopInsertStartBusy");
//					ScreenSlidePagerActivity.appContext.sendBroadcast(v1);

					// used for receipt
					Globals.entryMethod = "Chip";

					byte[] atr = null;
					pinpad.scCardPowerOff(Pinpad.SC_SLOT_MAIN);
					try {
						atr = pinpad.scCardPowerOn(Pinpad.SC_SLOT_MAIN);
						Log.i("EMVPROCESSOR", "� Smart card detected\n");
						Log.i("EMVPROCESSOR",
								"  ATR: " + HexUtil.byteArrayToHexString(atr)
										+ "\n");
					} catch (PinpadException e) {
						Log.i("EMVPROCESSOR", "  No smart card detected\n");
					}

					if (atr != null) {
						Log.i("EMVPROCESSOR", "� ATR Validation\n");
						pinpad.emvATRValidation(false, atr);
						if (pinpad.emvGetLastStatus() != EMVStatusCodes.EMV_SUCCESS) {
							Log.i("EMVPROCESSOR", "  Invalid EMV card\n");
							continue;
						}

						processEMVTransaction(pinpad, response, request);
						completed = true;
					}
				}

				if (completed)
					continue;

				// If smart card transaction can not be finished, then try with
				// magnetic card.
				if ((cardType & PinpadHelper.CARD_MS) != 0) {
					Globals.entryMethod = "Stripe";
					byte[] cardData = null;
					byte[] maskData = null;
					String cardHolder = null;
					try {
						cardData = pinpad.msGetCardData3DESCBC(KEY_DATA_INDEX,
								0xaabbccdd);
						maskData = pinpad.msGetMaskedCardData(5, 4, 7);
						Log.i("EMVPROCESSOR", "  Masked data: "
								+ new String(maskData) + "\n");
						cardHolder = pinpad.msGetCardholder();
						Log.i("EMVPROCESSOR", "  Card holder: " + cardHolder
								+ "\n");
					} catch (PinpadException e) {
						if (e.getErrorCode() == Pinpad.ERROR_NO_DATA) {
							Log.i("EMVPROCESSOR", "  Invalid magnetic card\n");
							continue;
						}
						throw e;
					}

					byte[] chunk = new byte[cardData.length - 1];
					System.arraycopy(cardData, 1, chunk, 0, chunk.length);

					byte[] track = decryptData(chunk);
					if (track == null) {
						throw new TransactionAbortedException(
								"Failed to decrypt data");
					}

					processMagneticCardTransaction(pinpad, track);
					completed = true;
				}
			} while (!completed);

			PinpadHelper.removeCard(pinpad);
			PinpadHelper.showMessage(pinpad, Globals.returnMessage);
			Log.i("EMVPROCESSOR", "  Transaction is successful.\n\n");

		}catch(JSONException e){

			PaypadFacade.callbackContext.sendPluginResult(
				new PluginResult(PluginResult.Status.ERROR, ""+e.getMessage()));
			PinpadHelper.showAborted(pinpad);
		} 
		catch (TransactionAbortedException e) {
			response.setVerboseFailureDescription(e.getMessage());

			JSONObject obj = new JSONObject();
			obj.put("operation",Globals.state);
			obj.put("status","Aborted");

			PaypadFacade.callbackContext.sendPluginResult(
				new PluginResult(PluginResult.Status.ERROR, obj));
			PinpadHelper.showAborted(pinpad);

		} catch (TransactionCanceledException e) {
			response.setVerboseFailureDescription(e.getMessage());

			JSONObject obj = new JSONObject();
			obj.put("operation",Globals.state);
			obj.put("status","Canceled");

			PaypadFacade.callbackContext.sendPluginResult(
				new PluginResult(PluginResult.Status.ERROR, obj));
			PinpadHelper.showCanceled(pinpad);
		} catch (TransactionDeniedException e) {
			response.setVerboseFailureDescription(e.getMessage());
			PinpadHelper.showDenied(pinpad);
			JSONObject obj = new JSONObject();
			obj.put("operation",Globals.state);
			obj.put("status","Denied");
			PaypadFacade.callbackContext.sendPluginResult(
				new PluginResult(PluginResult.Status.ERROR, obj));
		} catch (PinpadException e) {
			// response.setVerboseFailureDescription(e.getMessage());
			PinpadHelper.showAborted(pinpad);
			PaypadFacade.callbackContext.sendPluginResult(
				new PluginResult(PluginResult.Status.ERROR, "Pinpad Exception"));

		} catch (IOException e) {
			response.setVerboseFailureDescription(e.getMessage());
			PinpadHelper.showAborted(pinpad);
			PaypadFacade.callbackContext.sendPluginResult(
				new PluginResult(PluginResult.Status.ERROR, ""+e.getMessage()));
		}

		return response;
	}
	catch(JSONException e){
		PaypadFacade.callbackContext.sendPluginResult(
				new PluginResult(PluginResult.Status.ERROR, ""+e.getMessage()));
	}

	return response;
	}

	private void processEMVTransaction(Pinpad pinpad, EmvResponse response,
			EmvRequest request) throws PinpadException, IOException,
			InterruptedException, TransactionCanceledException,
			TransactionAbortedException, TransactionDeniedException,
			TransactionException {

		boolean completed = false;
		int emvStatus = 0;

		Log.i("EMVPROCESSOR", "� Process EMV card\n");
		PinpadHelper.showBusy(pinpad);

		// Initialize EMV kernel
		Log.i("EMVPROCESSOR", "� Init EMV kernel\n");
		pinpad.emvDeinitialise();
		pinpad.emvInit();

		// /////////////////////////////////////////////////////////////////////
		// SET INITIAL CONFIGURATION
		// /////////////////////////////////////////////////////////////////////

		// Set EMV tags.
		Log.i("EMVPROCESSOR", "� Set EMV tags\n");

		pinpad.emvSetDataAsString(EMVTags.TAG_ADD_TERM_CAPABILITIES,
				"600080A000");
		pinpad.emvSetDataAsString(EMVTags.TAG_SERIAL_NUMBER, "12345678");
		pinpad.emvSetDataAsString(EMVTags.TAG_TERMINAL_COUNTRY_CODE, "0566");
		pinpad.emvSetDataAsString(EMVTags.TAG_TERMINAL_TYPE, "22");
		throwOnEMVError(pinpad);
		pinpad.emvSetDataAsString(EMVTags.TAG_TERMINAL_CAPABILITIES,
				Globals.terminalCapabilities);
		throwOnEMVError(pinpad);

		// /////////////////////////////////////////////////////////////////////
		// APPLICATION SELECTION & INITIALIZATION
		// /////////////////////////////////////////////////////////////////////

		// Load terminal application list.
		final EMVApplication[] emvApps = new EMVApplication[27];
		emvApps[0] = new EMVApplication(decode("A0 00 00 00 03 10 10"),
				"VISA CR/DB", EMVApplication.FULL_MATCH);
		emvApps[1] = new EMVApplication(decode("A0 00 00 00 03 20 10"),
				"VISA ELECTRON", EMVApplication.FULL_MATCH);
		emvApps[2] = new EMVApplication(decode("A0 00 00 00 04 10 10"),
				"MASTERCARD CR/DB", EMVApplication.FULL_MATCH);
		emvApps[3] = new EMVApplication(decode("A0 00 00 00 04 30 60"),
				"MAESTRO", EMVApplication.FULL_MATCH);
		emvApps[4] = new EMVApplication(decode("A0 00 00 00 04 99 99"),
				"MASTERCARD", EMVApplication.FULL_MATCH);
		emvApps[5] = new EMVApplication(decode("A0 00 00 00 03 40 10"), "VISA",
				EMVApplication.FULL_MATCH);
		emvApps[6] = new EMVApplication(decode("A0 00 00 00 03 50 10"), "VISA",
				EMVApplication.FULL_MATCH);
		emvApps[7] = new EMVApplication(decode("A0 00 00 00 04 20 10"),
				"MASTERCARD", EMVApplication.FULL_MATCH);
		emvApps[8] = new EMVApplication(decode("A0 00 00 00 04 30 10"),
				"MASTERCARD", EMVApplication.FULL_MATCH);
		emvApps[9] = new EMVApplication(decode("A0 00 00 00 04 40 10"),
				"MASTERCARD", EMVApplication.FULL_MATCH);
		emvApps[10] = new EMVApplication(decode("A0 00 00 00 04 50 10"),
				"MASTERCARD", EMVApplication.FULL_MATCH);
		emvApps[11] = new EMVApplication(decode("A0 00 00 00 03 20 20"),
				"V PAY", EMVApplication.FULL_MATCH);
		emvApps[12] = new EMVApplication(decode("A0 00 00 00 03 80 10"),
				"VISA PLUS", EMVApplication.FULL_MATCH);
		emvApps[13] = new EMVApplication(decode("A0 00 00 00 03 30 10"),
				"VISA INTERLINK", EMVApplication.FULL_MATCH);
		emvApps[14] = new EMVApplication(decode("A0 00 00 00 04 60 00"),
				"CIRRUS", EMVApplication.FULL_MATCH);
		emvApps[15] = new EMVApplication(decode("A0 00 00 00 25 01 00"),
				"AMERICAN EXPRESS", EMVApplication.PARTIAL_MATCH_VISA);
		emvApps[16] = new EMVApplication(decode("A0 00 00 00 25 00 00"),
				"AMERICAN EXPRESS", EMVApplication.PARTIAL_MATCH_VISA);
		emvApps[17] = new EMVApplication(decode("A0 00 00 00 65 10 10"), "JCB",
				EMVApplication.FULL_MATCH);
		emvApps[18] = new EMVApplication(decode("A0 00 00 00 10 30 30"),
				"UNKNOWN", EMVApplication.FULL_MATCH);
		emvApps[19] = new EMVApplication(decode("A0 00 00 00 99 90 90"),
				"UNKNOWN", EMVApplication.FULL_MATCH);
		emvApps[20] = new EMVApplication(decode("A0 00 00 00 05 00 01"),
				"MAESTRO UK", EMVApplication.FULL_MATCH);
		emvApps[21] = new EMVApplication(decode("A0 00 00 00 05 00 02"),
				"UK SOLO", EMVApplication.FULL_MATCH);
		emvApps[22] = new EMVApplication(decode("A0 00 00 01 52 30 10"),
				"DISCOVER", EMVApplication.FULL_MATCH);
		emvApps[23] = new EMVApplication(decode("A0 00 00 00 29 10 10"),
				"LINK ATM NETWORK", EMVApplication.FULL_MATCH);
		emvApps[24] = new EMVApplication(decode("A0 00 00 01 21 10 10"),
				"DANKORT", EMVApplication.FULL_MATCH);
		emvApps[25] = new EMVApplication(decode("A0 00 00 01 41 00 01"),
				"CoGeBan", EMVApplication.FULL_MATCH);
		emvApps[26] = new EMVApplication(decode("A0 00 00 03 71 00 01"),
				"VERVE", EMVApplication.PARTIAL_MATCH_VISA);

		Log.i("EMVPROCESSOR", "� Load application list\n");
		pinpad.emvLoadAppList(EMVApplication.SELECTION_METHOD_PSE, false,
				emvApps);
		throwOnEMVError(pinpad);

		do {
			EMVApplication emvApp = null;
			// Get common application list
			EMVCommonApplications emvCommonApps = pinpad.emvGetCommonAppList();

			// The EMV status of this operation must be EMV_LIST_AVAILABLE or
			// EMV_APPLICATION_AVAILABLE
			emvStatus = pinpad.emvGetLastStatus();

			switch (emvStatus) {
			case EMVStatusCodes.EMV_APPLICATION_AVAILABLE: {
				emvApp = emvCommonApps.getApplications()[0];

				if (emvCommonApps.isConfirmationRequired()) {
					if (!PinpadHelper.confirm(pinpad, emvApp.getLabelString()
							+ "?")) {
						throw new TransactionCanceledException(
								"Cancel application confirmation");
					}
				}
				break;
			}
			case EMVStatusCodes.EMV_LIST_AVAILABLE: {
				Log.i("EMVPROCESSOR", "� Select application:\n");
				String[] items = new String[emvCommonApps.getApplications().length];
				for (int i = 0; i < emvCommonApps.getApplications().length; i++) {
					EMVApplication app = emvCommonApps.getApplications()[i];
					Log.i("EMVPROCESSOR", "  -> " + app.getLabelString() + "\n");
					Log.i("EMVPROCESSOR",
							"  "
									+ "AID: "
									+ HexUtil.byteArrayToHexString(app.getAID())
									+ "\n");
					items[i] = app.getLabelString();
				}

				int index = PinpadHelper.select(pinpad, items);
				emvApp = emvCommonApps.getApplications()[index];
				break;
			}
			case EMVStatusCodes.EMV_NO_COMMON_APPLICATION: {
				throw new TransactionAbortedException(
						"No common application found");
			}
			default: {
				throwOnEMVError(pinpad);
			}
			}

			if (emvApp == null) { // ?!?
				throw new TransactionAbortedException("SYSTEM ERROR");
			}

			Log.i("EMVPROCESSOR", "  Application: " + emvApp.getLabelString()
					+ "\n");
			Log.i("EMVPROCESSOR",
					"  AID: " + HexUtil.byteArrayToHexString(emvApp.getAID())
							+ "\n");
			CAID = HexUtil.byteArrayToHexString(emvApp.getAID());
			Log.i("EMVPROCESSOR", "� Set EMV tags\n");
			pinpad.emvSetDataAsString(EMVTags.TAG_TRANSACTION_TIME, iccTime());
			throwOnEMVError(pinpad);
			pinpad.emvSetDataAsString(EMVTags.TAG_TRANSACTION_DATE, iccDate());
			throwOnEMVError(pinpad);
			pinpad.emvSetDataAsString(EMVTags.TAG_TRANSACTION_SEQ_COUNTER,
					"0001");
			throwOnEMVError(pinpad);

			// Initial application processing.
			pinpad.emvInitialAppProcessing(emvApp.getAID());
			throwOnEMVError(pinpad);
			emvStatus = pinpad.emvGetLastStatus();
			switch (emvStatus) {
			case EMVStatusCodes.EMV_BLOCKED_APPLICATION: {
				throw new TransactionAbortedException("Application is blocked");
			}
			case EMVStatusCodes.EMV_APPLICATION_NOT_FOUND:
			case EMVStatusCodes.EMV_INVALID_APPLICATION: {
				continue;
			}
			default: {
				// throwOnEMVError(pinpad);
			}
			}

			completed = true;
		} while (!completed);

		PinpadHelper.showBusy(pinpad);

		String tag;
		Log.i("EMVPROCESSOR", "� Read EMV tags\n");
		tag = pinpad.emvGetDataAsString(EMVTags.TAG_LANGUAGE_PREFERENCE);
		throwOnEMVError(pinpad);
		Log.i("EMVPROCESSOR", "  TAG_LANGUAGE_PREFERENCE: " + tag + "\n");
		tag = pinpad.emvGetDataAsString(EMVTags.TAG_ISSUER_CODE_INDEX);
		throwOnEMVError(pinpad);
		Log.i("EMVPROCESSOR", "  TAG_ISSUER_CODE_INDEX: " + tag + "\n");

		Log.i("EMVPROCESSOR", "� Read application data\n");
		pinpad.emvReadAppData(new int[] {});
		throwOnEMVError(pinpad);

		// /////////////////////////////////////////////////////////////////////
		// TRANSACTION DATA PROCESSING
		// /////////////////////////////////////////////////////////////////////
		tag = pinpad.emvGetDataAsString(EMVTags.TAG_EXPIRY_DATE);
		throwOnEMVError(pinpad);
		Log.i("EMVPROCESSOR", "  TAG_EXPIRY_DATE: " + tag + "\n");

		// Tags with sensitive data
		EmvCardData emvCardData = new EmvCardData();
		tag = readTagAsString(pinpad, EMVTags.TAG_PAN);
		throwOnEMVError(pinpad);
		Log.i("EMVPROCESSOR", "  TAG_PAN: " + tag + "\n");
		if (tag.charAt(tag.length() - 1) == 'F') {
			tag = tag.replaceAll("F", "");
		}
		response.setPan(tag);

		int lengthpan = tag.length();
		int astrisk = lengthpan - 10;
		String asteriskString = "";

		for (int i = 0; i < astrisk; i++) {
			asteriskString += "*";
		}

		Globals.cardNo = tag.substring(0, 6) + asteriskString
				+ tag.substring(lengthpan - 4, lengthpan);

		byte[] pan = pinpad.emvGetDataAsBinary(EMVTags.TAG_PAN); // // The pan

		emvCardData.setPan(tag);
		tag = readTagAsString(pinpad, EMVTags.TAG_PAN_SEQUENCE_NUMBER);
		throwOnEMVError(pinpad);
		Log.i("EMVPROCESSOR", "  TAG_PAN_SEQUENCE_NUMBER: " + tag + "\n");
		emvCardData.setCardSequenceNo(tag);
		tag = readTagAsString(pinpad, EMVTags.TAG_TRACK2_EQUIVALENT_DATA);
		throwOnEMVError(pinpad);
		Log.i("EMVPROCESSOR", "  TAG_TRACK2_EQUIVALENT_DATA: " + tag + "\n");
		emvCardData.setTrack2(tag);
		track = tag;
		if (track.charAt(track.length() - 1) == 'F') {
			track = track.replace("F", "");
		}
		byte[] tmp = pinpad.msGetMaskedCardData(2, 4, 5);
		Log.i("EMVPROCESSOR", "  MASKED DATA: " + new String(tmp) + "\n");

		tag = pinpad.emvGetDataAsString(EMVTags.TAG_ISSUER_COUNTRY_CODE);
		throwOnEMVError(pinpad);
		Log.i("EMVPROCESSOR", "  TAG_ISSUER_COUNTRY_CODE: " + tag + "\n");

		tag = pinpad.emvGetDataAsString(EMVTags.TAG_APP_USAGE_CONTROL);
		throwOnEMVError(pinpad);
		Log.i("EMVPROCESSOR", "  TAG_APP_USAGE_CONTROL: " + tag + "\n");

		Log.i("EMVPROCESSOR", "� Set EMV tags\n");
		pinpad.emvSetDataAsString(EMVTags.TAG_TERM_ACTION_ONLINE, "DC4004F800");
		throwOnEMVError(pinpad);
		pinpad.emvSetDataAsString(EMVTags.TAG_TERM_ACTION_DENIAL, "0010000000");
		throwOnEMVError(pinpad);
		pinpad.emvSetDataAsString(EMVTags.TAG_TERM_ACTION_DEFAULT, "DC4000A800");
		throwOnEMVError(pinpad);
		pinpad.emvSetDataAsString(EMVTags.TAG_DEFAULT_DDOL, "9F3704");
		throwOnEMVError(pinpad);
		pinpad.emvSetDataAsString(EMVTags.TAG_DEFAULT_TDOL, "9F3704");
		throwOnEMVError(pinpad);
		pinpad.emvSetDataAsString(EMVTags.TAG_TRANSACTION_TYPE, "00");
		throwOnEMVError(pinpad);
		String transactionAmount = String.format("%012d",
				request.getMinorAmount());
		pinpad.emvSetDataAsString(EMVTags.TAG_AMOUNT_AUTHORISED_NUM,
				transactionAmount);
		throwOnEMVError(pinpad);
		String otherAmount = String.format("%012d", request.getOtherAmount());
		pinpad.emvSetDataAsString(EMVTags.TAG_AMOUNT_OTHER_NUM, otherAmount);
		throwOnEMVError(pinpad);
		pinpad.emvSetDataAsString(EMVTags.TAG_TRANSACTION_CURR_CODE, "0566");
		throwOnEMVError(pinpad);

		Log.i("EMVPROCESSOR", "� Authentication\n");
		pinpad.emvAuthentication(false);

		Log.i("EMVPROCESSOR", "� Process restrictions\n");
		pinpad.emvProcessRestrictions();
		throwOnEMVError(pinpad);

		Log.i("EMVPROCESSOR", "� Set EMV tags\n");
		pinpad.emvSetDataAsString(EMVTags.TAG_RISK_AMOUNT, "00000000");
		throwOnEMVError(pinpad);
		pinpad.emvSetDataAsString(EMVTags.TAG_FLOOR_LIMIT_CURRENCY, "0566");
		throwOnEMVError(pinpad);
		pinpad.emvSetDataAsString(EMVTags.TAG_TERMINAL_FLOOR_LIMIT, "00000000");
		throwOnEMVError(pinpad);
		pinpad.emvSetDataAsString(EMVTags.TAG_THRESHOLD_VALUE, "00000000");
		throwOnEMVError(pinpad);
		pinpad.emvSetDataAsString(EMVTags.TAG_TARGET_PERCENTAGE, "20");
		throwOnEMVError(pinpad);
		pinpad.emvSetDataAsString(EMVTags.TAG_MAX_TARGET_PERCENTAGE, "80");
		throwOnEMVError(pinpad);

		Log.i("EMVPROCESSOR", "� Terminal risk\n");
		pinpad.emvTerminalRisk(false);
		throwOnEMVError(pinpad);

		tag = pinpad.emvGetDataAsString(EMVTags.TAG_TVR);
		throwOnEMVError(pinpad);
		Log.i("EMVPROCESSOR", "  TAG_TVR: " + tag + "\n");
		response.setTvr(tag);
		completed = false;

		do {
			try{
			Log.i("EMVPROCESSOR", "� Get authentication method\n");
			pinpad.emvGetAuthenticationMethod();
			emvStatus = pinpad.emvGetLastStatus();

			if (emvStatus == EMVStatusCodes.EMV_AUTH_COMPLETED) {
				Log.i("EMVPROCESSOR", "  EMV Status: AUTH COMPLETED\n");
				completed = true;
			} else {
				int authResult = -1;

				if (emvStatus == EMVStatusCodes.EMV_ONLINE_PIN) {
					Log.i("EMVPROCESSOR", "  EMV Status: ONLINE PIN\n");

					String myamount = "";

					if (_0200type.equals(_0200Type.purchase)) {

						myamount = ReferenceList.amount;
					} else if (_0200type.equals(_0200Type.cashback)) {

						myamount = ReferenceList.totalCashbackAmount;
					} else if (_0200type.equals(_0200Type.cashadvance)) {

						myamount = ReferenceList.amount;
					} else if (_0200type.equals(_0200Type.balance)) {

						myamount = ReferenceList.amount;
					} else if (_0200type.equals(_0200Type.refund)) {

						myamount = ReferenceList.amount;
					} else if (_0200type.equals(_0200Type.repower)) {

						myamount = ReferenceList.amount;
					}
					Log.i("EMVPROCESSOR", "� Enter PIN\n");

					Globals.state = "payment";
					JSONObject objP = new JSONObject();
					objP.put("operation",Globals.state);
					objP.put("status","enterPin");

					PluginResult pr = new PluginResult(PluginResult.Status.OK, objP);
					pr.setKeepCallback(true);
					PaypadFacade.callbackContext.sendPluginResult(pr);

					PinpadHelper.enterPin(pinpad, myamount);
					PinpadHelper.showBusy(pinpad);

					try {

						byte pinBlock[] = pinpad.uiVerifyPINOnline(Pinpad.MKSK,
								Pinpad.ISO0, pinKey,
								PayPadManager.KEY_PIN_INDEX_OTHER, pan);

						String pinBlockHex = HexUtil.byteArrayToHexString(
								pinBlock).replace(" ", "");

						Log.i("EMVPROCESSOR", "  ENCRTYPTED PIN: "
								+ pinBlockHex + "\n");
						response.setPinData(pinBlockHex);
					} catch (Exception e) {
						Log.i("PAYPADSDK", e.getMessage());
					}

					// Here you need to perform online PIN processing
					authResult = Pinpad.EMV_AUTH_RESULT_SUCCESS;
				} else if (emvStatus == EMVStatusCodes.EMV_OFFLINE_PIN_CIPHERED
						|| emvStatus == EMVStatusCodes.EMV_OFFLINE_PIN_PLAIN) {
					Log.i("EMVPROCESSOR",
							"  EMV Status: OFFLINE PIN (CIPHERED/PLAIN)\n");

					try {
						Log.i("EMVPROCESSOR", "� Enter PIN");

						String myamount = "";

						if (_0200type.equals(_0200Type.purchase)) {

							myamount = ReferenceList.amount;
						} else if (_0200type.equals(_0200Type.cashback)) {

							myamount = ReferenceList.totalCashbackAmount;
						} else if (_0200type.equals(_0200Type.cashadvance)) {

							myamount = ReferenceList.amount;
						} else if (_0200type.equals(_0200Type.balance)) {

							myamount = ReferenceList.amount;
						} else if (_0200type.equals(_0200Type.refund)) {

							myamount = ReferenceList.amount;
						} else if (_0200type.equals(_0200Type.repower)) {

							myamount = ReferenceList.amount;
						}

						Globals.state = "payment";
						JSONObject objP = new JSONObject();
						objP.put("operation",Globals.state);
						objP.put("status","enterPin");

						PluginResult pr = new PluginResult(PluginResult.Status.OK, objP);
						pr.setKeepCallback(true);
						PaypadFacade.callbackContext.sendPluginResult(pr);

						// PaypadFacade.callbackContext.sendPluginResult(
						// 	new PluginResult(PluginResult.Status.OK, objP));

						PinpadHelper.enterPin(pinpad, myamount);
						PinpadHelper.showBusy(pinpad);

					} catch (PinpadException e) {
						int err = e.getErrorCode();

						if (err == Pinpad.ERROR_NO_DATA) {
							// If the empty pin entry is permit
							authResult = Pinpad.EMV_AUTH_FAIL_PIN_ENTRY_NOT_DONE;
						} else {
							authResult = Pinpad.EMV_AUTH_RESULT_FAILURE;
						}
					}

					if (authResult == -1) {
						Log.i("EMVPROCESSOR", "� Verify PIN offline");
						pinpad.emvVerifyPinOffline();
						emvStatus = pinpad.emvGetLastStatus();
						if (emvStatus == EMVStatusCodes.EMV_SUCCESS) {
							authResult = Pinpad.EMV_AUTH_RESULT_SUCCESS;
							PinpadHelper.validPIN(pinpad);
						} else {
							authResult = Pinpad.EMV_AUTH_RESULT_FAILURE;
							PinpadHelper.invalidPIN(pinpad);
							// PinpadHelper.invalidPINRetry(pinpad,
							// ReferenceList.amount);
						}
					}
				}// end else

				Log.i("EMVPROCESSOR", "� Set authentication result: "
						+ authResult + "\n");
				pinpad.emvSetAuthenticationResult(authResult);
				throwOnEMVError(pinpad);
			}
		}catch(JSONException e){
			PaypadFacade.callbackContext.sendPluginResult(
						new PluginResult(PluginResult.Status.ERROR, ""+e.getMessage()));
		}
		} while (!completed);

       try{
			Globals.state = "payment";
			JSONObject objP = new JSONObject();
			objP.put("operation",Globals.state);
			objP.put("status","processing");

			PluginResult pr = new PluginResult(PluginResult.Status.OK, objP);
			pr.setKeepCallback(true);
			PaypadFacade.callbackContext.sendPluginResult(pr);

			// PaypadFacade.callbackContext.sendPluginResult(
			// 				new PluginResult(PluginResult.Status.OK, objP));
		}catch(JSONException ex){
			PaypadFacade.callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.ERROR, ""+ex.getMessage()));
		}


		/* Start progress dialog */
//		Intent v1 = new Intent();
//		v1.setAction("com.firstpad");
//		v1.putExtra("response", "stopBusyStartProcessing");
//		ScreenSlidePagerActivity.appContext.sendBroadcast(v1);

		Log.i("EMVPROCESSOR", "� Read EMV tag\n");
		tag = pinpad.emvGetDataAsString(EMVTags.TAG_CH_VERIF_METHOD_RESULT);
		throwOnEMVError(pinpad);
		Log.i("EMVPROCESSOR", "  TAG_CH_VERIF_METHOD_RESULT: " + tag + "\n");

		tag = pinpad.emvGetDataAsString(EMVTags.TAG_TVR);
		throwOnEMVError(pinpad);
		Log.i("EMVPROCESSOR", "  TAG_TVR: " + tag + "\n");
		response.setTvr(tag);

		// /////////////////////////////////////////////////////////////////////
		// APPLICATION TRANSACTION DECISION
		// /////////////////////////////////////////////////////////////////////
		// If card is into hot list
		// pinpad.emvUpdateTVR(...); throwOnEMVError(pinpad);
		Log.i("EMVPROCESSOR", "� Make transaction decision\n");
		pinpad.emvMakeTransactionDecision();
		emvStatus = pinpad.emvGetLastStatus();

		int reqCertificate = 0;
		switch (emvStatus) {
		case EMVStatusCodes.EMV_TRANSACTION_APPROVED: {
			Log.i("EMVPROCESSOR", "  EMV Status: TRANSACTION APPROVED\n");

			final boolean OFFLINE_POSIBLE = true;
			if (OFFLINE_POSIBLE) {
				pinpad.emvSetDataAsString(EMVTags.TAG_AUTH_RESP_CODE, "Y1");
				throwOnEMVError(pinpad);
				reqCertificate = Pinpad.EMV_CERTIFICATE_TC;
			} else {
				reqCertificate = Pinpad.EMV_CERTIFICATE_ARQC;
			}
			break;
		}
		case EMVStatusCodes.EMV_TRANSACTION_DENIED: {
			Log.i("EMVPROCESSOR", "  EMV Status: TRANSACTION DENIED\n");
			pinpad.emvSetDataAsString(EMVTags.TAG_AUTH_RESP_CODE, "Z1");
			throwOnEMVError(pinpad);
			reqCertificate = Pinpad.EMV_CERTIFICATE_AAC;
			break;
		}
		case EMVStatusCodes.EMV_TRANSACTION_ONLINE: {
			Log.i("EMVPROCESSOR", "  EMV Status: TRANSACTION ONLINE\n");
			reqCertificate = Pinpad.EMV_CERTIFICATE_ARQC;
			break;
		}
		default: {
			throwOnEMVError(pinpad);
		}
		}

		Log.i("EMVPROCESSOR", "� Generate certificate (CDOL 1)\n");
		pinpad.emvGenerateCertificate(reqCertificate, Pinpad.EMV_RISK_CDOL_1);
		throwOnEMVError(pinpad);

		tag = pinpad.emvGetDataAsString(EMVTags.TAG_CRYPT_INFO_DATA);
		throwOnEMVError(pinpad);
		Log.i("EMVPROCESSOR", "  TAG_CRYPT_INFO_DATA: " + tag + "\n");
		int cryptogramInfo = Integer.parseInt(tag, 16);

		tag = pinpad.emvGetDataAsString(EMVTags.TAG_ATC);
		throwOnEMVError(pinpad);
		Log.i("EMVPROCESSOR", "  TAG_ATC: " + tag + "\n");
		tag = pinpad.emvGetDataAsString(EMVTags.TAG_APP_CRYPTOGRAM);
		throwOnEMVError(pinpad);
		Log.i("EMVPROCESSOR", "  TAG_APP_CRYPTOGRAM: " + tag + "\n");
		tag = pinpad.emvGetDataAsString(EMVTags.TAG_ISSUER_APP_DAT);
		throwOnEMVError(pinpad);
		Log.i("EMVPROCESSOR", "  TAG_ISSUER_APP_DAT: " + tag + "\n");
		tag = pinpad.emvGetDataAsString(EMVTags.TAG_TVR);
		throwOnEMVError(pinpad);
		Log.i("EMVPROCESSOR", "  TAG_TVR: " + tag + "\n");
		tag = pinpad.emvGetDataAsString(EMVTags.TAG_TSI);
		throwOnEMVError(pinpad);
		Log.i("EMVPROCESSOR", "  TAG_TSI: " + tag + "\n");
		tag = pinpad.emvGetDataAsString(EMVTags.TAG_ISSUER_APP_DAT);
		Log.i("EMVPROCESSOR", "  TAG_IAD: " + tag + "\n");

		Log.i("EMVPROCESSOR", "� Read EMV tag\n");

		tag = pinpad.emvGetDataAsString(EMVTags.TAG_CH_VERIF_METHOD_RESULT);
		throwOnEMVError(pinpad);
		Log.i("EMVPROCESSOR", "  TAG_CH_VERIF_METHOD_RESULT: " + tag + "\n");
		response.setCvmResult(tag);

		tag = pinpad.emvGetDataAsString(EMVTags.TAG_TVR);
		throwOnEMVError(pinpad);
		Log.i("EMVPROCESSOR", "  TAG_TVR: " + tag + "\n");
		response.setTvr(tag);

		tag = pinpad.emvGetDataAsString(EMVTags.TAG_APP_CRYPTOGRAM);
		throwOnEMVError(pinpad);
		Log.i("EMVPROCESSOR", "  TAG_APP_CRYPTOGRAM: " + tag + "\n");
		response.setCryptogram(tag);

		tag = pinpad.emvGetDataAsString(EMVTags.TAG_CRYPT_INFO_DATA);
		throwOnEMVError(pinpad);
		Log.i("EMVPROCESSOR", "  TAG_CRYPT_INFO_DATA: " + tag + "\n");
		response.setCryptogramInformationData(tag);

		tag = pinpad.emvGetDataAsString(EMVTags.TAG_ATC);
		throwOnEMVError(pinpad);
		Log.i("EMVPROCESSOR", "  TAG_ATC: " + tag + "\n");
		response.setAtc(tag);

		tag = pinpad.emvGetDataAsString(EMVTags.TAG_AIP);
		throwOnEMVError(pinpad);
		Log.i("EMVPROCESSOR", "  TAG_AIP: " + tag + "\n");
		response.setAip(tag);

		tag = pinpad.emvGetDataAsString(EMVTags.TAG_UNPREDICTABLE_NUMBER);
		throwOnEMVError(pinpad);
		Log.i("EMVPROCESSOR", "  TAG_UNPREDICTABLE_NUMBER: " + tag + "\n");
		response.setUnpredictableNo(tag);

		tag = pinpad.emvGetDataAsString(EMVTags.TAG_AMOUNT_AUTHORISED_NUM);
		throwOnEMVError(pinpad);
		Log.i("EMVPROCESSOR", "  TAG_AMOUNT_AUTHORISED_NUM: " + tag + "\n");
		response.setAmountAuthorized(tag);

		tag = pinpad.emvGetDataAsString(EMVTags.TAG_AMOUNT_OTHER_NUM);
		throwOnEMVError(pinpad);
		Log.i("EMVPROCESSOR", "  TAG_AMOUNT_OTHER_NUM: " + tag + "\n");
		response.setAmountOther(tag);

		tag = pinpad.emvGetDataAsString(EMVTags.TAG_APP_VERSION_NUMBER);
		throwOnEMVError(pinpad);
		Log.i("EMVPROCESSOR", "  TAG_APP_VERSION_NUMBER: " + tag + "\n");
		response.setAppVersionName(tag);

		tag = pinpad.emvGetDataAsString(EMVTags.TAG_PAN_SEQUENCE_NUMBER);
		sequenceNo = tag;
		throwOnEMVError(pinpad);
		Log.i("EMVPROCESSOR", "  TAG_PAN_SEQUENCE_NUMBER: " + tag + "\n");
		response.setPanSequenceNo(tag);

		tag = pinpad.emvGetDataAsString(EMVTags.TAG_TRANSACTION_DATE);
		throwOnEMVError(pinpad);
		Log.i("EMVPROCESSOR", "  TAG_TRANSACTION_DATE: " + tag + "\n");
		response.setTransDate(tag);

		tag = pinpad.emvGetDataAsString(EMVTags.TAG_TSI);
		throwOnEMVError(pinpad);
		Log.i("EMVPROCESSOR", "TAG_TSI: " + tag + "\n");
		response.setTsi(tag);

		tag = pinpad.emvGetDataAsString(EMVTags.TAG_TRANSACTION_TYPE);
		throwOnEMVError(pinpad);
		Log.i("EMVPROCESSOR", "TAG_TRANSACTION_TYPE: " + tag + "\n");
		response.setTransactionType(tag);

		tag = pinpad.emvGetDataAsString(EMVTags.TAG_TERMINAL_CAPABILITIES);
		throwOnEMVError(pinpad);
		Log.i("EMVPROCESSOR", "TAG_TERMINAL_CAPABILITIES: " + tag + "\n");
		response.setTerminalCapabilities(tag);

		tag = pinpad.emvGetDataAsString(EMVTags.TAG_TERMINAL_TYPE);
		throwOnEMVError(pinpad);
		Log.i("EMVPROCESSOR", "TAG_TERMINAL_TYPE: " + tag + "\n");
		response.setTerminalType(tag);

		tag = pinpad.emvGetDataAsString(EMVTags.TAG_TERMINAL_COUNTRY_CODE);
		throwOnEMVError(pinpad);
		Log.i("EMVPROCESSOR", "TAG_TERMINAL_COUNTRY_CODE: " + tag + "\n");
		response.setTerminalCountryCode(tag);

		tag = pinpad.emvGetDataAsString(EMVTags.TAG_TRANSACTION_CURR_CODE);
		throwOnEMVError(pinpad);
		Log.i("EMVPROCESSOR", "TAG_TRANSACTION_CURR_CODE: " + tag + "\n");
		response.setTransactionCurrencyCode(tag);

		tag = pinpad.emvGetDataAsString(EMVTags.TAG_TRANSACTION_CATEGORY_CODE);
		throwOnEMVError(pinpad);
		Log.i("EMVPROCESSOR", "TAG_TRANSACTION_CATEGORY_CODE: " + tag + "\n");
		response.setTransactionCategoryCode(tag);

		tag = pinpad.emvGetDataAsString(EMVTags.TAG_ISSUER_APP_DAT);
		throwOnEMVError(pinpad);
		Log.i("EMVPROCESSOR", "  TAG_IAD: " + tag + "\n");
		response.setIad(tag);

		tag = pinpad.emvGetDataAsString(EMVTags.TAG_CDOL_1);
		throwOnEMVError(pinpad);
		Log.i("EMVPROCESSOR", "  TAG_CDOL: " + tag + "\n");

		tag = pinpad.emvGetDataAsString(EMVTags.TAG_APP_LABEL);
		throwOnEMVError(pinpad);
		Log.i("EMVPROCESSOR", "TAG_APP_LABEL: " + tag + "\n");
		emvCardData.setAppLabel(tag);
		Globals.tenderType = tag;

		tag = pinpad.emvGetDataAsString(EMVTags.TAG_SERIAL_NUMBER);
		throwOnEMVError(pinpad);
		Log.i("EMVPROCESSOR", "TAG_SERIAL_NUMBER: " + tag + "\n");

		tag = pinpad.emvGetDataAsString(EMVTags.TAG_EXPIRY_DATE);
		throwOnEMVError(pinpad);
		Log.i("EMVPROCESSOR", "TAG_EXPIRY_DATE: " + tag + "\n");
		emvCardData.setCardExpiryDate(tag);

		tag = pinpad.emvGetDataAsString(EMVTags.TAG_CARDHOLDER_NAME);
		throwOnEMVError(pinpad);
		Log.i("EMVPROCESSOR", "TAG_CARDHOLDER_NAME: " + tag + "\n");
		emvCardData.setCardHolderName(tag);
		Globals.cardholder = tag;

		String aid = pinpad.emvGetDataAsString(0x4F);
		Log.i("EMVPROCESSOR", "aid is " + aid);
		Globals.aid = aid;

		emvCardData.setAid(aid);
		response.setCardData(emvCardData);

		// Check cryptogram information data after certificate generation.
		switch ((cryptogramInfo >> 6)) {
		case Pinpad.EMV_CERTIFICATE_AAC: {
			throw new TransactionDeniedException(
					"Transaction is denied by kernel");
		}
		case Pinpad.EMV_CERTIFICATE_TC: {
			if (reqCertificate < Pinpad.EMV_CERTIFICATE_TC) {
				throw new TransactionDeniedException(
						"Transaction is denied (AC requested < TC)");
			} else {
				Log.i("EMVPROCESSOR", "  Transaction is offline authorized\n");
			}
			break;
		}
		case Pinpad.EMV_CERTIFICATE_ARQC: {
			if (reqCertificate < Pinpad.EMV_CERTIFICATE_ARQC) {
				throw new TransactionDeniedException(
						"Transaction is denied (AC requested < ARQC)");
			} else {
				// Online processing
				processEMVOnlineTransaction(pinpad, response, request);
			}
			break;
		}
		default: {
			throw new TransactionAbortedException("Invalid certificate data");
		}
		}
	}

	private void throwOnEMVError(Pinpad pinpad) throws InterruptedException {
		int status = pinpad.emvGetLastStatus();
		if (status != EMVStatusCodes.EMV_SUCCESS) {
			throw new InterruptedException("EMV Error: "
					+ emvStatusToString(status));
		}

	}

	public String packICCDataJpos(EmvResponse response) {

		String iccdata = "";
		String temp = "";

		temp = response.getCryptogram();
		iccdata += String.format("9F26%02x%s", temp.length() / 2, temp);

		temp = response.getCryptogramInformationData();
		iccdata += String.format("9F27%02x%s", temp.length() / 2, temp);

		temp = response.getIad();
		iccdata += String.format("9F10%02x%s", temp.length() / 2, temp);

		temp = response.getUnpredictableNo();
		iccdata += String.format("9F37%02x%s", temp.length() / 2, temp);

		temp = response.getAtc();
		iccdata += String.format("9F36%02x%s", temp.length() / 2, temp);

		temp = response.getTvr();
		iccdata += String.format("95%02x%s", temp.length() / 2, temp);

		temp = response.getTransDate();
		iccdata += String.format("9A%02x%s", temp.length() / 2, temp);

		temp = response.getTransactionType();
		iccdata += String.format("9C%02x%s", temp.length() / 2, temp);

		Long amountLong = Long.parseLong(response.getAmountAuthorized());
		temp = String.format("%012d", amountLong);
		iccdata += String.format("9F02%02x%s", temp.length() / 2, temp);

		temp = response.getAip();
		iccdata += String.format("82%02x%s", temp.length() / 2, temp);

		temp = response.getTerminalCountryCode().length() == 3 ? "0"
				+ response.getTerminalCountryCode() : response
				.getTerminalCountryCode();
		iccdata += String.format("9F1A%02x%s", temp.length() / 2, temp);

		temp = response.getTransactionCurrencyCode().length() == 3 ? "0"
				+ response.getTransactionCurrencyCode() : response
				.getTransactionCurrencyCode();
		iccdata += String.format("5F2A%02x%s", temp.length() / 2, temp);

		temp = response.getCvmResult();
		iccdata += String.format("9F34%02x%s", temp.length() / 2, temp);

		temp = response.getTerminalCapabilities();
		iccdata += String.format("9F33%02x%s", temp.length() / 2, temp);

		temp = response.getTerminalType();
		iccdata += String.format("9F35%02x%s", temp.length() / 2, temp);

		Long otherAmountLong = Long.parseLong(response.getAmountOther());
		temp = String.format("%012d", otherAmountLong);
		iccdata += String.format("9F03%02x%s", temp.length() / 2, temp);

		return iccdata;
	}

	private void processEMVOnlineTransaction(Pinpad pinpad,
			EmvResponse response, EmvRequest request) throws PinpadException,
			IOException, TransactionException, InterruptedException {
		Log.i("EMVPROCESSOR", "� Process online\n");

		int emvStatus = 0;
		int emvReqCer = 0;
		String tag = null;

		// Database date
		Calendar date = Calendar.getInstance();
		Date transdate = date.getTime();
		Format formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
		dbDate = formatter.format(transdate);
		Globals.transDate = dbDate;

		// TODO: Build & transmit online request to issuer
		String pan = response.getPan();

		if (pan.charAt(pan.length() - 1) == 'F') {
			pan = pan.replaceAll("F", "");
		}

		String purchaseProcessingCode = "00" + Globals.AccountTypeFrom + "00";
		String cashbackProcessingCode = "09" + Globals.AccountTypeFrom + "00";
		String cashadvanceProcessingCode = "01" + Globals.AccountTypeFrom
				+ "00";
		String balanceProcessingCode = "31" + Globals.AccountTypeFrom + "00";
		String refundProcessingCode = "20" + Globals.AccountTypeFrom + "00";
		String repowerProcessingCode = "default";

		String transactionAmount = String.format("%012d",
				request.getMinorAmount());

		stan = String.valueOf(Globals.stanVas);
		int stanlenght = stan.length();
		int stanpadding = 0;
		if (stanlenght < 6) {

			stanpadding = 6 - stanlenght;

			for (int i = 0; i < stanpadding; i++) {
				stan = "0" + stan;
			}
		}

		// PaypadFacade.showStaticToast("stan "+stan);
		Globals.stanVas = Globals.stanVas + 1;

		SimpleDateFormat format = new SimpleDateFormat("hhmmss");
		String localTransactionTime = format.format(transdate);
		int day = Calendar.getInstance().get(Calendar.DAY_OF_MONTH);
		int month = Calendar.getInstance().get(Calendar.MONTH) + 1;
		String stringDay = String.valueOf(day);
		String stringMonth = String.valueOf(month);
		if (stringDay.length() == 1) {
			stringDay = "0" + stringDay;
		}

		if (stringMonth.length() == 1) {
			stringMonth = "0" + stringMonth;
		}
		String localTransactionDate = stringMonth + stringDay;
		String transmissionDateTime = localTransactionDate
				+ localTransactionTime;

		String cardExpirationDate = "";
		if (response.getCardData().getCardExpiryDate().length() == 4) {

			cardExpirationDate = response.getCardData().getCardExpiryDate();

		} else {

			cardExpirationDate = response.getCardData().getCardExpiryDate()
					.substring(0, 4).trim();

		}
		Globals.cardExpiry = cardExpirationDate;

		String merchantType = ReferenceList.config.getString(
				ReferenceList.merchantType, "none");
		String posEntryMode = "051";
		String cardSequenceNumber = null;
		cardSequenceNumber = response.getCardData().getCardSequenceNo();
		if (cardSequenceNumber.length() == 2) {
			cardSequenceNumber = "0" + cardSequenceNumber;
		}
		String posConditionCode = "00";
		String posPinCaptureCode = "04";
		String transactionFee = "C00000000";
		String acquiringInstIdCode = "111129";
		String retrievalReferenceNumber = String.valueOf(Globals.rrnVas);

		int len = retrievalReferenceNumber.length();
		int pad = 0;
		if (len < 12) {

			pad = 12 - len;

			for (int i = 0; i < pad; i++) {
				retrievalReferenceNumber = "0" + retrievalReferenceNumber;
			}
		}

		Globals.rrnVas = Globals.rrnVas + 1;

		// PaypadFacade.showStaticToast("rrn "+retrievalReferenceNumber);

		String terminalId = "";
		String cardAcceptorIdCode = "";
		String cardAcceptorNameLocation = "";
		String currencyCode = "566";

		String pinData = null;
		if (response.getPinData() != null) {
			pinData = response.getPinData();
		}

		String iccData = "";

		String posDataCode = "511101512344101";

		String track2Data = track;

		String getSRC = "";
		int index = 0;
		if (track2Data.contains("D")) {
			index = track2Data.indexOf('D');
		} else if (track2Data.contains("=")) {
			index = track2Data.indexOf('=');
		}
		getSRC = track2Data.substring(index + 1, index + 8);
		String serviceRestrictionCode = getSRC.substring(4);

		String securityRelatedInformation = "";
		String additionalAmounts = String.format("%012d",
				ReferenceList.otherAmount);
		String messageReasonCode = "";

		/* Data used for Reversal in case of timeout */
		String originaldataelements = String.format("%s%s%s%s%s", "0200", stan,
				transmissionDateTime, "00000111129", "00000000000");

		String replacementAmounts = String.format("%s%s%s%s",
				transactionAmount, transactionAmount, "C00000000", "C00000000");
		String transportData = "000000000000";
		String paymentInformation = "";
		String secondaryHashValue = "";

		String iccData2 = packICCDataJpos(response);

		terminalId = Globals.merchantTerminalIDVas;
		Globals.terminalIDVas = terminalId;
		cardAcceptorIdCode = Globals.acceptorIDVas;
		cardAcceptorNameLocation = Globals.acceptorNameVas;
		// Globals.RRN = retrievalReferenceNumber;
		// Globals.amount1 = ReferenceList.amount;

		PurchaseRequest purchaseRequest = null;
		CashBackRequest cashbackRequest = null;
		CashAdvanceRequest cashadvanceRequest = null;
		BalanceRequest balanceRequest = null;
		RefundRequest refundRequest = null;
		RePowerRequest repowerRequest = null;

		if (_0200type.equals(_0200Type.purchase)) {

			Globals.cashback = "0.00";
			Globals.cashadvance = "0.00";
			Globals.purchase = ReferenceList.amount;
			Globals.total = ReferenceList.amount;

			purchaseRequest = new PurchaseRequest();
			purchaseRequest.setPan(pan);
			purchaseRequest.setProcessingCode(purchaseProcessingCode);
			purchaseRequest.setTransactionAmount(transactionAmount);
			purchaseRequest.setTransmissionDateTime(transmissionDateTime);
			purchaseRequest.setStan(stan);
			purchaseRequest.setLocalTransactionDate(localTransactionDate);
			purchaseRequest.setLocalTransactionTime(localTransactionTime);
			purchaseRequest.setCardExpirationDate(cardExpirationDate);
			purchaseRequest.setMerchantType(merchantType);
			purchaseRequest.setPosEntryMode(posEntryMode);
			purchaseRequest.setCardSequenceNumber(cardSequenceNumber);
			purchaseRequest.setPosConditionCode(posConditionCode);
			purchaseRequest.setPosPinCaptureCode(posPinCaptureCode);
			purchaseRequest.setTransactionFee(transactionFee);
			purchaseRequest.setAcquiringInstIdCode(acquiringInstIdCode);
			purchaseRequest.setTrack2Data(track2Data);
			purchaseRequest
					.setRetrievalReferenceNumber(retrievalReferenceNumber);
			purchaseRequest.setTerminalId(terminalId);
			purchaseRequest.setCardAcceptorIdCode(cardAcceptorIdCode);
			purchaseRequest
					.setCardAcceptorNameLocation(cardAcceptorNameLocation);
			purchaseRequest.setCurrencyCode(currencyCode);
			purchaseRequest.setPinData(pinData);
			purchaseRequest.setIccData(iccData2.replace(" ", ""));
			purchaseRequest.setPosDataCode(posDataCode);
			purchaseRequest.setServiceRestrictionCode(serviceRestrictionCode);
			purchaseRequest
					.setSecurityRelatedInformation(securityRelatedInformation);
			purchaseRequest.setAdditionalAmounts(additionalAmounts);
			purchaseRequest.setMessageReasonCode(messageReasonCode);
			purchaseRequest.setTransportData(transportData);
			purchaseRequest.setPaymentInformation(paymentInformation);
			purchaseRequest.setOriginalDataElements(originaldataelements); // set for reversal purposes


			// This connects to the switch to do the key processing

			// PaypadFacade.showStaticToast("sessionKey "+sessionKey);

			Globals._0200RequestVas = purchaseRequest;

			NibssIsoProcessorVas.process(
						purchaseRequest, sessionKey);

			try{

				JSONObject jsonObject = new JSONObject();
				jsonObject.put("operation","payment");
	            jsonObject.put("pan",Globals.cardNo);
	            jsonObject.put("cardholder",Globals.cardholder);
	            jsonObject.put("stan",Globals.stanVas);
	            jsonObject.put("rrn", Globals.rrnVas);
	            jsonObject.put("auth",Globals.authCode);
	            jsonObject.put("expiry",Globals.cardExpiry);
	            jsonObject.put("responsecode",Globals.responseCode);
	            jsonObject.put("responsemessage",Globals.appResponse);
	            jsonObject.put("aid",CAID);
	            jsonObject.put("sequenceno",sequenceNo);
	            jsonObject.put("accounttype",Globals.AccountTypeFromString);


				 if(Globals.responseCode != null){
				 	PaypadFacade.callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.OK, jsonObject));
				 }

			}catch(Exception ex){
				PaypadFacade.callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.ERROR, ""+ex.getMessage()));
			}

		} else if (_0200type.equals(_0200Type.cashback)) {

			Globals.cashback = ReferenceList.cashbackAmount;
			Globals.purchase = ReferenceList.totalCashbackAmount;
			Globals.total = ReferenceList.totalCashbackAmount;
			Globals.cashadvance = "0.00";

			cashbackRequest = new CashBackRequest();
			cashbackRequest.setPan(pan);
			cashbackRequest.setProcessingCode(cashbackProcessingCode);
			cashbackRequest.setTransactionAmount(transactionAmount);
			cashbackRequest.setTransmissionDateTime(transmissionDateTime);
			cashbackRequest.setStan(stan);
			cashbackRequest.setLocalTransactionDate(localTransactionDate);
			cashbackRequest.setLocalTransactionTime(localTransactionTime);
			cashbackRequest.setCardExpirationDate(cardExpirationDate);
			cashbackRequest.setMerchantType(merchantType);
			cashbackRequest.setPosEntryMode(posEntryMode);
			cashbackRequest.setCardSequenceNumber(cardSequenceNumber);
			cashbackRequest.setPosConditionCode(posConditionCode);
			cashbackRequest.setPosPinCaptureCode(posPinCaptureCode);
			cashbackRequest.setTransactionFee(transactionFee);
			cashbackRequest.setAcquiringInstIdCode(acquiringInstIdCode);
			cashbackRequest.setTrack2Data(track2Data);
			cashbackRequest
					.setRetrievalReferenceNumber(retrievalReferenceNumber);
			cashbackRequest.setTerminalId(terminalId);
			cashbackRequest.setCardAcceptorIdCode(cardAcceptorIdCode);
			cashbackRequest
					.setCardAcceptorNameLocation(cardAcceptorNameLocation);
			cashbackRequest.setCurrencyCode(currencyCode);
			cashbackRequest.setPinData(pinData);
			cashbackRequest.setIccData(iccData2.replace(" ", ""));
			cashbackRequest.setPosDataCode(posDataCode);
			cashbackRequest.setServiceRestrictionCode(serviceRestrictionCode);
			cashbackRequest
					.setSecurityRelatedInformation(securityRelatedInformation);
			cashbackRequest.setAdditionalAmounts(additionalAmounts);
			cashbackRequest.setMessageReasonCode(messageReasonCode);
			cashbackRequest.setTransportData(transportData);
			cashbackRequest.setPaymentInformation(paymentInformation);
			cashbackRequest.setOriginalDataElements(originaldataelements); // set
																			// for
																			// reversal
																			// purposes

		} else if (_0200type.equals(_0200Type.cashadvance)) {

			Globals.cashadvance = ReferenceList.cashadvanceAmount;
			Globals.purchase = "0.00";
			Globals.total = ReferenceList.cashadvanceAmount;
			Globals.cashback = "0.00";

			cashadvanceRequest = new CashAdvanceRequest();
			cashadvanceRequest.setPan(pan);
			cashadvanceRequest.setProcessingCode(cashadvanceProcessingCode);
			cashadvanceRequest.setTransactionAmount(transactionAmount);
			cashadvanceRequest.setTransmissionDateTime(transmissionDateTime);
			cashadvanceRequest.setStan(stan);
			cashadvanceRequest.setLocalTransactionDate(localTransactionDate);
			cashadvanceRequest.setLocalTransactionTime(localTransactionTime);
			cashadvanceRequest.setCardExpirationDate(cardExpirationDate);
			cashadvanceRequest.setMerchantType(merchantType);
			cashadvanceRequest.setPosEntryMode(posEntryMode);
			cashadvanceRequest.setCardSequenceNumber(cardSequenceNumber);
			cashadvanceRequest.setPosConditionCode(posConditionCode);
			cashadvanceRequest.setPosPinCaptureCode(posPinCaptureCode);
			cashadvanceRequest.setTransactionFee(transactionFee);
			cashadvanceRequest.setAcquiringInstIdCode(acquiringInstIdCode);
			cashadvanceRequest.setTrack2Data(track2Data);
			cashadvanceRequest
					.setRetrievalReferenceNumber(retrievalReferenceNumber);
			cashadvanceRequest.setTerminalId(terminalId);
			cashadvanceRequest.setCardAcceptorIdCode(cardAcceptorIdCode);
			cashadvanceRequest
					.setCardAcceptorNameLocation(cardAcceptorNameLocation);
			cashadvanceRequest.setCurrencyCode(currencyCode);
			cashadvanceRequest.setPinData(pinData);
			cashadvanceRequest.setIccData(iccData2.replace(" ", ""));
			cashadvanceRequest.setPosDataCode(posDataCode);
			cashadvanceRequest
					.setServiceRestrictionCode(serviceRestrictionCode);
			cashadvanceRequest
					.setSecurityRelatedInformation(securityRelatedInformation);
			cashadvanceRequest.setAdditionalAmounts(additionalAmounts);
			cashadvanceRequest.setMessageReasonCode(messageReasonCode);
			cashadvanceRequest.setTransportData(transportData);
			cashadvanceRequest.setPaymentInformation(paymentInformation);
			cashadvanceRequest.setOriginalDataElements(originaldataelements); // set// for// reversal // purposes

		} else if (_0200type.equals(_0200Type.balance)) {

			Globals.cashadvance = "0.00";
			Globals.purchase = "0.00";
			Globals.total = "0.00";
			Globals.cashback = "0.00";

			balanceRequest = new BalanceRequest();
			balanceRequest.setPan(pan);
			balanceRequest.setProcessingCode(balanceProcessingCode);
			balanceRequest.setTransactionAmount(transactionAmount);
			balanceRequest.setTransmissionDateTime(transmissionDateTime);
			balanceRequest.setStan(stan);
			balanceRequest.setLocalTransactionDate(localTransactionDate);
			balanceRequest.setLocalTransactionTime(localTransactionTime);
			balanceRequest.setCardExpirationDate(cardExpirationDate);
			balanceRequest.setMerchantType(merchantType);
			balanceRequest.setPosEntryMode(posEntryMode);
			balanceRequest.setCardSequenceNumber(cardSequenceNumber);
			balanceRequest.setPosConditionCode(posConditionCode);
			balanceRequest.setPosPinCaptureCode(posPinCaptureCode);
			balanceRequest.setTransactionFee(transactionFee);
			balanceRequest.setAcquiringInstIdCode(acquiringInstIdCode);
			balanceRequest.setTrack2Data(track2Data);
			balanceRequest
					.setRetrievalReferenceNumber(retrievalReferenceNumber);
			balanceRequest.setTerminalId(terminalId);
			balanceRequest.setCardAcceptorIdCode(cardAcceptorIdCode);
			balanceRequest
					.setCardAcceptorNameLocation(cardAcceptorNameLocation);
			balanceRequest.setCurrencyCode(currencyCode);
			balanceRequest.setPinData(pinData);
			balanceRequest.setIccData(iccData2.replace(" ", ""));
			balanceRequest.setPosDataCode(posDataCode);
			balanceRequest.setServiceRestrictionCode(serviceRestrictionCode);
			balanceRequest
					.setSecurityRelatedInformation(securityRelatedInformation);
			balanceRequest.setAdditionalAmounts(additionalAmounts);
			balanceRequest.setMessageReasonCode(messageReasonCode);
			balanceRequest.setTransportData(transportData);
			balanceRequest.setPaymentInformation(paymentInformation);
			balanceRequest.setOriginalDataElements(originaldataelements); // set
																			// for
																			// reversal
																			// purposes

		} else if (_0200type.equals(_0200Type.refund)) {

			Globals.cashadvance = "0.00";
			Globals.purchase = ReferenceList.amount;
			Globals.total = ReferenceList.amount;
			Globals.cashback = "0.00";

			refundRequest = new RefundRequest();
			refundRequest.setPan(pan);
			refundRequest.setProcessingCode(refundProcessingCode);
			refundRequest.setTransactionAmount(transactionAmount);
			refundRequest.setTransmissionDateTime(transmissionDateTime);
			refundRequest.setStan(stan);
			refundRequest.setLocalTransactionDate(localTransactionDate);
			refundRequest.setLocalTransactionTime(localTransactionTime);
			refundRequest.setCardExpirationDate(cardExpirationDate);
			refundRequest.setMerchantType(merchantType);
			refundRequest.setPosEntryMode(posEntryMode);
			refundRequest.setCardSequenceNumber(cardSequenceNumber);
			refundRequest.setPosConditionCode(posConditionCode);
			refundRequest.setPosPinCaptureCode(posPinCaptureCode);
			refundRequest.setTransactionFee(transactionFee);
			refundRequest.setAcquiringInstIdCode(acquiringInstIdCode);
			refundRequest.setTrack2Data(track2Data);
			refundRequest.setRetrievalReferenceNumber(retrievalReferenceNumber);
			refundRequest.setTerminalId(terminalId);
			refundRequest.setCardAcceptorIdCode(cardAcceptorIdCode);
			refundRequest.setCardAcceptorNameLocation(cardAcceptorNameLocation);
			refundRequest.setCurrencyCode(currencyCode);
			refundRequest.setPinData(pinData);
			refundRequest.setIccData(iccData2.replace(" ", ""));
			refundRequest.setPosDataCode(posDataCode);
			refundRequest.setServiceRestrictionCode(serviceRestrictionCode);
			refundRequest
					.setSecurityRelatedInformation(securityRelatedInformation);
			refundRequest.setAdditionalAmounts(additionalAmounts);
			refundRequest.setMessageReasonCode(messageReasonCode);
			refundRequest.setTransportData(transportData);
			refundRequest.setPaymentInformation(paymentInformation);
			refundRequest.setOriginalDataElements(originaldataelements); // set
																			// for
																			// reversal
																			// purposes
			refundRequest.setReplacementAmount(replacementAmounts);
		} else if (_0200type.equals(_0200Type.repower)) {

			Globals.cashback = "0.00";
			Globals.cashadvance = "0.00";
			Globals.purchase = ReferenceList.amount;
			Globals.total = ReferenceList.amount;

			repowerRequest = new RePowerRequest();
			repowerRequest.setPan(pan);
			repowerRequest.setProcessingCode(purchaseProcessingCode);
			repowerRequest.setTransactionAmount(transactionAmount);
			repowerRequest.setTransmissionDateTime(transmissionDateTime);
			repowerRequest.setStan(stan);
			repowerRequest.setLocalTransactionDate(localTransactionDate);
			repowerRequest.setLocalTransactionTime(localTransactionTime);
			repowerRequest.setCardExpirationDate(cardExpirationDate);
			repowerRequest.setMerchantType(merchantType);
			repowerRequest.setPosEntryMode(posEntryMode);
			repowerRequest.setCardSequenceNumber(cardSequenceNumber);
			repowerRequest.setPosConditionCode(posConditionCode);
			repowerRequest.setPosPinCaptureCode(posPinCaptureCode);
			repowerRequest.setTransactionFee(transactionFee);
			repowerRequest.setAcquiringInstIdCode(acquiringInstIdCode);
			repowerRequest.setTrack2Data(track2Data);
			repowerRequest
					.setRetrievalReferenceNumber(retrievalReferenceNumber);
			repowerRequest.setTerminalId(terminalId);
			repowerRequest.setCardAcceptorIdCode(cardAcceptorIdCode);
			repowerRequest
					.setCardAcceptorNameLocation(cardAcceptorNameLocation);
			repowerRequest.setCurrencyCode(currencyCode);
			repowerRequest.setPinData(pinData);
			repowerRequest.setIccData(iccData2.replace(" ", ""));
			repowerRequest.setPosDataCode(posDataCode);
			repowerRequest.setServiceRestrictionCode(serviceRestrictionCode);
			repowerRequest
					.setSecurityRelatedInformation(securityRelatedInformation);
			repowerRequest.setAdditionalAmounts(additionalAmounts);
			repowerRequest.setMessageReasonCode(messageReasonCode);
			repowerRequest.setTransportData(transportData);
			repowerRequest.setPaymentInformation(paymentInformation);
			repowerRequest.setOriginalDataElements(originaldataelements);
		}

		if (COMMUNICATION_FAILURE) {
			Log.i("EMVPROCESSOR", "  Connection failed\n");

			if (OFFLINE_PROCESSING) {
				Log.i("EMVPROCESSOR", "� Make default decision\n");
				pinpad.emvMakeDefaultDecision();
				emvStatus = pinpad.emvGetLastStatus();
				switch (emvStatus) {
				case EMVStatusCodes.EMV_TRANSACTION_APPROVED: {
					pinpad.emvSetDataAsString(EMVTags.TAG_AUTH_RESP_CODE, "Y3");
					throwOnEMVError(pinpad);
					break;
				}
				case EMVStatusCodes.EMV_TRANSACTION_DENIED: {
					pinpad.emvSetDataAsString(EMVTags.TAG_AUTH_RESP_CODE, "Z3");
					throwOnEMVError(pinpad);
					break;
				}
				default: {
					throwOnEMVError(pinpad);
				}
				}
			} else {
				pinpad.emvSetDataAsString(EMVTags.TAG_AUTH_RESP_CODE, "Z3");
				throwOnEMVError(pinpad);
				emvStatus = EMVStatusCodes.EMV_TRANSACTION_DENIED;
			}
		} else {

			// Issuer authentication data is received.
			if (Globals.authData != null) {
				pinpad.emvSetDataAsBinary(EMVTags.TAG_ISSUER_AUTH_DAT,
						HexUtil.hexStringToByteArray(Globals.authData));
				throwOnEMVError(pinpad);
				pinpad.emvAuthenticateIssuer();
				throwOnEMVError(pinpad);
				Globals.authData = null;
			}

			// Script 71 is received
			if (Globals.script71 != null) {
				pinpad.emvSetDataAsBinary(EMVTags.TAG_ISSUER_SCRIPTS,
						HexUtil.hexStringToByteArray(Globals.script71));
				throwOnEMVError(pinpad);
				pinpad.emvScriptProcessing(0x71);
				Globals.script71 = null;
			}

			emvStatus = EMVStatusCodes.EMV_TRANSACTION_APPROVED;
		}

		switch (emvStatus) {
		case EMVStatusCodes.EMV_TRANSACTION_APPROVED: {
			Log.i("EMVPROCESSOR", "� Generate TC certificate (CDOL 2)\n");
			pinpad.emvGenerateCertificate(Pinpad.EMV_CERTIFICATE_TC,
					Pinpad.EMV_RISK_CDOL_2);
			throwOnEMVError(pinpad);
			emvReqCer = Pinpad.EMV_CERTIFICATE_TC;
			break;
		}
		case EMVStatusCodes.EMV_TRANSACTION_DENIED: {
			Log.i("EMVPROCESSOR", "� Generate AAC certificate (CDOL 2)\n");
			pinpad.emvGenerateCertificate(Pinpad.EMV_CERTIFICATE_AAC,
					Pinpad.EMV_RISK_CDOL_2);
			throwOnEMVError(pinpad);
			emvReqCer = Pinpad.EMV_CERTIFICATE_AAC;
			break;
		}
		default: {
			throwOnEMVError(pinpad);
		}
		}

		if (Globals.script72 != null) {
			pinpad.emvSetDataAsBinary(EMVTags.TAG_ISSUER_SCRIPTS,
					HexUtil.hexStringToByteArray(Globals.script72));
			throwOnEMVError(pinpad);
			pinpad.emvScriptProcessing(0x72);
			Globals.script72 = null;
		}

		switch (pinpad.emvGetLastStatus()) {
		case EMVStatusCodes.EMV_SUCCESS:
			break;
		case EMVStatusCodes.EMV_ABORT_TRANSACTION:
		case EMVStatusCodes.EMV_ERROR_AC_PROCESS:
			throw new TransactionAbortedException(
					emvStatusToString(pinpad.emvGetLastStatus()));
		case EMVStatusCodes.EMV_CDA_FAILED:
			throw new TransactionDeniedException(
					emvStatusToString(pinpad.emvGetLastStatus()));
		default:
			throwOnEMVError(pinpad);
		}

		tag = pinpad.emvGetDataAsString(EMVTags.TAG_CRYPT_INFO_DATA);
		throwOnEMVError(pinpad);
		Log.i("EMVPROCESSOR", "  TAG_CRYPT_INFO_DATA: " + tag + "\n");
		int cryptogramInfo = Integer.parseInt(tag, 16);

		tag = pinpad.emvGetDataAsString(EMVTags.TAG_ATC);
		throwOnEMVError(pinpad);
		Log.i("EMVPROCESSOR", "  TAG_ATC: " + tag + "\n");
		tag = pinpad.emvGetDataAsString(EMVTags.TAG_APP_CRYPTOGRAM);
		throwOnEMVError(pinpad);
		Log.i("EMVPROCESSOR", "  TAG_APP_CRYPTOGRAM: " + tag + "\n");
		tag = pinpad.emvGetDataAsString(EMVTags.TAG_ISSUER_APP_DAT);
		throwOnEMVError(pinpad);
		Log.i("EMVPROCESSOR", "  TAG_ISSUER_APP_DAT: " + tag + "\n");
		tag = pinpad.emvGetDataAsString(EMVTags.TAG_TVR);
		throwOnEMVError(pinpad);
		Log.i("EMVPROCESSOR", "  TAG_TVR: " + tag + "\n");
		tag = pinpad.emvGetDataAsString(EMVTags.TAG_TSI);
		throwOnEMVError(pinpad);
		Log.i("EMVPROCESSOR", "  TAG_TSI: " + tag + "\n");

	}

	private void processMagneticCardTransaction(Pinpad pinpad, byte[] cardData)
			throws PinpadException, IOException, InterruptedException,
			PinpadException, IOException, TransactionCanceledException,
			TransactionAbortedException {
		Log.i("EMVPROCESSOR", "� Process magnetic card\n");
		PinpadHelper.showBusy(pinpad);

		// Parse magnetic card information.
		StringBuffer[] tracks = new StringBuffer[] { new StringBuffer(),
				new StringBuffer(), new StringBuffer(), };

		for (int i = 0, j = -1; i < cardData.length; i++) {
			int value = cardData[i] & 0xff;

			switch (value) {
			case 0xF1:
				j = 0;
				continue;
			case 0xF2:
				j = 1;
				continue;
			case 0xF3:
				j = 2;
				continue;
			default: {
				if (j > -1) {
					tracks[j].append((char) value);
				}
			}
			}
		}

		Log.i("EMVPROCESSOR", "  (1)Track data: " + tracks[0].toString() + "\n");
		Log.i("EMVPROCESSOR", "  (2)Track data: " + tracks[1].toString() + "\n");
		Log.i("EMVPROCESSOR", "  (3)Track data: " + tracks[2].toString() + "\n");

		Log.i("EMVPROCESSOR", "� Enter PIN\n");
		PinpadHelper.enterPin(pinpad, "Pin");
		PinpadHelper.showBusy(pinpad);

		// Generate new DUKPT key, which stay active up to 3 minutes and will be
		// erased after method uiVerifyPINOnline is called.
		byte[] ksn = pinpad.dukptGenerateKeyOnline(0);
		Log.i("EMVPROCESSOR",
				"  DUKPT KSN: " + HexUtil.byteArrayToHexString(ksn) + "\n");

		byte pinBlock[] = pinpad.uiVerifyPINOnline(Pinpad.DUKPT, Pinpad.ISO1,
				"0000000000000000".getBytes() /*
											 * variant must be 16 bytes long
											 */, 0x00, null /*
															 * pan is not used
															 * with ISO1
															 */);
		Log.i("EMVPROCESSOR",
				"  ENCRTYPTED PIN: " + HexUtil.byteArrayToHexString(pinBlock)
						+ "\n");

	}

	private void processManualEntryTransaction(Pinpad pinpad)
			throws PinpadException, IOException, InterruptedException {

		/*
		 * String pan = PinpadHelper.enterPAN(pinpad, 60000);
		 * Log.i("EMVPROCESSOR","  Card Number: " + pan + "\n");
		 * 
		 * String exp = PinpadHelper.enterExpiryDate(pinpad, 60000);
		 * Log.i("EMVPROCESSOR","  Card Exp: " + exp + "\n");
		 */
	}

	private String readTagAsString(Pinpad pinpad, int tag)
			throws PinpadException, IOException, InterruptedException {
		byte[] ksn = pinpad.dukptGenerateKeyOnline(0);
		byte[] encData = pinpad.emvGetTags3DESCBC(0xFF, 0xAABBCCDD,
				new Tag(tag).getBytes());
		byte[] tagData = decryptData(encData, ksn);// decryptData(encData);
		if (tagData == null) {
			throw new InterruptedException("Failed to decrypt data");
		}
		return BerTlv.create(tagData).getValueAsHexString();
	}

	private static String emvStatusToString(int status) {
		switch (status) {
		case EMVStatusCodes.EMV_SUCCESS:
			return "Operation successful";
		case EMVStatusCodes.EMV_LIST_AVAILABLE:
			return "More than one matching applications found";
		case EMVStatusCodes.EMV_APPLICATION_AVAILABLE:
			return "Only one matching application found";
		case EMVStatusCodes.EMV_NO_COMMON_APPLICATION:
			return "No matching applications found";
		case EMVStatusCodes.EMV_EASY_ENTRY_APP:
			return "Easy Entry application";
		case EMVStatusCodes.EMV_AMOUNT_NEEDED:
			return "Amount is requested by the dynamic data authentication";
		case EMVStatusCodes.EMV_RESULT_NEEDED:
			return "Result needed";
		case EMVStatusCodes.EMV_AUTH_COMPLETED:
			return "Authentication is completed";
		case EMVStatusCodes.EMV_AUTH_NOT_DONE:
			return "Authentication was not performed";
		case EMVStatusCodes.EMV_OFFLINE_PIN_PLAIN:
			return "OFFLINE plain text pin is required";
		case EMVStatusCodes.EMV_ONLINE_PIN:
			return "ONLINE pin is required";
		case EMVStatusCodes.EMV_OFFLINE_PIN_CIPHERED:
			return "OFFLINE ciphered pin is required";
		case EMVStatusCodes.EMV_BLOCKED_APPLICATION:
			return "Explicit selection was done and blocked AIDs were found";
		case EMVStatusCodes.EMV_TRANSACTION_ONLINE:
			return "An online request should be done";
		case EMVStatusCodes.EMV_TRANSACTION_APPROVED:
			return "Transaction can be accepted offline";
		case EMVStatusCodes.EMV_TRANSACTION_DENIED:
			return "Transaction must be declined";
		case EMVStatusCodes.EMV_CDA_FAILED:
			return "CDA failed and the cryptogram got is not an AAC or the data handed for DDA was not found";
		case EMVStatusCodes.EMV_INVALID_PIN:
			return "Incorrect PIN";
		case EMVStatusCodes.EMV_INVALID_PIN_LAST_ATTEMPT:
			return "Incorrect PIN, last attempt available only";
		case EMVStatusCodes.EMV_FAILURE:
			return "Command failed, possibly due wrong input parameters - wrong ATR, bit values, etc";
		case EMVStatusCodes.EMV_NO_DATA_FOUND:
			return "Incoming data pointer is null or empty";
		case EMVStatusCodes.EMV_SYSTEM_ERROR:
			return "Internal system error occurred";
		case EMVStatusCodes.EMV_DATA_FORMAT_ERROR:
			return "Incorrect format found in the input parameters";
		case EMVStatusCodes.EMV_INVALID_ATR:
			return "Invalid ATR sequence, not according to specification";
		case EMVStatusCodes.EMV_ABORT_TRANSACTION:
			return "Severe error occurred transaction must be aborted";
		case EMVStatusCodes.EMV_APPLICATION_NOT_FOUND:
			return "AID not found in the card";
		case EMVStatusCodes.EMV_INVALID_APPLICATION:
			return "Application is not correct";
		case EMVStatusCodes.EMV_ERROR_IN_APPLICATION:
			return "Some error during read process";
		case EMVStatusCodes.EMV_CARD_BLOCKED:
			return "Status word got from the PSE selection indicates that the card is blocked";
		case EMVStatusCodes.EMV_NO_SCRIPT_LOADED:
			return "No script loaded";
		case EMVStatusCodes.EMV_TAG_NOT_FOUND:
			return "Tag not found";
		case EMVStatusCodes.EMV_INVALID_TAG:
			return "Tag cannot be read";
		case EMVStatusCodes.EMV_INVALID_LENGTH:
			return "Length of the buffer is incorrect";
		case EMVStatusCodes.EMV_INVALID_HASH:
			return "Error in the HASH verification";
		case EMVStatusCodes.EMV_INVALID_KEY:
			return "No key was found to do the verification";
		case EMVStatusCodes.EMV_NO_MORE_KEYS:
			return "No more available locations for keys";
		case EMVStatusCodes.EMV_ERROR_AC_PROCESS:
			return "Error processing the AC generation";
		case EMVStatusCodes.EMV_ERROR_AC_DENIED:
			return "Status word got from the card is 6985";
		case EMVStatusCodes.EMV_NO_CURRENT_METHOD:
			return "No method is currently applicable";
		case EMVStatusCodes.EMV_RESULT_ALREADY_LOADED:
			return "Result already loaded for the current method";
		case EMVStatusCodes.EMV_INVALID_REMAINDER:
			return "Invalid reminder";
		case EMVStatusCodes.EMV_INVALID_HEADER:
			return "Invalid header";
		case EMVStatusCodes.EMV_INVALID_FOOTER:
			return "Invalid footer";
		case EMVStatusCodes.EMV_INVALID_FORMAT:
			return "Invalid format";
		case EMVStatusCodes.EMV_INVALID_CERTIFICATE:
			return "Invalid certificate";
		case EMVStatusCodes.EMV_INVALID_SIGNATURE:
			return "Invalid signature";
		default:
			return "Unpecified status code " + status;
		}
	}

	private byte[] decode(String s) {
		return HexUtil.hexStringToByteArray(s, ' ');
	}

	private byte[] decryptData(byte[] data) {
		byte[] DATA_KEY = decode("B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF");
		byte[] decrypted = CryptoUtil.decrypt3DESCBC(DATA_KEY, new byte[8],
				data);
		if (decrypted.length < 12)
			return null;

		int length = (decrypted[8] & 0xff) + (decrypted[9] & 0xff);
		if (decrypted.length < (length + 12))
			return null;

		int origCrc = ((decrypted[10 + length] & 0xff) << 8)
				+ (decrypted[11 + length] & 0xff);
		int calcCrc = CryptoUtil.crcccitt16(0xFFFF, decrypted, 0, 10 + length);
		if (origCrc != calcCrc)
			return null;

		return Arrays.copyOfRange(decrypted, 10, 10 + length);
	}

	private byte[] decryptData(byte[] data, byte[] ksn) {
		// byte[] KEY_IPEK =
		// decode("A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF");

		// String bdk = "";
		byte[] KEY_IPEK = HexUtil.hexStringToByteArray(bdk);

		byte[] dataKey = CryptoUtil.calculateDataKey(ksn, KEY_IPEK);
		byte[] decrypted = CryptoUtil
				.decrypt3DESCBC(dataKey, new byte[8], data);
		if (decrypted.length < 12)
			return null;

		int length = (decrypted[8] & 0xff) + (decrypted[9] & 0xff);
		if (decrypted.length < (length + 12))
			return null;

		int origCrc = ((decrypted[10 + length] & 0xff) << 8)
				+ (decrypted[11 + length] & 0xff);
		int calcCrc = CryptoUtil.crcccitt16(0xFFFF, decrypted, 0, 10 + length);
		if (origCrc != calcCrc)
			return null;

		return Arrays.copyOfRange(decrypted, 10, 10 + length);
	}

	public static String iccDate() {

		String today = "";
		int day = Calendar.getInstance().get(Calendar.DAY_OF_MONTH);
		int month = Calendar.getInstance().get(Calendar.MONTH) + 1;
		int year = Calendar.getInstance().get(Calendar.YEAR);
		String stringDay = String.valueOf(day);
		String stringMonth = String.valueOf(month);
		String stringYear = String.valueOf(year);
		if (stringDay.length() == 1) {
			stringDay = "0" + stringDay;
		}

		if (stringMonth.length() == 1) {
			stringMonth = "0" + stringMonth;
		}
		stringYear = stringYear.substring(2);
		today = stringYear + stringMonth + stringDay;

		return today;
	}

	public static String iccTime() {

		String time = "";
		Calendar date = Calendar.getInstance();
		Date transdate = date.getTime();
		SimpleDateFormat format = new SimpleDateFormat("hhmmss");
		time = format.format(transdate);
		return time;
	}
}
