/**
	* process the payment and return the result
	* @param int $order_id
	* @return array
	*/
	public function process_payment($order_id) {
		global $woocommerce;

		$order = new WC_Order($order_id);
		$ccfields = $this->getCardFields();

		$isLiveSite = ($this->eway_sandbox != 'yes');

		if ($this->eway_stored == 'yes')
			$eway = new EwayPaymentsStoredPayment($this->eway_customerid, $isLiveSite);
		else
			$eway = new EwayPaymentsPayment($this->eway_customerid, $isLiveSite);

		$eway->invoiceDescription		= get_bloginfo('name');
		$eway->invoiceReference			= $order->get_order_number();						// customer invoice reference
		$eway->transactionNumber		= $order_id;										// transaction reference
		$eway->cardHoldersName			= $ccfields['eway_card_name'];
		$eway->cardNumber				= strtr($ccfields['eway_card_number'], array(' ' => '', '-' => ''));
		$eway->cardExpiryMonth			= $ccfields['eway_expiry_month'];
		$eway->cardExpiryYear			= $ccfields['eway_expiry_year'];
		$eway->cardVerificationNumber	= $ccfields['eway_cvn'];
		$eway->firstName				= $order->billing_first_name;
		$eway->lastName					= $order->billing_last_name;
		$eway->emailAddress				= $order->billing_email;
		$eway->postcode					= $order->billing_postcode;

		// for Beagle (free) security
		if ($this->eway_beagle == 'yes') {
			$eway->customerCountryCode = $order->billing_country;
		}

		// convert WooCommerce country code into country name
		$billing_country = $order->billing_country;
		if (isset($woocommerce->countries->countries[$billing_country])) {
			$billing_country = $woocommerce->countries->countries[$billing_country];
		}

		// aggregate street, city, state, country into a single string
		$parts = array (
			$order->billing_address_1,
			$order->billing_address_2,
			$order->billing_city,
			$order->billing_state,
			$billing_country,
		);
		$eway->address = implode(', ', array_filter($parts, 'strlen'));

		// use cardholder name for last name if no customer name entered
		if (empty($eway->firstName) && empty($eway->lastName)) {
			$eway->lastName				= $eway->cardHoldersName;
		}

		// allow plugins/themes to modify invoice description and reference, and set option fields
		$eway->invoiceDescription		= apply_filters('woocommerce_eway_invoice_desc', $eway->invoiceDescription, $order_id);
		$eway->invoiceReference			= apply_filters('woocommerce_eway_invoice_ref', $eway->invoiceReference, $order_id);
		$eway->option1					= apply_filters('woocommerce_eway_option1', '', $order_id);
		$eway->option2					= apply_filters('woocommerce_eway_option2', '', $order_id);
		$eway->option3					= apply_filters('woocommerce_eway_option3', '', $order_id);

		// if live, pass through amount exactly, but if using test site, round up to whole dollars or eWAY will fail
		$total = $order->order_total;
		$eway->amount					= $isLiveSite ? $total : ceil($total);

		try {
			$response = $eway->processPayment();

			if ($response->status) {
				// transaction was successful, so record details and complete payment
				update_post_meta($order_id, 'Transaction ID', $response->transactionNumber);
				if (!empty($response->authCode)) {
					update_post_meta($order_id, 'Authcode', $response->authCode);
				}
				if (!empty($response->beagleScore)) {
					update_post_meta($order_id, 'Beagle score', $response->beagleScore);
				}

				if ($this->eway_stored == 'yes') {
					// payment hasn't happened yet, so record status as 'on-hold' and reduce stock in anticipation
					$order->reduce_order_stock();
					$order->update_status('on-hold', 'Awaiting stored payment');
					unset($_SESSION['order_awaiting_payment']);
				}
				else {
					$order->payment_complete();
				}
				$woocommerce->cart->empty_cart();

				$result = array(
					'result' => 'success',
					'redirect' => $this->get_return_url($order),
				);
			}
			else {
				// transaction was unsuccessful, so record transaction number and the error
				$order->update_status('failed', nl2br(esc_html($response->error)));
				wc_add_notice(nl2br(esc_html($response->error)), 'error');
				$result = array('result' => 'failure');
			}
		}
		catch (EwayPaymentsException $e) {
			// an exception occured, so record the error
			$order->update_status('failed', nl2br(esc_html($e->getMessage())));
			wc_add_notice(nl2br(esc_html($e->getMessage())), 'error');
			$result = array('result' => 'failure');
		}

		return $result;
	}
	/**
	* process transaction against eWAY
	* @return $response
	*/
	public function processTransaction($transaction) {
		$isLiveSite = !get_awpcp_option('paylivetestmode');
		$eway_stored = get_awpcp_option('eway_stored');

		if (!$isLiveSite && get_awpcp_option('eway_test_force')) {
			$eway_customerid = EWAY_PAYMENTS_TEST_CUSTOMER;
		}
		else {
			$eway_customerid = get_awpcp_option('eway_customerid');
		}

		// TODO: add Beagle if new version supports taking country info before billing
		//~ $eway_beagle = get_awpcp_option('eway_beagle');

		$item = $transaction->get_item(0); // no support for multiple items
		$user = wp_get_current_user();

		if ($eway_stored) {
			$eway = new EwayPaymentsStoredPayment($eway_customerid, $isLiveSite);
		}
		else {
			$eway = new EwayPaymentsPayment($eway_customerid, $isLiveSite);
		}

		$eway->invoiceDescription			= $item->name;
		$eway->invoiceReference				= $transaction->id;									// customer invoice reference
		//~ $eway->transactionNumber		= $transaction->id;									// transaction reference
		$eway->cardHoldersName				= self::getPostValue('eway_card_name');
		$eway->cardNumber					= strtr(self::getPostValue('eway_card_number'), array(' ' => '', '-' => ''));
		$eway->cardExpiryMonth				= self::getPostValue('eway_expiry_month');
		$eway->cardExpiryYear				= self::getPostValue('eway_expiry_year');
		$eway->cardVerificationNumber		= self::getPostValue('eway_cvn');
		$eway->firstName					= $user ? $user->first_name : '';
		$eway->lastName						= $user ? $user->last_name : '';
		$eway->emailAddress					= $user ? $user->email : '';
		//~ $eway->postcode					= $order->billing_postcode;

		// TODO: add Beagle if new version supports taking country info before billing
		// for Beagle (free) security
		//~ if ($this->eway_beagle == 'yes') {
			//~ $eway->customerCountryCode = $order->billing_country;
		//~ }

		// aggregate street, city, state into a single string
		if ($user) {
			$profile = get_user_meta($user->ID, 'awpcp-profile', true);
			$parts = array (
				isset($profile['address']) ? $profile['address'] : '',
				isset($profile['city'])    ? $profile['city']    : '',
				isset($profile['state'])   ? $profile['state']   : '',
			);
			$eway->address = implode(', ', array_filter($parts, 'strlen'));
		}

		// use cardholder name for last name if no customer name available
		if (empty($eway->firstName) && empty($eway->lastName)) {
			$eway->lastName = $eway->cardHoldersName;
		}

		// allow plugins/themes to modify invoice description and reference, and set option fields
		$eway->invoiceDescription			= apply_filters('awpcp_eway_invoice_desc', $eway->invoiceDescription, $transaction);
		$eway->invoiceReference				= apply_filters('awpcp_eway_invoice_ref', $eway->invoiceReference, $transaction);
		$eway->option1						= apply_filters('awpcp_eway_option1', '', $transaction);
		$eway->option2						= apply_filters('awpcp_eway_option2', '', $transaction);
		$eway->option3						= apply_filters('awpcp_eway_option3', '', $transaction);

		// if live, pass through amount exactly, but if using test site, round up to whole dollars or eWAY will fail
		if (method_exists($transaction, 'get_totals')) {
			// AWPCP v3.0+
			$totals = $transaction->get_totals();
			$total = $totals['money'];
		}
		else {
			// AWPCP v < 3.0
			$total = $transaction->get('amount');
		}
		$eway->amount = $isLiveSite ? $total : ceil($total);

		$response = $eway->processPayment();

		return $response;
	}
	/**
	* submit to gateway
	*/
	public function submit() {
		global $wpdb;

		// check for missing or invalid values
		$errors = $this->validateData();

		// if there were errors, fail the transaction so that user can fix things up
		if ($errors) {
			$this->set_purchase_processed_by_purchid(1);	// failed
			//~ $this->go_to_transaction_results($this->cart_data['session_id']);
			return;
		}

		// get purchase logs
		if ($this->purchase_id > 0) {
			$purchase_logs = new WPSC_Purchase_Log($this->purchase_id);
		}
		elseif (!empty($this->session_id)) {
			$purchase_logs = new WPSC_Purchase_Log($this->session_id, 'sessionid');

			$this->purchase_id = $purchase_logs->get('id');
		}
		else {
			$this->set_error_message('No cart ID and no active session!');
			return;
		}

		// process the payment
		$isLiveSite = !get_option('eway_test');
		$useStored = get_option('wpsc_merchant_eway_stored');

		if ($useStored) {
			$eway = new EwayPaymentsStoredPayment(get_option('ewayCustomerID_id'), $isLiveSite);
		}
		else {
			$eway = new EwayPaymentsPayment(get_option('ewayCustomerID_id'), $isLiveSite);
		}

		$eway->invoiceDescription		= get_bloginfo('name');
		$eway->invoiceReference			= $this->purchase_id;								// customer invoice reference
		$eway->transactionNumber		= $this->purchase_id;								// transaction reference
		$eway->cardHoldersName			= $this->collected_gateway_data['card_name'];
		$eway->cardNumber				= $this->collected_gateway_data['card_number'];
		$eway->cardExpiryMonth			= $this->collected_gateway_data['expiry_month'];
		$eway->cardExpiryYear			= $this->collected_gateway_data['expiry_year'];
		$eway->cardVerificationNumber	= $this->collected_gateway_data['c_v_n'];
		$eway->firstName				= $this->collected_gateway_data['first_name'];
		$eway->lastName					= $this->collected_gateway_data['last_name'];
		$eway->emailAddress				= $this->collected_gateway_data['email'];
		$eway->postcode					= $this->collected_gateway_data['post_code'];

		// for Beagle (free) security
		if (get_option('wpsc_merchant_eway_beagle')) {
			$eway->customerCountryCode	= $this->collected_gateway_data['country'];
		}

		// convert wp-e-commerce country code into country name
		$country = $this->collected_gateway_data['country'] ? wpsc_get_country($this->collected_gateway_data['country']) : '';

		// aggregate street, city, state, country into a single string
		$parts = array (
			$this->collected_gateway_data['address'],
			$this->collected_gateway_data['city'],
			$this->collected_gateway_data['state'],
			$country,
		);
		$eway->address					= implode(', ', array_filter($parts, 'strlen'));

		// use cardholder name for last name if no customer name entered
		if (empty($eway->firstName) && empty($eway->lastName)) {
			$eway->lastName				= $eway->cardHoldersName;
		}

		// allow plugins/themes to modify invoice description and reference, and set option fields
		$eway->invoiceDescription		= apply_filters('wpsc_merchant_eway_invoice_desc', $eway->invoiceDescription, $this->purchase_id);
		$eway->invoiceReference			= apply_filters('wpsc_merchant_eway_invoice_ref', $eway->invoiceReference, $this->purchase_id);
		$eway->option1					= apply_filters('wpsc_merchant_eway_option1', '', $this->purchase_id);
		$eway->option2					= apply_filters('wpsc_merchant_eway_option2', '', $this->purchase_id);
		$eway->option3					= apply_filters('wpsc_merchant_eway_option3', '', $this->purchase_id);

		// if live, pass through amount exactly, but if using test site, round up to whole dollars or eWAY will fail
		$total = $purchase_logs->get('totalprice');
		$eway->amount					= $isLiveSite ? $total : ceil($total);

		try {
			$response = $eway->processPayment();

			if ($response->status) {
				// transaction was successful, so record transaction number and continue
				if ($useStored) {
					$status = 2; // WPSC_Purchase_Log::ORDER_RECEIVED
				}
				else {
					$status = 3; // WPSC_Purchase_Log::ACCEPTED_PAYMENT
				}
				$log_details = array(
					'processed'			=> $status,
					'transactid'		=> $response->transactionNumber,
					'authcode'			=> $response->authCode,
				);

				if (!empty($response->beagleScore)) {
					$log_details['notes'] = 'Beagle score: ' . $response->beagleScore;
				}

				wpsc_update_purchase_log_details($this->purchase_id, $log_details);

				$this->go_to_transaction_results($this->cart_data['session_id']);
			}
			else {
				// transaction was unsuccessful, so record transaction number and the error
				$status = 6; // WPSC_Purchase_Log::PAYMENT_DECLINED
				$this->set_error_message(nl2br(esc_html($response->error)));

				$log_details = array(
					'processed'			=> $status,
					'notes'				=> $response->error,
				);
				wpsc_update_purchase_log_details($this->purchase_id, $log_details);

				return;
			}
		}
		catch (EwayPaymentsException $e) {
			// an exception occured, so record the error
			$status = 1; // WPSC_Purchase_Log::INCOMPLETE_SALE
			$this->set_error_message(nl2br(esc_html($e->getMessage())));
			$this->set_purchase_processed_by_purchid($status);
			return;
		}

	 	exit();
	}
	/**
	* attempt to process payment
	* @param EM_Booking $EM_Booking
	* @return boolean
	*/
	public function processPayment($EM_Booking){
		// process the payment
		$isLiveSite = !(get_option('em_' . EM_EWAY_GATEWAY . '_mode') == 'sandbox');
		if (!$isLiveSite && get_option('em_' . EM_EWAY_GATEWAY . '_test_force')) {
			$customerID = EWAY_PAYMENTS_TEST_CUSTOMER;
		}
		else {
			$customerID = get_option('em_' . EM_EWAY_GATEWAY . '_cust_id');
		}

		if (get_option('em_' . EM_EWAY_GATEWAY . '_stored')) {
			$eway = new EwayPaymentsStoredPayment($customerID, $isLiveSite);
		}
		else {
			$eway = new EwayPaymentsPayment($customerID, $isLiveSite);
		}

		$eway->invoiceDescription			= $EM_Booking->get_event()->event_name;
		//~ $eway->invoiceDescription		= $EM_Booking->output('#_BOOKINGTICKETDESCRIPTION');
		$eway->invoiceReference				= $EM_Booking->booking_id;						// customer invoice reference
		$eway->transactionNumber			= $EM_Booking->booking_id;						// transaction reference
		$eway->cardHoldersName				= self::getPostValue('x_card_name');
		$eway->cardNumber					= strtr(self::getPostValue('x_card_num'), array(' ' => '', '-' => ''));
		$eway->cardExpiryMonth				= self::getPostValue('x_exp_date_month');
		$eway->cardExpiryYear				= self::getPostValue('x_exp_date_year');
		$eway->cardVerificationNumber		= self::getPostValue('x_card_code');
		$eway->emailAddress					= $EM_Booking->get_person()->user_email;
		$eway->postcode						= self::getPostValue('zip');

		// for Beagle (free) security
		if (get_option('em_' . EM_EWAY_GATEWAY . '_beagle')) {
			$eway->customerCountryCode		= EM_Gateways::get_customer_field('country', $EM_Booking);
		}

		// attempt to split name into parts, and hope to not offend anyone!
		$names = explode(' ', $EM_Booking->get_person()->get_name());
		if (!empty($names[0])) {
			$eway->firstName				= array_shift($names);		// remove first name from array
		}
		$eway->lastName						= trim(implode(' ', $names));

		// use cardholder name for last name if no customer name entered
		if (empty($eway->firstName) && empty($eway->lastName)) {
			$eway->lastName = $eway->cardHoldersName;
		}

		// aggregate street, city, state, country into a single string
		$parts = array (
			EM_Gateways::get_customer_field('address', $EM_Booking),
			EM_Gateways::get_customer_field('address_2', $EM_Booking),
			EM_Gateways::get_customer_field('city', $EM_Booking),
			EM_Gateways::get_customer_field('state', $EM_Booking),
			self::getCountryName(EM_Gateways::get_customer_field('country', $EM_Booking)),
		);
		$eway->address						= implode(', ', array_filter($parts, 'strlen'));

		// if live, pass through amount exactly, but if using test site, round up to whole dollars or eWAY will fail
		$amount = $EM_Booking->get_price(false, false, true);
		$amount = apply_filters('em_eway_amount', $amount, $EM_Booking);
		$eway->amount						= $isLiveSite ? $amount : ceil($amount);

		// allow plugins/themes to modify invoice description and reference, and set option fields
		$eway->invoiceDescription			= apply_filters('em_eway_invoice_desc', $eway->invoiceDescription, $EM_Booking);
		$eway->invoiceReference				= apply_filters('em_eway_invoice_ref', $eway->invoiceReference, $EM_Booking);
		$eway->option1						= apply_filters('em_eway_option1', '', $EM_Booking);
		$eway->option2						= apply_filters('em_eway_option2', '', $EM_Booking);
		$eway->option3						= apply_filters('em_eway_option3', '', $EM_Booking);

		// Get Payment
		try {
			$result = false;
			$response = $eway->processPayment();

			if ($response->status) {
				// transaction was successful, so record transaction number and continue
				$EM_Booking->booking_meta[EM_EWAY_GATEWAY] = array(
					'txn_id'	=> $response->transactionNumber,
					'authcode'	=> $response->authCode,
					'amount'	=> $response->amount,
				);

				$notes = array();
				if (!empty($response->authCode)) {
					$notes[] = 'Authcode: ' . $response->authCode;
				}
				if (!empty($response->beagleScore)) {
					$notes[] = 'Beagle score: ' . $response->beagleScore;
				}
				$note = implode("\n", $notes);

				$status = get_option('em_' . EM_EWAY_GATEWAY . '_stored') ? 'Pending' : 'Completed';
				$this->record_transaction($EM_Booking, $response->amount, 'AUD', date('Y-m-d H:i:s', current_time('timestamp')), $response->transactionNumber, $status, $note);
				$result = true;
			}
			else {
				// transaction was unsuccessful, so record the error
				$EM_Booking->add_error($response->error);
			}
		}
		catch (Exception $e) {
			// an exception occured, so record the error
			$EM_Booking->add_error($e->getMessage());
			return;
		}

		// Return status
		return apply_filters('em_gateway_eway_authorize', $result, $EM_Booking, $this);
	}