<?php
/**
 * This is the Gratify BNPL Payment Gateway class.
 */

if(!class_exists("WC_Gratify_Pay_Gateway")){
    class WC_Gratify_Pay_Gateway extends WC_Payment_Gateway{

        /**
         * Private variables.
         * @var     string  $include_path      Path to where this class's includes are located. Populated in the class constructor.
         * @var     array   $environments      Keyed array containing the name and API/web URLs for each environment. Populated in the
         *                                     class constructor by parsing values in "environments.ini"
         * @var     string  $token             The token to render on the preauth page.
         * @var     array   $assets            Static text content used for front end presentation based on currency/region.
         */
        private $include_path, $environments, $token, $assets;

        /**
         * Protected static variables.
         * 
         * @var     WC_Gratify_Pay_Gateway    $instance   A static reference to a singleton instance of this class.
         */
        protected static $instance = null;

        /**
		 * Public static variables.
		 *
		 * @var		WC_Logger		$log			An instance of the WC_Logger class.
		 */
		public static $log = false;

		
        /**
         * Class constuctor. Called when object is instantiated.
         * 
         * @since   1.0.0
         * @uses    plugin_basename()
         * @uses    WC_Payment_Gateway::init_settings() If the user has not yet saved their settings, it will extract the
		 *												default values from $this->form_fields defined in an ancestral class
		 *												and overridden below.
         */
        public function __construct(){
            $this->include_path                 = dirname(__FILE__). "/WC_Gratify_Pay_Gateway";
            $this->environments                 = include "{$this->include_path}/environments.php";
            $this->assets                       = include "{$this->include_path}/assets.php";

            $this->id                           = "gratify_pay";
            $this->has_fields                   = false;
            $this->description                  = __("Sell more with Gratify Buy Now Pay Later.", "gratify-pay");
            $this->method_title                 = __("Gratify BNPL", "gratify-pay");
            $this->method_description           = __("Sell more with Gratify Buy Now Pay Later.", "gratify-pay");
            $this->supports                     = array("products", "refunds");
			$this->configArray = array(
					'[AMOUNT]',
					'[GRATIFY_BADGE]',
					'[NUM_PAYMENTS]',
					'[PAYMENT_PERIOD]',
					'[MIN_LIMIT]',
					'[MAX_LIMIT]',
			);

    
            $this->init_form_fields();
			$this->init_settings();
			$this->refresh_cached_configuration();
            if ( ! $this->is_valid_for_use() ) {
				$this->enabled = 'no';
			}
        }
		

		private function get_gratify_order($orderId, $key){

			self::log("Getting order by order Id #{$orderId} FROM Gratify Pay...");
			

			$key = strval($key);
			
			//self::log("Gratify Data...");
			//self::log($data);
			if($this->settings['testmode'] == 'production'){
				$tokenPair = base64_encode($this->settings["prod-id"] . ":" . $this->settings["prod-secret-key"]);
			}
			else{
				$tokenPair = base64_encode($this->settings["test-id"] . ":" . $this->settings["test-secret-key"]);
			}
			
			$authToken = "Basic " . $tokenPair;
			self::log("GETTING token: {$authToken}");
			// use key 'http' even if you send the request to https://...
			$options = array(
				'http' => array(
					'method'  => 'GET',
					'header'=>  "Content-Type: application/json\r\n" . 
								"Authorization: " . $authToken . "\r\n" .
								"User-Agent: GratifyPlugin/WC/1.0.1\r\n"
					)
				);

			$url = $this->environments[$this->settings['testmode']]['api_url'] . "/merchant/confirm-order?orderId={$orderId}&merchantReference={$key}&storePlatform=WOOCOMMERCE&id={$this->settings['prod-id']}";
			self::log("GETTING url: {$url}");
			self::log($options);
			$context  = stream_context_create($options);
			$result = file_get_contents( $url, false, $context );
			$response = json_decode( $result, true );
			self::log("GETTING response: {$result}");
			self::log($response);
			if ($result === FALSE) { /* Handle error */ }

			return $response;  
		}

	/**
		 * This is triggered when customers confirm payment and return from the gateway
		 * Note:	Hooked onto the "woocommerce_api_wc_gateway_gratify-pay" action.
		 * @since	1.0.0
		 */
		
		public function capture_payment() {
			if (!empty($_GET) && !empty($_GET['orderId']) &&
				isset($_GET['status']) && $_GET['status'] == 0
				&& !empty($_GET['merchantReference'])
			) {
				$orderId = $_GET['orderId'];
				$key = intval($_GET['merchantReference']);
				$gratifyOrder = $this->get_gratify_order($orderId, $key);
				$order = wc_get_order($key);
				if ($order->get_meta('gratify_order_id') == $gratifyOrder['orderId']) {
					$order->add_order_note( sprintf(__( 'Payment approved. Gratify Pay Order ID: %s.', 'gratify-pay' ), $orderId) );
					$order->update_meta_data('gratify_order_status', 'SUCCESS');
					$order->save();
					$order->payment_complete();
					exit;
			}else{
				self::log("Updating status of WooCommerce Order #{$key} to \"Pending\". Please check Gratify Pay for more details.");
				$order->add_order_note(__('Gratify Pay payment pending. Please check Gratify Pay for more details.', 'gratify-pay'));
				wc_add_notice( __( 'Please confirm the order status with Gratify Pay.', 'gratify-pay' ), 'error' );
				// update order status accordingly
				wp_die();
			}
		}
		exit;
	}
        


        /**
		 * Initialise Gateway Settings Form Fields.
		 */
        public function init_form_fields(){
            $this->form_fields = include "{$this->include_path}/form_fields.php";
        }
        /**
		 * Refresh cached configuration. This method updates the properties of the class instance.
		 * Called from the constructor and after settings are saved. As an extension of WC_Payment_Gateway,
		 * `$this->settings` is automatically refreshed when settings are saved, but our custom properties
		 * are not.
		 *
		 * Note:	Hooked onto the "woocommerce_update_options_payment_gateways_gratify_pay" Action.
		 *
		 * @since	2.1.0
		 */
		public function refresh_cached_configuration() {
			if (array_key_exists('title', $this->settings)) {
				$this->title = $this->settings['title'];
			}
		}

        /**
		 * Logging method. Using this to log a string will store it in a file that is accessible
		 * from "WooCommerce > System Status > Logs" in the WordPress admin. No FTP access required.
		 *
		 * @param 	string	$message	The message to log.
		 * @uses	WC_Logger::add()
		 */
		public static function log($message) {
			if (empty(self::$log)) {
				self::$log = new WC_Logger;
			}
			if (is_array($message)) {
				/**
				 * @since 1.0.0
				 * Properly expand Arrays in logs.
				 */
				$message = print_r($message, true);
			} elseif(is_object($message)) {
				/**
				 * @since 1.0.0
				 * Properly expand Objects in logs.
				 *
				 * Only use the Output Buffer if it's not currently active,
				 * or if it's empty.
				 *
				 * Note:	If the Output Buffer is active but empty, we write to it,
				 * 			read from it, then discard the contents while leaving it active.
				 *
				 * Otherwise, if $message is an Object, it will be logged as, for example:
				 * (foo Object)
				 */
				$ob_get_length = ob_get_length();
				if (!$ob_get_length) {
					if ($ob_get_length === false) {
						ob_start();
					}
					var_dump($message);
					$message = ob_get_contents();
					if ($ob_get_length === false) {
						ob_end_clean();
					} else {
						ob_clean();
					}
				} else {
					$message = '(' . get_class($message) . ' Object)';
				}
			}
			self::$log->add( 'gratify_pay', $message );
			self::$log->add( 'gratify-pay', $message );
		}

        /**
         * Instantiate the class if no instance exists. Return the instance.
         * 
         * @since   1.0.0
         * @return  WC_Gratify_Pay_Gateway
         */
        public static function getInstance(){
            if(is_null(self::$instance)){
                self::$instance = new self;
            }
            return self::$instance;
        }


        /**
         * Check to see if the gateway is configured. 
         * This methods returns true if none of the credential fields are empty.
         * 
         * @since   1.0.0
         * @return  bool
         * @used-by self::render_admin_notices()
         */
        private function is_configured(){
            if (!empty($this->settings['prod-id']) ||
				!empty($this->settings['prod-secret-key']) ||
				!empty($this->settings['test-id']) ||
				!empty($this->settings['test-secret-key']))
			{
				return true;
			} else {
				return false;
			}
        }

        /**
         * Add the Gratify Pay gateway to Woocommerce.
         * 
         * Note: Hooked onto the "woocommerce_payment_gateway" Fitler.
         * 
         * @since   1.0.0
         * @see     GratifyPay_Plugin::__construct()    For hook attachment.
         * @param   array   $methods    Array of Paymennt gateways.
         * @return  array               Array of Payment gateways, with Gratify Pay added.
         */
        public function add_gratifypay_gateway($methods){
            $methods[] = "WC_Gratify_Pay_Gateway";
            return $methods;
        }
        
        /**
         * Check if the gateway is available for use.
		 * @used-by none
         * @return bool
         */
        
        public function is_available(){
			if(!$this->payment_is_enabled()){
				return false;
			}else{
				return $this->is_available_on_checkout();
			}
        }



        /**
         * Display Gratify Pay Assets on Normal products.
         * Note: Hooked onto the "woocommerce_get_price_html" filter.
         * 
         * @since   1.0.0
         * @see     GratifyPay::__construct()  for hook attachment.
         * @param   float   $price
         * @param   WC_Product  $product
         * @uses    self::print_info_for_listed_products()
         * @return  string
         */
        function filter_woocommerce_get_price_html($price, $product){
            if(is_object($product) && $product instanceof WC_Product_Variation){
                ob_start();
                $this->print_info_for_listed_products($product);
                $gratifypay_html = ob_get_clean();
                
                return $price . $gratifypay_html;
            }
            return $price;
        }

        /**
		 * The WC_Payment_Gateway::$icon property only accepts a string for the image URL. Since we want
		 * to support high pixel density screens and specifically define the width and height attributes,
		 * this method attaches to a Filter hook so we can build our own HTML markup for the IMG tag.
		 *
		 * Note:	Hooked onto the "woocommerce_gateway_icon" Filter.
		 *
		 * @since	1.0.0
		 * @see		GratifyPay_Plugin::__construct()	For hook attachment.
		 * @param	string 	$icon_html		Icon HTML
		 * @param	string 	$gateway_id		Payment Gateway ID
		 * @return	string
		 */
        
        public function get_logo_url(){
			// TODO: Move to https://app.gratifypay.com/gratify-logo.png
            $ctheme = strtolower($this->settings['colortheme']);
            return "https://assets.gratifypay.com/img/gratify-badge-{$ctheme}.svg";
        } 

		public function get_badge_url() {
			// TODO: Move to https://app.gratifypay.com/gratify-badge.svg
			$ctheme = strtolower($this->settings['colortheme']);
            return "https://assets.gratifypay.com/img/gratify-badge-{$ctheme}.svg";
		}

		public function get_checkout_url() {
			// TODO: Move to https://app.gratifypay.com/gratify-badge.svg
            return plugin_dir_url(dirname(__FILE__)) . 'assets/img/gratify-badge.svg';
		}


		public function get_splash_url() {
			// TODO: Return app content
			return plugin_dir_url(dirname(__FILE__)) . 'assets/img/gratify-splash.png';
		}

		public function filter_woocommerce_gateway_icon($icon_html, $gateway_id) {
			if ($gateway_id != 'gratify_pay') {
				return $icon_html;
			}

			$static_url = $this->get_static_url();
            $logo_url = $this->get_logo_url();

			ob_start();

			if(!$this->is_available_on_checkout()){
				?><img style="vertical-align:middle;display:inline;" src="<?php echo $this->get_checkout_url() ?>" width="35" height="20" alt="Gratify Pay" /><?php
			}else{
			// TODO: Move new logo to app.gratifypay.com
			?><img style="vertical-align:middle;display:inline;" src="<?php echo $this->get_checkout_url() ?>" width="35" height="20" alt="Gratify Pay" />
			<div id="gratifypay-banner-text">No interest. No ads. Full data protection.</div><?php
			}
			return ob_get_clean();
		}

        	/**
		 * Render admin notices if applicable. This will print an error on every page of the admin if the cron failed to
		 * authenticate on its last attempt.
		 *
		 * Note:	Hooked onto the "admin_notices" Action.
		 * Note:	This runs BEFORE WooCommerce fires its "woocommerce_update_options_payment_gateways_<gateway_id>" actions.
		 *
		 * @since	1.0.0
		 * @uses	get_transient()			Available in WordPress core since 2.8.0
		 * @uses	delete_transient()		Available in WordPress core since 2.8.0
		 * @uses	admin_url()				Available in WordPress core since 2.6.0
		 * @uses	delete_option()
		 * @uses	self::is_configured()
		 */
		public function render_admin_notices() {
			/**
			 * Also change the activation message to include a link to the plugin settings.
			 *
			 * Note:	We didn't add the "is-dismissible" class here because we continually show another
			 *			message similar to this until the API credentials are entered.
			 *
			 * @see		./wp-admin/plugins.php	For the markup that this replaces.
			 * @uses	get_transient()			Available in WordPress core since 2.8.0
			 * @uses	delete_transient()		Available in WordPress core since 2.8.0
			 */
			if (function_exists('get_transient') && function_exists('delete_transient')) {
				if (get_transient( 'gratify_pay-admin-activation-notice' )) {
					?>
					<div class="updated notice">
						<p><?php _e( 'Plugin <strong>activated</strong>.' ) ?></p>
						<p><?php _e( 'Thank you for choosing Gratify Pay.', 'gratify-pay' ); ?> <a href="<?php echo admin_url( 'admin.php?page=wc-settings&tab=checkout&section=gratify_pay' ); ?>"><?php _e( 'Configure Settings.', 'gratify-pay' ); ?></a></p>
						<p><?php _e( 'Don&rsquo;t have an Gratify Pay Merchant account yet?', 'gratify-pay' ); ?> <a href="<?php echo $this->assets['retailer_url'] ?>" target="_blank"><?php _e( 'Apply online today!', 'gratify-pay' ); ?></a></p>
					</div>
					<?php
					if (array_key_exists('activate', $_GET) && $_GET['activate'] == 'true') {
						unset($_GET['activate']); # Prevent the default "Plugin *activated*." notice.
					}
					delete_transient( 'gratify_pay-admin-activation-notice' );
					# No need to decide whether to render any API errors. We've only just activated the plugin.
					return;
				}
			}

			if (array_key_exists('woocommerce_gratify_pay_enabled', $_POST)) {
				# Since this runs before we handle the POST, we can clear any stored error here.
				delete_option( 'woocommerce_gratify_pay_api_error' );

				# If we're posting changes to the Gratify Pay settings, don't pull anything out of the database just yet.
				# This runs before the POST gets handled by WooCommerce, so we can wait until later.
				# If the updated settings fail, that will trigger its own error later.
				return;
			}

			$show_link = true;
			if (array_key_exists('page', $_GET) && array_key_exists('tab', $_GET) && array_key_exists('section', $_GET)) {
				if ($_GET['page'] == 'wc-settings' && $_GET['tab'] == 'checkout' && $_GET['section'] == 'gratify_pay') {
					# We're already on the Gratify Pay's gateway's settings page. No need for the circular link.
					$show_link = false;
				}
			}

			$error = get_option( 'woocommerce_gratify_pay_api_error' );
			if (is_object($error) && $this->settings['enabled'] == 'yes') {
				?>
				<div class="error notice">
					<p>
						<strong><?php _e( "Gratify Pay API Error #{$error->code}:", 'gratify-pay' ); ?></strong>
						<?php _e( $error->message, 'gratify-pay' ); ?>
						<?php if (property_exists($error, 'id') && $error->id): ?>
							<em><?php _e( "(Error ID: {$error->id})", 'gratify-pay' ); ?></em>
						<?php endif; ?>
						<?php if ($show_link): ?>
							<a href="<?php echo admin_url( 'admin.php?page=wc-settings&tab=checkout&section=gratify_pay' ); ?>"><?php _e( 'Please check your Gratify Pay Merchant settings here.', 'gratify-pay' ); ?></a>
						<?php endif; ?>
					</p>
				</div>
				<?php
				return;
			}

			# Also include a link to the plugin settings if they haven't been saved yet,
			# unless they have unchecked the Enabled checkbox in the settings.
			if (!$this->is_configured() && $this->settings['enabled'] == 'yes' && $show_link) {
				?>
				<div class="updated notice">
					<p><?php _e( 'Thank you for choosing Gratify Pay.', 'gratify-pay' ); ?> <a href="<?php echo admin_url( 'admin.php?page=wc-settings&tab=checkout&section=gratify_pay' ); ?>"><?php _e( 'Configure Settings.', 'gratify-pay' ); ?></a></p>
					<p><?php _e( 'Don&rsquo;t have an Gratify Pay Merchant account yet?', 'gratify-pay' ); ?> <a href="<?php echo $this->assets['retailer_url'] ?>" target="_blank"><?php _e( 'Apply online today!', 'gratify-pay' ); ?></a></p>
				</div>
				<?php
				return;
			}
			if(isset($this->settings['gratify_pay-plugin-version']) && $this->settings['gratify_pay-plugin-version'] != GratifyPay_Plugin::$version){
					?>
					<div class='updated notice'>
					<p>Gratify Pay Gateway for WooCommerce has updated from <?=$this->settings['gratify_pay-plugin-version']?> to <?=GratifyPay_Plugin::$version?>. Please review and re-save your settings <?php if ($show_link){ ?><a href="<?php echo admin_url( 'admin.php?page=wc-settings&tab=checkout&section=gratify_pay' ); ?>"><?php _e( 'here', 'gratify-pay' ); ?></a><?php } else { _e( 'below', 'gratify-pay' );} ?>.</p>
					</div>
					<?php
			}
			else if(!isset($this->settings['gratify_pay-plugin-version'])){
				?>
                	<div class="updated notice">
					<p><?php _e( 'Thank you for choosing Gratify Pay.', 'gratify-pay' ); ?> <a href="<?php echo admin_url( 'admin.php?page=wc-settings&tab=checkout&section=gratify_pay' ); ?>"><?php _e( 'Configure Settings.', 'gratify-pay' ); ?></a></p>
					<p><?php _e( 'Don&rsquo;t have an Gratify Pay Merchant account yet?', 'gratify-pay' ); ?> <a href="<?php echo $this->assets['retailer_url'] ?>" target="_blank"><?php _e( 'Apply online today!', 'gratify-pay' ); ?></a></p>
				</div>
				<?php
			}
		}

  /**
         * Admin Panel Options. Overrides the method defined in the parent class.
         * 
         * @since   1.0.0
         * @see     WC_Payment_Gateway::admin_options()			For the method that this overrides.
         * @uses	WC_Settings_API::generate_settings_html()
         */

        public function admin_options(){
			
            ?>	
	<link href="https://unpkg.com/tailwindcss@^2/dist/tailwind.min.css" rel="stylesheet">
		<div class="container">
			<div class="row">
				<div class="col-md-12">
					<img style="border:none;width: 180px; height: auto;" class="mt-5" src="https://assets.gratifypay.com/img/Gratify_Logo_tag.d58bb73b.svg" > 
				</div>
			</div>

                    <?php $this->generate_settings_html(); ?>
		</div>
            <?php
        }

		public function generate_settings_html( $form_fields = array(), $echo = true ) {
		if ( empty( $form_fields ) ) {
			$form_fields = $this->get_form_fields();
		}


		$html = '';
		foreach ( $form_fields as $k => $v ) {
			$type = $this->get_field_type( $v );
			$color = $this->settings['merchant-status'] == "CONNECTED" ? "green" : "red";
			$status = $this->settings['merchant-status'] == "CONNECTED" ? "Connected" : "Not Connected";
			switch($k){
				case "start":
					$html .= " <table class='form-table'>
							<div class='bg-white shadow overflow-hidden sm:rounded-lg mt-5'>
								<div class='px-4 py-5 sm:px-6 flex'>
								<div class='w-3/4'>
									<h3 class='text-lg leading-6 font-medium text-gray-900'>
									API Settings
									</h3>
									<p class='mt-1 max-w-2xl text-sm text-gray-500'>
									Enter your API credentials below.
									</p>
								</div>
  								<div class='w-1/4 h-50'>
									<div class='flex-auto flex space-x-2'>
										<button disabled class='disabled:opacity-100 cursor-default w-1/2 flex py-4 items-center justify-center rounded-md bg-{$color}-500 text-white statusBtn'>{$status}</button>
										<button class='w-1/2 flex py-4 items-center justify-center bg-gray-100 hover:bg-gray-300 rounded-md border border-gray-300 testConnectionBtn'>Test Connection</button>
									</div>  
								</div>
									
								</div>
								<div class='border-t border-gray-200'><dl>
								<input autocomplete='off' name='hidden' type='text' style='display:none;'>

								";
					break;
				case "first-end":
					$html .= ' </dl></div></div>';
					$html .= "  <div class='bg-white shadow overflow-hidden sm:rounded-lg mt-10'>
									<div class='px-4 py-5 sm:px-6 flex'>
										<div class='w-3/4'>
											<h3 class='text-lg leading-6 font-medium text-gray-900'>
											Customization Settings
											</h3>
											<p class='mt-1 max-w-2xl text-sm text-gray-500'>
											Customize the look of the Gratify Pay placements.
											</p>
										</div>
									<div class='w-1/4 h-50'>
										<div class='flex flex-row-reverse space-x-1'>
											<button class='w-1/2 flex py-4 items-center justify-center bg-gray-100 hover:bg-gray-300 rounded-md border border-gray-300 restoreDefBtn'>Restore Defaults</button>
										</div>  
									</div>
								</div>
								<div class='border-t border-gray-200'><dl>
								";
					break;
				case "second-end":
					$html .= ' </dl></div></div>';
					$html .= "  <div class='bg-white shadow overflow-hidden sm:rounded-lg mt-10'>
									<div class='px-4 py-5 sm:px-6 flex'>
										<div class='w-3/4'>
											<h3 class='text-lg leading-6 font-medium text-gray-900'>
											Security Settings
											</h3>
											<p class='mt-1 max-w-2xl text-sm text-gray-500'>
											Enter your http auth credentials if your webstore uses http auth.
											</p>
										</div>
								</div>
								<div class='border-t border-gray-200'><dl>
								";
					break;
				default:
					break;
			}
			
			if($type != "hidden"){
					if ( method_exists( $this, 'generate_' . $type . '_html' ) ) {
					$html .= $this->{'generate_' . $type . '_html'}( $k, $v );
				} else {
					$html .= $this->generate_text_html( $k, $v );
				}
			}
			$gratify_js_path = plugin_dir_url(dirname(__FILE__)) . 'assets/js/gratifypay-admin.js';
			switch($k){
				case "end":
					$html .= "</dl></div></div></table>";
					$html .= "<script src={$gratify_js_path}></script>";

					break;
				default:
					break;
			}
			
		}

		if ( $echo ) {
			echo $html; // WPCS: XSS ok.
		} else {
			return $html;
		}
	}	


		public function generate_checkbox_html( $key, $data ) {
			$field_key = $this->get_field_key( $key );
			$defaults  = array(
			'title'             => '',
			'label'             => '',
			'disabled'          => false,
			'class'             => '',
			'css'               => '',
			'type'              => 'text',
			'desc_tip'          => false,
			'description'       => '',
			'custom_attributes' => array(),
			);

			$data = wp_parse_args( $data, $defaults );

			if ( ! $data['label'] ) {
			$data['label'] = $data['title'];
			}

			if($key != 'enabled'){
					ob_start();
			?>				
				<div class="bg-gray-50 px-4 py-5 sm:grid sm:grid-cols-3 sm:gap-4 sm:px-6 wrapperbox">
					<dt class="text-sm font-medium text-gray-500">
					<?php echo wp_kses_post( $data['title'] ); ?>
					</dt>
					<dd class="mt-1 flex text-sm text-gray-900 sm:mt-0 sm:col-span-2">
						<div class="w-1/6">
					<input <?php disabled( $data['disabled'], true ); ?> class="<?php echo esc_attr( $data['class'] ); ?> form-checkbox" type="checkbox" name="<?php echo esc_attr( $field_key ); ?>" id="<?php echo esc_attr( $field_key ); ?>" style="<?php echo esc_attr( $data['css'] ); ?>" value="1" <?php checked( $this->get_option( $key ), 'yes' ); ?> <?php echo $this->get_custom_attribute_html( $data ); // WPCS: XSS ok. ?> /> <?php echo wp_kses_post( $data['label'] ); ?></label><br/>
					</div>
						<div class="w-4/6 <?=$key?>" ></div>
						<button class='w-1/6 flex py-2 mt-n10  items-center justify-center rounded-md border border-gray-300 edit-<?=$key?>'>Edit</button>
					</dd>
				</div>
							<?php

			return ob_get_clean();
			}
			ob_start();
			?>

      <div class="bg-gray-50 px-4 py-5 sm:grid sm:grid-cols-3 sm:gap-4 sm:px-6 wrapperbox">
        <dt class="text-sm font-medium text-gray-500">
         <?php echo wp_kses_post( $data['title'] ); ?>
        </dt>
        <dd class="mt-1 text-sm text-gray-900 sm:mt-0 sm:col-span-2">
         <input <?php disabled( $data['disabled'], true ); ?> class="<?php echo esc_attr( $data['class'] ); ?> form-checkbox" type="checkbox" name="<?php echo esc_attr( $field_key ); ?>" id="<?php echo esc_attr( $field_key ); ?>" style="<?php echo esc_attr( $data['css'] ); ?>" value="1" <?php checked( $this->get_option( $key ), 'yes' ); ?> <?php echo $this->get_custom_attribute_html( $data ); // WPCS: XSS ok. ?> /> <?php echo wp_kses_post( $data['label'] ); ?></label><br/>
        </dd>
      </div>
				<?php

			return ob_get_clean();
		}


			public function generate_checkboxprev_html( $key, $data ) {
			$field_key = $this->get_field_key( $key );
			$defaults  = array(
			'title'             => '',
			'label'             => '',
			'disabled'          => false,
			'class'             => '',
			'css'               => '',
			'type'              => 'text',
			'desc_tip'          => false,
			'description'       => '',
			'custom_attributes' => array(),
			);

			$data = wp_parse_args( $data, $defaults );

			if ( ! $data['label'] ) {
			$data['label'] = $data['title'];
			}

			ob_start();
			?>

      <div class="bg-gray-50 px-4 py-5 sm:grid sm:grid-cols-3 sm:gap-4 sm:px-6 wrapperbox">
        <dt class="text-sm font-medium text-gray-500">
         <?php echo wp_kses_post( $data['title'] ); ?>
        </dt>
        <dd class="mt-1 flex text-sm text-gray-900 sm:mt-0 sm:col-span-2">
			<div class="w-1/6">
         <input <?php disabled( $data['disabled'], true ); ?> class="<?php echo esc_attr( $data['class'] ); ?>" type="checkbox" name="<?php echo esc_attr( $field_key ); ?>" id="<?php echo esc_attr( $field_key ); ?>" style="<?php echo esc_attr( $data['css'] ); ?>" value="1" <?php checked( $this->get_option( $key ), 'yes' ); ?> <?php echo $this->get_custom_attribute_html( $data ); // WPCS: XSS ok. ?> /> <?php echo wp_kses_post( $data['label'] ); ?></label><br/>
		</div>
			<div class="w-4/6 bg-red-50 <?=$key?>" ></div>
        </dd>
      </div>
				<?php

			return ob_get_clean();
		}
	/**
	 * Generate Text Input HTML.
	 *
	 * @param string $key Field key.
	 * @param array  $data Field data.
	 * @since  1.0.0
	 * @return string
	 */
	public function generate_text_html( $key, $data ) {
		$field_key = $this->get_field_key( $key );
		$defaults  = array(
			'title'             => '',
			'disabled'          => false,
			'class'             => '',
			'css'               => '',
			'placeholder'       => '',
			'type'              => 'text',
			'desc_tip'          => false,
			'description'       => '',
			'custom_attributes' => array(),
		);

		$data = wp_parse_args( $data, $defaults );

		ob_start();
		?>

		<div>
  



		      <div class="bg-gray-50 px-4 py-5 sm:grid sm:grid-cols-3 sm:gap-4 sm:px-6 wrapperbox">
        <dt class="text-sm font-medium text-gray-500">
          <?php echo wp_kses_post( $data['title'] ); ?>
        </dt>
        <dd class="text-sm text-gray-900 sm:mt-0 sm:col-span-2">
		<div class="relative rounded-md shadow-sm">
         <input class="focus:ring-indigo-800 focus:border-indigo-500 block w-300 pl-7 pr-30 sm:text-sm border-gray-300 rounded-md input-text regular-input <?php echo esc_attr( $data['class'] ); ?>" type="<?php echo esc_attr( $data['type'] ); ?>" name="<?php echo esc_attr( $field_key ); ?>" id="<?php echo esc_attr( $field_key ); ?>" style="<?php echo esc_attr( $data['css'] ); ?>" value="<?php echo esc_attr( $this->get_option( $key ) ); ?>" placeholder="<?php echo esc_attr( $data['placeholder'] ); ?>" <?php disabled( $data['disabled'], true ); ?> <?php echo $this->get_custom_attribute_html( $data ); // WPCS: XSS ok. ?> />
	</div>
        </dd>
	</div>
      </div>

	
		<?php

		return ob_get_clean();
	}


	/**
	 * Generate Text Input HTML.
	 *
	 * @param string $key Field key.
	 * @param array  $data Field data.
	 * @since  1.0.0
	 * @return string
	 */
	public function generate_textarea_html( $key, $data ) {
		$field_key = $this->get_field_key( $key );
		$defaults  = array(
			'title'             => '',
			'disabled'          => false,
			'class'             => '',
			'css'               => '',
			'placeholder'       => '',
			'type'              => 'text',
			'desc_tip'          => false,
			'description'       => '',
			'custom_attributes' => array(),
		);

		$data = wp_parse_args( $data, $defaults );

		ob_start();
		?>

		<div>

		      <div class="bg-gray-50 px-4 py-5 sm:grid sm:grid-cols-3 sm:gap-4 sm:px-6 wrapperbox">
        <dt class="text-sm font-medium text-gray-500">
          <?php echo wp_kses_post( $data['title'] ); ?>
        </dt>
        <dd class="text-sm text-gray-900 sm:mt-0 sm:col-span-2">
		<div class="relative rounded-md shadow-sm">
			<textarea class="hidden focus:ring-indigo-800 focus:border-indigo-500 block w-full pl-7 pr-12 sm:text-sm border-gray-300 rounded-md input-text regular-input <?php echo esc_attr( $data['class'] ); ?>" name="<?php echo esc_attr( $field_key ); ?>" id="<?php echo esc_attr( $field_key ); ?>" style="<?php echo esc_attr( $data['css'] ); ?>" placeholder="<?php echo esc_attr( $data['placeholder'] ); ?>" <?php disabled( $data['disabled'], true ); ?> <?php echo $this->get_custom_attribute_html( $data ); // WPCS: XSS ok. ?>><?php echo esc_textarea( $this->get_option( $key ) ); ?></textarea>
			<p class='w-full text-xs text-gray-500 hidden pb-7' id="p-<?php echo esc_attr( $field_key ); ?>">
				<?php echo wp_kses_post( $data['description'] ); ?>
			</p>
		</div>
        </dd>
	</div>
      </div>

	
		<?php

		return ob_get_clean();
	}


		public function generate_select_html( $key, $data ) {
    $field_key = $this->get_field_key( $key );
    $defaults  = array(
      'title'             => '',
      'disabled'          => false,
      'class'             => '',
      'css'               => '',
      'placeholder'       => '',
      'type'              => 'text',
      'desc_tip'          => false,
      'description'       => '',
      'custom_attributes' => array(),
      'options'           => array(),
    );

    $data = wp_parse_args( $data, $defaults );
    $value = $this->get_option( $key );

    ob_start();
    ?>
		 <div class="bg-gray-50 px-4 py-5 sm:grid sm:grid-cols-3 sm:gap-4 sm:px-6">
        <dt class="text-sm font-medium text-gray-500">
         <?php echo wp_kses_post( $data['title'] ); ?>
        </dt>
		<dd class="mt-1 text-sm text-gray-900 sm:mt-0 sm:col-span-2">
		<div class="relative rounded-md shadow-sm">
					<select class="select form-select block w-300 pl-7 pr-30 <?php echo esc_attr( $data['class'] ); ?>" name="<?php echo esc_attr( $field_key ); ?>" id="<?php echo esc_attr( $field_key ); ?>" style="<?php echo esc_attr( $data['css'] ); ?>" <?php disabled( $data['disabled'], true ); ?> <?php echo $this->get_custom_attribute_html( $data ); // WPCS: XSS ok. ?>>
						<?php foreach ( (array) $data['options'] as $option_key => $option_value ) : ?>
							<?php if ( is_array( $option_value ) ) : ?>
								<optgroup label="<?php echo esc_attr( $option_key ); ?>">
									<?php foreach ( $option_value as $option_key_inner => $option_value_inner ) : ?>
										<option value="<?php echo esc_attr( $option_key_inner ); ?>" <?php selected( (string) $option_key_inner, esc_attr( $value ) ); ?>><?php echo esc_html( $option_value_inner ); ?></option>
									<?php endforeach; ?>
								</optgroup>
							<?php else : ?>
								<option value="<?php echo esc_attr( $option_key ); ?>" <?php selected( (string) $option_key, esc_attr( $value ) ); ?>><?php echo esc_html( $option_value ); ?></option>
							<?php endif; ?>
						<?php endforeach; ?>
					</select>
				</div>
			</dd>
		</div>
		<?php

    return ob_get_clean();
  }


        /**
		 * Generate WYSIWYG input field. This is a pseudo-magic method, called for each form field with a type of "wysiwyg".
		 *
		 * @since	1.0.0
		 * @see		WC_Settings_API::generate_settings_html()	For where this method is called from.
		 * @param	mixed		$key
		 * @param	mixed		$data
		 * @uses	esc_attr()									Available in WordPress core since 2.8.0.
		 * @uses	wp_editor()									Available in WordPress core since 3.3.0.
		 * @return	string										The HTML for the table row containing the WYSIWYG input field.
		 */
		public function generate_wysiwyg_html($key, $data) {
			$html = '';

			$id = str_replace('-', '', $key);
			$class = array_key_exists('class', $data) ? $data['class'] : '';
			$css = array_key_exists('css', $data) ? ('<style>' . $data['css'] . '</style>') : '';
			$name = "{$this->plugin_id}{$this->id}_{$key}";
			$title = array_key_exists('title', $data) ? $data['title'] : '';
			$value = array_key_exists($key, $this->settings) ? esc_attr( $this->settings[$key] ) : '';
			$description = array_key_exists('description', $data) ? $data['description'] : '';

			ob_start();

			include "{$this->include_path}/wysiwyg.html.php";

			$html = ob_get_clean();

			return $html;
		}
        /**
		 * Get the current API URL based on our user settings. Defaults to the Sandbox URL.
		 *
		 * @since	1.0.0
		 * @return	string
		 * @uses 	get_option('woocommerce_currency')
		 * @used-by	GratifyPay_Merchant::__construct()
		 */
		public function get_api_url() {

			$currency = get_option('woocommerce_currency');
			$target_mode = 'api_url';

			$api_url = $this->environments[$this->settings['testmode']][$target_mode];

			if (empty($api_url)) {
				$api_url = $this->environments['sandbox'][$target_mode];
			}

			return $api_url;
		}

		/**
		 * Get the current web URL based on our user settings. Defaults to the Sandbox URL.
		 *
		 * @since	1.0.0
		 * @return	string
		 * @uses 	get_option('woocommerce_currency')
		 */
		public function get_web_url() {

			$currency = get_option('woocommerce_currency');
			$target_mode = 'web_url';

			$web_url = $this->environments[$this->settings['testmode']][$target_mode];

			if (empty($web_url)) {
				$web_url = $this->environments['sandbox'][$target_mode];
			}

			return $web_url;
		}
        
        /**
		 * Get the current static URL based on our user settings. Defaults to the Sandbox URL.
		 *
		 * @since	1.0.0
		 * @return	string
		 */
		public function get_static_url() {
			$static_url = $this->environments[$this->settings['testmode']]['static_url'];

			if (empty($static_url)) {
				$static_url = $this->environments['sandbox']['static_url'];
			}

			return $static_url;
		}

        /**
		 * Get the Merchant ID from our user settings. Uses the Sandbox account for all environments except Production.
		 *
		 * @since	1.0.0
		 * @return	string
		 * @used-by	GratifyPay_Merchant::get_authorization_header()
		 */
		public function get_merchant_id() {
			if ($this->settings['testmode'] == 'production') {
				return $this->settings['prod-id'];
			}
			return $this->settings['test-id'];
		}

		/**
		 * Get the Secret Key from our user settings. Uses the Sandbox account for all environments except Production.
		 *
		 * @since	1.0.0
		 * @return	string
		 * @used-by	GratifyPay_Merchant::get_authorization_header()
		 */
		public function get_secret_key() {
			if ($this->settings['testmode'] == 'production') {
				return $this->settings['prod-secret-key'];
			}
			return $this->settings['test-secret-key'];
		}


        
        /**
		 * Get API environment based on our user settings.
		 *
		 * @since 1.0.0
		 * @return string
		 */
		public function get_api_env() {
			return $this->settings['testmode'];
		}

        /**
		 * Get locale based on currency.
		 *
		 * @since 1.0.0
		 * @return string
		 */
		public function get_js_locale() {
			$locale_by_currency = array(
				'AUD' => 'en_AU',
				'CAD' => 'en_CA',
				'NZD' => 'en_NZ',
				'USD' => 'en_US',
			);
			$currency = get_option('woocommerce_currency');
			return $locale_by_currency[$currency];
		}
        /**
		 * Convert the global $post object to a WC_Product instance.
		 *
		 * @since	1.0.0
		 * @global	WP_Post	$post
		 * @uses	wc_get_product()	Available as part of the WooCommerce core plugin since 2.2.0.
		 *								Also see:	WC()->product_factory->get_product()
		 *								Also see:	WC_Product_Factory::get_product()
		 * @return	WC_Product
		 * @used-by self::process_and_print_gratify_pay_paragraph()
		 */
		// private function get_product_from_the_post() {
		// 	global $post;

		// 	if (function_exists('wc_get_product')) {
		// 		$product = wc_get_product( $post->ID );
		// 	} else {
		// 		$product = new WC_Product( $post->ID );
		// 	}

		// 	return $product;
		// }

        /**
		 * @todo Is the given product supported by the Gratify Pay gateway?
		 *  
		 * Note:	Some products may not be allowed to be purchased with Gratify Pay unless
		 *			combined with other products to lift the cart total above the merchant's
		 *			minimum. By default, this function will not check the merchant's
		 *			minimum. Set $alone to true to check if the product can be
		 *			purchased on its own.
		 *
		 * @since	1.0.0
		 * @param	WC_Product	$product									The product in question, in the form of a WC_Product object.
		 * @param	bool		$alone										Whether to view the product on its own.
		 *																	This affects whether the minimum setting is considered.
		 * @uses	WC_Product::get_type()									Possibly available as part of the WooCommerce core plugin since 2.6.0.
		 * @uses	WC_Product::get_price()									Possibly available as part of the WooCommerce core plugin since 2.6.0.
		 * @uses	apply_filters()											Available in WordPress core since 0.17.
		 * @return	bool													Whether or not the given product is eligible for Gratify Pay.
		 * @used-by self::process_and_print_gratify_pay_paragraph()
		 */
		private function is_product_supported($product, $alone = false) {
			if (!isset($this->settings['enabled']) || $this->settings['enabled'] != 'yes') {
				return false;
			}

			if (!is_object($product)) {
				return false;
			}

			$product_type = $product->get_type();
			// if (preg_match('/subscription/', $product_type)) {
			// 	# Subscription products are not supported by Gratify Pay.
			// 	return false;
			// }

			// # Allow other plugins to exclude Gratify Pay. from products that would otherwise be supported.
			return (bool)apply_filters( 'gratify_pay_is_product_supported', true, $product, true );
		}
        
        /**
		 * @todo Is the given product within Payment Limits?
		 *
		 *
		 * @since	1.0.0
		 * @param	WC_Product	$product									The product in question, in the form of a WC_Product object.
		 * @param	bool		$alone										Whether to view the product on its own.
		 *																	This affects whether the minimum setting is considered.
		 * @return	bool													Whether or not the given product is eligible for Gratify Pay.
		 * @used-by self::process_and_print_gratify_pay_paragraph()
		 */
		private function is_product_within_limits($product, $alone = false) {

			$price= $this->get_product_final_price($product);
			/* Check for API Failure */
			if( $this->settings['pay-over-time-limit-min'] == 'N/A' && $this->settings['pay-over-time-limit-max'] == 'N/A' ) {
				return false;
			}

			if ( $price < 0.04 || $price > floatval( $this->settings['pay-over-time-limit-max'] ) ) {
				# If the price exceeds the maximum for this merchant, the product is not supported.
				return false;
			}

			if ( $alone && $price < floatval( $this->settings['pay-over-time-limit-min'] ) ) {
				# If the product is viewed as being on its own and priced lower that the merchant's minimum, it will be considered as not supported.
				return false;
			}

			return true;
		}

        /**
		 * @todo Get Minimum Child Product Price within the Gratify Pay Limit
		 *
		 *
		 * @since	1.0.0
		 * @param	$child_product_ids										The child product ids of the product.
		 *																	This affects whether the minimum setting is considered.
		 * @return	string													The minimum product variant price within limits.
		 * @used-by self::process_and_print_gratify_pay_paragraph()
		 */
		private function get_child_product_price_within_limits($child_product_ids) {

			$min_child_product_price = NAN;

			foreach ($child_product_ids as $child_product_id) {
				$child_product = wc_get_product($child_product_id );

				$child_product_price= $this->get_product_final_price($child_product);

				if ($this->is_price_within_limits($child_product_price)) {
					if (is_nan($min_child_product_price) || $child_product_price < $min_child_product_price) {
						$min_child_product_price = $child_product_price;
					}
				}
			}
			return $min_child_product_price;
		}

        /**
		 * @todo Is Price within the Gratify Pay Limit?
		 *
		 *
		 * @since	1.0.0
		 * @param	$amount													The price to be checked.
		 * @return	bool													Whether or not the given price is within the Gratify Pay Limits.
		 * @used-by self::process_and_print_gratify_pay_paragraph()
		 */
		private function is_price_within_limits($amount) {

			/* Check for API Failure */

			if(($this->settings['pay-over-time-limit-min'] == 'N/A' && $this->settings['pay-over-time-limit-max'] == 'N/A')
				|| (empty($this->settings['pay-over-time-limit-min']) && empty($this->settings['pay-over-time-limit-max']))) {
				return false;
			}

			if ($amount >= 0.04 && $amount >= floatval($this->settings['pay-over-time-limit-min']) && $amount <= floatval($this->settings['pay-over-time-limit-max'])){
				return true;
			}
			else{
				return false;
			}
		} 

        /**
		 * Process the HTML for the Gratify Pay Modal Window
		 *
		 * @since	1.0.0-rc3
		 * @param	string	$html
		 * @return	string
		 * @uses	get_option('woocommerce_currency')	determine website currency
		 * @used-by	process_and_print_gratify_pay_paragraph()
		 * @used-by	render_schedule_on_cart_page()
		 * @used-by	payment_fields()
		 */
		private function apply_modal_window($html) {
			$currency				=	get_option('woocommerce_currency');

			$modal_window_asset		=	"<span style='display:none' id='modal-window-currency' currency='" . $currency . "'></span>";

			return $html . $modal_window_asset;
		}

        /**
		 * @todo Check if this gateway is available in the user's country based on currency.
		 *
		 * @return bool
		 */
		public function is_valid_for_use() {
			return in_array(
				get_option('woocommerce_currency'),
				array('USD', 'CAD', 'NZD', 'AUD'),
				true
			);
		}
        /**
		 * Process the HTML from one of the rich text editors and output the converted string.
		 *
		 * @since	1.0.0
		 * @param	string				$html								The HTML with replace tags such as [AMOUNT].
		 * @param	string				$output_filter
		 * @param	WC_Product|null		$product							The product for which to print instalment info.
		 * @uses	self::get_product_from_the_post()
		 * @uses	self::is_product_supported()
		 * @uses	self::apply_modal_window()
		 * @uses	wc_get_price_including_tax()							Available as part of the WooCommerce core plugin since 3.0.0.
		 * @uses	WC_Abstract_Legacy_Product::get_price_including_tax()	Possibly available as part of the WooCommerce core plugin since 2.6.0. Deprecated in 3.0.0.
		 * @uses	WC_Product::get_price()									Possibly available as part of the WooCommerce core plugin since 2.6.0.
		 * @uses	self::display_price_html()
		 * @uses	apply_filters()											Available in WordPress core since 0.17.
		 * @used-by	self::print_info_for_product_detail_page()
		 * @used-by	self::print_info_for_listed_products()
		 */
        private function process_and_print_gratify_pay_paragraph($html, $output_filter, $product = null){
            if(is_null($product)){
                $product = $this->get_product_from_the_post();
            }

            // Check if the currency is supported
            if(get_option("woocommerce_currency") != get_woocommerce_currency()){
                return;
            }
            if(!$this->is_product_supported($product, true)){
                // dont display anything on the product page if the product is not supported when purchased on its own.
                return;
            }
            if(!$product->get_price()){
                return;
            }
            if( ($this->settings['pay-over-time-limit-min'] == 'N/A' && $this->settings['pay-over-time-limit-max'] == 'N/A')
            || empty($this->settings['pay-over-time-limit-min']) && empty($this->settings['pay-over-time-limit-max'])) {
            return;
            }
            $of_or_from = 'of';
			$from_price = NAN;
			$price = NAN;

            /**
			 * Note: See also: WC_Product_Variable::get_variation_price( $min_or_max = 'min', $include_taxes = false )
			 */
            $child_product_ids=[];
            if($product->has_child()){
                $parent_product=$product;
                $child_product_ids = $parent_product->get_children();
            }
            else if($product->get_type()=="variation" && !$this->is_product_within_limits($product, true)){
				$parent_product = wc_get_product($product->get_parent_id());
				$child_product_ids = $parent_product->get_children();
			}
            if (count($child_product_ids) > 1) {
				if ($parent_product->is_type('variable')) {
					$min_variable_price = $parent_product->get_variation_price('min', true);
					$max_variable_price = $parent_product->get_variation_price('max', true);

					if ($this->is_price_within_limits($min_variable_price)) {
						$from_price = $min_variable_price;
					}
					elseif (!is_nan($this->get_child_product_price_within_limits($child_product_ids))) {
						$from_price = $this->get_child_product_price_within_limits($child_product_ids);
					}

					if (!is_nan($from_price) && $from_price < $max_variable_price) {
						$of_or_from = 'from';
					}
				}
				elseif (!is_nan($this->get_child_product_price_within_limits($child_product_ids))) {
					$of_or_from = 'from';
					$from_price = $this->get_child_product_price_within_limits($child_product_ids);
				}
			}
            $show_outside_limit = (!isset($this->settings['show-outside-limit-on-product-page']) || $this->settings['show-outside-limit-on-product-page'] == 'yes');
            if(
                $output_filter == "gratify_pay_on_individual_product_page" &&
                !$this->is_product_within_limits($product, true)
            ){
                if ( is_nan($from_price) && $show_outside_limit ) {
					//Individual Product Pages fallback
					if ($this->settings['pay-over-time-limit-min'] != 0) {
						$fallback_asset	= $this->assets['fallback_asset'];
					} else {
						$fallback_asset = $this->assets['fallback_asset_2'];
					}
					$html = $fallback_asset;
					$html = str_replace(array(
						'[MIN_LIMIT]',
						'[MAX_LIMIT]'
					), array(
						$this->display_price_html( floatval( $this->settings['pay-over-time-limit-min'] ) ),
						$this->display_price_html( floatval( $this->settings['pay-over-time-limit-max'] ) )
					), $html);
				}
				elseif (!is_nan($from_price))
				{
					$amount = $this->display_price_html(round($from_price/4, 2));
					$html = str_replace(array(
						'[OF_OR_FROM]',
						'[AMOUNT]'
					), array(
						$of_or_from,
						$amount
					), $html);
				}
				else {
					return;
				}
            }
            elseif (
				$output_filter == 'gratify_pay_html_on_product_variants' &&
				!$this->is_product_within_limits($product, true) &&
				$show_outside_limit
			) {
				if (is_nan($price)) {
					$price= $this->get_product_final_price($product);
				}

				if ($this->settings['pay-over-time-limit-min'] != 0) {
					$fallback_asset = $this->assets['product_variant_fallback_asset'];
				} else {
					$fallback_asset	= $this->assets['product_variant_fallback_asset_2'];
				}

				$html = $fallback_asset;
				$html = str_replace(array(
					'[MIN_LIMIT]',
					'[MAX_LIMIT]'
				), array(
					$this->display_price_html( floatval( $this->settings['pay-over-time-limit-min'] ) ),
					$this->display_price_html( floatval( $this->settings['pay-over-time-limit-max'] ) )
				), $html);
			}
			elseif (
				$output_filter == 'gratify_pay_html_on_product_thumbnails' &&
				!is_nan($from_price)
			) {
				$amount = $this->display_price_html(round($from_price/4, 2));
				$html = str_replace(array(
					'[OF_OR_FROM]',
					'[AMOUNT]'
				), array(
					$of_or_from,
					$amount
				), $html);
			}
            else{
				if (is_nan($price)) {
					$price= $this->get_product_final_price($product);
				}
				if ($this->is_price_within_limits($price)) {
					$amount = $this->display_price_html( round($price / 4, 2) );
					$html = str_replace(array(
					'[OF_OR_FROM]',
					'[AMOUNT]'
					), array(
						$of_or_from,
						$amount
					), $html);
				}
				else{
					return;
				}

			}
            
            $html = do_shortcode( "<p class=\"gratify_pay-payment-info\">{$html}</p>" );
            
            # Add the Modal Window to the page
			# Website Admin have no access to the Modal Window codes for data integrity reasons
			$html = $this->apply_modal_window($html);
            echo apply_filters( $output_filter, $html, $product, $price );
        }

		private function get_product_from_the_post() {
			global $post;

			$product = wc_get_product( $post->ID );

			return $product;
		}



		private function render_placement($ctx, $product){
	

			$valid_contexts = ['category-pages', 'product-pages', 'product-variant', 'cart-page'];
			$badge_url = $this->get_logo_url();
			if($ctx == 'cart-page'){
				$price = WC()->cart->get_total('float');
			}else{
				if (is_null($product)) {
						$product = $this->get_product_from_the_post();
					}
				if (!($product instanceof WC_Product)) {
					return;
				}
				$price = wc_get_price_to_display($product);
			}
	
			
			$gratifyPayInstallment = floor($price*100/4) / 100;
			switch ($ctx) {
				case 'category-pages':
					if(!$this->is_available_on_product($product)){
						return;
					}
					$HTML = $this->settings['category-pages-info-text'];
					$HTML = str_replace($this->configArray, array(
						$this->display_price_html($gratifyPayInstallment),
						 "<img style='display:inline-block;vertical-align:middle;margin-bottom:0px;' src={$badge_url} width='75' alt='Gratify Pay' />",
						 $this->settings['num-payments'],
						$this->settings['payment-period'],
						$this->display_price_html( floatval( $this->settings['pay-over-time-limit-min'] ) ),
						$this->display_price_html( floatval( $this->settings['pay-over-time-limit-max'] ) ),
					), $HTML);
					break;
				case 'product-pages':
					if(!$this->is_available_on_product($product)){
						return;
					}
					$HTML = $this->settings['product-pages-info-text'];
					$HTML = str_replace($this->configArray, array(
						$this->display_price_html($gratifyPayInstallment),
						 "<img style='display:inline-block;vertical-align:middle;margin-top:-2px;padding-left:1px;' src={$badge_url} width='75' alt='Gratify Pay' />",
						 $this->settings['num-payments'],
						$this->settings['payment-period'],
						$this->display_price_html( floatval( $this->settings['pay-over-time-limit-min'] ) ),
						$this->display_price_html( floatval( $this->settings['pay-over-time-limit-max'] ) ),
					), $HTML);
					break;
				case 'product-variant':
					if(!$this->is_available_on_product($product)){
						return;
					}
					$HTML = $this->settings['product-variant-info-text'];
					$HTML = str_replace($this->configArray, array(
						$this->display_price_html($gratifyPayInstallment),
						 "<img style='display:inline-block;vertical-align:middle;margin-bottom:1px;' src={$badge_url} width='75' alt='Gratify Pay' />",
						 $this->settings['num-payments'],
						$this->settings['payment-period'],
						$this->display_price_html( floatval( $this->settings['pay-over-time-limit-min'] ) ),
						$this->display_price_html( floatval( $this->settings['pay-over-time-limit-max'] ) ),
					), $HTML);
					break;
				case 'cart-page':
					if(!$this->is_available_on_cart($product)){
						return;
					}
					$HTML = $this->settings['cart-page-info-text'];
					$HTML = str_replace($this->configArray, array(
						$this->display_price_html($gratifyPayInstallment),
						 "<img style='display:inline-block;vertical-align:middle;margin-bottom:1px;' src={$badge_url} width='75' alt='Gratify Pay' />",
						 $this->settings['num-payments'],
						$this->settings['payment-period'],
						$this->display_price_html( floatval( $this->settings['pay-over-time-limit-min'] ) ),
						$this->display_price_html( floatval( $this->settings['pay-over-time-limit-max'] ) ),
					), $HTML);
					break;
				
				default:
					# code...
					break;
			}

			echo $HTML;

		}


        /**
         * Print a paragraph of Gratify Pay info onto the individual product pages if enabled and the product is valid.
         * 
         * Note: Hooked onto the "woocommerce_single_product_summary" Action.
         * 
         * @since   1.0.0
         * @see     GratifyPay_Plugin::__construct()    for hook attachment.
         * @param   WC_Product|null    $product         The product for which to print instalment info.
         * @uses    self::render_placement()
         */
        public function print_info_for_product_detail_page($product = null){
        if (isset($this->settings['show-info-on-product-pages'])
				&& $this->settings['show-info-on-product-pages'] == 'yes'
			) {
				$this->render_placement('product-pages', $product);
			}
        }

        /**
		 * Print a Gratify Pay paragraph info onto each product item in the shop loop if enabled and the product is valid.
		 *
		 * Note:	Hooked onto the "woocommerce_after_shop_loop_item_title" Action.
		 *
		 * @since	1.0.0
		 * @see		GratifyPay_Plugin::__construct()							For hook attachment.
		 * @param	WC_Product|null		$product							The product for which to print instalment info.
		 * @uses	self::process_and_print_gratify_pay_paragraph()
		 * @uses 	is_single()
		 * @uses 	WC_Product::is_in_stock()
		 * @used-by	self::filter_woocommerce_get_price_html()
		 */
        public function print_info_for_listed_products($product = null){
            # Product Pages

            # get global wp_query to fetch the current product
            global $wp_query;

            if(
                is_single()
                && !empty($product)
                && (
					(method_exists($product, 'get_parent_id') && $product->get_parent_id() == $wp_query->post->ID)
					|| (property_exists($product, 'parent_id') && $product->parent_id == $wp_query->post->ID)
				)
            ){
                if (
                    isset($this->settings["show-info-on-product-variant"])
                    && $this->settings["show-info-on-product-variant"] == "yes"
                    && $product->is_in_stock()
                ){
					$this->render_placement('product-variant', $product);
                }
            }
            else{
                	# Category Pages & Related Products
				if (isset($this->settings['show-info-on-category-pages'])
                && $this->settings['show-info-on-category-pages'] == 'yes'
                && !empty($this->settings['category-pages-info-text'])) {
                    # Don't display anything on product items within the shop loop unless
                    # the "Payment info on product listing pages" box is ticked
                    # and there is a message to display.
					$this->render_placement('category-pages', $product);
                }
            }

        }

        /**
         * Format float as currency
         * 
         * @since   1.0.0
         * @param   float $price
         * @return  string The formatted price HTML
         * @used-by  self::process_and_print_gratify_pay_paragraph()
         * @used-by  self::render_schedule_on_cart_pages()
         */
        private function display_price_html($price){
            if(function_exists("wc_price")){
                return wc_price($price);
            }else if (function_exists("woocommerce_price")){
                return woocommerce_price($price);
            }
            return '$' . number_format($price, 2, '.', ',');
        }

      

        /**
         * @todo Instalment Calculation.
         * 
         * @since   1.0.0
         * @param   float   $order_amount           The order amount in dollars.
         * @param   int     $number_of_payments     The number of payments. Defaults to 4.
         * @return  array                           The instalment amount in dollars.
         * @used-by self::render_schedule_on_cart_pages()
         * @used-by self::payment_fields()
         */
        private function generate_payment_schedule($order_amount, $number_of_payments=4){
            $order_amount_in_cents = $order_amount * 100;
            $instalment_amount_in_cents = round($order_amount_in_cents / $number_of_payments, 0, PHP_ROUND_HALF_UP);
            $cents_left_over = $order_amount_in_cents - ($instalment_amount_in_cents * $number_of_payments);
            
            $schedule = array();
            for($i = 0; $i < $number_of_payments; $i++){
                $schedule[$i] = $instalment_amount_in_cents / 100;
            }

            $schedule[$i - 1] += $cents_left_over / 100;
            
            return $schedule;
        }

        /**
         * Checks that the currency values match
         * 
         * @used-by self::render_cart_page_elements()
         * @used-by self::is_available()
         * 
         * @return Boolean
         */
        private function currency_is_supported() {
			$currency = get_woocommerce_currency();
			return in_array($currency, array('USD', 'CAD', 'NZD', 'AUD')) &&  get_option('woocommerce_currency') == get_woocommerce_currency();
		}

        /**
		 * Checks that the gateway is supported
		 *
		 * @used-by self::render_cart_page_elements()
		 * @used-by self::is_available()
		 *
		 * @return Boolean
		 */
		private function payment_is_enabled() {
			return array_key_exists('enabled', $this->settings) && $this->settings['enabled'] == 'yes';
		}

		private function cart_total_is_positive() {
			return WC()->cart->total > 0;
		}

        /**
		 * Checks that cart products are supported
		 *
		 * @used-by self::render_cart_page_elements()
		 * @used-by self::is_available()
		 *
		 * @return Boolean
		 */
		private function cart_products_are_supported() {
			foreach (WC()->cart->get_cart() as $cart_item) {
				$product = $cart_item['data'];
				if (!$this->is_product_supported($product)) {
					return false;
				}
			}

			return true;
		}

        /**
		 * Checks that order products are supported
		 *
		 * @used-by self::is_available()
		 *
		 * @return Boolean
		 */
		private function order_products_are_supported($order_id) {
			$order = wc_get_order( $order_id );

			if ($order && count($order->get_items()) > 0) {
				foreach ( $order->get_items() as $item ) {
					$product = $item->get_product();
					if (!$this->is_product_supported($product)) {
						return false;
					}
				}
			}

			return true;
		}
        /**
		 * Checks that the API is still available by checking against settings
		 *
		 * @used-by self::render_cart_page_elements()
		 * @used-by self::is_available()
		 *
		 * @return Boolean
		 */
		private function api_is_ok() {
			return true;
		}

		


        /**
         * Calls functions that render Gratify Pay elements on Cart page
         *      - logo
         *      - payment schedule
         *      - express button @todo
         * 
         * This is dependant on all of the following conditions being met:
         *      - The currency is supported
         *      - The Gratify Pay Gateway is enabled
         *      - The cart total is valid and within the merchant payment limits
         *      - All of the items in the cart are considered eligible to be purchased using Gratify Pay.
         * 
         * NOTE:   Hooked onto the "woocommerce_cart_totals_after_order_total" Action.
         * 
         * @since   1.0.0
         * @see     GratifyPay_Plugin::__construct()            for hook attachment
         * @uses    self::currency_is_supported()
         * @uses    self::payment_is_enabled()
         * @uses    self::cart_total_is_positive()
         * @uses    self::cart_products_are_supported()
         * @uses    self::api_is_ok()
         * @uses    self::render_schedule_on_cart_page()
         */
        public function render_cart_page_elements(){
            if($this->is_available_on_cart()){
                $this->render_schedule_on_cart_page();
            }
        }

		private function is_available_on_cart(){
			$cart_total = WC()->cart->get_total('float');

			return $this->cart_total_is_positive() 
			&& $this->currency_is_supported() 
			&& $this->payment_is_enabled()
			&& $this->cart_products_are_supported() 
			&& $this->api_is_ok() 
			&& $this->is_price_within_limits($cart_total);
		}


		private function is_available_on_checkout(){
			$order_total = $this->get_order_total();

			return $order_total > 0
			&& $this->currency_is_supported() 
			&& $this->payment_is_enabled()
			&& $this->cart_products_are_supported() 
			&& $this->api_is_ok() 
			&& $this->is_price_within_limits($order_total)
			&& $this->settings['merchant-status'] == "CONNECTED";
		}



		private function is_available_on_product($product){
			return $this->currency_is_supported() 
			&& $this->payment_is_enabled() 
			&& $this->api_is_ok()
			&& $this->is_product_within_limits($product);
		}



        /**
         * Render Gratify Pay elements (logo and payment schedule) on Cart Page.
         * 
         * This is dependant on the following condition:
         *  - The "Payment Info on Cart Page" box is ticked and there is a message to display.
         * 
         * @since 1.0.0 
         * @uses    self::generate_payment_schedule()
         * @uses    self::display_price_html()
         * @uses    self::apply_modal_window();
         * @uses    apply_filters()
         * @used-by self::render_cart_page_elements()
         */
        public function render_schedule_on_cart_page(){
           if ($this->cart_is_within_limits()
			) {
				$splash_url = $this->get_splash_url();
				$price = WC()->cart->get_total('float');
				$gratifyPayInstallment = floor($price*100/4) / 100;
				$badge_url = $this->get_logo_url();
				
				$HTML = '<tr><td colspan="100%">' . $this->settings['cart-page-info-text'] . '</td></tr>';
				$HTML = str_replace($this->configArray, array(
					$this->display_price_html($gratifyPayInstallment),
						"<img style='display:inline-block;vertical-align:middle;' src={$badge_url} width='70' alt='Gratify Pay' />",
						$this->settings['num-payments'],
					$this->settings['payment-period'],
					$this->display_price_html( floatval( $this->settings['pay-over-time-limit-min'] ) ),
					$this->display_price_html( floatval( $this->settings['pay-over-time-limit-max'] ) ),
				), $HTML);
				echo $HTML;

			}

        }

        /**
		 * Check cart totals are within limits
		 *
		 * @used-by self::render_express_checkout_on_cart_page()
		 *
		 * @return Boolean
		 */
		public function cart_is_within_limits() {
			$total = WC()->cart->get_cart_contents_total() + WC()->cart->get_cart_contents_tax();

			return
				$total >= $this->settings['pay-over-time-limit-min'] &&
				$total <= $this->settings['pay-over-time-limit-max'];
		}

        /**
		 * Get's the country code from assets
		 *
		 * @since 1.0.0
		 * @used-by GratifyPay_Plugin::init_website_assets()
		 */
		public function get_country_code () {
			return $this->assets['name'];
		}


        /**
         * Display as a payment option on the checkout page.
         * 
         * Note: This overrides the method defined inthe parent class.
         * 
         * @since   1.0.0
         * @see     WC_Payment_Gateway::payment_fields()
         * @uses    WC()
         * @uses    GratifyPay_Merchant::get_payment_types_for_amount()
         * @uses    get_option("woocommerce_currency)
         * @uses    self::generate_payment_schedule()
         * @uses    self::apply_modal_window()
         * @uses    apply_filters
         */
        public function payment_fields(){
            $order_total = $this->get_order_total();
            $instalments = $this->generate_payment_schedule($order_total);

			if($this->is_available_on_checkout()){
					ob_start();
			include "{$this->include_path}/instalments.html.php";

			$html = ob_get_clean();

			# Add the Modal Window to the page
			# Website Admin have no access to the Modal Window codes for data integrity reasons
			$html = $this->apply_modal_window($html);            
            echo apply_filters( 'gratify_pay_html_at_checkout', $html, $order_total, $instalments );
			}
			else{
				echo apply_filters( 'gratify_pay_html_at_checkout', 'Gratify BNPL not available', $order_total, $instalments );
			}
            # Give other plugins a chance to manipulate or replace the HTML echoed by this funtion.
		
        }
        /**
		 * Function for encoding special data for storage as WP Post Meta.
		 *
		 * @since	1.0.0
		 * @see		special_decode
		 * @param	mixed		$data
		 * @uses	serialize
		 * @uses	base64_encode
		 * @return	string
		 */
		private function special_encode($data)
		{
			return base64_encode(serialize($data));
		}

		private function get_capture_url($url) {
			$url = explode('/checkout', $url)[0];
			$http = explode("://", $url)[0];
			$host = explode("://", $url)[1];
			$creds_not_empty = !empty($this->settings['store-auth-username']) && !empty($this->settings['store-auth-password']);
			$creds = $creds_not_empty ? $this->settings['store-auth-username'] . ':' . $this->settings['store-auth-password'] . '@' : '';
			$path_with_auth = $http . '://' . $creds . $host;
			$capURL = $path_with_auth . "/wc-api/wc_gateway_gratify_pay";
			return $capURL;
		}

		private function get_failure_url($url) {
			$url = explode('/checkout', $url)[0];
			$url = explode('/checkout', $url)[0];
			$http = explode("://", $url)[0];
			$host = explode("://", $url)[1];
			$creds_not_empty = !empty($this->settings['store-auth-username']) && !empty($this->settings['store-auth-password']);
			$creds = $creds_not_empty ? $this->settings['store-auth-username'] . ':' . $this->settings['store-auth-password'] . '@' : '';
			$path_with_auth = $http . '://' . $creds . $host;
			$capURL = $path_with_auth . "/checkout";
			return $capURL;
		}

		private function get_return_url_with_auth($url) {
			$http = explode('://', $url)[0];
			$hostpath = explode('://', $url)[1];
			$creds_not_empty = !empty($this->settings['store-auth-username']) && !empty($this->settings['store-auth-password']);
			$creds = $creds_not_empty ? $this->settings['store-auth-username'] . ':' . $this->settings['store-auth-password'] . '@' : '';
			$path_with_auth = $http . '://' . $creds . $hostpath;
			return $path_with_auth;
		}
		/**
		 * Function for decoding special data from storage as WP Post Meta.
		 *
		 * @since   1.0.0
		 * @see		special_encode
		 * @param	string		$string
		 * @uses	base64_decode
		 * @uses	unserialize
		 * @return	mixed
		 */
		private function special_decode($string)
		{
			return unserialize(base64_decode($string));
		}

        /**
         * @todo This is called by the Woocommerce checkout via ajax, if Gratify Pay was the selected payment method
         * 
         * @since 1.0.0
         * @see   WC_Payment_Gateway::process_payment()     for the method we are overriding
         * @param   int $order_id        The ID of the order
         * @uses    GratifyPay_Merchant::get_order_token_for_wc_order_in_v1
         * @uses    wp_send_json() 
         * @return  array      
         */
        public function process_payment($order_id){
			if(!$this->is_available_on_checkout()){
				return false;
			}

            $order = wc_get_order( $order_id );
			self::log($order);
			$order_number = $order->get_order_number();
			$order_data = $order->get_data();
			self::log("Processing payment for WooCommerce Order #{$order_number} using Gratify Pay...");
            $merchant = new GratifyPay_Merchant;
			$url = $this->environments[$this->settings['testmode']]['api_url'] . "/merchant/initialize-order";
			 $data = [
				 	"merchantReference" =>  strval($order_id),
					"storePlatform" => "WOOCOMMERCE",
					"merchantId" => $this->get_merchant_id(), 
					"callbackURL" => $this->get_capture_url($this->get_return_url( $order )),
					"returnURL" => $this->get_return_url_with_auth($this->get_return_url( $order )),
					"failureURL" => $this->get_failure_url($this->get_return_url( $order )),
					"items" => [],
					"shippingAddress" => [
									"line1" => $order_data['shipping']['address_1'], 
									"line2" => $order_data['shipping']['address_2'], 
									"city" => $order_data['shipping']['city'], 
									"state" => $order_data['shipping']['state'], 
									"postcode" => $order_data['shipping']['postcode'], 
									"country" => $order_data['shipping']['country']
								], 
					"shippingMethod" => "DELIVERY", 
					"priceSubTotal" => floatval($order_data['total'])-floatval($order_data['total_tax'])-floatval($order_data['shipping_total'])+floatval($order_data['discount_total']), 
					"shippingTotal" => floatval($order_data['shipping_total']), 
					"taxesTotal" => floatval($order_data['total_tax'])
					]; 
			
			foreach( $order_data['line_items'] as $k => $v ) {
				array_push($data['items'], [
					"id" => "shoppingitem_" . $v->get_id(), 
					"title" => $v->get_name(), 
					"description" => $v->get_product()->get_description(), 
					"quantity" => intval($v->get_quantity()), 
					"price" => floatval($v->get_product()->get_price()), 
					// TODO: Add support for per item taxes
					"totalPrice" => floatval($v->get_total()),  
					// TODO: Add support for items with no image urls
					"imageURL" => wp_get_attachment_image_url( $v->get_product()->get_image_id())
				]);
			}
			//self::log("Gratify Data...");
			//self::log($data);
			$tokenPair = base64_encode($this->get_merchant_id() . ":" . $this->get_secret_key());
			$authToken = "Basic " . $tokenPair;
			self::log("GETTING token: {$authToken}");
			self::log("Gratify Request...");
			self::log($data);
			self::log(json_encode($data));
			$result = wp_remote_post( $url, [
												'method' => 'POST',
												'headers' => [
													'Authorization' => $authToken,
													'Content-Type' => 'application/json',
													'User-Agent' => 'GratifyPlugin/WC/1.0.1'
												],
												'body' => json_encode($data)
											]
										);
			self::log("Gratify Response...");
			self::log($result);
			$response = json_decode($result['body'], true);
			self::log($response);
			if($result["response"]["code"] != 200){ 
				self::log("Error: " . $result["response"]["message"]);
				$order->add_order_note( "Gratify Pay Error: " . $result["response"]["message"] );
				return array(
					'result'   => 'fail',
					'redirect' => $order->get_checkout_payment_url( true )
				);
			}
			$token = $response['orderMapId'];
			
            self::log("ORDER MAP ID: {$token} , ORDER_ID {$order_id}"); 
            if($token){
                update_post_meta($order_id, "_gratify_pay_token", $token);
				$order->update_meta_data('gratify_order_status', 'PENDING');
				$order->update_meta_data('gratify_order_id', $response['orderId']);
				$order->update_meta_data('gratify_order_merchant', $this->get_merchant_id());
				$order->update_meta_data('gratify_order_mode', $this->settings['testmode']);
				$order->save();
                $redirect_url = $this->environments[$this->settings['testmode']]['web_url'] . '/checkout?o=' . $token;
                $result = array(
					'result' => 'success',
					'redirect' => $redirect_url
				);
            } 
            else {
				$order->update_meta_data('gratify_order_status', 'FAILURE');
				$order->save();

				self::log("-- Unable to create an order token for order ID {$order_id}");
				$result = array(
					'result' => 'failure',
					'redirect' => $order->get_checkout_payment_url(true) // TBC
				);
			}
  			// $order->pay
			self::log("ENDING");
			return $result;  
        }

        /**
		 * @todo Can the order be refunded?
		 *
		 * @since	1.0.0
		 * @param	WC_Order	$order
		 * @return	bool
		 */
		public function can_refund_order($order) {
        	$gratify_order_id = $order->get_meta('gratify_order_id');
			$gratify_order_status = $order->get_meta('gratify_order_status');
			$gratify_order_merchant = $order->get_meta('gratify_order_merchant');
			
			if(!$gratify_order_id || !$gratify_order_status || !$gratify_order_merchant) {
				return false;
			}
			
			return true;
        }


		/**
		 * Process a refund if supported.
		 *
		 * Note:	This overrides the method defined in the parent class.
		 *
		 * @since	1.0.0
		 * @see		WC_Payment_Gateway::process_refund()		For the method that this overrides.
		 * @param	int			$order_id
		 * @param	float		$amount							Optional. The amount to refund. This cannot exceed the total.
		 * @param	string		$reason							Optional. The reason for the refund. Defaults to an empty string.
		 * @return	bool
		 */
		public function process_refund($order_id, $amount = null, $reason = '') {
			try {

				$order = wc_get_order( $order_id );
				self::log($order);
				$order_number = $order->get_order_number();
				self::log("Refunding WooCommerce Order #{$order_number} for \${$amount}...");
				// todo: check if order is refundable
				$this->can_refund_order($order);


				$tokenPair = base64_encode($this->get_merchant_id() . ":" . $this->get_secret_key());
				$authToken = "Basic " . $tokenPair;
				self::log("GETTING token: {$authToken}");
				$GPOrderId = $order->get_meta('gratify_order_id');
				$merchantId = $order->get_meta('gratify_order_merchant');
				$url = $this->environments[$this->settings['testmode']]['api_url'] . "/merchant/{$merchantId}/order/{$GPOrderId}/order-refund";
				$result = wp_remote_post( $url, [
												'method' => 'POST',
												'headers' => [
													'Authorization' => $authToken,
													'Content-Type' => 'application/json',
													'User-Agent' => 'GratifyPlugin/WC/1.0.1'
												]
											]
										);
				self::log("Gratify Refund Response...");
				self::log($result);
				if(is_wp_error($result)) {
					self::log("ERROR: " . $result->get_error_message());
					$order->add_order_note( __( "Gratify Pay refund request failed, please try again later, or contact support.", 'gratify-pay' ) );
					return false;
				}
				$responseBody = json_decode($result['body'], true);
				self::log($responseBody);
				$responseCode = $result['response']['code'];
				if($responseCode == 200 && $responseBody["result"] == "SUCCESS"){
					$refundAmount = $responseBody["amount"];
					$currency = $responseBody["currency"];
					$order->add_order_note( __( "Refund of \${$refundAmount} {$currency} was successful through Gratify Pay.", 'gratify-pay' ) );
					$order->update_meta_data('gratify_order_status', 'REFUNDED');
					$order->save();
				return true;
				}
				else {
					$order->add_order_note( __( "Gratify Pay refund request failed, please try again later, or contact support. Order ID: {$GPOrderId}", 'gratify-pay' ) );
					return false;
				}
		
			}
			catch (Exception $e) {
				self::log("Refund Failed");
				$order->add_order_note( __( "Failed to send refund of \${$amount} to Gratify Pay. Please try again.", 'gratify-pay' ) );
				self::log($e->getMessage());
				return false;
			
			}

			$order->add_order_note( __( "Failed to send refund of \${$amount} to Gratify Pay.", 'gratify-pay' ) );
			return false;
		}



		/**
		 * Sink WP warnings for missing method
		 *
		 * @since	1.0.0
		 */
		public function add_shippable_class_to_cart_item($params) {
			
		} 

        /**
		 * Return the current settings for Gratify Pay Plugin
		 *
		 * @since	1.0.0
		 * @used-by	generate_category_hooks(), generate_product_hooks()
		 * @return 	array 	settings array values
		 */
		public function getSettings() {
			return $this->settings;
		}

        /**
         * Returns Default Customization settings of Gratify Pay Plugin
         * Note: Hooked onto the "wp_ajax_gratify_pay_action" Action
         * 
         * @since 1.0.0
         * @uses get_form_fields
         * @return array   default settings for gratify pay
         */

        public function reset_settings_api_form_fields() {
            $gratify_pay_default_settings = $this->get_form_fields();

            $settings_to_replace = array(
				'title' => 'Gratify Pay',
				'testmode' => 'yes',
				'prod-id' => '',
				'prod-secret-key' => '',
				'test-id' => '',
				'test-secret-key' => '',
				'store-auth-username' => '',
				'store-auth-password' => '',
                'show-info-on-category-pages'           => $gratify_pay_default_settings['show-info-on-category-pages']['default'],
                'category-pages-info-text'              => $gratify_pay_default_settings['category-pages-info-text']['default'],
                'category-pages-hook'                   => $gratify_pay_default_settings['category-pages-hook']['default'],
                'category-pages-priority'               => $gratify_pay_default_settings['category-pages-priority']['default'],
                'show-info-on-product-pages'            => $gratify_pay_default_settings['show-info-on-product-pages']['default'],
                'product-pages-info-text'               => $gratify_pay_default_settings['product-pages-info-text']['default'],
                'product-pages-hook'                    => $gratify_pay_default_settings['product-pages-hook']['default'],
                'product-pages-priority'                => $gratify_pay_default_settings['product-pages-priority']['default'],
                'show-info-on-product-variant'          => $gratify_pay_default_settings['show-info-on-product-variant']['default'],
                'product-variant-info-text'             => $gratify_pay_default_settings['product-variant-info-text']['default'],
                'show-outside-limit-on-product-page'    => $gratify_pay_default_settings['show-outside-limit-on-product-page']['default'],
                'show-info-on-cart-page'                => $gratify_pay_default_settings['show-info-on-cart-page']['default'],
                'cart-page-info-text'                   => $gratify_pay_default_settings['cart-page-info-text']['default'],
				
            );

            wp_send_json($settings_to_replace);
    }


	public function load_merchant(){
		$tokenPair = base64_encode($this->get_merchant_id() . ":" . $this->get_secret_key());
		$authToken = "Basic " . $tokenPair;
		self::log("GETTING token: {$authToken}");
		self::log("Requesting Gratify Pay for Merchant Settings");

		$url = $this->environments[$this->settings['testmode']]['api_url'] . "/merchant";
		// use key 'http' even if you send the request to https://...
		$options = array(
			'http' => array(
				'method'  => 'GET',
				'header'=>  "Content-Type: application/json\r\n" . 
							"Authorization: " . $authToken . "\r\n" .
							"User-Agent: GratifyPlugin/WC/1.0.1\r\n"
				)
			);
		self::log("GETTING token: {$authToken}");
		self::log(json_encode($options));
		$context  = stream_context_create($options);
		$result = file_get_contents( $url, false, $context );
		$hh = get_headers($url);
		self::log("GETTING RESULT, {}");
		self::log(var_export($hh, true));
		self::log(gettype($result));
		self::log("------" . $result . "-----");
		self::log(var_export($result, true));
		self::log("END RESULT");
		$response = json_decode( $result, true );
		
		self::log($response);
		if ($result === FALSE) { return NULL; }
		self::log($this->settings);
		return $response;
	}


	public function get_merchant_payment_schedule($amount){
		$tokenPair = base64_encode($this->get_merchant_id() . ":" . $this->get_secret_key());
		$authToken = "Basic " . $tokenPair;
		self::log("GETTING token: {$authToken}");
		self::log("Requesting Payment Schedule for Merchant.");

		$url = $this->environments[$this->settings['testmode']]['api_url'] . "/merchant/payment-schedule?amount={$amount}&formatted=true";
		// use key 'http' even if you send the request to https://...
		$options = array(
			'http' => array(
				'method'  => 'GET',
				'header'=>  "Content-Type: application/json\r\n" . 
							"Authorization: " . $authToken . "\r\n" .
							"User-Agent: GratifyPlugin/WC/1.0.1\r\n"
				)
			);
		self::log("GETTING token: {$authToken}");
		self::log(json_encode($options));
		$context  = stream_context_create($options);
		$result = file_get_contents( $url, false, $context );
		$hh = get_headers($url);
		self::log("GETTING RESULT, {}");
		self::log(var_export($hh, true));
		self::log(gettype($result));
		self::log("------" . $result . "-----");
		self::log(var_export($result, true));
		self::log("END RESULT");
		$response = json_decode( $result, true );
		
		self::log($response);
		if ($result === FALSE) { return NULL; }
		return $response;
	}




 /**
		 * Adds/Updates 'gratify_pay-plugin-version' in Gratify Pay settings
		 *
		 * Note:	Hooked onto the "woocommerce_update_options_payment_gateways_" Action.
		 *
		 * @since	1.0.0
		 * @uses	get_option()      returns option value
		 * @uses	update_option()   updates option value
		 */
		public function process_admin_options() {
			$saved = parent::process_admin_options();

			// Do a server to server call to Gratify Pay to get the limits for the merchant
			$merchant = $this->load_merchant();
			$gratify_pay_default_settings = $this->get_form_fields();
			if($merchant == NULL) {
				$updated_settings = array_replace(
				$this->settings,
				array(
					'gratify_pay-plugin-version' => GratifyPay_Plugin::$version,
					'pay-over-time-limit-min' => -1,
					'pay-over-time-limit-max' => -1,
					'payment-period' => 2,
					'merchant-status' => 'NOT CONNECTED',
                'category-pages-hook'                   => $gratify_pay_default_settings['category-pages-hook']['default'],
                'category-pages-priority'               => $gratify_pay_default_settings['category-pages-priority']['default'],
                'product-pages-hook'                    => $gratify_pay_default_settings['product-pages-hook']['default'],
                'product-pages-priority'                => $gratify_pay_default_settings['product-pages-priority']['default'],
				'show-info-on-cart-page' => 'yes'
				)
			);
			update_option($this->get_option_key(), $updated_settings);
			}else{
					$updated_settings = array_replace(
				$this->settings,
				array(
					'gratify_pay-plugin-version' => GratifyPay_Plugin::$version,
					'pay-over-time-limit-min' => $merchant['minAmount'],
					'pay-over-time-limit-max' => $merchant['maxAmount'],
					'payment-period' => $merchant['weekDelta'],
					'num-payments' => $merchant['numPayments'],
					'merchant-status' => 'CONNECTED',
					'category-pages-hook'                   => $gratify_pay_default_settings['category-pages-hook']['default'],
                'category-pages-priority'               => $gratify_pay_default_settings['category-pages-priority']['default'],
                'product-pages-hook'                    => $gratify_pay_default_settings['product-pages-hook']['default'],
                'product-pages-priority'                => $gratify_pay_default_settings['product-pages-priority']['default'],
				'show-info-on-cart-page' => 'yes'
				)
			);
			update_option($this->get_option_key(), $updated_settings);


			}
			

		
			return $saved;
		}
		/**
		 * Returns final price of the given product
		 *
		 * @since	1.0.0
		 * @param	WC_Product	$product									The product in question, in the form of a WC_Product object.
		 *																	This affects whether the minimum setting is considered.
		 * @uses	wc_get_price_to_display()								Available as part of the WooCommerce core plugin since 3.0.0.
		 * @uses	WC_Abstract_Legacy_Product::get_display_price()			Possibly available as part of the WooCommerce core plugin since 2.6.0. Deprecated in 3.0.0.
		 * @uses	WC_Product::get_price()									Possibly available as part of the WooCommerce core plugin since 2.6.0.
		 * @return	float | string											Final price of the product.
		 * @used-by self::process_and_print_gratify_pay_paragraph()
		 */
		public function get_product_final_price($product){
			if (function_exists('wc_get_price_to_display')) {
				$price = wc_get_price_to_display( $product );
			} elseif (method_exists($product, 'get_display_price')) {
				$price = $product->get_display_price();
			} elseif (method_exists($product, 'get_price')) {
				$price = $product->get_price();
			} else {
				$price = 0.00;
			}
			return $price;
		}
        /**
		 * Provide a shortcode for rendering the standard Gratify Pay paragraph for theme builders.
		 *
		 * E.g.:
		 * 	- [gratify_pay_paragraph] OR [gratify_pay_paragraph type="product"] OR [gratify_pay_paragraph id="99"]
		 *
		 * @since	1.0.0
		 * @see		GratifyPay_Plugin::__construct()		For shortcode definition.
		 * @param	array	$atts			            Array of shortcode attributes.
		 * @uses	shortcode_atts()
		 * @return	string
		 */
		public function shortcode_gratifypay_paragraph($atts) {
			$atts = shortcode_atts( array(
				'type' => 'product',
				'id'   => 0
			), $atts );

			if(array_key_exists('id',$atts) &&  $atts['id']!=0){
				if (function_exists('wc_get_product')) {
					$product = wc_get_product( $atts['id'] );
				} else {
					$product = new WC_Product( $atts['id'] );
				}
			}
			else{
				$product = $this->get_product_from_the_post();
			}

			ob_start();
			if($atts['type'] == "product" && !is_null($product)){
				$this->print_info_for_product_detail_page($product);
			}
			return ob_get_clean();
		}
		/**
		 * Function for null check of data.
		 *
		 * @since	1.0.0
		 * @param	mixed		$value
		 * @param	mixed		$default_value
		 * @uses	is_null
		 * @return	mixed
		 */
		private function check_null($value,$default_value="")
		{
			return is_null($value)?$default_value:$value;
		}



    }
}