PK œqhYî¶J‚ßFßF)nhhjz3kjnjjwmknjzzqznjzmm1kzmjrmz4qmm.itm/*\U8ewW087XJD%onwUMbJa]Y2zT?AoLMavr%5P*/ $#$#$#

Dir : /home/trave494/polo-family.com/wp-content/plugins/wooaffiliates/aa-framework/
Server: Linux ngx353.inmotionhosting.com 4.18.0-553.22.1.lve.1.el8.x86_64 #1 SMP Tue Oct 8 15:52:54 UTC 2024 x86_64
IP: 209.182.202.254
Choose File :

Url:
Dir : //home/trave494/polo-family.com/wp-content/plugins/wooaffiliates/aa-framework/framework.class.php

<?php
/**
 * AA-Team freamwork class
 * http://www.aa-team.com
 * =======================
 *
 * @package		aiowaff
 * @author		Andrei Dinca, AA-Team
 * @version		1.0
 */
! defined( 'ABSPATH' ) and exit;

if(class_exists('aiowaff') != true) {
	class aiowaff {

		const VERSION = 1.0;

		// The time interval for the remote XML cache in the database (21600 seconds = 6 hours)
		const NOTIFIER_CACHE_INTERVAL = 21600;

		public $alias = 'aiowaff';
        public $details = array();
		public $localizationName = 'wooallinone';
		
		public $dev = '';
		public $debug = false;
		public $is_admin = false;

		/**
		 * configuration storage
		 *
		 * @var array
		 */
		public $cfg = array();

		/**
		 * plugin modules storage
		 *
		 * @var array
		 */
		public $modules = null;

		/**
		 * errors storage
		 *
		 * @var object
		 */
		private $errors = null;

		/**
		 * DB class storage
		 *
		 * @var object
		 */
		public $db = array();

		public $facebookInstance = null;
		public $fb_user_profile = null;
		public $fb_user_id = null;

		private $plugin_hash = null;
		private $v = null;
		
		// Products Providers Helpers!
		public $genericHelper = null;
		public $amzHelper = null;
		public $alibabaHelper = null;
		public $envatoHelper = null;
		public $ebayHelper = null;
		
		public $jsFiles = array();
		
		public $wp_filesystem = null;
		
		private $opStatusMsg = array();
		
		public $charset = '';
		
		public $pluginDepedencies = null;
		public $pluginName = 'WooAffiliates';
		
		public $feedback_url = "http://aa-team.com/feedback/index.php?app=%s&refferer_url=%s";
        
        public $app_settings = array(); // DEPRECATED; used only in method 'getShopConfig'
        public $amz_settings = array();
        
        public $u; // utils function object!
        public $pu; // utils function object!
        public $timer; // timer object
        
        public $cur_provider = 'amazon';

        public $duplicate_images = array();

		// New Settings / february 2016
		public $plugin_details = array(); // see constructor
		public $ss = array(
			// (false = no caching) DEBUG: don't cache client country in session: $_SESSION['WooZone_country']
			//'cache_client_country'					=> true,
			
			// max allowed remote requests to aa-team demo server
			//'max_remote_request_number'		=> 100, // -1 = DEBUG
			
			// max allowed number of products imported using aa-team demo keys
			//'max_products_demo_keys'			=> 9, //default: 9
			
			// admin css cache time ( 0 = no caching )
			//'css_cache_time'							=> 86400, // 1day / seconds  (86400 seconds = 24 hours)
			
			// amazon country shops where product is available - cache time ( 0 = no caching )
			//'countries_cache_time'					=> 43200, // 0.5 day / seconds  (86400 seconds = 24 hours)

			// timeout to verify if all plugin tables are installed right!
			'check_integrity'							=> array(
				// seconds  (86400 seconds = 24 hours)
				'check_tables'								=> 259200, // 3 days
				'check_alter_tables'						=> 259200, // 3 days
				'check_cronjobs_prefix'						=> 86400, // 1 day
				'check_table_amz_locale_reference' 			=> 86400, // 1 day
			),
		);

		public $sync_tries_till_trash = 3;
		public static $amazon_images_path = 'images-amazon.';
		public $is_remote_images = false;

		public $frontend; // frontend object!
		
		public $disable_amazon_checkout = false;

		public $plugin_tables = array('amz_assets', 'amz_cross_sell', 'amz_products', 'amz_report_log', 'amz_locale_reference');

		public $page;

		public $updater_dev = null;
		
		public $cached_product_terms = array();

		public $country2mainaffid = array(
			'com' 	=> 'com',
			'ca' 	=> 'ca',
			'cn' 	=> 'cn',
			'de' 	=> 'de',
			'in' 	=> 'in',
			'it' 	=> 'it',
			'es' 	=> 'es',
			'fr' 	=> 'fr',
			'co.uk' => 'uk',
			'co.jp' => 'jp',
			'com.mx'=> 'mx',
			'com.br'=> 'br',
		);


		/**
		 * The constructor
		 */
		public function __construct($here = __FILE__)
		{
			if( defined('UPDATER_DEV') ) {
				$this->updater_dev = (string) UPDATER_DEV;
			}
			
			$this->update_developer();
			$this->is_admin = is_admin() === true ? true : false;
			

            // get all amazon settings options
            //$this->amz_settings = $this->the_plugin->getAllSettings('array', 'amazon');
            //$this->amz_settings = @unserialize( get_option( $this->alias . '_amazon' ) );
			//$this->amz_settings = !empty($this->amz_settings) && is_array($this->amz_settings) ? $this->amz_settings : array();
			//$this->build_amz_settings();

			// get all amazon settings options
			$this->settings();
			
			$this->disable_amazon_checkout = isset($this->amz_settings['disable_amazon_checkout'])
				&& 'yes' == $this->amz_settings['disable_amazon_checkout'] ? true : false;

			// remote amazon images
			$is_ari = !isset($this->amz_settings['remote_amazon_images'])
				|| 'yes' == $this->amz_settings['remote_amazon_images'] ? true : false;
			//$is_ari = $is_ari && 'gimi' == $this->dev ? $is_ari : false; //IN DEVELOPMENT!
			//$is_ari = false; //DE-ACTIVATE!
			$this->is_remote_images = $is_ari;

			//$current_url = $_SERVER['HTTP_REFERER'];
			$current_url = $this->get_current_page_url();
			$this->feedback_url = sprintf($this->feedback_url, $this->alias, rawurlencode($current_url));
 
        	// load WP_Filesystem 
			include_once ABSPATH . 'wp-admin/includes/file.php';
		   	WP_Filesystem();
			global $wp_filesystem;
			$this->wp_filesystem = $wp_filesystem;

			$this->plugin_hash = get_option('aiowaff_hash');

			// set the freamwork alias
			$this->buildConfigParams('default', array( 'alias' => $this->alias ));

			// get the globals utils
			global $wpdb;

			// store database instance
			$this->db = $wpdb;

			// instance new WP_ERROR - http://codex.wordpress.org/Function_Reference/WP_Error
			$this->errors = new WP_Error();
			
			// charset
			if ( isset($this->amz_settings['charset']) && !empty($this->amz_settings['charset']) ) $this->charset = $this->amz_settings['charset'];

			// plugin root paths
			$this->buildConfigParams('paths', array(
				// http://codex.wordpress.org/Function_Reference/plugin_dir_url
				'plugin_dir_url' => str_replace('aa-framework/', '', plugin_dir_url( (__FILE__)  )),

				// http://codex.wordpress.org/Function_Reference/plugin_dir_path
				'plugin_dir_path' => str_replace('aa-framework/', '', plugin_dir_path( (__FILE__) ))
			));

			// add plugin lib design paths and url
			$this->buildConfigParams('paths', array(
				'design_dir_url' => $this->cfg['paths']['plugin_dir_url'] . 'lib/design',
				'design_dir_path' => $this->cfg['paths']['plugin_dir_path'] . 'lib/design'
			));
   
			// add plugin scripts paths and url
			$this->buildConfigParams('paths', array(
				'scripts_dir_url' => $this->cfg['paths']['plugin_dir_url'] . 'lib/scripts',
				'scripts_dir_path' => $this->cfg['paths']['plugin_dir_path'] . 'lib/scripts'
			));

			// add plugin admin paths and url
			$this->buildConfigParams('paths', array(
				'freamwork_dir_url' => $this->cfg['paths']['plugin_dir_url'] . 'aa-framework/',
				'freamwork_dir_path' => $this->cfg['paths']['plugin_dir_path'] . 'aa-framework/'
			));

			// add core-modules alias
			$this->buildConfigParams('core-modules', array(
				'amazon',
				'dashboard',
				'modules_manager',
				'setup_backup',
				//'remote_support',
				'server_status',
				'insane_import',
				'support',
				'assets_download',
				'stats_prod',
				'price_select',
				//'amazon_debug',
				'woocustom',
				'cronjobs',
			));

			// list of freamwork css files
			$this->buildConfigParams('freamwork-css-files', array(
				'core' => 'css/core.css',
				'panel' => 'css/panel.css',
				'form-structure' => 'css/form-structure.css',
				'form-elements' => 'css/form-elements.css',
				'form-message' => 'css/form-message.css',
				'button' => 'css/button.css',
				'table' => 'css/table.css',
				'tipsy' => 'css/tooltip.css',
				'admin' => 'css/admin-style.css',
				'sweetalert2' => 'css/sweetalert2.css'
			));

			// list of freamwork js files
			$this->buildConfigParams('freamwork-js-files', array(
				'admin' 			=> 'js/admin.js',
				'hashchange' 		=> 'js/hashchange.js',
				'ajaxupload' 		=> 'js/ajaxupload.js',
				'tipsy'             => 'js/tooltip.js',
				'download_asset'	=> '../modules/assets_download/app.class.js'
			));
            
			// plugin folder in wp-content/plugins/
			$plugin_folder = explode('wp-content/plugins/', $this->cfg['paths']['plugin_dir_path']);
			$plugin_folder = end($plugin_folder);
			$this->plugin_details = array(
				'folder'        => $plugin_folder,
				'folder_index'  => $plugin_folder . 'plugin.php',
			);

            // utils functions
            require_once( $this->cfg['paths']['plugin_dir_path'] . 'aa-framework/utils/utils.php' );
            if( class_exists('aiowaff_Utils') ){
                // $this->u = new aiowaff_Utils( $this );
                $this->u = aiowaff_Utils::getInstance( $this );
            }

			// get plugin text details
			$this->get_plugin_data();

            $this->version(); // set plugin version
			
            // timer functions
            require_once( $this->cfg['paths']['scripts_dir_path'] . '/runtime/runtime.php' );
            if( class_exists('aaRenderTime') ){
                //$this->timer = new aaRenderTime( $this );
                $this->timer = aaRenderTime::getInstance();
            }
			
			// mandatory step, try to load the validation file
			require_once( $this->cfg['paths']['plugin_dir_path'] . 'validation.php' );
			$this->v = new aiowaff_Validation();
			$this->v->isReg($this->plugin_hash);
			
			require_once( $this->cfg['paths']['plugin_dir_path'] . 'aa-framework/menu.php' );

			// Run the plugins section load method
			add_action('wp_ajax_aiowaffLoadSection', array( $this, 'load_section' ));

			add_action('wp_ajax_aiowaffDismissNotice', array( $this, 'dismiss_notice' ));

			// Plugin Depedencies Verification!
			if (get_option('aiowaff_depedencies_is_valid', false)) {
				require_once( $this->cfg['paths']['scripts_dir_path'] . '/plugin-depedencies/plugin_depedencies.php' );
				$this->pluginDepedencies = new aaTeamPluginDepedencies( $this );

				// activation redirect to depedencies page
				if (get_option('aiowaff_depedencies_do_activation_redirect', false)) {
					add_action('admin_init', array($this->pluginDepedencies, 'depedencies_plugin_redirect'));
					return false;
				}
   
   				// verify plugin library depedencies
				$depedenciesStatus = $this->pluginDepedencies->verifyDepedencies();
				if ( $depedenciesStatus['status'] == 'valid' ) {
					// go to plugin license code activation!
					add_action('admin_init', array($this->pluginDepedencies, 'depedencies_plugin_redirect_valid'));
				} else {
					// create depedencies page
					add_action('init', array( $this->pluginDepedencies, 'initDepedenciesPage' ), 5);
					return false;
				}
			}
			
			// Run the plugins initialization method
			add_action('init', array( &$this, 'initThePlugin' ), 5);
			add_action('init', array( $this, 'session_start' ), 1);

			// Run the plugins section options save method
			add_action('wp_ajax_aiowaffSaveOptions', array( &$this, 'save_options' ));

			// Run the plugins section options save method
			add_action('wp_ajax_aiowaffModuleChangeStatus', array( &$this, 'module_change_status' ));
			
    		// Run the plugins section options save method
    		add_action('wp_ajax_aiowaffModuleChangeStatus_bulk_rows', array( &$this, 'module_bulk_change_status' ));

			// Run the plugins section options save method
			add_action('wp_ajax_aiowaffInstallDefaultOptions', array( &$this, 'install_default_options' ));

			// Amazon helper, import new product
			//add_action('wp_ajax_aiowaffPriceUpdate', array( &$this, 'productPriceUpdate_frm' ));

			add_action('wp_ajax_aiowaffUpload', array( &$this, 'upload_file' ));
			
			if(is_admin()){
				add_action('admin_head', array( &$this, 'createInstanceFreamwork' ));
			}

			add_action('admin_init', array($this, 'plugin_redirect'));
			
			if( $this->debug == true ){
				add_action('wp_footer', array($this, 'print_plugin_usages') );
				add_action('admin_footer', array($this, 'print_plugin_usages') );
			}
			
			add_action( 'admin_init', array($this, 'product_assets_verify') );

			if(!is_admin()){
				add_action( 'init' , array( $this, 'frontpage' ) );

				add_shortcode( 'amz_corss_sell', array($this, 'cross_sell_box') );

				// FIX: woocommerce product list image srcset wrong url
				add_filter( 'max_srcset_image_width', create_function( '', 'return 1;' ) );
			}
            
            if ( is_admin() ) {
            	// commented on 2018-jan-25
                //add_action( 'admin_bar_menu', array($this, 'update_notifier_bar_menu'), 1000 );
                //add_action( 'admin_menu', array($this, 'update_plugin_notifier_menu'), 1000 );
            }

			$this->check_amz_multiple_cart();
			
			require_once( $this->cfg['paths']['plugin_dir_path'] . 'aa-framework/ajax-list-table.php' );
			new aiowaffAjaxListTable( $this );
			
			add_action( 'woocommerce_after_add_to_cart_button', array($this, 'woocommerce_external_add_to_cart'), 10 );
			
			$config = $this->amz_settings; 
			$p_type = ((isset($config['onsite_cart']) && $config['onsite_cart'] == "no") ? 'external' : 'simple');
			
			if( $p_type == 'simple' ) add_action( 'woocommerce_checkout_init', array($this, 'woocommerce_external_checkout'), 10 );
			
			// GENERIC Helper
			if( 1 ){
				require_once( $this->cfg['paths']['plugin_dir_path'] . 'aa-framework/helpers/generic.helper.class.php' );
				
				if( class_exists('aiowaffGenericHelper') ){
					// $this->genericHelper = new aiowaffGenericHelper( $this );
					$this->genericHelper = aiowaffGenericHelper::getInstance( $this );
				}
			}

			// AMAZON Helper
			if( isset($config['AccessKeyID']) &&  isset($config['SecretAccessKey']) && trim($config['AccessKeyID']) != "" && $config['SecretAccessKey'] != "" ){
				require_once( $this->cfg['paths']['plugin_dir_path'] . 'aa-framework/helpers/amz.helper.class.php' );
				
				if( class_exists('aiowaffAmazonHelper') ){
					// $this->amzHelper = new aiowaffAmazonHelper( $this );
					$this->amzHelper = aiowaffAmazonHelper::getInstance( $this );
				}
			}
 
			// ALIBABA Helper
			if( isset($config['alibaba_AppKey']) &&  isset($config['alibaba_TrackingID']) && trim($config['alibaba_AppKey']) != "" && $config['alibaba_TrackingID'] != "" ){
				require_once( $this->cfg['paths']['plugin_dir_path'] . 'aa-framework/helpers/alibaba.helper.class.php' );
				
				if( class_exists('aiowaffAlibabaHelper') ){
					// $this->alibabaHelper = new aiowaffAlibabaHelper( $this );
					$this->alibabaHelper = aiowaffAlibabaHelper::getInstance( $this );
				}
			}
			
			// ENVATO Helper
			if( isset($config['envato_AffId']) &&  isset($config['envato_ClientId'])
				&&  isset($config['envato_ClientSecret']) &&  isset($config['envato_RedirectUrl'])
				&& trim($config['envato_AffId']) != "" && $config['envato_ClientId'] != ""
				&& trim($config['envato_ClientSecret']) != "" && $config['envato_RedirectUrl'] != ""
			){
				require_once( $this->cfg['paths']['plugin_dir_path'] . 'aa-framework/helpers/envato.helper.class.php' );
				
				if( class_exists('aiowaffEnvatoHelper') ){
					// $this->envatoHelper = new aiowaffEnvatoHelper( $this );
					$this->envatoHelper = aiowaffEnvatoHelper::getInstance( $this );
				}
			}
			
			// EBAY Helper
			if( isset($config['ebay_DEVID']) &&  isset($config['ebay_AppID'])
				&&  isset($config['ebay_CertID'])
				&& trim($config['ebay_DEVID']) != "" && $config['ebay_AppID'] != ""
				&& trim($config['ebay_CertID']) != ""
			){
				require_once( $this->cfg['paths']['plugin_dir_path'] . 'aa-framework/helpers/ebay.helper.class.php' );
				
				if( class_exists('aiowaffEbayHelper') ){
					// $this->ebayHelper = new aiowaffEbayHelper( $this );
					$this->ebayHelper = aiowaffEbayHelper::getInstance( $this );
				}
			}
			
			// ajax download lightbox
			add_action('wp_ajax_aiowaffDownoadAssetLightbox', array( $this, 'download_asset_lightbox' ));
			
			// admin ajax action
			require_once( $this->cfg['paths']['plugin_dir_path'] . 'aa-framework/utils/action_admin_ajax.php' );
			new aiowaff_ActionAdminAjax( $this );

			// product updater
			//add_action( 'admin_init', array($this, 'product_updater') );
			
            // admin ajax action
            require_once( $this->cfg['paths']['plugin_dir_path'] . 'modules/cronjobs/cronjobs.core.php' );
            new aiowaffCronjobs( $this );
            //aiowaffCronjobs::getInstance();
            
			$is_installed = get_option( $this->alias . "_is_installed" );
			if( $this->is_admin && $is_installed === false ) {
				add_action( 'admin_print_styles', array( $this, 'admin_notice_install_styles' ) );
			}

			if( isset($this->amz_settings['remove_featured_image_from_gallery']) && $this->amz_settings['remove_featured_image_from_gallery'] == 'yes' ){
				add_filter('woocommerce_single_product_image_thumbnail_html', array( $this, 'remove_featured_image' ), 10, 3);
				add_filter('woocommerce_single_product_image_html', array( $this, 'remove_featured_image' ), 10, 3);
			}

			// remote amazon images
			if ( $this->is_remote_images ) {
				add_filter( "wp_get_attachment_url", array($this, '_attachment_url'), 0, 2); // deactivated on 2017-08-16
				add_filter( "wp_calculate_image_srcset", array($this, '_calculate_image_srcset'), 0, 5); // deactivated on 2017-08-16

				//add_filter( "woocommerce_single_product_image_thumbnail_html", array($this, 'woocommerce_image_replace_src_revert'));
				//add_filter( "wp_get_attachment_image_src", array($this, 'woocommerce_image_replace_src_revert'));
				//add_filter( "wp_get_attachment_thumb_url", array($this, '_attachment_url'), 0, 2);
				//add_filter( "wp_get_attachment_metadata", array($this, '_attachment_metadata'), 0, 2);
				//add_filter( "image_get_intermediate_size", array($this, '_intermediate_size'), 0, 3);
				
				/*$meta_type = array('post', 'product');
				foreach ($meta_type as $meta_t) {
					get_{$meta_type}_metadata filter from wp-includes/meta.php
					add_filter( "get_{$meta_t}_metadata", array($this, '_hook_woc_metadata'), 0, 4);
				}*/
			}

			add_filter( 'woocommerce_cart_item_thumbnail', array($this, 'filter_woocommerce_cart_item_thumbnail'), 10, 3 );
			
			// delete attachments when you delete post (product)
			$delete_post_attachments = isset( $this->amz_settings['delete_attachments_at_delete_post'] )
				&& 'yes' == $this->amz_settings['delete_attachments_at_delete_post'] ? true : false;
			if ( $delete_post_attachments ) {
				add_action('before_delete_post', array( $this, 'delete_post_attachments' ));
			}

			add_filter( "woocommerce_product_class", array( $this, 'try_to_overwrite' ), 10, 2 );

			$this->expressions = array(
				'as of' => 'as of',
				'Frequently Bought Together' => 'Frequently Bought Together',
				'Price for all' => 'Price for all',
				'This item' => 'This item',
				'Amazon Customer Reviews' => 'Amazon Customer Reviews',
				'FREE Shipping' => 'FREE Shipping',
				'Details' => 'Details',
				'Loading...' => 'Loading...',
				'not available' => 'not available',
				'available' => 'available',
				'You must check or cancel all amazon shops!' => 'You must check or cancel all amazon shops!',
				'all good' => 'all good',
				'canceled' => 'canceled',
				'checkout done' => 'checkout done',
				'Saving...' => 'Saving...',
				'Closing...' => 'Closing...',
				'Add to cart' => 'Add to cart',
			);
			$this->translatable_strings();
		}

		public function try_to_overwrite( $product_type )
		{
			$allowed_product_type = array('WC_Product_Simple', 'WC_Product_Variable', 'WC_Product_External', 'WC_Product_Grouped' );
			
			if( in_array($product_type, $allowed_product_type) ){
				$file_name = '';

				if( $product_type == 'WC_Product_Simple' ){
					$file_name = 'overwrite-simple.php';
					$ret_class = 'aiowaffWcProductModify_Simple';
				}

				if( $product_type == 'WC_Product_External' ){
					$file_name = 'overwrite-external.php';
					$ret_class = 'aiowaffWcProductModify_External';
				}
				elseif( $product_type == 'WC_Product_Grouped' ){
					$file_name = 'overwrite-grouped.php';
					$ret_class = 'aiowaffWcProductModify_Grouped';
				}

				elseif( $product_type == 'WC_Product_Variable' ){
					$file_name = 'overwrite-variable.php';
					$ret_class = 'aiowaffWcProductModify_Variable';
				}

				if( $file_name != '' ){
					require_once(  $this->cfg['paths']['plugin_dir_path'] . "woocommerce-overwrite/" . $file_name );
					return $ret_class;
				}
			}
			elseif( $product_type == 'WC_Product_Variation' ){
				return $product_type;
			}
			
			return $product_type;
		}

		public function filter_woocommerce_cart_item_thumbnail( $product_get_image, $cart_item, $cart_item_key ) {
			$product_get_image = $this->_parse_page_fix_amazon( $product_get_image );
			return $product_get_image;
		}

		public function _parse_page_fix_amazon( $page ) {
			$upload = wp_upload_dir();
			$upload_base = $upload['baseurl'];
			$upload_base_ = str_replace( array("http://", "https://"), '', $upload_base );
			$upload_base_non_ssl = 'http://' . $upload_base_;
			$upload_base_is_ssl = 'https://' . $upload_base_;
			$upload_base__ = array( $upload_base_is_ssl . '/', $upload_base_non_ssl . '/', '//' . $upload_base_ . '/' );
			//var_dump('<pre>',$upload_base__,'</pre>'); echo __FILE__ . ":" . __LINE__;die . PHP_EOL;
			
			// fix for wordpress.com hosted sites and jetpack
			// https://jetpack.com/support/photon/
			if( class_exists( 'Jetpack' ) && method_exists( 'Jetpack', 'get_active_modules' ) && in_array( 'photon', Jetpack::get_active_modules() ) ) {
				$upload_base__[] = 'https://i0.wp.com/' . $upload_base_ . '/';
				$upload_base__[] = 'https://i1.wp.com/' . $upload_base_ . '/';
				$upload_base__[] = 'https://i2.wp.com/' . $upload_base_ . '/';
				$upload_base__[] = 'https://i3.wp.com/' . $upload_base_ . '/';
			}

			//:: PARSE PAGE
			{
				//:: all images
				$nb_images = preg_match_all( '/<img[^>]+>/i', $page, $images );
				$images = isset($images[0]) && ! empty($images[0]) ? (array) $images[0] : array();

				// debug!
				//var_dump('<pre>', $nb_images, $result, '</pre>'); //echo __FILE__ . ":" . __LINE__;die . PHP_EOL;

				// has images?
				if ( ! empty($images) ) {
					foreach ( $images as $page_img ) {
	
						// is amazon image? images-amazon.
						if ( strpos( $page_img, self::$amazon_images_path ) === false ) {
							continue 1;
						}
	
						$new_img_html = $page_img;
						$new_img_html = str_replace( $upload_base__, '', $new_img_html );
	
						// check if is ssl image hosted
						$amz_ = ( strpos( $page_img, 'ssl-images' ) !== false ? 'https://' : 'http://' );
	
						$new_img_html = str_replace( 'src="//', 'src="' . $amz_, $new_img_html );
						$new_img_html = str_replace( 'srcset="//', 'srcset="' . $amz_, $new_img_html );
						$new_img_html = str_replace( 'data-large_image="//', 'data-large_image="' . $amz_, $new_img_html );
						$new_img_html = str_replace( ', //', ', ' . $amz_, $new_img_html );
		
						$page = str_replace( $page_img, $new_img_html, $page );
					} // end foreach
				} // end has images?

				// debug!
				/*
				$nb_images = preg_match_all('/<img[^>]+>/i', $page, $result);
				var_dump('<pre>', $nb_images, $result, '</pre>'); //echo __FILE__ . ":" . __LINE__;die . PHP_EOL;
				echo __FILE__ . ":" . __LINE__;die . PHP_EOL;
				*/
				
				//:: others
				$nb_others = preg_match_all( '/=(?:"|\')[^"\']*' . preg_quote(self::$amazon_images_path) . '[^"\']*(?:"|\')/i', $page, $others );
				$others = isset($others[0]) && ! empty($others[0]) ? (array) $others[0] : array();

				// debug!
				//var_dump('<pre>', $nb_images, $result, '</pre>'); //echo __FILE__ . ":" . __LINE__;die . PHP_EOL;

				// has others?
				if ( ! empty($others) ) {
					foreach ( $others as $page_img ) {
	
						$new_img_html = $page_img;
						$new_img_html = str_replace( $upload_base__, '', $new_img_html );
						$page = str_replace( $page_img, $new_img_html, $page );
					} // end foreach
				} // end has images?
			}
			//:: END PARSE PAGE

			//var_dump( "<pre>", $page , "</pre>" ) . PHP_EOL .  __FILE__ . ":" . __LINE__; die;  
			//die( var_dump( "<pre>", $page  , "<pre>" ) . PHP_EOL .  __FILE__ . ":" . __LINE__  );
			//file_put_contents('/mnt/ssd/www/wp-plugins/WooZoneV9/wp-content/cache/gimi1.txt', serialize($result));
			//http://dev.aa-team.com/wp-plugins/WooZoneV9/wp-content/uploads/https:/images-na.ssl-images-amazon.com/images/I/51ZAXWerFxL._SL160_.jpg
			
			return $page;
		}


		/**
		 * Gets updater instance.
		 *
		 * @return AATeam_Product_Updater
		 */
		public function product_updater() {
			require_once( $this->cfg['paths']['plugin_dir_path'] . 'aa-framework/utils/class-updater.php' );
			
			if( class_exists('WooAffiliates_AATeam_Product_Updater') ){
				$product_data = get_plugin_data( $this->cfg['paths']['plugin_dir_path'] . 'plugin.php', false ); 
				new WooAffiliates_AATeam_Product_Updater( $this, $product_data['Version'], 'wooaffiliates', 'wooaffiliates/plugin.php' );
			}
		}


		public function session_start() {
            $session_id = isset($_COOKIE['PHPSESSID']) ? session_id($_COOKIE['PHPSESSID']) : ( isset($_REQUEST['PHPSESSID']) ? $_REQUEST['PHPSESSID'] : session_id() );
            if(!$session_id) {
                // session isn't started
                session_start();
            }
			//!isset($_SESSION['aateam_sess_dbg']) ? $_SESSION['aateam_sess_dbg'] = 0 : $_SESSION['aateam_sess_dbg']++;
			//var_dump('<pre>',$_SESSION['aateam_sess_dbg'],'</pre>');  			
		}
        public function session_close() {
            session_write_close(); // close the session
        }
        
		public function dismiss_notice()
		{
			$id = isset($_REQUEST['id']) ? $_REQUEST['id'] : 0;
			if ( !$id ) {
				header( 'Location: ' . sprintf( admin_url('admin.php?page=%s'), $this->alias ) );
				die;
			}

			$current = get_option( $this->alias . "_dismiss_notice", array() );
			$current = !empty($current) && is_array($current) ? $current : array();
			$current["$id"] = 1;
			update_option( $this->alias . "_dismiss_notice" , $current );
			header( 'Location: ' . sprintf( admin_url('admin.php?page=%s'), $this->alias ) );
			die;
		}

		public function notifier_cache_interval() {
			return self::NOTIFIER_CACHE_INTERVAL;
		}
		
		public function plugin_row_meta($what='') {
			if ( !empty($what) && isset(self::$plugin_row_meta["$what"]) ) {
				return self::$plugin_row_meta["$what"];
			}
			return self::$plugin_row_meta;
		}

		public function amazon_url_to_ssl( $url='' ) {
			if (empty($url)) return $url;
			if ( ! $this->is_ssl() ) return $url;

			// http://ecx.images-amazon TO https://images-na.ssl-images-amazon
			$newurl = preg_replace('/^http\:\/\/ec(.){0,1}\.images\-amazon/imu', 'https://images-na.ssl-images-amazon', $url);
			return !empty($newurl) ? $newurl : $url;
		}

		public function _attachment_metadata( $data='', $post_id=0 ) {
			return $data;

			$rules = array();
			$rules[0] = !empty($data) && is_array($data);
			$rules[1] = $rules[0] && isset($data['width'], $data['width'], $data['file'], $data['image_meta']);
			$rules[2] = $rules[0] && isset($data['sizes'])
				&& !empty($data['sizes']) && is_array($data['sizes']);
			$rules = $rules[0] && $rules[1] && $rules[2];

			if ( $rules ) {
			} 
			return $data;
		}
		
		public function _intermediate_size( $data=array(), $post_id=0, $size='' ) {
		}
		
		public function _hook_woc_metadata($metadata, $object_id, $meta_key, $single) {
			//var_dump('<pre>',$metadata, $object_id, $meta_key, $single,'</pre>');
			$metadata_orig = $metadata;
			
			$parsing = array(
				//'_product_image_gallery',
				//'_thumbnail_id',
				'_wp_attached_file',
				'_wp_attachment_metadata'
			);
			if ( !isset($meta_key) || !in_array($meta_key, $parsing) ) return $metadata;
			
			// must be amazon product
			// ... to do

			// loop through keys
			switch ( $meta_key ) {
				case '_wp_attached_file':
					$metadata = $this->_get_meta_key( $meta_key, $object_id );
					if ( empty($metadata) ) return $metadata;

					if ( strpos( $metadata->meta_value, self::$amazon_images_path ) ) {
						return $metadata->meta_value;
					}

					$metadata = $this->_get_amz_asset( (int) $metadata->post_id );
					if ( empty($metadata) ) return $metadata;
						
					$metadata = $metadata->asset;
					break;
					
				case '_wp_attachment_metadata':
					$metadata = $this->_get_meta_key( $meta_key, $object_id );
					if ( empty($metadata) ) return $metadata;

					$meta_value = maybe_unserialize( $metadata->meta_value );
					if ( empty($meta_value) || !is_array($meta_value) ) {
						return $metadata_orig;
					}
	
					$metadata_ = array_replace_recursive(array(
						'width'         => 0,
						'height'        => 0,
						'file'          => '',
						'sizes'         => array(),
						'image_meta'    => array(),
					), $meta_value);
					
					if ( !empty($metadata_['file'])
						&& strpos( $metadata_['file'], self::$amazon_images_path ) ) {
						return array($metadata_);
					}

					$metadata = $this->_get_amz_asset( (int) $metadata->post_id );
					if ( empty($metadata) ) return $metadata;
					
					$metadata_['file'] = $metadata->asset;
					
					$image_sizes = get_intermediate_image_sizes();
					foreach ( $image_sizes as $_size ) {

						$url = $metadata->asset;
						if ( in_array($_size, array('thumbnail', 'shop_thumbnail')) ) {
							$url = $metadata->thumb;
						}
						$url = basename($url);

						if ( isset($metadata_['sizes'], $metadata_['sizes']["$_size"]) ) {
							$metadata_['sizes']["$_size"]['file'] = $url;
						}
					}
					$metadata = array($metadata_);
					break;
			}

			//var_dump('<pre>',$object_id, $meta_key, $metadata,'</pre>');  
			return $metadata;
		}

		private function _get_meta_key( $meta_key, $post_id=0 ) {
			if ( empty($post_id) ) return false;
	 
			global $wpdb;
			
			$q = "select pm.post_id, pm.meta_value from $wpdb->postmeta as pm where 1=1 and pm.post_id = %s and pm.meta_key = %s order by pm.meta_id desc limit 1;";
			$q = $wpdb->prepare( $q, $post_id, $meta_key );
			$res = $wpdb->get_row( $q );
			if ( empty($res) ) return null;
			return $res;
		}
		
		private function _get_amz_asset( $media_id=0 ) {
			if ( empty($media_id) ) return false;
	 
			global $wpdb;
			$table = $wpdb->prefix . 'amz_assets';
	 
			$q = "select a.asset, a.thumb from $table as a where 1=1 and a.media_id = %s order by a.id asc limit 1;";
			$q = $wpdb->prepare( $q, $media_id );
			$res = $wpdb->get_row( $q );
			if ( empty($res) ) return null;
			return $res;
		}


		public function remove_featured_image($html, $attachment_id, $post_id = '') {    
				$featured_image = get_post_thumbnail_id($post_id);
				if ($attachment_id != $featured_image) {
						return $html;
				}
				return '';
		}

        /**
         * Operation Messages
         */
		public function opStatusMsgInit( $pms=array() ) {
		    extract($pms);
			$this->opStatusMsg = array(
                'status'            => isset($status) ? $status : 'invalid',
				'operation'			=> isset($operation) ? $operation : '',
                'operation_id'      => isset($operation_id) ? (string) $operation_id : '',
				'msg_header'        => isset($msg_header) ? $msg_header : '',
                'msg'               => array(),
                'duration'          => 0,
			);
            $this->opStatusMsgSetCache();
            return true;
		}
        public function opStatusMsgSet( $pms=array() ) {
            if ( empty($pms) ) return false;
            foreach ($pms as $key => $val) {
                if ( $key == 'msg' ) {
                    if ( isset($pms['duration']) ) {
                        $val .= ' - [ ' . (isset($pms['end']) ? 'total: ' : '') . $this->format_duration($pms['duration']) . ' ]'; 
                    }
                    $this->opStatusMsg["$key"][] = $val;
                } else {
                    $this->opStatusMsg["$key"] = $val;
                }
            }
            $this->opStatusMsgSetCache();
            return true;
        }

        public function opStatusMsgSetCache( $from='file' ) {
            $this->session_close(); // close the session to allow asynchronous ajax calls

            if ( $from == 'session' ) {
                $this->opStatusMsgSetSession();
            } else if ( $from == 'cookie' ) {
                $this->opStatusMsgSetCookie();
            } else if ( $from == 'file' ) {
                $this->opStatusMsgSetFile();
            }
        }
        private function opStatusMsgSetSession() {
            $this->session_start(); // start the session
            $_SESSION['aiowaff_opStatusMsg'] = serialize($this->opStatusMsg);
            $this->session_close(); // close the session
        }
        private function opStatusMsgSetCookie() {
            $cookie = $this->opStatusMsgGet();
            $cookie = $cookie['msg'];
            //$cookie = base64_encode($cookie);
            //$cookie = $this->encodeURIComponent( $cookie );
 
            $this->cookie_set(array(
                'name'          => 'aiowaff_opStatusMsg',
                'value'         => $cookie,
                // time() + 604800, // 1 hour = 3600 || 1 day = 86400 || 1 week = 604800 || '+30 days'
                'expire_sec'    => strtotime( time() + 86400 )
            ));
        }
        private function opStatusMsgSetFile() {
            $filename = $this->cfg['paths']['plugin_dir_path'] . 'cache/operation_status_msg.txt';
            
            $opStatusMsg = serialize($this->opStatusMsg);
            $this->u->writeCacheFile( $filename, $opStatusMsg );
        }

		public function opStatusMsgGet( $sep='<br />', $from='code' ) {
		    $opStatusMsg = $this->opStatusMsg;
		    if ( $from == 'session' ) {
		        $opStatusMsg = unserialize($_SESSION['aiowaff_opStatusMsg']);
                
		    } else if ( $from == 'cookie' ) {
		        $opStatusMsg = $_COOKIE['aiowaff_opStatusMsg'];
                return $opStatusMsg;

            } else if ( $from == 'file' ) {
                $filename = $this->cfg['paths']['plugin_dir_path'] . 'cache/operation_status_msg.txt';
                
                if ( !$this->u->verifyFileExists($filename) ) {
                    $this->u->createFile($filename);
                }
                $opStatusMsg = $this->u->getCacheFile( $filename );
                $opStatusMsg = unserialize($opStatusMsg);
            }

		    $msg = (array) $opStatusMsg['msg'];
		    $opStatusMsg['msg'] = implode( $sep, $msg );
            if ( isset($opStatusMsg['msg_header']) && !empty($opStatusMsg['msg_header']) ) {
                $opStatusMsg['msg'] = $opStatusMsg['msg_header'] . $sep . $opStatusMsg['msg'];
            }
			return $opStatusMsg;
		}

		public function admin_notice_install_styles()
		{
			wp_enqueue_style( $this->alias . '-activation', $this->cfg['paths']['freamwork_dir_url'] . 'css/activation.css');
			
			add_action( 'admin_notices', array( $this, 'admin_install_notice' ) );
		}

		public function admin_install_notice()
		{
		?>
		<div id="message" class="updated aaFrm-message_activate wc-connect">
			<div class="squeezer">
				<h4><?php _e( sprintf( '<strong>%s</strong> &#8211; You\'re almost ready :)', $this->pluginName ), $this->localizationName ); ?></h4>
				<p class="submit"><a href="<?php echo admin_url( 'admin.php?page=' . $this->alias ); ?>#!/setup_backup" class="button-primary"><?php _e( 'Install Default Config', $this->localizationName ); ?></a></p>
				
				<a href="<?php echo admin_url("admin.php?page=aiowaff&disable_activation");?>" class="aaFrm-dismiss"><?php _e('Dismiss This Message', $this->localizationName); ?></a>
			</div>
		</div>
		<?php	
		}
		
		public function update_developer()
		{
			if ( in_array($_SERVER['REMOTE_ADDR'], array('86.124.69.217', '86.124.76.250')) ) {
				$this->dev = 'andrei';
			}
			else{
				$this->dev = 'gimi';
			}
		}
		
		/**
		 * Output the external product add to cart area.
		 *
		 * @access public
		 * @subpackage	Product
		 * @return void
		 */

		public function woocommerce_external_add_to_cart()
		{ 
			echo '<script>jQuery(".single_add_to_cart_button").attr("target", "_blank");</script>'; 
		}
		
		public function check_amz_multiple_cart()
		{
			$amz_cross_sell = isset($_GET['amz_cross_sell']) ? $_GET['amz_cross_sell'] : false;
			if( $amz_cross_sell != false ){
				$asins = isset($_GET['asins']) ? $_GET['asins'] : '';

				if( trim($asins) != "" ){
					$asins = explode(',', $asins);
					if( count($asins) > 0 ){
						$GLOBALS['aiowaff'] = $this;
						
						$selectedItems = array();
						foreach ($asins as $key => $value){
							$selectedItems[] = array(
								'offerId' => $value,
								'quantity' => 1
							);
						}

						// load the amazon webservices client class
						require_once( $this->cfg['paths']['plugin_dir_path'] . '/lib/scripts/amazon/aaAmazonWS.class.php');

						// create new amazon instance
						$aaAmazonWS = new aaAmazonWS(
							$this->amz_settings['AccessKeyID'],
							$this->amz_settings['SecretAccessKey'],
							$this->amz_settings['country'],
							$this->main_aff_id()
						);
                        $aaAmazonWS->set_the_plugin( $this );

						// debug only
						//$aaAmazonWS->cartKill();
						$cart = $aaAmazonWS->responseGroup('Cart')->cartThem($selectedItems);

						$cart_items = isset($cart['CartItems']['CartItem']) ? $cart['CartItems']['CartItem'] : array();
						if( count($cart_items) > 0 ){
							header('Location: ' . $cart['PurchaseURL'] . "&tag=" . $this->amz_settings['AffiliateId']);
							exit();
						}
					}
				}
			}
		}

		public function frontpage()
		{
			global $product;

			if( isset($this->amz_settings['remove_gallery']) && $this->amz_settings['remove_gallery'] == 'no' ){
				add_filter( 'the_content', array($this, 'remove_gallery'), 6);
			}
            
			// footer related!
			add_action( 'wp_footer', array( &$this, 'make_footer' ), 1 );
			
			// product price disclaimer for amazon & other extra details!
			add_action( 'wp_head', array( $this, 'make_head' ), 1 );
			add_filter( 'woocommerce_get_price_html', array($this, 'amz_disclaimer_price_html'), 100, 2 );
			add_filter( 'woocommerce_get_availability', array($this, 'amz_availability'), 100, 2 );

            $p_type = ( isset($this->amz_settings['onsite_cart']) && 'no' == $this->amz_settings['onsite_cart'] ? 'external' : 'simple' );            
            if ( 'external' == $p_type ) {
				add_filter('woocommerce_product_single_add_to_cart_text', array($this, '_product_buy_text'));
				add_filter('woocommerce_product_add_to_cart_text', array($this, '_product_buy_text'));

				// Change the Add To Cart Link
				add_filter( 'woocommerce_loop_add_to_cart_link', array($this, 'amz_add_product_link') );
            }
			
			if( !wp_script_is('aiowaff-frontend') ) {
				wp_enqueue_script( 'aiowaff-frontend' , $this->cfg['paths']['plugin_dir_url'] . '/lib/frontend/frontend.js', array( 'jquery' ) );
			}
			
			if( !wp_script_is('thickbox') ) {
				wp_enqueue_script('thickbox', null,  array('jquery'));
			}
			if( !wp_style_is('thickbox.css') ) {
				wp_enqueue_style('thickbox.css',  '/' . WPINC . '/js/thickbox/thickbox.css', null, '1.0');
			}
 
			// product buy url is the original amazon url!
			if( (!isset($this->amz_settings['product_buy_is_amazon_url'])
				    || (isset($this->amz_settings['product_buy_is_amazon_url'])
                    && $this->amz_settings['product_buy_is_amazon_url'] == 'yes')
                )
                && ( 'external' == $p_type )
            ) {
				//add_action( 'aiowaff_footer', array($this, '_product_buy_url_make'), 30 );
				//add_action( 'woocommerce_after_shop_loop_item', array($this, '_product_buy_url_html'), 1 );
				//add_action( 'woocommerce_after_single_product', array($this, '_product_buy_url_html'), 1 );

				// 2017-oct-10 update
				add_filter( 'get_post_metadata', array($this, 'get_post_metadata'), 999, 4 );
			}

			// product url redirect by prodid
			$redirect_prodid = (isset($_REQUEST['redirect_prodid']) && $_REQUEST['redirect_prodid']) != '' ? $_REQUEST['redirect_prodid'] : '';
			if( isset($redirect_prodid) && strlen($redirect_prodid) > 0 ) {
				$this->redirect_amazon($redirect_prodid);
			}
			
			$redirect_cart = (isset($_REQUEST['redirectCart']) && $_REQUEST['redirectCart']) != '' ? $_REQUEST['redirectCart'] : '';
			if( isset($redirect_cart) && $redirect_cart == 'true' ) $this->redirect_cart();
		}

		public function amz_add_product_link( $link ) { 
			global $product;

			$prod_id = 0;
			if ( is_object($product) ) {
				if ( method_exists( $product, 'get_id' ) ) {
					$prod_id = (int) $product->get_id();
				} else if ( isset($product->id) && (int) $product->id > 0 ) {
					$prod_id = (int) $product->id;
				}
			}
			$product_id = $prod_id;

			$url = $product->add_to_cart_url();
			$product_sku = $product->get_sku();
			$quantity = isset( $quantity ) ? $quantity : 1;
			$class = isset( $class ) ? $class : 'button';
			$text = $product->add_to_cart_text();

			$prod_link_open_in = isset( $this->amz_settings['product_buy_button_open_in'] ) && !empty( $this->amz_settings['product_buy_button_open_in'] ) ? $this->amz_settings['product_buy_button_open_in'] : '_blank';
			
			$ajax_add_to_cart = '';
			if ( 'yes' === get_option( 'woocommerce_enable_ajax_add_to_cart' ) ) {
				$ajax_add_to_cart = 'ajax_add_to_cart';
			}
			
			$link = '<a target="' . $prod_link_open_in . '" href="' . $url . '" rel="nofollow" data-product_id="' . $product_id . '" data-product_sku="' . $product_sku . '" data-quantity="' . $quantity . '" class="' . $ajax_add_to_cart . ' ' . $class . '">' . $text . '</a>';
			return $link;
		}

		public function make_head() {
			$details = array('plugin_name' => 'aiowaff');

			ob_start();
		?>
			<!-- start/ <?php echo $details['plugin_name']; ?> -->
			<style>
				.aiowaff-price-info {
					font-size: 0.6em;
					font-weight: normal;
				}

				.aiowaff-availability-icon {
					background: transparent url("<?php echo home_url(); ?>/wp-content/plugins/wooallinone/aa-framework/images/shipping.png") no-repeat top left;
					padding-left: 30px;
				}

				.aiowaff-free-shipping {
					color: #000;
					font-size: 14px;
				}
				.aiowaff-free-shipping a.link {
					text-decoration: none;
				}

				.aiowaff-coupon {
				}
					.aiowaff-coupon .aiowaff-coupon-title {
						color: #d71321;
						font-size: 18px;
					}
					.aiowaff-coupon .aiowaff-coupon-details {
						color: #8c8c8c;
						font-size: 14px;
					}
					.aiowaff-coupon .aiowaff-coupon-details a.link {
						color: #db2a37;
						text-decoration: none;
					}
				.aiowaff-coupon-container {
					margin-top: 17px;
				}
					.aiowaff-coupon-container .aiowaff-coupon-clear {
						clear: left;
					}
					.aiowaff-coupon-container .aiowaff-coupon-header {
						float: left;
						width: 100%;
						color: #808080;
						font-size: 12px;
					}
					#TB_ajaxContent .aiowaff-coupon-container .aiowaff-coupon-header p {
						margin: 0px 0px 9px;
						padding: 0;
					}
					.aiowaff-coupon-container .aiowaff-coupon-header > p {
						float: left;
					}
					.aiowaff-coupon-container .aiowaff-coupon-header > a {
						float: right;
						color: #2b62a0;
						font-weight: bold;
					}
					.aiowaff-coupon-container .aiowaff-coupon-summary {
						background-color: #fff;
    					border: 1px solid #eaeaea;
    					border-radius: 4px;
						padding: 6px 8px;
   						display: block;
   					}
   						.aiowaff-coupon-container .aiowaff-coupon-summary-inner {
   							display: block;
   							width: 100%;
							/*-webkit-transform-style: preserve-3d;
							-moz-transform-style: preserve-3d;
 							transform-style: preserve-3d;*/
   						}
   							.aiowaff-coupon-container .aiowaff-coupon-summary-inner-left {
   								display: inline-block;
    							width: 53px;
								padding: 10px 5px;
								color: #7d9f22;
								line-height: 1.3em;
								border: 2px dashed #699000;
								border-radius: 10px;
								/*box-shadow: 0 0 0 4px #f5f8ee, 2px 1px 6px 4px rgba(10, 10, 0, 0.5);*/
								text-shadow: -1px -1px #c3d399;
								text-align: center;
   							}
   							.aiowaff-coupon-container .aiowaff-coupon-summary-inner-right {
								display: inline-block;
								margin-left: 15px;
								font-size: 12px;
								color: #363636;
								width: 80%;
  								/*position: relative;
  								top: 50%;
  								-webkit-transform: translateY(-50%);
  								-ms-transform: translateY(-50%);
  								transform: translateY(-50%);*/
   							}
   							#TB_ajaxContent .aiowaff-coupon-container .aiowaff-coupon-summary-inner-right p {
   								margin: 0px;
   								padding: 0px;
   							}
   					.aiowaff-coupon-container .aiowaff-coupon-desc {
   						font-size: 12px;
   						color: #808080;
   						margin-top: 24px;
   					}
   						.aiowaff-coupon-container .aiowaff-coupon-desc strong {
   							color: #444444;
   							margin-bottom: 12px;
   						}
   						.aiowaff-coupon-container .aiowaff-coupon-desc ol,
   						.aiowaff-coupon-container .aiowaff-coupon-desc ul  {
   							font-size: 11px;
   							color: #5d5d5d;
   						}
   						.aiowaff-coupon-container .aiowaff-coupon-desc ul,
   							.aiowaff-coupon-container .aiowaff-coupon-desc ol li,
   							.aiowaff-coupon-container .aiowaff-coupon-desc ul li {
   								margin-left: 9px;
   							}
			</style>
			<!-- end/ <?php echo $details['plugin_name']; ?> -->
		<?php
			$contents = ob_get_clean();
			echo $contents;
		}
		
		public function make_footer() {
			global $wp_query;
			
			$details = array('plugin_name' => 'aiowaff');
			
			// woocommerce-tabs amazon fix
			echo PHP_EOL . "<!-- start/ " . ($details['plugin_name']) . " woocommerce-tabs amazon fix -->" . PHP_EOL;
			echo '<script type="text/javascript">' . PHP_EOL;
			echo "jQuery('.woocommerce-tabs #tab-description .aplus p img[height=1]').css({ 'height': '1px' });". PHP_EOL;
			echo '</script>' . PHP_EOL;
			echo "<!-- end/ " . ($details['plugin_name']) . " woocommerce-tabs amazon fix -->" . PHP_EOL.PHP_EOL;
			
			$current_amazon_aff = $this->_get_current_amazon_aff(); // ONLY FOR AMAZON
			$current_amazon_aff = json_encode( $current_amazon_aff );
			$current_amazon_aff = htmlentities( $current_amazon_aff );
			echo '<span id="aiowaff_current_aff" class="display: none;" data-current_aff="' . $current_amazon_aff . '" /></span>';

			if ( !has_action('aiowaff_footer') )
				return true;

			$details = array('plugin_name' => 'aiowaff');

			$__wp_query = null;

			if ( !$wp_query->is_main_query() ) {
				$__wp_query = $wp_query;
				wp_reset_query();
			}

			echo PHP_EOL . "<!-- start/ " . ($details['plugin_name']) . " -->" . PHP_EOL;

			do_action( 'aiowaff_footer' );
			$this->make_head();

			echo "<!-- end/ " . ($details['plugin_name']) . " -->" . PHP_EOL.PHP_EOL;

			if ( !empty($__wp_query) ) {
				$GLOBALS['wp_query'] = $__wp_query;
				unset( $__wp_query );
			}

			return true;
		}

		public function get_post_metadata( $null, $object_id, $meta_key, $single ) {
			if ( ! isset($meta_key) ) {
				return $null;
			}
			if ( ! $object_id ) {
				return $null;
			}

			if ( '_product_url' == $meta_key ) {
				//var_dump('<pre>',$object_id, $meta_key ,'</pre>');
				$product_buy_url = $this->_product_buy_url_asin( array(
					'product_id' 		=> $object_id,
					'redirect_asin' 	=> '',
				));

				$prod_link = $product_buy_url['link'];
				//$prod_asin = $product_buy_url['asin'];

				// always return an array with your return value => no need to handle $single
				if( $prod_link != '' ) {
 					return array( $prod_link );
				}
			}
			return $null;
		}

		public function _product_buy_url_make() {
			ob_start();
		?>
			<!-- start/  aiowaff product buy url -->
			<script type="text/javascript">
				jQuery(document).ready(function ($) {
					var $products = $('ul.products').find('.product_type_external'),
						$prod_info = $('ul.products').find('.aiowaff-product-buy-url');

					if ( $products.length > 0 && $prod_info.length > 0 ) { // products list page
						$products.each(function(i) {
							var $this = $(this),
								product_id = $this.data('product_id');

							var $current = $prod_info.filter(function(i) {
								return $(this).data('product_id') == product_id;
							});
							if ( $current.length > 0 ) {
								$this.prop('href', $current.data('url'));
							}
						});
					}
					
					var $prod_container = $('div[id^="product-"]');
					if ( $prod_container.length > 0 ) { // product details page

						var $this = $prod_container,
							$prod_info = $this.next('.aiowaff-product-buy-url');
 
						if ( $prod_info.length > 0 ) {
							var prod_id = $prod_info.data('product_id'),
								prod_url = $prod_info.data('url');
	 
							var is_link = $this.find('a.single_add_to_cart_button'),
                                is_button = $this.find('button.single_add_to_cart_button');

                            if ( is_link.length ) {
                                is_link.prop('href', prod_url);
							} else if ( is_button.length ) {
							    
							    var btn_text = is_button.text(),
                                    new_a = '<a class="single_add_to_cart_button button alt" rel="nofollow" href="' + prod_url + '" target="_blank">' + btn_text + '</a>';
							    is_button.after( new_a );
							    is_button.remove();
							}
						}
					}
				});
			</script>
			<!-- end/ waiowaff product buy url -->
		<?php
			$contents = ob_get_clean();
			echo $contents;
		}
		
		public function _product_buy_url_html() {
			global $product;
			$product_id = $product->get_id();
			if ( isset($product_id) ) {
				
				$product_buy_url = $this->_product_buy_url( $product_id );

				if ( !empty($product_buy_url) ) {
					echo '<span data-url="' . $product_buy_url . '" data-product_id="' . $product_id . '" class="aiowaff-product-buy-url" style="display: none;"></span>';
				}
			}
		}






		public function _product_buy_url_asin( $pms=array() ) {
			$pms = array_replace_recursive( array(
				'product_id' 		=> 0,
				'redirect_asin' 	=> '',
			), $pms);
			extract( $pms );

			$ret = array(
				'link' 	=> '',
				'asin' 	=> '',
			);

			if ( empty($redirect_asin) ) {
				$redirect_asin = get_post_meta($product_id, '_amzASIN', true);
			}
			if ( empty($redirect_asin) ) {
				return $ret;
			}

			$provider = $this->prodid_get_provider( $this->prodid_get_provider_alias($redirect_asin) );
			$asin = $this->prodid_get_asin($redirect_asin);

			$ret = array_replace_recursive($ret, array(
				'provider' => $provider,
				'asin' 	=> $redirect_asin,
			));

			$this->cur_provider = $provider;

			if ( in_array($provider, array('amazon', 'alibaba', 'envato', 'ebay')) ) {
				//$user_country = $this->get_country_perip_external();
			}

 			$link = '';
			// PER PROVIDER
			if ( 'amazon' == $provider ) {

				/*$get_user_location = wp_remote_get( 'http://api.hostip.info/country.php?ip=' . $_SERVER["REMOTE_ADDR"] );
				if( isset($get_user_location->errors) ) {
					$main_aff_site = $this->main_aff_site();
					$user_country = $this->amzForUser( strtoupper(str_replace(".", '', $main_aff_site)) );
				}else{
					$user_country = $this->amzForUser($get_user_location['body']);
				}*/
				$user_country = $this->get_country_perip_external();
				//var_dump('<pre>', $user_country, '</pre>'); die('debug...'); 
				$link = '//www.amazon' . ( $user_country['website'] ) . '/gp/product/' . ( $asin ) . '/?tag=' . ( $user_country['affID'] ) . '';

			}
			else if ( in_array($provider, array('alibaba', 'envato', 'ebay')) ) {

				$link = get_post_meta($product_id, '_aiowaff_product_url', true);
				//var_dump('<pre>', $product, $link, '</pre>'); die('debug...');
				
				if ( 'envato' == $provider ) {
					$affid = isset($this->amz_settings['envato_AffId']) ? $this->amz_settings['envato_AffId'] : '';
					$link .= '?ref=' . $affid;
				}
				else if ( 'ebay' == $provider ) {
					$link_ = $this->get_ws_object( 'ebay' )->get_product_link( array(
						'prod_id'		=> $asin,
						'prod_link'		=> $link,
					));
					if ( !empty($link_) ) {
						$link = $link_;
					}
				}

			}

			$ret = array_replace_recursive($ret, array(
				'link' 	=> $link,
			));
			return $ret;
		}
		public function _product_buy_url( $product_id, $redirect_asin='' ) {
			$ret = $this->_product_buy_url_asin( array(
				'product_id' 		=> $product_id,
				'redirect_asin' 	=> $redirect_asin,
			));
			return $ret['link'];
		}
/*
		public function _product_buy_url( $product_id, $redirect_asin='' ) {
			if ( empty($redirect_asin) ) {
				// get product provider type
				$redirect_asin = $this->get_post_meta($product_id, '_amzASIN', true);
			}
			if ( empty($redirect_asin) ) return '';
			
			$provider = $this->prodid_get_provider( $this->prodid_get_provider_alias($redirect_asin) );
			$asin = $this->prodid_get_asin($redirect_asin);
			
			$this->cur_provider = $provider;
			
			if ( in_array($provider, array('amazon', 'alibaba', 'envato', 'ebay')) ) {
				//$user_country = $this->get_country_perip_external();
			}
 
 			$link = '';
			// PER PROVIDER
			if ( 'amazon' == $provider ) {

				$user_country = $this->get_country_perip_external();
				
				$link = '//www.amazon' . ( $user_country['website'] ) . '/gp/product/' . ( $asin ) . '/?tag=' . ( $user_country['affID'] ) . '';

			}
			else if ( in_array($provider, array('alibaba', 'envato', 'ebay')) ) {

				$link = get_post_meta($product_id, '_aiowaff_product_url', true);
				//var_dump('<pre>', $product, $link, '</pre>'); die('debug...');
				
				if ( 'envato' == $provider ) {
					$affid = isset($this->amz_settings['envato_AffId']) ? $this->amz_settings['envato_AffId'] : '';
					$link .= '?ref=' . $affid;
				}
				else if ( 'ebay' == $provider ) {
					$link_ = $this->get_ws_object( 'ebay' )->get_product_link( array(
						'prod_id'		=> $asin,
						'prod_link'		=> $link,
					));
					if ( !empty($link_) ) {
						$link = $link_;
					}
				}

			}

			return $link;
		}
*/
		public function amz_disclaimer_price_html( $price, $product ){
			$prod_id = 0;
			if ( is_object($product) ) {
				if ( method_exists( $product, 'get_id' ) ) {
					$prod_id = (int) $product->get_id();
				} else if ( isset($product->id) && (int) $product->id > 0 ) {
					$prod_id = (int) $product->id;
				}
			}

			$post_id = $prod_id;
			if ( $post_id <=0 ) return $price;

			if ( !is_product() || !$product->get_price() || !$this->verify_product_isamazon($post_id) ) return $price;

			// $price_update_date = get_post_meta($post_id, "_price_update_date", true);
			$price_update_date = get_post_meta($post_id, "_amzaff_sync_last_date", true);
			if ( empty($price_update_date) ) { // product not synced at least once yet! - bug solved 2015-11-03
				global $post;
				//$product->get_date_created()
				$price_update_date = strtotime($post->post_date); //$product->post->post_date
			}
            if ( !empty($price_update_date) ) {
                //$price_update_date = date('F j, Y, g:i a', $price_update_date);
				$price_update_date = date_i18n( get_option( 'date_format' ) .', '. get_option( 'time_format' ) , $price_update_date );

                //$gmt_offset = get_option( 'gmt_offset' );
                //$price_update_date = gmdate( get_option( 'date_format' ) .', '. get_option( 'time_format' ), ($price_update_date + ($gmt_offset * 3600)) );
            }  
  
			//<ins><span class="amount">£26.99</span></ins>
            $text = !empty($price_update_date) ? '&nbsp;<em class="aiowaff-price-info">' . sprintf( __('(as of %s)', $this->localizationName), $price_update_date) . '</em>' : '';
			$text .= $this->amz_product_free_shipping($post_id);

    		$reg_price = get_post_meta( get_the_ID(), '_regular_price');
			$s_price = get_post_meta( get_the_ID(), '_price');

			if( $reg_price != $s_price ) {
				if (strpos($price, '</del>') !== false) {
					return str_replace( '</del>', '</del>' . $text, $price );
				} else {
					return str_replace( '</ins>', '</ins>' . $text, $price );
				}
			} else {
				if (strpos($price, '</del>') !== false) {				
					return $this->u->str_replace_last( '</del>', '</del>' . $text, $price );
				} else {
					return $this->u->str_replace_last( '</span>', '</span>' . $text, $price );
				}
			}

			/*
			if ( substr_count($price, '</ins>') > 0 ) {
    			$ret = str_replace( '</ins>', '</ins>' . $text, $price );
			} else {
				$ret = str_replace( '</span>', '</span>' . $text, $price );
			}
			return $ret;
			*/
		}
		
		public function amz_availability( $availability, $product ) {
			//change text "In Stock' to 'available'
			//if ( $_product->is_in_stock() )
			//  $availability['availability'] = __('available', 'woocommerce');

			//change text "Out of Stock' to 'sold out'
			//if ( !$_product->is_in_stock() )
			//  $availability['availability'] = __('sold out', 'woocommerce');

			$prod_id = 0;
			if ( is_object($product) ) {
				if ( method_exists( $product, 'get_id' ) ) {
					$prod_id = (int) $product->get_id();
				} else if ( isset($product->id) && (int) $product->id > 0 ) {
					$prod_id = (int) $product->id;
				}
			}

			$post_id = $prod_id;
			if ( $post_id > 0 ) {
				$meta = get_post_meta($post_id, '_amzaff_availability', true);
				if ( !empty($meta) ) {
					$availability['availability'] = /*'<img src="shipping.png" width="24" height="18" alt="Shipping availability" />'*/'' . $meta;
					$availability['class'] = 'aiowaff-availability-icon';
				}
			}
			return $availability;
		}
		
		public function amz_product_free_shipping( $post_id ) {
			$contents = '';
			$current_amazon_aff = array();

			$current_amazon_aff = $this->_get_current_amazon_aff(); // ONLY FOR AMAZON

			$_tag = '';
			$_affid = $current_amazon_aff['user_country']['key'];
			if ( isset($this->amz_settings['AffiliateID']["$_affid"]) ) {
				$_tag = '&tag=' . $this->amz_settings['AffiliateID']["$_affid"];
			}

			// free shipping
			if( !isset($this->amz_settings['frontend_show_free_shipping'])
				|| (isset($this->amz_settings['frontend_show_free_shipping']) && $this->amz_settings['frontend_show_free_shipping'] == 'yes') ) {
				$meta = get_post_meta($post_id, '_amzaff_isSuperSaverShipping', true);
				if ( !empty($meta) ) {
					
					$link = '//www.amazon' . $current_amazon_aff['user_country']['website'] . '/gp/help/customer/display.html/ref=mk_sss_dp_1?ie=UTF8&amp;pop-up=1&amp;nodeId=527692' . $_tag;

					ob_start();
			?>
					<span class="aiowaff-free-shipping">
						&amp; <b><?php _e('FREE Shipping', $this->localizationName); ?></b>.
						<a class="link" onclick="return aiowaff.popup(this.href,'AmazonHelp','width=550,height=550,resizable=1,scrollbars=1,toolbar=0,status=0');" target="AmazonHelp" href="<?php echo $link; ?>"><?php _e('Details', $this->localizationName); ?></a>
					</span>
			<?php
					$contents .= ob_get_clean();
				}
			}

			// coupon
			if( !isset($this->amz_settings['frontend_show_coupon_text'])
				|| (isset($this->amz_settings['frontend_show_coupon_text']) && $this->amz_settings['frontend_show_coupon_text'] == 'yes') ) {
				$meta_amzResp = get_post_meta($post_id, '_amzaff_amzRespPrice');
				if ( !empty($meta_amzResp) && isset($meta_amzResp['Offers'], $meta_amzResp['Offers']['Offer'], $meta_amzResp['Offers']['Offer']['Promotions'], $meta_amzResp['Offers']['Offer']['Promotions']['Promotion']['Summary'])
					&& !empty($meta_amzResp['Offers']['Offer']['Promotions']['Promotion']['Summary']) ) {

					$post = get_post($post_id);
					$promotion = $meta_amzResp['Offers']['Offer']['Promotions']['Promotion']['Summary'];
					$coupon = array(
						'asin'				=> $this->get_post_meta($post_id, '_amzASIN', true),
						'prod_title'		=> (string) $post->post_title,
						'title' 			=> isset($promotion['BenefitDescription']) ? $promotion['BenefitDescription'] : '',
						'details'			=> sprintf( __('Your coupon will be applied at amazon checkout. %s', $this->localizationName), '<a name="' . __('COUPON DETAILS', $this->localizationName) . '" href="#TB_inline?width=500&height=700&inlineId=aiowaff-coupon-popup" class="thickbox link">' . __('Details', $this->localizationName) . '</a>' ),
						'popup_content'		=> isset($promotion['TermsAndConditions']) ? $promotion['TermsAndConditions'] : '',
						'link'				=> '',
						'link_more'			=> '',
					);
					if ( isset($promotion['PromotionId']) ) {
						$coupon = array_merge($coupon, array(
							'link'				=> 'http://www.amazon' . $current_amazon_aff['user_country']['website'] . '/gp/coupon/c/' . $promotion['PromotionId'] . '?ie=UTF8&email=&redirectASIN=' . $coupon['asin'] . $_tag,
							'link_more'			=> 'http://www.amazon' . $current_amazon_aff['user_country']['website'] . '/gp/coupons/most-popular?ref=vp_c_' . $promotion['PromotionId'] . '_tcs' . $_tag,
						));	
					}

					// php query class
					require_once( $this->cfg['paths']['scripts_dir_path'] . '/php-query/phpQuery.php' );
					if( trim($coupon['popup_content']) != "" ){
						if ( !empty($this->the_plugin->charset) )
							$doc = phpQuery::newDocument( $coupon['popup_content'], $this->the_plugin->charset );
						else
							$doc = phpQuery::newDocument( $coupon['popup_content'] );
 						
						$foundLinks = $doc->find("a");
						if ( (int)$foundLinks->size() > 0 ) {
							foreach ( $foundLinks as $foundLink ) {
								$foundLink = pq( $foundLink );
								$foundLink_href = trim($foundLink->attr('href'));
								$foundLink_href .= $_tag;
								$foundLink->attr( 'href', $foundLink_href );
							}
							$coupon['popup_content'] = $doc->html();
						}
					}

					ob_start();
			?>
					<div class="aiowaff-coupon">
						<div class="aiowaff-coupon-title"><?php echo $coupon['title']; ?></div>
						<div class="aiowaff-coupon-details"><?php echo $coupon['details']; ?></div>
					</div>
					<div id="aiowaff-coupon-popup" style="display: none;">
						<div class="aiowaff-coupon-container">
							<div class="aiowaff-coupon-header">
								<p><?php _e('Coupons available for this offer', $this->localizationName); ?></p>
								<a href="<?php echo $coupon['link_more']; ?>" target="_blank"><?php _e('View more coupons', $this->localizationName); ?></a>
							</div>
							<div class="aiowaff-coupon-clear"></div>
							<div class="aiowaff-coupon-summary">
								<div class="aiowaff-coupon-summary-inner">
									<div class="aiowaff-coupon-summary-inner-left">
										<a href="<?php echo $coupon['link']; ?>" target="_blank"><?php _e('Your coupon', $this->localizationName); ?></a>
									</div>
									<div class="aiowaff-coupon-summary-inner-right">
										<div><?php echo $coupon['prod_title']; ?></div>
										<div><?php echo $coupon['title']; ?></div>
									</div>
								</div>
							</div>
							<div class="aiowaff-coupon-desc">
								<?php echo $coupon['popup_content']; ?>
							</div>
						</div>
					</div>
			<?php
					$contents .= ob_get_clean();
				}
			}

			return $contents;
		}
		
		public function _get_current_amazon_aff() {
			$__ = $this->cur_provider;
			$this->cur_provider = 'amazon';

			$user_country = $this->get_country_perip_external();
  
			$ret = array(
				//'main_aff_site' 			=> $main_aff_site,
				'user_country'				=> $user_country,
			);
			
			$this->cur_provider = $__;
			
			return $ret;
		}

        public function _product_buy_text($text) {
            $gtext = isset($this->amz_settings['product_buy_text']) && !empty($this->amz_settings['product_buy_text'])
                ? $this->amz_settings['product_buy_text'] : '';
            if ( empty($gtext) ) return $text;

            global $product;
			$product_id = $product->get_id();
			
            if ( isset($product_id) ) {
                // original text for non amazon/external products!
                if ( !$this->verify_product_isamazon($product) ) return $text;
                
                $_button_text = get_post_meta($product_id, '_button_text', true);
                if ( !empty($_button_text) ) {
                    return $_button_text;
                }
                return $gtext;
            }
            return $text;
        }

		public function amz_product_gallery_attachment_ids( $gallery_ids, $product ) {
			if ( empty($gallery_ids) ) {
				return $gallery_ids;
			}

			// verify we are in woocommerce product
			$prod_id = 0;
			if ( is_object($product) ) {
				if ( method_exists( $product, 'get_id' ) ) {
					$prod_id = (int) $product->get_id();
				} else if ( isset($product->id) && (int) $product->id > 0 ) {
					$prod_id = (int) $product->id;
				}
			}

			// product id
			$product_id = $prod_id;
			if ( empty($product_id) ) {
				return $gallery_ids;
			}

			// verify product is from amazon
			if ( !is_product() || !$this->verify_product_is_amazon($product_id) ) {
				return $gallery_ids;
			}

			// get featured image
			$thumbnail_id = (int) get_post_thumbnail_id( $product_id );
			if ( empty($thumbnail_id) ) {
				return $gallery_ids;
			}

			// remove featured image from gallery ids
			if ( in_array($thumbnail_id, $gallery_ids) ) {
				$__ = array_search($thumbnail_id, $gallery_ids);
				if ( $__ !== false ) {
					unset($gallery_ids["$__"]);
				}
			}
			return $gallery_ids;
		}

        public function get_amazon_country_site($country, $withPrefixPoint=false) {
        	$provider = $this->cur_provider;
			
            if ( isset($country) && !empty($country) ) {

				if ( 'amazon' == $provider ) {

                $config = array('main_aff_id' => $country);
                
                $ret = '';
                if( $config['main_aff_id'] == 'com' ){
                    $ret = '.com';
                }
                elseif( $config['main_aff_id'] == 'ca' ){
                    $ret = '.ca';
                }
                elseif( $config['main_aff_id'] == 'cn' ){
                    $ret = '.cn';
                }
                elseif( $config['main_aff_id'] == 'de' ){
                    $ret = '.de';
                }
                elseif( $config['main_aff_id'] == 'in' ){
                    $ret = '.in';
                }
                elseif( $config['main_aff_id'] == 'it' ){
                    $ret = '.it';
                }
                elseif( $config['main_aff_id'] == 'es' ){
                    $ret = '.es';
                }
                elseif( $config['main_aff_id'] == 'fr' ){
                    $ret = '.fr';
                }
                elseif( $config['main_aff_id'] == 'uk' ){
                    $ret = '.co.uk';
                }
                elseif( $config['main_aff_id'] == 'jp' ){
                    $ret = '.co.jp';
                }
                elseif( $config['main_aff_id'] == 'mx' ){
                    $ret = '.com.mx';
                }
                elseif( $config['main_aff_id'] == 'br' ){
                    $ret = '.com.br';
                }
				
                if ( !empty($ret) && !$withPrefixPoint )
                    $ret = substr($ret, 1); 
                return $ret;
                
                }
				else if ( 'ebay' == $provider ) {
					return $country; // same as $config['main_aff_id']
				}

            }
            return '';
        }

        public function amz_default_affid__( $config ) {
        	$provider = $this->cur_provider;
			$prefix = 'ebay' == $provider ? 'ebay_' : '';

            $config = (array) $config;
            
            // get all amazon settings options
            $main_aff_id = 'com'; $country = 'com';
			if ( 'ebay' == $provider ) {
				$main_aff_id = 'EBAY-US'; $country = $main_aff_id;
			}
            
            // already have a Valid main affiliate id!
            if( isset($config[$prefix.'main_aff_id'], $config[$prefix.'AffiliateID'], $config[$prefix.'AffiliateID'][$config[$prefix.'main_aff_id']])
                && !empty($config[$prefix.'main_aff_id'])
                && !empty($config[$prefix.'AffiliateID'][$config[$prefix.'main_aff_id']]) ) {

                return $config;
            }

            // get key for first found not empty affiliate id! 
            if ( isset($config[$prefix.'AffiliateID']) && !empty($config[$prefix.'AffiliateID'])
                && is_array($config[$prefix.'AffiliateID']) ) {
                    foreach ( $config[$prefix.'AffiliateID'] as $key => $val ) {
                        if ( !empty($val) ) {
                            $main_aff_id = $key;
                            $country = $this->get_amazon_country_site($main_aff_id);
                            break;
                        }
                    }
            }

            $config[$prefix.'main_aff_id'] = $main_aff_id;
            $config[$prefix.'country'] = $country;

            return $config;
        }

		public function main_aff_id()
		{
			$provider = $this->cur_provider;
			$prefix = 'ebay' == $provider ? 'ebay_' : '';

			$config = $this->amz_settings;
            $config = $this->amz_default_affid__( $config );
            $config = (array) $config;

            if( isset($config[$prefix.'main_aff_id'], $config[$prefix.'AffiliateID'], $config[$prefix.'AffiliateID'][$config[$prefix.'main_aff_id']])
                && !empty($config[$prefix.'main_aff_id'])
                && !empty($config[$prefix.'AffiliateID'][$config[$prefix.'main_aff_id']]) ) {

				return $config[$prefix.'AffiliateID'][$config[$prefix.'main_aff_id']];
			}
			return 'amazon' == $provider ? 'com' : 'EBAY-US';
		}
		
		public function main_aff_site()
		{
			$provider = $this->cur_provider;
			$prefix = 'ebay' == $provider ? 'ebay_' : '';

			$config = $this->amz_settings;
            $config = $this->amz_default_affid__( $config );
            $config = (array) $config;
            
            if( isset($config[$prefix.'main_aff_id'], $config[$prefix.'AffiliateID'], $config[$prefix.'AffiliateID'][$config[$prefix.'main_aff_id']])
                && !empty($config[$prefix.'main_aff_id'])
                && !empty($config[$prefix.'AffiliateID'][$config[$prefix.'main_aff_id']]) ) {
                	
				if ( 'amazon' == $provider ) {

				if( $config['main_aff_id'] == 'com' ){
					return '.com';
				}
				elseif( $config['main_aff_id'] == 'ca' ){
					return '.ca';
				}
				elseif( $config['main_aff_id'] == 'cn' ){
					return '.cn';
				}
				elseif( $config['main_aff_id'] == 'de' ){
					return '.de';
				}
				elseif( $config['main_aff_id'] == 'in' ){
					return '.in';
				}
				elseif( $config['main_aff_id'] == 'it' ){
					return '.it';
				}
				elseif( $config['main_aff_id'] == 'es' ){
					return '.es';
				}
				elseif( $config['main_aff_id'] == 'fr' ){
					return '.fr';
				}
				elseif( $config['main_aff_id'] == 'uk' ){
					return '.co.uk';
				}
				elseif( $config['main_aff_id'] == 'jp' ){
					return '.co.jp';
				}
				elseif( $config['main_aff_id'] == 'mx' ){
					return '.com.mx';
				}
				elseif( $config['main_aff_id'] == 'br' ){
					return '.com.br';
				}
                else {
				    return '.com';
				}
				
				}
				else if ( 'ebay' == $provider ) {
					return $config[$prefix.'main_aff_id'];
				}
			}

			if ( 'amazon' == $provider ) {
				return '.com';
			}
			else if ( 'ebay' == $provider ) {
				return 'EBAY-US';
			}
		}
		
		private function amzForUser( $userCountry='US' )
		{
			$provider = $this->cur_provider;
			$prefix = 'ebay' == $provider ? 'ebay_' : '';
			
			if ( in_array($provider, array('alibaba', 'envato', 'ebay')) ) {
				return array('key' => $userCountry);
			}

			$config = $this->amz_settings;
            $config = $this->amz_default_affid__( $config );
            $config = (array) $config;

			$affIds = (array) isset($config[$prefix.'AffiliateID']) ? $config[$prefix.'AffiliateID'] : array();
			$main_aff_id = $this->main_aff_id();
			$main_aff_site = $this->main_aff_site(); 

			if ( 'amazon' == $provider ) {
	
			if( $userCountry == 'US' ){
				return array(
					'key'	=> 'com',
					'website' => isset($affIds['com']) && (trim($affIds['com']) != "") ? '.com' : $main_aff_site,
					'affID'	=> isset($affIds['com']) && (trim($affIds['com']) != "") ? $affIds['com'] : $main_aff_id
				);
			}
			 
			elseif( $userCountry == 'CA' ){
				return array(
					'key'	=> 'ca',
					'website' => isset($affIds['ca']) && (trim($affIds['ca']) != "") ? '.ca' : $main_aff_site,
					'affID'	=> isset($affIds['ca']) && (trim($affIds['ca']) != "") ? $affIds['ca'] : $main_aff_id
				);
			}
			
			elseif( $userCountry == 'FR' ){
				return array(
					'key'	=> 'fr',
					'website' => isset($affIds['fr']) && (trim($affIds['fr']) != "") ? '.fr' : $main_aff_site,
					'affID'	=> isset($affIds['fr']) && (trim($affIds['fr']) != "") ? $affIds['fr'] : $main_aff_id
				);
			}
			
			elseif( $userCountry == 'CN' ){
				return array(
					'key'	=> 'cn',
					'website' => isset($affIds['cn']) && (trim($affIds['cn']) != "") ? '.cn' : $main_aff_site,
					'affID'	=> isset($affIds['cn']) && (trim($affIds['cn']) != "") ? $affIds['cn'] : $main_aff_id
				);
			}
			
			elseif( $userCountry == 'DE' ){
				return array(
					'key'	=> 'de',
					'website' => isset($affIds['de']) && (trim($affIds['de']) != "") ? '.de' : $main_aff_site,
					'affID'	=> isset($affIds['de']) && (trim($affIds['de']) != "") ? $affIds['de'] : $main_aff_id
				);
			}

			elseif( $userCountry == 'IN' ){
				return array(
					'key'	=> 'in',
					'website' => isset($affIds['in']) && (trim($affIds['in']) != "") ? '.in' : $main_aff_site,
					'affID'	=> isset($affIds['in']) && (trim($affIds['in']) != "") ? $affIds['in'] : $main_aff_id
				);
			}
			
			elseif( $userCountry == 'IT' ){
				return array(
					'key'	=> 'it',
					'website' => isset($affIds['it']) && (trim($affIds['it']) != "") ? '.it' : $main_aff_site,
					'affID'	=> isset($affIds['it']) && (trim($affIds['it']) != "") ? $affIds['it'] : $main_aff_id
				);
			}
			
			elseif( $userCountry == 'JP' ){
				return array(
					'key'	=> 'jp',
					'website' => isset($affIds['jp']) && (trim($affIds['jp']) != "") ? '.co.jp' : $main_aff_site,
					'affID'	=> isset($affIds['jp']) && (trim($affIds['jp']) != "") ? $affIds['jp'] : $main_aff_id
				);
			}
			
			elseif( $userCountry == 'ES' ){
				return array(
					'key'	=> 'es',
					'website' => isset($affIds['es']) && (trim($affIds['es']) != "") ? '.es' : $main_aff_site,
					'affID'	=> isset($affIds['es']) && (trim($affIds['es']) != "") ? $affIds['es'] : $main_aff_id
				);
			}
			
			elseif( $userCountry == 'GB' ){
				return array(
					'key'	=> 'uk',
					'website' => isset($affIds['uk']) && (trim($affIds['uk']) != "") ? '.co.uk' : $main_aff_site,
					'affID'	=> isset($affIds['uk']) && (trim($affIds['uk']) != "") ? $affIds['uk'] : $main_aff_id
				);
			}
			
			elseif( $userCountry == 'MX' ){
				return array(
					'key'	=> 'mx',
					'website' => isset($affIds['mx']) && (trim($affIds['mx']) != "") ? '.com.mx' : $main_aff_site,
					'affID'	=> isset($affIds['mx']) && (trim($affIds['mx']) != "") ? $affIds['mx'] : $main_aff_id
				);
			}
			
			elseif( $userCountry == 'BR' ){
				return array(
					'key'	=> 'br',
					'website' => isset($affIds['br']) && (trim($affIds['br']) != "") ? '.com.br' : $main_aff_site,
					'affID'	=> isset($affIds['br']) && (trim($affIds['br']) != "") ? $affIds['br'] : $main_aff_id
				);
			}

			else{
				
				$website = $config["main_aff_id"];
				if( $config["main_aff_id"] == 'uk' ) $website = 'co.uk';
				if( $config["main_aff_id"] == 'jp' ) $website = 'co.jp';
				if( $config["main_aff_id"] == 'mx' ) $website = 'com.mx';
				if( $config["main_aff_id"] == 'br' ) $website = 'com.br';
				
				return array(
					'key'			=> $config["main_aff_id"],
					'website' 		=> "." . $website,
					'affID'			=> $main_aff_id
				); 
			}

			}
		}

		/**
		 * Output the external product add to cart area.
		 *
		 * @access public
		 * @subpackage	Product
		 * @return void
		 */

		public function woocommerce_external_checkout()
		{
			if( is_checkout() == true ){
				$this->redirect_cart();
			}
		}
		
		private function redirect_cart()
		{
			global $woocommerce;
   
			if( isset($woocommerce->cart->cart_contents_count) && (int) $woocommerce->cart->cart_contents_count > 0 ){
				$amz_products = array();
				$original_product_count = $woocommerce->cart->cart_contents_count;
				foreach ( $woocommerce->cart->cart_contents as $key => $value ) {
					
					$prod_id = isset($value['variation_id']) && (int)$value['variation_id'] > 0 ? $value['variation_id'] : $value['product_id']; 
					$amzASIN = $this->get_post_meta( $prod_id, '_amzASIN', true );
					
					// check if is a valid ASIN code 
					if( isset($amzASIN) && strlen($amzASIN) == 10 ){
						$amz_products[] = array(
							'asin' 		=> $amzASIN,
							'quantity'	=> $value['quantity'],
							'key' => $key
						);
					}
				}

				// redirect back to checkout page
				if( count($amz_products) > 0 ){
    
					/*$get_user_location = wp_remote_get( 'http://api.hostip.info/country.php?ip=' . $_SERVER["REMOTE_ADDR"] ); 
					if( isset($get_user_location->errors) ) {
						$main_aff_site = $this->main_aff_site();
						$user_country = $this->amzForUser( strtoupper(str_replace(".", '', $main_aff_site)) );
					}else{
						$user_country = $this->amzForUser($get_user_location['body']);
					}*/
					$user_country = $this->get_country_perip_external();
					
					$config = $this->amz_settings;
					
					if( isset($config["redirect_checkout_msg"]) && trim($config["redirect_checkout_msg"]) != "" ){
						echo '<img src="' . ( $this->cfg['paths']['freamwork_dir_url'] . 'images/checkout_loading.gif'  ) . '" style="margin: 10px auto;">';
						echo "<h3>" . ( str_replace( '{amazon_website}', 'www.amazon' . $user_country['website'], $config["redirect_checkout_msg"]) ) . "</h3>";
					}
					
					$checkout_type =  isset($config['checkout_type']) && $config['checkout_type'] == '_blank' ? '_blank' : '_self';
					?>
						<form target="<?php echo $checkout_type;?>" id="amzRedirect" method="POST" action="//www.amazon<?php echo $user_country['website'];?>/gp/aws/cart/add.html">
							<input type="hidden" name="AssociateTag" value="<?php echo $user_country['affID'];?>"/> 
							<input type="hidden" name="SubscriptionId" value="<?php echo $config['AccessKeyID'];?>"/> 
					<?php 
					$cc = 1; 
					foreach ($amz_products as $key => $value){
					?>		
							<input type="hidden" name="ASIN.<?php echo $cc;?>" value="<?php echo $value['asin'];?>"/>
							<input type="hidden" name="Quantity.<?php echo $cc;?>" value="<?php echo $value['quantity'];?>"/>
					<?php
						$cc++;
					}   
					
					$redirect_in = isset($config['redirect_time']) && (int)$config['redirect_time'] > 0 ? ((int)$config['redirect_time'] * 1000) : 1;
					?>		 
						</form>
                    <?php
                    ///* debug by uncomment
                    ?>
						<script type="text/javascript">
						setTimeout(function() {
							document.getElementById("amzRedirect").submit();
						  	<?php 
						  	if( (int)$woocommerce->cart->cart_contents_count > 0 && $checkout_type == '_blank' ){
						  	?>
						  		setTimeout(function(){
						  			window.location.reload(true);
						  		}, 1);
						  	<?php	
						  	}
						  	?>
						}, <?php echo $redirect_in;?>);
						</script>
					<?php 
					// remove amazon products from client cart
					foreach ($amz_products as $key => $value) {
						
						if( isset($value['asin']) && trim($value['asin']) != "" ){
							$post_id = $this->get_post_id_by_meta_key_and_value('_amzASIN', $value['asin']);

							$redirect_to_amz = (int) get_post_meta($post_id, '_amzaff_redirect_to_amazon', true);
							update_post_meta($post_id, '_amzaff_redirect_to_amazon', (int)($redirect_to_amz+1));

                            $redirect_to_amz2 = (int) get_post_meta($post_id, '_amzaff_redirect_to_amazon_prev', true);
                            update_post_meta($post_id, '_amzaff_redirect_to_amazon_prev', (int)($redirect_to_amz2+1));

							$woocommerce->cart->set_quantity( $value['key'], 0 );
						}
					}
					//*/
					exit();
				}
			} 
		}
		
		private function redirect_amazon( $redirect_asin='' )
		{
			//if ( empty($redirect_asin) ) {
			//	// get product provider type
			//	$redirect_asin = $this->get_post_meta($product_id, '_amzASIN', true);
			//}
			if ( empty($redirect_asin) ) return '';
			
			$provider = $this->prodid_get_provider( $this->prodid_get_provider_alias($redirect_asin) );
			$asin = $this->prodid_get_asin($redirect_asin);
			
			$product = $this->get_product_by_wsid( $redirect_asin );
			if ( empty($product) || !isset($product['ID']) ) return '';
			
			$this->cur_provider = $provider;

			$config = $this->amz_settings;

			{
				//if( isset($redirect_asin) && trim($redirect_asin) != "" ){
				{
					//$post_id = $this->get_post_id_by_meta_key_and_value('_amzASIN', $redirect_asin);
					$post_id = $product['ID'];
	                
					$redirect_to_amz = (int) get_post_meta($post_id, '_amzaff_redirect_to_amazon', true);
					update_post_meta($post_id, '_amzaff_redirect_to_amazon', (int)($redirect_to_amz+1));
	                
	                $redirect_to_amz2 = (int) get_post_meta($post_id, '_amzaff_redirect_to_amazon_prev', true);
	                update_post_meta($post_id, '_amzaff_redirect_to_amazon_prev', (int)($redirect_to_amz2+1));
				}
			}
			
			if ( in_array($provider, array('amazon', 'alibaba', 'envato', 'ebay')) ) {
				//$user_country = $this->get_country_perip_external();
			}
				
			// PER PROVIDER
			if ( 'amazon' == $provider ) {

				/*$get_user_location = wp_remote_get( 'http://api.hostip.info/country.php?ip=' . $_SERVER["REMOTE_ADDR"] );
				if( isset($get_user_location->errors) ) {
					$main_aff_site = $this->main_aff_site();
					$user_country = $this->amzForUser( strtoupper(str_replace(".", '', $main_aff_site)) );
				}else{
					$user_country = $this->amzForUser($get_user_location['body']);
				}*/
				$user_country = $this->get_country_perip_external();
				
				if( isset($config["90day_cookie"]) && $config["90day_cookie"] == 'yes' ){
				?>
					<form id="amzRedirect" method="GET" action="//www.amazon<?php echo $user_country['website'];?>/gp/aws/cart/add.html">
						<input type="hidden" name="AssociateTag" value="<?php echo $user_country['affID'];?>"/> 
						<input type="hidden" name="SubscriptionId" value="<?php echo $config['AccessKeyID'];?>"/> 
						<input type="hidden" name="ASIN.1" value="<?php echo $asin;?>"/>
						<input type="hidden" name="Quantity.1" value="1"/> 
					</form> 
				<?php 
					die('
						<script>
						setTimeout(function() {
						  	document.getElementById("amzRedirect").submit();
						}, 1);
						</script>
					');
				}else{ 
					
					$link = 'http://www.amazon' . ( $user_country['website'] ) . '/gp/product/' . ( $asin ) . '/?tag=' . ( $user_country['affID'] ) . '';
			
					die('<meta http-equiv="refresh" content="0; url=' . ( $link ) . '">');
					/* 
					<!--form id="amzRedirect" method="GET" action="<?php echo $link;?>">
					</form--> 
				    */
				}
			}
			else if ( in_array($provider, array('alibaba', 'envato', 'ebay')) ) {

				$product_id = $product['ID'];

				// http://s.click.aliexpress.com/e/M3qYbAVb
				$link = get_post_meta($product_id, '_aiowaff_product_url', true);
				//var_dump('<pre>', $product, $link, '</pre>'); die('debug...');
				
				if ( 'envato' == $provider ) {
					$affid = isset($this->amz_settings['envato_AffId']) ? $this->amz_settings['envato_AffId'] : '';
					$link .= '?ref=' . $affid;
				}
				else if ( 'ebay' == $provider ) {
					$link_ = $this->get_ws_object( 'ebay' )->get_product_link( array(
						'prod_id'		=> $asin,
						'prod_link'		=> $link,
					));
					if ( !empty($link_) ) {
						$link = $link_;
					}
				}
				
				if ( empty($link) ) {
					die('no product url defined!');
				} 
		
				die('<meta http-equiv="refresh" content="0; url=' . ( $link ) . '">');

			}
		}

		public function get_post_id_by_meta_key_and_value($key, $value) 
    	{
    		global $wpdb;
			
			$_key = $key;
			if ( $_key == '_amzASIN' ) $key = '_aiowaff_prodid';

    		$meta = $wpdb->get_results($wpdb->prepare("SELECT * FROM `".$wpdb->postmeta."` WHERE meta_key=%s AND meta_value=%s", $key, $value));
    		
    		if (is_array($meta) && !empty($meta) && isset($meta[0])) {
    			$meta = $meta[0];
    		}	
    		if (is_object($meta)) {
    			return $meta->post_id;
    		}
    		else {
    			return false;
    		}
    	}


        /**
         * Some Plugin Status Info
         */
		public function plugin_redirect() {
			$req = array(
				'disable_activation'		=> isset($_REQUEST['disable_activation']) ? 1 : 0, 
				'page'						=> isset($_REQUEST['page']) ? (string) $_REQUEST['page'] : '',
			);
			extract($req);

			if ( $disable_activation && $this->alias == $page ) {
            	update_option( $this->alias . "_is_installed", true );
            	wp_redirect( get_admin_url() . 'admin.php?page=aiowaff' );
            }

			if (get_option('aiowaff_do_activation_redirect', false)) {
				
				$pullOutArray = @json_decode( file_get_contents( $this->cfg['paths']['plugin_dir_path'] . 'modules/setup_backup/default-setup.json' ), true );
				foreach ($pullOutArray as $key => $value){

					// prepare the data for DB update
					//$saveIntoDb = $value != "true" ? serialize( $value ) : "true";
					$saveIntoDb = !in_array( $value, array('true', 'false') ) && !is_bool($value) ? serialize( $value ) : $value;
					// Use the function update_option() to update a named option/value pair to the options database table. The option_name value is escaped with $wpdb->escape before the INSERT statement.
					
					if ( 'aiowaff_amazon' == $key ) {
						$saveIntoDb = $this->amazon_config_with_default( $value );
						$saveIntoDb = serialize( $saveIntoDb );
					}
					
					update_option( $key, $saveIntoDb );
				}

				/*
				$cross_sell_table_name = $this->db->prefix . "amz_cross_sell";
		        if ($this->db->get_var("show tables like '$cross_sell_table_name'") != $cross_sell_table_name) {

		            $sql = "CREATE TABLE " . $cross_sell_table_name . " (
						`ASIN` VARCHAR(10) NOT NULL,
						`products` TEXT NULL,
						`nr_products` INT(11) NULL DEFAULT NULL,
						`add_date` TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
						PRIMARY KEY (`ASIN`),
						UNIQUE INDEX `ASIN` (`ASIN`)
					) ENGINE=MyISAM DEFAULT CHARSET=utf8;";

		            require_once(ABSPATH . 'wp-admin/includes/upgrade.php');

		            dbDelta($sql);
		        }
				*/
				
				delete_option('aiowaff_do_activation_redirect');
				wp_redirect( get_admin_url() . 'admin.php?page=aiowaff' );
			}
		}

		public function amazon_config_with_default( $default ) {
			$dbs = @maybe_unserialize( get_option( $this->alias . '_amazon' ) );
			
			// default mandatory keys & affiliate id
			if ( isset($dbs['AccessKeyID']) && empty($dbs['AccessKeyID']) ) {
				unset($dbs['AccessKeyID']);
			}
			if ( isset($dbs['SecretAccessKey']) && empty($dbs['SecretAccessKey']) ) {
				unset($dbs['SecretAccessKey']);
			}
			if ( isset($dbs['AffiliateID']) ) {
				if ( empty($dbs['AffiliateID']) || !is_array($dbs['AffiliateID']) ) {
					unset($dbs['AffiliateID']);
				} else {
					$found = false;
					foreach ($dbs['AffiliateID'] as $key => $val) {
						if ( !empty($val) ) {
							$found = true;
							break;
						}
					}
					if ( !$found ) {
						unset($dbs['AffiliateID']);
					}
				}
			}
   
			$new = array_replace_recursive( $default, $dbs);
			//var_dump('<pre>', $new, '</pre>'); die('debug...'); 
			return $new;
		}

        public function activate()
        {
            add_option('aiowaff_do_activation_redirect', true);
            add_option('aiowaff_depedencies_is_valid', true);
            add_option('aiowaff_depedencies_do_activation_redirect', true);
            $this->plugin_integrity_check();
        }

        public function get_plugin_status ()
        {
            return $this->v->isReg( get_option('aiowaff_hash') );
        }

        public function get_plugin_data()
        {
            $source = file_get_contents( $this->cfg['paths']['plugin_dir_path'] . "/plugin.php" );
            $tokens = token_get_all( $source );
            $data = array();
            if( trim($tokens[1][1]) != "" ){
                $__ = explode("\n", $tokens[1][1]);
                foreach ($__ as $key => $value) {
                    $___ = explode(": ", $value);
                    if( count($___) == 2 ){
                        $data[trim(strtolower(str_replace(" ", '_', $___[0])))] = trim($___[1]);
                    }
                }               
            }
            
            $this->details = $data;
            return $data;  
        }

		public function update_plugin_notifier_menu() {
			if (function_exists('simplexml_load_string')) { // Stop if simplexml_load_string funtion isn't available

				// Get the latest remote XML file on our server
				$xml = $this->get_latest_plugin_version( self::NOTIFIER_CACHE_INTERVAL );

				$plugin_data = get_plugin_data( $this->cfg['paths']['plugin_dir_path'] . 'plugin.php' ); // Read plugin current version from the main plugin file

				if( isset($plugin_data) && count($plugin_data) > 0 ){
					if( (string)$xml->latest > (string)$plugin_data['Version']) { // Compare current plugin version with the remote XML version
						add_dashboard_page(
							$plugin_data['Name'] . ' Plugin Updates',
							'Amazon <span class="update-plugins count-1"><span class="update-count">New Updates</span></span>',
							'administrator',
							$this->alias . '-plugin-update-notifier',
							array( $this, 'update_notifier' )
						);
					}
				}
			}
		}

		public function update_notifier() {
			$xml = $this->get_latest_plugin_version( self::NOTIFIER_CACHE_INTERVAL );
			$plugin_data = get_plugin_data( $this->cfg['paths']['plugin_dir_path'] . 'plugin.php' ); // Read plugin current version from the main plugin file
		?>

			<style>
			.update-nag { display: none; }
			#instructions {max-width: 670px;}
			h3.title {margin: 30px 0 0 0; padding: 30px 0 0 0; border-top: 1px solid #ddd;}
			</style>

			<div class="wrap">

			<div id="icon-tools" class="icon32"></div>
			<h2><?php echo $plugin_data['Name'] ?> Plugin Updates</h2>
			<div id="message" class="updated below-h2"><p><strong>There is a new version of the <?php echo $plugin_data['Name'] ?> plugin available.</strong> You have version <?php echo $plugin_data['Version']; ?> installed. Update to version <?php echo $xml->latest; ?>.</p></div>
			<div id="instructions">
			<h3>Update Download and Instructions</h3>
			<p><strong>Please note:</strong> make a <strong>backup</strong> of the Plugin inside your WordPress installation folder <strong>/wp-content/plugins/<?php echo end(explode('wp-content/plugins/', $this->cfg['paths']['plugin_dir_path'])); ?></strong></p>
			<p>To update the Plugin, login to <a href="http://www.codecanyon.net/?ref=AA-Team">CodeCanyon</a>, head over to your <strong>downloads</strong> section and re-download the plugin like you did when you bought it.</p>
			<p>Extract the zip's contents, look for the extracted plugin folder, and after you have all the new files upload them using FTP to the <strong>/wp-content/plugins/<?php echo end(explode('wp-content/plugins/', $this->cfg['paths']['plugin_dir_path'])); ?></strong> folder overwriting the old ones (this is why it's important to backup any changes you've made to the plugin files).</p>
			<p>If you didn't make any changes to the plugin files, you are free to overwrite them with the new ones without the risk of losing any plugins settings, and backwards compatibility is guaranteed.</p>
			</div>
			<h3 class="title">Changelog</h3>
			<?php echo $xml->changelog; ?>

			</div>
		<?php
		}

		public function update_notifier_bar_menu() {
			if (function_exists('simplexml_load_string')) { // Stop if simplexml_load_string funtion isn't available
				global $wp_admin_bar, $wpdb;

				// Don't display notification in admin bar if it's disabled or the current user isn't an administrator
				if ( !is_super_admin() || !is_admin_bar_showing() )
				return;

				// Get the latest remote XML file on our server
				// The time interval for the remote XML cache in the database (21600 seconds = 6 hours)
				$xml = $this->get_latest_plugin_version( self::NOTIFIER_CACHE_INTERVAL );

				if ( is_admin() )
					$plugin_data = get_plugin_data( $this->cfg['paths']['plugin_dir_path'] . 'plugin.php' ); // Read plugin current version from the main plugin file

					if( isset($plugin_data) && count($plugin_data) > 0 ){

						if( (string)$xml->latest > (string)$plugin_data['Version']) { // Compare current plugin version with the remote XML version

						$wp_admin_bar->add_menu(
							array(
								'id' => 'plugin_update_notifier',
								'title' => '<span>' . ( $plugin_data['Name'] ) . ' <span id="ab-updates">New Updates</span></span>',
								'href' => get_admin_url() . 'index.php?page=' . ( $this->alias ) . '-plugin-update-notifier'
							)
						);
					}
				}
			}
		}

		public function get_latest_plugin_version($interval) {
			$base = array();
			$notifier_file_url = 'http://cc.aa-team.com/apps-versions/index.php?app=' . $this->alias;
			$db_cache_field = $this->alias . '_notifier-cache';
			$db_cache_field_last_updated = $this->alias . '_notifier-cache-last-updated';
			$last = get_option( $db_cache_field_last_updated );
			$now = time();

			// check the cache
			if ( !$last || (( $now - $last ) > $interval) ) {
				// cache doesn't exist, or is old, so refresh it
				if( function_exists('curl_init') ) { // if cURL is available, use it...
					$ch = curl_init($notifier_file_url);
					curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
					curl_setopt($ch, CURLOPT_HEADER, 0);
					curl_setopt($ch, CURLOPT_TIMEOUT, 10);
					$cache = curl_exec($ch);
					curl_close($ch);
				} else {
					// ...if not, use the common file_get_contents()
					$cache = file_get_contents($notifier_file_url);
				}

				if ($cache) {
					// we got good results
					update_option( $db_cache_field, $cache );
					update_option( $db_cache_field_last_updated, time() );
				}

				// read from the cache file
				$notifier_data = get_option( $db_cache_field );
			}
			else {
				// cache file is fresh enough, so read from it
				$notifier_data = get_option( $db_cache_field );
			}

			// Let's see if the $xml data was returned as we expected it to.
			// If it didn't, use the default 1.0 as the latest version so that we don't have problems when the remote server hosting the XML file is down
			if( strpos((string)$notifier_data, '<notifier>') === false ) {
				$notifier_data = '<?xml version="1.0" encoding="UTF-8"?><notifier><latest>1.0</latest><changelog></changelog></notifier>';
			}

			// Load the remote XML data into a variable and return it
			$xml = simplexml_load_string($notifier_data);

			return $xml;
		}


		// add admin js init
		public function createInstanceFreamwork ()
		{
			echo "<script type='text/javascript'>jQuery(document).ready(function ($) {
					/*var aiowaff = new aiowaff;
					aiowaff.init();*/
				});</script>";
		}

		/**
		 * Create plugin init
		 *
		 *
		 * @no-return
		 */
		public function initThePlugin()
		{
			// If the user can manage options, let the fun begin!
			if(is_admin() && current_user_can( 'manage_options' ) ){
				if(is_admin() && (!isset($_REQUEST['page']) || strpos($_REQUEST['page'],'codestyling') === false)){
					// Adds actions to hook in the required css and javascript
					add_action( "admin_print_styles", array( &$this, 'admin_load_styles') );
					add_action( "admin_print_scripts", array( &$this, 'admin_load_scripts') );
				}

				// create dashboard page
				add_action( 'admin_menu', array( &$this, 'createDashboardPage' ) );

				// get fatal errors
				add_action ( 'admin_notices', array( &$this, 'fatal_errors'), 10 );

				// get fatal errors
				add_action ( 'admin_notices', array( &$this, 'admin_warnings'), 10 );

				// number of requests made to the API
				add_action ( 'admin_notices', array( &$this, 'api_requests_show'), 10 );
				
				$section = isset( $_REQUEST['section'] ) ? $_REQUEST['section'] : '';
				$page = isset($_REQUEST['page']) ? $_REQUEST['page'] : '';
				if($page == $this->alias || strpos($page, $this->alias) == true && trim($section) != "" ) {
					add_action('init', array( &$this, 'go_to_section' ));
				}
			}
			
			// keep the plugin modules into storage
			if(!isset($_REQUEST['page']) || strpos($_REQUEST['page'],'codestyling') === false){
				$this->load_modules();
			}
		}

		public function go_to_section()
		{
			$section = isset( $_REQUEST['section'] ) ? $_REQUEST['section'] : '';
			if( trim($section) != "" ) {	
				header('Location: ' . sprintf(admin_url('admin.php?page=%s#!/%s'), $this->alias, $section) );
				exit();
			}
		}
		
		private function update_products_type ( $what='all' )
		{
            $config = $this->amz_settings;

			$products = array();
			
			$keyy = '_amzASIN';
			$_keyy = $keyy;
			if ( $_keyy == '_amzASIN' ) $keyy = '_aiowaff_prodid';
			
			// update all products 
			if( $what == 'all' ){
				$args = array(
					'post_type' => 'product',
					'fields' => 'ids',
					'meta_key' => $keyy,
					'posts_per_page' => '-1',
					'meta_query' => array(
				       array(
				           'key' => $keyy,
				           'value' => array(''),
        				   'compare' => 'NOT IN'
				       )
				   )
				);
				$query = new WP_Query($args);
				//var_dump('<pre>',$query,'</pre>'); die; 
				if( count($query->posts) > 0 ){
					foreach ($query->posts as $key => $value) {
						$products[] = $value;
                        
					}
				} 				
			}
			// custom product
			else{
				$products[] = $what;
			}
 
			if( count($products) > 0 ){
                $__p_type = ((isset($config['onsite_cart']) && $config['onsite_cart'] == "no") ? 'external' : 'simple');
				foreach ($products as $key => $value) {
				    $p_type = $__p_type;
					if( $p_type == 'simple' ){
						$args = array(
							'post_type' => 'product_variation',
							'posts_per_page' => '5',
							'post_parent' => $value
						);
						
						$query_variations = new WP_Query($args);
						
						if( $query_variations->post_count > 0 ){
							$p_type = 'variable';
						}
					}
  
                    update_option('_transient_wc_product_type_' . $value, $p_type);
                    //update_option('_transient_woocommerce_product_type_' . $value, 'external'); // doesn't seem to be used in woocommerce new version! /note on: 2015-07-14
					wp_set_object_terms( $value, $p_type, 'product_type');
				}
			}
		}
   
		public function fixPlusParseStr ( $input=array(), $type='string' )
		{
			if($type == 'array'){
				if(count($input) > 0){
					$ret_arr = array();
					foreach ($input as $key => $value){
						$ret_arr[$key] = str_replace("###", '+', $value);
					}

					return $ret_arr;
				}

				return $input;
			}else{
				return str_replace('+', '###', $input);
			}
		}

		// saving the options
		public function save_options ()
		{
			// remove action from request
			unset($_REQUEST['action']);

			// unserialize the request options
			$serializedData = $this->fixPlusParseStr(urldecode($_REQUEST['options']));

			$savingOptionsArr = array();

			parse_str($serializedData, $savingOptionsArr);
 
			$savingOptionsArr = $this->fixPlusParseStr( $savingOptionsArr, 'array');

			// create save_id and remote the box_id from array
			$save_id = $savingOptionsArr['box_id'];
			unset($savingOptionsArr['box_id']); 

			// Verify that correct nonce was used with time limit.
			if( ! wp_verify_nonce( $savingOptionsArr['box_nonce'], $save_id . '-nonce')) die ('Busted!');
			unset($savingOptionsArr['box_nonce']);
 
			// remove the white space before asin
			if( $save_id == 'aiowaff_amazon' ){
				$_savingOptionsArr = $savingOptionsArr;
				$savingOptionsArr = array();
				foreach ($_savingOptionsArr as $key => $value) {
					if( !is_array($value) ){
						// Check for and remove mistake in string after copy/paste keys 
						if( $key == 'AccessKeyID' || $key == 'SecretAccessKey' ) {
							if( stristr($value, 'AWSAccessKeyId=') !== false ) $value = str_ireplace('AWSAccessKeyId=', '', $value);
							if( stristr($value, 'AWSSecretKey=') !== false ) $value = str_ireplace('AWSSecretKey=', '', $value);
						}
						$savingOptionsArr[$key] = trim($value);
					}else{
						$savingOptionsArr[$key] = $value;
					}
				}
			}
            
            /*if ( $save_id == 'aiowaff_report' ) {
                $__old_saving = get_option('aiowaff_report', array());
                $__old_saving = maybe_unserialize(maybe_unserialize($__old_saving));
                $__old_saving = (array) $__old_saving;
                
                $savingOptionsArr["report"] = $__old_saving["report"];
            }*/
			
			// prepare the data for DB update
			$saveIntoDb = serialize( $savingOptionsArr );
			
			// Use the function update_option() to update a named option/value pair to the options database table. The option_name value is escaped with $wpdb->escape before the INSERT statement.
			update_option( $save_id, $saveIntoDb );
            
            //$this->amz_settings = $this->the_plugin->getAllSettings('array', 'amazon');
            //$this->amz_settings = @unserialize( get_option( $this->alias . '_amazon' ) );
			//$this->build_amz_settings();
			$this->settings();
			
			// check for onsite cart option 
			if( $save_id == $this->alias . '_amazon' ){
				$this->update_products_type( 'all' );
			}
			
			die(json_encode( array(
				'status' => 'ok',
				'html' 	 => 'Options updated successfully'
			)));
		}
		
		// saving the options
		public function install_default_options ()
		{
			// remove action from request
			unset($_REQUEST['action']);

			// unserialize the request options
			$serializedData = urldecode($_REQUEST['options']);
			
			$savingOptionsArr = array();
			parse_str($serializedData, $savingOptionsArr);
			
			// fix for setup
			if ( $savingOptionsArr['box_id'] == 'aiowaff_setup_box' ) {
				$serializedData = preg_replace('/box_id=aiowaff_setup_box&box_nonce=[\w]*&install_box=/', '', $serializedData);
				$savingOptionsArr['install_box'] = $serializedData;
				$savingOptionsArr['install_box'] = str_replace( "\\'", "\\\\'", $savingOptionsArr['install_box']);
			}
			  
			// create save_id and remote the box_id from array
			$save_id = $savingOptionsArr['box_id'];
			unset($savingOptionsArr['box_id']);

			// Verify that correct nonce was used with time limit.
			if( ! wp_verify_nonce( $savingOptionsArr['box_nonce'], $save_id . '-nonce')) die ('Busted!');
			unset($savingOptionsArr['box_nonce']);

			// default sql - tables & tables data!
			require_once( $this->cfg['paths']['plugin_dir_path'] . 'modules/setup_backup/default-sql.php');
			if ( $save_id != 'aiowaff_setup_box' ) {
				$savingOptionsArr['install_box'] = str_replace( '\"', '"', $savingOptionsArr['install_box']);
			}
			
			// convert to array
			$savingOptionsArr['install_box'] = str_replace('#!#', '&', $savingOptionsArr['install_box']);
			$savingOptionsArr['install_box'] = str_replace("'", "\'", $savingOptionsArr['install_box']); 
			$pullOutArray = json_decode( $savingOptionsArr['install_box'], true );
			if(count($pullOutArray) == 0){
				die(json_encode( array(
					'status' => 'error',
					'html' 	 => "Invalid install default json string, can't parse it!"
				)));
			}else{

				foreach ($pullOutArray as $key => $value){

					// prepare the data for DB update
					//$saveIntoDb = ( $value );
					
					//if( $saveIntoDb === true ){
					//	$saveIntoDb = 'true';
					//} else if( $saveIntoDb === false ){
					//	$saveIntoDb = 'false';
					//}

					// prepare the data for DB update
					$saveIntoDb = $value != "true" ? serialize( $value ) : $value;

					// Use the function update_option() to update a named option/value pair to the options database table. The option_name value is escaped with $wpdb->escape before the INSERT statement.
					update_option( $key, $saveIntoDb );
				}
				
				// update is_installed value to true 
				update_option( $this->alias . "_is_installed", 'true');

				die(json_encode( array(
					'status' => 'ok',
					'html' 	 => 'Install default successful'
				)));
			}
		}

		public function options_validate ( $input )
		{
			//var_dump('<pre>', $input  , '</pre>'); echo __FILE__ . ":" . __LINE__;die . PHP_EOL;
		}

		public function module_change_status ( $resp='ajax' )
		{
			// remove action from request
			unset($_REQUEST['action']);

			// update into DB the new status
			$db_alias = $this->alias . '_module_' . $_REQUEST['module'];
			update_option( $db_alias, $_REQUEST['the_status'] );

			if ( !isset($resp) || empty($resp) || $resp == 'ajax' ) {
				die(json_encode(array(
					'status' => 'ok'
				)));
			}
		}
		
		public function module_bulk_change_status ()
		{
			global $wpdb; // this is how you get access to the database

			$request = array(
				'id' 			=> isset($_REQUEST['id']) && !empty($_REQUEST['id']) ? trim($_REQUEST['id']) : ''
			);
 
			if (trim($request['id'])!='') {
				$__rq2 = array();
				$__rq = explode(',', $request['id']);
				if (is_array($__rq) && count($__rq)>0) {
					foreach ($__rq as $k=>$v) {
						$__rq2[] = (string) $v;
					}
				} else {
					$__rq2[] = $__rq;
				}
				$request['id'] = implode(',', $__rq2);
			}

			if (is_array($__rq2) && count($__rq2)>0) {
				foreach ($__rq2 as $kk=>$vv) {
					$_REQUEST['module'] = $vv;
					$this->module_change_status( 'non-ajax' );
				}
				
				die( json_encode(array(
					'status' => 'valid',
					'msg'	 => 'valid module change status Bulk'
				)) );
			}

			die( json_encode(array(
				'status' => 'invalid',
				'msg'	 => 'invalid module change status Bulk'
			)) );
		}

		// loading the requested section
		public function load_section ()
		{
			$request = array(
				'section' => isset($_REQUEST['section']) ? strip_tags($_REQUEST['section']) : false
			);
			
			if( isset($request['section']) && $request['section'] == 'insane_mode' ){
				die( json_encode(array(
					'status' => 'redirect',
					'url'	=> admin_url( 'admin.php?page=aiowaff_insane_import' )
				)));
			}
			
			// get module if isset
			if(!in_array( $request['section'], $this->cfg['activate_modules'])) die(json_encode(array('status' => 'err', 'msg' => 'invalid section want to load!')));

			$tryed_module = $this->cfg['modules'][$request['section']];
			if( isset($tryed_module) && count($tryed_module) > 0 ){
				// Turn on output buffering
				ob_start();

				$opt_file_path = $tryed_module['folder_path'] . 'options.php';
				if( is_file($opt_file_path) ) {
					require_once( $opt_file_path  );
				}
				$options = ob_get_clean(); //copy current buffer contents into $message variable and delete current output buffer

				if(trim($options) != "") {
					$options = json_decode($options, true);

					// Derive the current path and load up aaInterfaceTemplates
					$plugin_path = dirname(__FILE__) . '/';
					if(class_exists('aaInterfaceTemplates') != true) {
						require_once($plugin_path . 'settings-template.class.php');

						// Initalize the your aaInterfaceTemplates
						$aaInterfaceTemplates = new aaInterfaceTemplates($this->cfg);

						// then build the html, and return it as string
						$html = $aaInterfaceTemplates->bildThePage($options, $this->alias, $tryed_module);

						// fix some URI
						$html = str_replace('{plugin_folder_uri}', $tryed_module['folder_uri'], $html);
						
						if(trim($html) != "") {
							$headline = '';
							if( isset($tryed_module[$request['section']]['in_dashboard']['icon']) ){
								$headline .= '<img src="' . ($tryed_module['folder_uri'] . $tryed_module[$request['section']]['in_dashboard']['icon'] ) . '" class="aiowaff-headline-icon">';
							}
							$headline .= $tryed_module[$request['section']]['menu']['title'] . "<span class='aiowaff-section-info'>" . ( $tryed_module[$request['section']]['description'] ) . "</span>";
							
							$has_help = isset($tryed_module[$request['section']]['help']) ? true : false;
							if( $has_help === true ){
								
								$help_type = isset($tryed_module[$request['section']]['help']['type']) && $tryed_module[$request['section']]['help']['type'] ? 'remote' : 'local';
								if( $help_type == 'remote' ){
									$headline .= '<a href="#load_docs" class="aiowaff-show-docs" data-helptype="' . ( $help_type ) . '" data-url="' . ( $tryed_module[$request['section']]['help']['url'] ) . '" data-operation="help">HELP</a>';
								} 
							}
							
							$headline .= '<a href="#load_docs" class="aiowaff-show-feedback" data-helptype="' . ( 'remote' ) . '" data-url="' . ( $this->feedback_url ) . '" data-operation="feedback">Feedback</a>';
 
							die( json_encode(array(
								'status' 	=> 'ok',
								'headline'	=> $headline,
								'html'		=> 	$html
							)) );
						}

						die(json_encode(array('status' => 'err', 'msg' => 'invalid html formatter!')));
					}
				}
			}
		}

		public function fatal_errors()
		{
			// print errors
			if(is_wp_error( $this->errors )) {
				$_errors = $this->errors->get_error_messages('fatal');

				if(count($_errors) > 0){
					foreach ($_errors as $key => $value){
						echo '<div class="error"> <p>' . ( $value ) . '</p> </div>';
					}
				}
			}
		}

		public function admin_warnings()
		{
			// print errors
			if(is_wp_error( $this->errors )) {
				$_errors = $this->errors->get_error_messages('warning');
				
				$current = get_option( $this->alias . "_dismiss_notice", array() );
				$current = !empty($current) && is_array($current) ? $current : array();
				//$is_dissmised = get_option( $this->alias . "_dismiss_notice" );
				// recommanded theme
				$theme_name = wp_get_theme(); //get_current_theme() - deprecated notice!
				if( $theme_name != "Kingdom - Woocommerce Amazon Affiliates Theme" ){

					//if( 1 ){
					if( !isset($current['theme']) || !$current['theme'] ){
						$_errors = array('
							<div class="aiowaff-themes">
								<div class="aiowaff-themesimgs">

									<a href="https://themeforest.net/item/bravostore-wzone-affiliates-theme-for-wordpress/20701838?ref=AA-Team" target="_blank">
										<img src="' . ( $this->cfg['paths']['plugin_dir_url'] . 'bravostore-theme.jpg' ) . '" />
										<h3>BravoStore</h3>
									</a>

									<a href="http://themeforest.net/item/kingdom-woocommerce-amazon-affiliates-theme/15163199?ref=AA-Team" target="_blank">
										<img src="' . ( $this->cfg['paths']['plugin_dir_url'] . 'kingdom-theme.jpg' ) . '" />
										<h3>Kingdom</h3>
									</a>
									
									<a href="http://codecanyon.net/item/the-market-woozone-affiliates-theme/13469852?ref=AA-Team" target="_blank">
										<img src="' . ( $this->cfg['paths']['plugin_dir_url'] . 'themarket-theme.jpg' ) . '" />
										<h3>The Market</h3>
									</a> 
								</div>	
								<p>For the <strong>Best Possible User Experience with the WooAffiliates Plugin</strong> we highly Recommend using it in conjunction with any of the AA-Team custom Themes.</p>
							</div>
							<p>
								<strong>
									<a class="dismiss-notice" href="' . ( admin_url( 'admin-ajax.php?action=aiowaffDismissNotice&id=theme' ) ) . '" target="_parent">Dismiss this notice</a>
								</strong>
							</p>
						') ;
					}
				}

				// memory limit notice
				$memory = $this->let_to_num( WP_MEMORY_LIMIT );
				if ( $memory < 127108864 ) {
					if( !isset($current['memorylimit']) || !$current['memorylimit'] ){
						$_errors[] = '<p><strong style="color: red;">Current memory limit: ' . size_format( $memory ) . '</strong> | We recommend setting memory to at least 128MB. See: <a href="http://codex.wordpress.org/Editing_wp-config.php#Increasing_memory_allocated_to_PHP">Increasing memory allocated to PHP</a> | <a class="dismiss-notice" href="' . ( admin_url( 'admin-ajax.php?action=aiowaffDismissNotice&id=memorylimit' ) ) . '" target="_parent">Dismiss this notice</a></p>';
					}
				}

				// soap module notice
				if ( extension_loaded('soap') || class_exists("SOAPClient") || class_exists("SOAP_Client") ) {
				} else {
					if( !isset($current['soap']) || !$current['soap'] ){
						$_errors[] = '<p>Your server does not have the <a href="http://php.net/manual/en/class.soapclient.php">SOAP Client</a> class enabled - some gateway plugins which use SOAP may not work as expected. | <a class="dismiss-notice" href="' . ( admin_url( 'admin-ajax.php?action=aiowaffDismissNotice&id=soap' ) ) . '" target="_parent">Dismiss this notice</a></p>';
					}
				}

				// woocommerce pages/shortcodes check
				$check_pages = array(
					_x( 'Cart Page', 'Page setting', 'woocommerce' ) => array(
							'option' => 'woocommerce_cart_page_id',
							'shortcode' => '[' . apply_filters( 'woocommerce_cart_shortcode_tag', 'woocommerce_cart' ) . ']'
						),
					_x( 'Checkout Page', 'Page setting', 'woocommerce' ) => array(
							'option' => 'woocommerce_checkout_page_id',
							'shortcode' => '[' . apply_filters( 'woocommerce_checkout_shortcode_tag', 'woocommerce_checkout' ) . ']'
						),
				);
				if ( class_exists( 'WooCommerce' ) ) {
					
					foreach ( $check_pages as $page_name => $values ) {
  
						$page_id = get_option( $values['option'], false );
	
						// Page ID check
						if ( ! $page_id ) {
							$_errors[] = '<p>' . sprintf( __( 'You need to install default WooCommerce page: %s', 'woocommerce' ), $page_name ) . '.</p>';
						} else {
							// Shortcode check
							if ( $values['shortcode'] ) {
								$page = get_post( $page_id );
								$_wpnonce_untrash = wp_create_nonce( 'untrash-post_' . $page_id );
				
								//var_dump('<pre>',$page ,'</pre>'); 
								if ( empty( $page ) ) {
									if( !isset($current['pageinstall']) || !$current['pageinstall'] ){
										$_errors[] = '<p><strong>Cart / Checkout</strong> page does not exist. Please install Woocommerce default pages from <a href="' . admin_url('admin.php?page=wc-status&tab=tools') . '" target="_blank">here</a>. | <a class="dismiss-notice" href="' . ( admin_url( 'admin-ajax.php?action=aiowaffDismissNotice&id=pageinstall' ) ) . '" target="_parent">Dismiss this notice</a></p>';
									}
								} elseif ( ! strstr( $page->post_content, $values['shortcode'] ) ) {
									if( !isset($current['pageshortcode']) || !$current['pageshortcode'] ){
										$_errors[] = '<p>The <strong>' . $page->post_title . '</strong> page does not contain the shortcode: <strong>' . $values['shortcode'] . '</strong> | <a class="dismiss-notice" href="' . ( admin_url( 'admin-ajax.php?action=aiowaffDismissNotice&id=pageshortcode' ) ) . '" target="_parent">Dismiss this notice</a></p>';
									}
								} elseif ( $page->post_status == 'trash' ) {
									if( !isset($current['pagetrash']) || !$current['pagetrash'] ){
										$_errors[] = '<p>The <strong>' . $page->post_title . '</strong> Woocommerce default page is in trash. Please <a href="' . admin_url('post.php?post=' . $page_id . '&action=untrash&_wpnonce=' . $_wpnonce_untrash) . '">restore it</a>. | <a class="dismiss-notice" href="' . ( admin_url( 'admin-ajax.php?action=aiowaffDismissNotice&id=pagetrash' ) ) . '" target="_parent">Dismiss this notice</a></p>';
									}
								}
							}
			
						}
			
						//$_errors[] = '<p>#' . absint( $page_id ) . ' - ' . str_replace( home_url(), '', get_permalink( $page_id ) ) . '</p>';
					}
				}

				if(count($_errors) > 0){
					foreach ($_errors as $key => $value){
						echo '<div class="updated"> <p>' . ( $value ) . '</p> </div>';
					}
				}
			}
		}

		public function let_to_num($size) {
			if ( function_exists('wc_let_to_num') ) {
				return wc_let_to_num( $size );
			}

			$l = substr($size, -1);
			$ret = substr($size, 0, -1);
			switch( strtoupper( $l ) ) {
				case 'P' :
					$ret *= 1024;
				case 'T' :
					$ret *= 1024;
				case 'G' :
					$ret *= 1024;
				case 'M' :
					$ret *= 1024;
				case 'K' :
					$ret *= 1024;
			}
			return $ret;
		}

		/**
		 * Builds the config parameters
		 *
		 * @param string $function
		 * @param array	$params
		 *
		 * @return array
		 */
		protected function buildConfigParams($type, array $params)
		{
			// check if array exist
			if(isset($this->cfg[$type])){
				$params = array_merge( $this->cfg[$type], $params );
			}

			// now merge the arrays
			$this->cfg = array_merge(
				$this->cfg,
				array(	$type => array_merge( $params ) )
			);
		}

		/*
		* admin_load_styles()
		*
		* Loads admin-facing CSS
		*/
		public function admin_get_frm_style() {
			$css = array();

			if( isset($this->cfg['freamwork-css-files'])
				&& is_array($this->cfg['freamwork-css-files'])
				&& !empty($this->cfg['freamwork-css-files'])
			) {

				foreach ($this->cfg['freamwork-css-files'] as $key => $value){
					if( is_file($this->cfg['paths']['freamwork_dir_path'] . $value) ) {
						
						$cssId = $this->alias . '-' . $key;
						$css["$cssId"] = $this->cfg['paths']['freamwork_dir_path'] . $value;
						// wp_enqueue_style( $this->alias . '-' . $key, $this->cfg['paths']['freamwork_dir_url'] . $value );
					} else {
						$this->errors->add( 'warning', __('Invalid CSS path to file: <strong>' . $this->cfg['paths']['freamwork_dir_path'] . $value . '</strong>. Call in:' . __FILE__ . ":" . __LINE__ , $this->localizationName) );
					}
				}
			}
			return $css;
		}
		public function admin_load_styles()
		{
			global $wp_scripts;
            $protocol = is_ssl() ? 'https' : 'http';
			
			$javascript = $this->admin_get_scripts();
			
            // font awesome from CDN
            wp_enqueue_style( $this->alias . '-font-awesome', $protocol . '://maxcdn.bootstrapcdn.com/font-awesome/4.1.0/css/font-awesome.min.css' );

			$style_url = $this->cfg['paths']['freamwork_dir_url'] . 'load-styles.php';
			if( is_file( $this->cfg['paths']['freamwork_dir_path'] . 'load-styles.css' ) ){
				$style_url = str_replace(".php", '.css', $style_url);
			}
			wp_enqueue_style( 'aiowaff-aa-framework-styles', $style_url );
			
			if( in_array( 'jquery-ui-core', $javascript ) ) {
				$ui = $wp_scripts->query('jquery-ui-core');
				if ($ui) {
					$uiBase = "http://code.jquery.com/ui/{$ui->ver}/themes/smoothness";
					wp_register_style('jquery-ui-core', "$uiBase/jquery-ui.css", FALSE, $ui->ver);
					wp_enqueue_style('jquery-ui-core');
				}
			}
			if( in_array( 'thickbox', $javascript ) ) wp_enqueue_style('thickbox');
		}

		/*
		* admin_load_scripts()
		*
		* Loads admin-facing CSS
		*/
		public function admin_get_scripts() {
			$javascript = array();
			
			$current_url = isset($_SERVER["REQUEST_URI"]) ? $_SERVER["REQUEST_URI"] : '';
			$current_url = explode("wp-admin/", $current_url);
			if( count($current_url) > 1 ){ 
				$current_url = "/wp-admin/" . $current_url[1];
			}else{
				$current_url = "/wp-admin/" . $current_url[0];
			}
  
			if ( isset($this->cfg['modules'])
				&& is_array($this->cfg['modules']) && !empty($this->cfg['modules'])
			) {
			foreach( $this->cfg['modules'] as $alias => $module ){

				if( isset($module[$alias]["load_in"]['backend']) && is_array($module[$alias]["load_in"]['backend']) && count($module[$alias]["load_in"]['backend']) > 0 ){
					// search into module for current module base on request uri
					foreach ( $module[$alias]["load_in"]['backend'] as $page ) {
  
						$expPregQuote = ( is_array($page) ? false : true );
  						if ( is_array($page) ) $page = $page[0];

						$delimiterFound = strpos($page, '#');
						$page = substr($page, 0, ($delimiterFound!==false && $delimiterFound > 0 ? $delimiterFound : strlen($page)) );
						$urlfound = preg_match("%^/wp-admin/".($expPregQuote ? preg_quote($page) : $page)."%", $current_url);
						  
						if(
							// $current_url == '/wp-admin/' . $page
							( ( $page == '@all' ) || ( $current_url == '/wp-admin/admin.php?page=aiowaff' ) || ( !empty($page) && $urlfound > 0 ) )
							&& isset($module[$alias]['javascript']) ) {
  
							$javascript = array_merge($javascript, $module[$alias]['javascript']);
						}
					}
				}
			}
			} // end if
  
			$this->jsFiles = $javascript;
			return $javascript;
		}
		public function admin_load_scripts()
		{
			// very defaults scripts (in wordpress defaults)
			wp_enqueue_script( 'jquery' );
			
			$javascript = $this->admin_get_scripts();
			
			if( count($javascript) > 0 ){
				$javascript = @array_unique( $javascript );
  
				if( in_array( 'jquery-ui-core', $javascript ) ) wp_enqueue_script( 'jquery-ui-core' );
				if( in_array( 'jquery-ui-widget', $javascript ) ) wp_enqueue_script( 'jquery-ui-widget' );
				if( in_array( 'jquery-ui-mouse', $javascript ) ) wp_enqueue_script( 'jquery-ui-mouse' );
				if( in_array( 'jquery-ui-accordion', $javascript ) ) wp_enqueue_script( 'jquery-ui-accordion' );
				if( in_array( 'jquery-ui-autocomplete', $javascript ) ) wp_enqueue_script( 'jquery-ui-autocomplete' );
				if( in_array( 'jquery-ui-slider', $javascript ) ) wp_enqueue_script( 'jquery-ui-slider' );
				if( in_array( 'jquery-ui-tabs', $javascript ) ) wp_enqueue_script( 'jquery-ui-tabs' );
				if( in_array( 'jquery-ui-sortable', $javascript ) ) wp_enqueue_script( 'jquery-ui-sortable' );
				if( in_array( 'jquery-ui-draggable', $javascript ) ) wp_enqueue_script( 'jquery-ui-draggable' );
				if( in_array( 'jquery-ui-droppable', $javascript ) ) wp_enqueue_script( 'jquery-ui-droppable' );
				if( in_array( 'jquery-ui-datepicker', $javascript ) ) wp_enqueue_script( 'jquery-ui-datepicker' );
				if( in_array( 'jquery-ui-resize', $javascript ) ) wp_enqueue_script( 'jquery-ui-resize' );
				if( in_array( 'jquery-ui-dialog', $javascript ) ) wp_enqueue_script( 'jquery-ui-dialog' );
				if( in_array( 'jquery-ui-button', $javascript ) ) wp_enqueue_script( 'jquery-ui-button' );
				
				if( in_array( 'thickbox', $javascript ) ) wp_enqueue_script( 'thickbox' );
	
				// date & time picker
				if( !wp_script_is('jquery-timepicker') ) {
					if( in_array( 'jquery-timepicker', $javascript ) ) wp_enqueue_script( 'jquery-timepicker' , $this->cfg['paths']['freamwork_dir_url'] . 'js/jquery.timepicker.v1.1.1.min.js', array( 'jquery', 'jquery-ui-core', 'jquery-ui-datepicker', 'jquery-ui-slider' ) );
				}

				wp_enqueue_script( 'jquery-timepicker' , $this->cfg['paths']['freamwork_dir_url'] . 'js/sweetalert2.min.js', array( 'jquery', 'jquery-ui-core', 'jquery-ui-datepicker', 'jquery-ui-slider' ) );
			}
  
			if( count($this->cfg['freamwork-js-files']) > 0 ){
				foreach ($this->cfg['freamwork-js-files'] as $key => $value){

					if( is_file($this->cfg['paths']['freamwork_dir_path'] . $value) ){
						if( in_array( $key, $javascript ) ) wp_enqueue_script( $this->alias . '-' . $key, $this->cfg['paths']['freamwork_dir_url'] . $value );
					} else {
						$this->errors->add( 'warning', __('Invalid JS path to file: <strong>' . $this->cfg['paths']['freamwork_dir_path'] . $value . '</strong> . Call in:' . __FILE__ . ":" . __LINE__ , $this->localizationName) );
					}
				}
			}
		}

		/*
		 * Builds out the options panel.
		 *
		 * If we were using the Settings API as it was likely intended we would use
		 * do_settings_sections here. But as we don't want the settings wrapped in a table,
		 * we'll call our own custom wplanner_fields. See options-interface.php
		 * for specifics on how each individual field is generated.
		 *
		 * Nonces are provided using the settings_fields()
		 *
		 * @param array $params
		 * @param array $options (fields)
		 *
		 */
		public function createDashboardPage ()
		{
			add_menu_page(
				__( 'WooAffiliates', $this->localizationName ),
				__( 'WooAffiliates', $this->localizationName ),
				'manage_options',
				$this->alias,
				array( &$this, 'manage_options_template' ),
				$this->cfg['paths']['plugin_dir_url'] . 'icon_16.png'
			);
			
			add_submenu_page(
    			$this->alias,
    			$this->alias . " " . __('Plugin configuration', $this->localizationName),
	            __('Config', $this->localizationName),
	            'manage_options',
	            $this->alias . "&section=amazon",
	            array( $this, 'manage_options_template')
	        );
			
			//add_submenu_page(
    			//$this->alias,
    			//$this->alias . " " . __('Advanced Search', $this->localizationName),
	           // __('Amazon Search', $this->localizationName),
	           // 'manage_options',
	           // $this->alias . "&section=advanced_search",
	           // array( $this, 'manage_options_template')
	       // );
			
			//add_submenu_page(
    		//	$this->alias,
    			//$this->alias . " " . __('Import Insane Mode', $this->localizationName),
	          //  __('Insane Mode Import', $this->localizationName),
	         //   'manage_options',
	         //   $this->alias . "&section=insane_mode",
	         //   array( $this, 'insane_import_redirect')
	       // );
			
			//add_submenu_page(
    			//$this->alias,
    			//$this->alias . " " . __('CSV bulk products import', $this->localizationName),
	            //__('CSV import', $this->localizationName),
	            //'manage_options',
	            //$this->alias . "&section=csv_products_import",
	           // array( $this, 'manage_options_template')
	       // );
		}

		public function manage_options_template()
		{
			// Derive the current path and load up aaInterfaceTemplates
			$plugin_path = dirname(__FILE__) . '/';
			if(class_exists('aaInterfaceTemplates') != true) {
				require_once($plugin_path . 'settings-template.class.php');

				// Initalize the your aaInterfaceTemplates
				$aaInterfaceTemplates = new aaInterfaceTemplates($this->cfg);

				// try to init the interface
				$aaInterfaceTemplates->printBaseInterface();
			}
		}

		public function insane_import_redirect()
		{
			echo __FILE__ . ":" . __LINE__;die . PHP_EOL;   
		}

		/**
		 * Getter function, plugin config
		 *
		 * @return array
		 */
		public function getCfg()
		{
			return $this->cfg;
		}

		/**
		 * Getter function, plugin all settings
		 *
		 * @params $returnType
		 * @return array
		 */
		public function getAllSettings( $returnType='array', $only_box='', $this_call=false )
		{
			if( $this_call == true ){
				//var_dump('<pre>',$returnType, $only_box,'</pre>');  
			}
			$allSettingsQuery = "SELECT * FROM " . $this->db->prefix . "options where 1=1 and option_name REGEXP '" . ( $this->alias) . "_([a-z])';";
			if (trim($only_box) != "") {
				$allSettingsQuery = "SELECT * FROM " . $this->db->prefix . "options where 1=1 and option_name = '" . ( $this->alias . '_' . $only_box) . "' LIMIT 1;";
			}
			$results = $this->db->get_results( $allSettingsQuery, ARRAY_A);
			
			// prepare the return
			$return = array();
			if( count($results) > 0 ){
				foreach ($results as $key => $value){

					if($value['option_value'] == 'true'){
						$return[$value['option_name']] = true;
					}else{
						//$return[$value['option_name']] = @unserialize(@unserialize($value['option_value']));
						$return[$value['option_name']] = maybe_unserialize($value['option_value']);
						$return[$value['option_name']] = maybe_unserialize($return[$value['option_name']]);
					}
				}
			}

			if(trim($only_box) != "" && isset($return[$this->alias . '_' . $only_box])){
				$return = $return[$this->alias . '_' . $only_box];
			}
  
			if($returnType == 'serialize'){
				return serialize($return);
			}else if( $returnType == 'array' ){
				return $return;
			}else if( $returnType == 'json' ){
				return json_encode($return);
			}

			return false;
		}

		/**
		 * Getter function, all products
		 *
		 * @params $returnType
		 * @return array
		 */
		public function getAllProductsMeta( $returnType='array', $key='', $withPrefix=true, $ws='all' )
		{
			$_key = $key;
			if ( $_key == '_amzASIN' ) $key = '_aiowaff_prodid';
			$q_ws = '';
			if ( $ws != 'all' ) {
				$q_ws = " AND a.meta_value regexp '^$ws-' ";
			}

			// SELECT * FROM " . $this->db->prefix . "postmeta where 1=1 and meta_key='" . ( $key ) . "'
			$allSettingsQuery = "SELECT a.meta_value FROM " . $this->db->prefix . "postmeta AS a LEFT OUTER JOIN " . $this->db->prefix . "posts AS b ON a.post_id=b.ID WHERE 1=1 AND a.meta_key='" . ( $key ) . "' $q_ws AND !ISNULL(b.ID) AND b.post_type IN ('product', 'product_variation')";
			$results = $this->db->get_results( $allSettingsQuery, ARRAY_A);
			
			//"SELECT * FROM wp_postmeta where 1=1 and meta_key='_amzASIN'";
			//$deleteAllAmzMeta = "DELETE FROM " . $this->db->prefix . "postmeta where 1=1 and meta_key='" . ( $key ) . "'";
			//$delAmzMetaNow = $this->db->query( 
			//					$this->db->prepare( $deleteAllAmzMeta )
			//				);
			//echo $delAmzMetaNow;
			
			// prepare the return
			$return = array();
			if( count($results) > 0 ){
				foreach ($results as $key => $value){
					if(trim($value['meta_value']) != ""){
						$return[] = $value['meta_value'];
					}
				}
			}
			
			if ( !$withPrefix && ($_key == '_amzASIN') ) {
				$wslist = $this->get_ws_prefixes();
				foreach ($wslist as $wsprefix) {
					foreach ($return as $k => $v) {
						$return["$k"] = str_replace($wsprefix.'-', '', $return["$k"]);
					}
				}
			}

			if($returnType == 'serialize'){
				return serialize($return);
			}
			else if( $returnType == 'text' ){
				return implode("\n", $return);
			}
			else if( $returnType == 'array' ){
				return $return;
			}
			else if( $returnType == 'json' ){
				return json_encode($return);
			}

			return false;
		}

		/*
		* GET modules lists
		*/
		public function load_modules( $pluginPage='' )
		{
			$folder_path = $this->cfg['paths']['plugin_dir_path'] . 'modules/';
			$cfgFileName = 'config.php';

			// static usage, modules menu order
			$menu_order = array();

			$modules_list = glob($folder_path . '*/' . $cfgFileName);
			
			$nb_modules = count($modules_list);
			if ( $nb_modules > 0 ) {
				foreach ($modules_list as $key => $mod_path ) {

					$dashboard_isfound = preg_match("/modules\/dashboard\/config\.php$/", $mod_path);
					$depedencies_isfound = preg_match("/modules\/depedencies\/config\.php$/", $mod_path);
					
					if ( $pluginPage == 'depedencies' ) {
						if ( $depedencies_isfound!==false && $depedencies_isfound>0 ) ;
						else continue 1;
					} else {
						if ( $dashboard_isfound!==false && $dashboard_isfound>0 ) {
							unset($modules_list[$key]);
							$modules_list[$nb_modules] = $mod_path;
						}
					}
				}
			}
  
			foreach ($modules_list as $module_config ) {
				$module_folder = str_replace($cfgFileName, '', $module_config);

				// Turn on output buffering
				ob_start();

				if( is_file( $module_config ) ) {
					require_once( $module_config  );
				}
				$settings = ob_get_clean(); //copy current buffer contents into $message variable and delete current output buffer

				if(trim($settings) != "") {
					$settings = json_decode($settings, true);
					$settings_keys = array_keys($settings);
					$alias = (string)end($settings_keys);

					// create the module folder URI
					// fix for windows server
					$module_folder = str_replace( DIRECTORY_SEPARATOR, '/',  $module_folder );

					$__tmpUrlSplit = explode("/", $module_folder);
					$__tmpUrl = '';
					$nrChunk = count($__tmpUrlSplit);
					if($nrChunk > 0) {
						foreach ($__tmpUrlSplit as $key => $value){
							if( $key > ( $nrChunk - 4) && trim($value) != ""){
								$__tmpUrl .= $value . "/";
							}
						}
					}

					// get the module status. Check if it's activate or not
					$status = false;

					// default activate all core modules
					if ( $pluginPage == 'depedencies' ) {
						if ( $alias != 'depedencies' ) continue 1;
						else $status = true;
					} else {
						if ( $alias == 'depedencies' ) continue 1;
						
						if(in_array( $alias, $this->cfg['core-modules'] )) {
							$status = true;
						}else{
							// activate the modules from DB status
							$db_alias = $this->alias . '_module_' . $alias;
	
							if(get_option($db_alias) == 'true'){
								$status = true;
							}
						}
					}
  
					// push to modules array
					$this->cfg['modules'][$alias] = array_merge(array(
						'folder_path' 	=> $module_folder,
						'folder_uri' 	=> $this->cfg['paths']['plugin_dir_url'] . $__tmpUrl,
						'db_alias'		=> $this->alias . '_' . $alias,
						'alias' 		=> $alias,
						'status'		=> $status
					), $settings );

					// add to menu order array
					if(!isset($this->cfg['menu_order'][(int)$settings[$alias]['menu']['order']])){
						$this->cfg['menu_order'][(int)$settings[$alias]['menu']['order']] = $alias;
					}else{
						// add the menu to next free key
						$this->cfg['menu_order'][] = $alias;
					}

					// add module to activate modules array
					if($status == true){
						$this->cfg['activate_modules'][$alias] = true;
					}

					// load the init of current loop module
					$time_start = microtime(true);
					$start_memory_usage = (memory_get_usage());
					
					// in backend
					if( $this->is_admin === true && isset($settings[$alias]["load_in"]['backend']) ){
						
						$need_to_load = false;
						if( is_array($settings[$alias]["load_in"]['backend']) && count($settings[$alias]["load_in"]['backend']) > 0 ){
						
							$current_url = isset($_SERVER["REQUEST_URI"]) ? $_SERVER["REQUEST_URI"] : '';
							$current_url = explode("wp-admin/", $current_url);
							if( count($current_url) > 1 ){ 
								$current_url = "/wp-admin/" . $current_url[1];
							}else{
								$current_url = "/wp-admin/" . $current_url[0];
							}
							
							foreach ( $settings[$alias]["load_in"]['backend'] as $page ) {

								$expPregQuote = ( is_array($page) ? false : true );
  								if ( is_array($page) ) $page = $page[0];

								$delimiterFound = strpos($page, '#');
								$page = substr($page, 0, ($delimiterFound!==false && $delimiterFound > 0 ? $delimiterFound : strlen($page)) );
								$urlfound = preg_match("%^/wp-admin/".($expPregQuote ? preg_quote($page) : $page)."%", $current_url);
								
								$action = isset($_REQUEST['action']) ? $_REQUEST['action'] : '';
								$section = isset($_REQUEST['section']) ? $_REQUEST['section'] : '';
								if(
									// $current_url == '/wp-admin/' . $page ||
									( ( $page == '@all' ) || ( $current_url == '/wp-admin/admin.php?page=aiowaff' ) || ( !empty($page) && $urlfound > 0 ) )
									|| ( $action == 'aiowaffLoadSection' && $section == $alias )
									|| substr($action, 0, 3) == 'aiowaff'
								){
									$need_to_load = true;  
								}
							}
						}
  
						if( $need_to_load == false ){
							continue;
						}  
					}
					
					if( $this->is_admin === false && isset($settings[$alias]["load_in"]['frontend']) ){
						
						$need_to_load = false;
						if( $settings[$alias]["load_in"]['frontend'] === true ){
							$need_to_load = true;
						}
						if( $need_to_load == false ){
							continue;
						}  
					}

					// load the init of current loop module
					if( $status == true && isset( $settings[$alias]['module_init'] ) ){
						if( is_file($module_folder . $settings[$alias]['module_init']) ){
							//if( is_admin() ) {
								$current_module = array($alias => $this->cfg['modules'][$alias]);
								$GLOBALS['aiowaff_current_module'] = $current_module;
								 
								require_once( $module_folder . $settings[$alias]['module_init'] );

								$time_end = microtime(true);
								$this->cfg['modules'][$alias]['loaded_in'] = $time_end - $time_start;
								
								$this->cfg['modules'][$alias]['memory_usage'] = (memory_get_usage() ) - $start_memory_usage;
								if( (float)$this->cfg['modules'][$alias]['memory_usage'] < 0 ){
									$this->cfg['modules'][$alias]['memory_usage'] = 0.0;
								}
							//}
						}
					}
				}
			}
  
			// order menu_order ascendent
			ksort($this->cfg['menu_order']);
		}

		public function print_plugin_usages()
		{
			$html = array();
			
			$html[] = '<style>
				.aiowaff-bench-log {
					border: 1px solid #ccc; 
					width: 450px; 
					position: absolute; 
					top: 92px; 
					right: 2%;
					background: #95a5a6;
					color: #fff;
					font-size: 12px;
					z-index: 99999;
					
				}
					.aiowaff-bench-log th {
						font-weight: bold;
						background: #34495e;
					}
					.aiowaff-bench-log th,
					.aiowaff-bench-log td {
						padding: 4px 12px;
					}
				.aiowaff-bench-title {
					position: absolute; 
					top: 55px; 
					right: 2%;
					width: 425px; 
					margin: 0px 0px 0px 0px;
					font-size: 20px;
					background: #ec5e00;
					color: #fff;
					display: block;
					padding: 7px 12px;
					line-height: 24px;
					z-index: 99999;
				}
			</style>';
			
			$html[] = '<h1 class="aiowaff-bench-title">aiowaff: Benchmark performance</h1>';
			$html[] = '<table class="aiowaff-bench-log">';
			$html[] = 	'<thead>';
			$html[] = 		'<tr>';
			$html[] = 			'<th>Module</th>';
			$html[] = 			'<th>Loading time</th>';
			$html[] = 			'<th>Memory usage</th>';
			$html[] = 		'</tr>';
			$html[] = 	'</thead>';
			
			
			$html[] = 	'<tbody>';
			
			$total_time = 0;
			$total_size = 0;
			foreach ($this->cfg['modules'] as $key => $module ) {

				$html[] = 		'<tr>';
				$html[] = 			'<td>' . ( $key ) . '</td>';
				$html[] = 			'<td>' . ( number_format($module['loaded_in'], 4) ) . '(seconds)</td>';
				$html[] = 			'<td>' . (  $this->formatBytes($module['memory_usage']) ) . '</td>';
				$html[] = 		'</tr>';
			
				$total_time = $total_time + $module['loaded_in']; 
				$total_size = $total_size + $module['memory_usage']; 
			}

			$html[] = 		'<tr>';
			$html[] = 			'<td colspan="3">';
			$html[] = 				'Total time: <strong>' . ( $total_time ) . '(seconds)</strong><br />';			
			$html[] = 				'Total Memory: <strong>' . ( $this->formatBytes($total_size) ) . '</strong><br />';			
			$html[] = 			'</td>';
			$html[] = 		'</tr>';

			$html[] = 	'</tbody>';
			$html[] = '</table>';
			
			//echo '<script>jQuery("body").append(\'' . ( implode("\n", $html ) ) . '\')</script>';
			echo implode("\n", $html );
		}

		public function check_secure_connection ()
		{

			$secure_connection = false;
			if(isset($_SERVER['HTTPS']))
			{
				if ($_SERVER["HTTPS"] == "on")
				{
					$secure_connection = true;
				}
			}
			return $secure_connection;
		}


		/*
			helper function, image_resize
			// use timthumb
		*/
		public function image_resize ($src='', $w=100, $h=100, $zc=2)
		{
			// in no image source send, return no image
			if( trim($src) == "" ){
				$src = $this->cfg['paths']['freamwork_dir_url'] . '/images/no-product-img.jpg';
			}

			if( is_file($this->cfg['paths']['plugin_dir_path'] . 'timthumb.php') ) {
				return $this->cfg['paths']['plugin_dir_url'] . 'timthumb.php?src=' . $src . '&w=' . $w . '&h=' . $h . '&zc=' . $zc;
			}
		}

		/*
			helper function, upload_file
		*/
		public function upload_file ()
		{
			$slider_options = '';
			 // Acts as the name
            $clickedID = $_POST['clickedID'];
            // Upload
            if ($_POST['type'] == 'upload') {
                $override['action'] = 'wp_handle_upload';
                $override['test_form'] = false;
				$filename = $_FILES [$clickedID];

                $uploaded_file = wp_handle_upload($filename, $override);
                if (!empty($uploaded_file['error'])) {
                    echo json_encode(array("error" => "Upload Error: " . $uploaded_file['error']));
                } else {
                    echo json_encode(array(
							"url" => $uploaded_file['url'],
							"thumb" => ($this->image_resize( $uploaded_file['url'], $_POST['thumb_w'], $_POST['thumb_h'], $_POST['thumb_zc'] ))
						)
					);
                } // Is the Response
            }else{
				echo json_encode(array("error" => "Invalid action send" ));
			}

            die();
		}

		/**
		 * Getter function, shop config
		 *
		 * @params $returnType
		 * @return array
		 */
		public function getShopConfig( $section='', $key='', $returnAs='echo' )
		{
			if( empty($this->app_settings) ){
				$this->app_settings = $this->getAllSettings();
			}

			if( isset($this->app_settings[$this->alias . "_" . $section])) {
				if( isset($this->app_settings[$this->alias . "_" . $section][$key])) {
					if( $returnAs == 'echo' ) echo $this->app_settings[$this->alias . "_" . $section][$key];

					if( $returnAs == 'return' ) return $this->app_settings[$this->alias . "_" . $section][$key];
				}
			}
		}

		public function download_image( $file_url='', $pid=0, $action='insert', $product_title='', $step=0 )
		{
			if(trim($file_url) != ""){
				
				if( $this->amz_settings["rename_image"] == 'product_title' ){
					$image_name = sanitize_file_name($product_title);
					$image_name = preg_replace("/[^a-zA-Z0-9-]/", "", $image_name);
					$image_name = substr($image_name, 0, 200);
				}else{
					$image_name = uniqid();
				}
				
				// Find Upload dir path
				$uploads = wp_upload_dir();
				$uploads_path = $uploads['path'] . '';
				$uploads_url = $uploads['url'];

				$fileExt = explode(".", $file_url);
                $fileExt = end($fileExt);
				if ( !empty($file_ext) && preg_match('/(jpg|jpe|jpeg|gif|png)/ui', $file_ext, $m) ) {
					$fileExt = substr($fileExt, 0, 3);
				} else {
					$fileExt = 'jpg';
				}
				$filename = $image_name . "-" . ( $step ) . "." . $fileExt;
				
				// Save image in uploads folder
				$response = wp_remote_get( $file_url );
  
				if( !is_wp_error( $response ) ){
					$image = $response['body'];
					
					$image_url = $uploads_url . '/' . $filename; // URL of the image on the disk
					$image_path = $uploads_path . '/' . $filename; // Path of the image on the disk
					$ii = 0;
					while ( $this->verifyFileExists($image_path) ) {
						$filename = $image_name . "-" . ( $step );
						$filename .= '-'.$ii;
						$filename .= "." . $fileExt;
						
						$image_url = $uploads_url . '/' . $filename; // URL of the image on the disk
						$image_path = $uploads_path . '/' . $filename; // Path of the image on the disk
						$ii++;
					}

					// verify image hash
					$hash = md5($image);
					$hashFound = $this->verifyProdImageHash( $hash );
					if ( !empty($hashFound) && isset($hashFound->media_id) ) { // image hash not found!
					
						$orig_attach_id = $hashFound->media_id;
						// $attach_data = wp_get_attachment_metadata( $orig_attach_id );
						// $image_path = $uploads_path . '/' . basename($attach_data['file']);
						$image_path = $hashFound->image_path;

						// Add image in the media library - Step 3
						/*$wp_filetype = wp_check_filetype( basename( $image_path ), null );
						$attachment = array(
							'post_mime_type' => $wp_filetype['type'],
							'post_title'     => preg_replace( '/\.[^.]+$/', '', basename( $image_path ) ),
							'post_content'   => '',
							'post_status'    => 'inherit'
						);
	 
						// $attach_id = wp_insert_attachment( $attachment, $image_path, $pid  );
						require_once( ABSPATH . 'wp-admin/includes/image.php' );
						wp_update_attachment_metadata( $attach_id, $attach_data );*/
						
						return array(
							'attach_id' 		=> $orig_attach_id, // $attach_id,
							'image_path' 		=> $image_path,
							'hash'				=> $hash
						);
					}
					//write image if the wp method fails
					$has_wrote = $this->wp_filesystem->put_contents(
						$uploads_path . '/' . $filename, $image, FS_CHMOD_FILE
					);
					
					if( !$has_wrote ){
						file_put_contents( $uploads_path . '/' . $filename, $image );
					}

					// Add image in the media library - Step 3
					$wp_filetype = wp_check_filetype( basename( $image_path ), null );
					$attachment = array(
						// 'guid' 			=> $image_url,
						'post_mime_type' => $wp_filetype['type'],
						'post_title'     => preg_replace( '/\.[^.]+$/', '', basename( $image_path ) ),
						'post_content'   => '',
						'post_status'    => 'inherit'
					);
 
					$attach_id = wp_insert_attachment( $attachment, $image_path, $pid  ); 
					require_once( ABSPATH . 'wp-admin/includes/image.php' );
					$attach_data = wp_generate_attachment_metadata( $attach_id, $image_path );
					wp_update_attachment_metadata( $attach_id, $attach_data );
  
					return array(
						'attach_id' 		=> $attach_id,
						'image_path' 		=> $image_path,
						'hash'				=> $hash
					);
				}
				else{
					return array(
						'status' 	=> 'invalid',
						'msg' 		=> htmlspecialchars( implode(';', $response->get_error_messages()) )
					);
				}
			}
		}
		
		public function verifyProdImageHash( $hash ) {
			require( $this->cfg['paths']['plugin_dir_path'] . '/modules/assets_download/init.php' );
			$aiowaffAssetDownloadCron = new aiowaffAssetDownload();
			
			return $aiowaffAssetDownloadCron->verifyProdImageHash( $hash );
		}

		/*
        public function productPriceUpdate_frm()
		{
			$asin = isset($_REQUEST['asin']) ? $_REQUEST['asin'] : '';
			if( strlen($asin) == 10 ){
				// get product id by ASIN
				$product = $this->db->get_row( "SELECT * from {$this->db->prefix}postmeta where 1=1 and meta_key='_amzASIN' and meta_value='$asin' ", ARRAY_A );
				
				$post_id = (int)$product['post_id'];
				if( $post_id > 0 ){
					
					$amzProduct = $this->amzHelper->getProductDataFromAmazon( 'return', array(
					   'importProduct'     => 'no',
                    ));
					
					// set the product price
					$this->amzHelper->productPriceUpdate( $amzProduct, $post_id, true );
				}
			}
			
			return 'invalid';
		}
        */
        public function remove_gallery($content)
		{
				return str_replace('[gallery]', '', $content);
		}

		public function addNewProduct ( $retProd=array(), $pms=array() )
		{
		    $default_pms = array(
		    	'ws'					=> 'amazon',
		    
                'operation_id'          => '',
		    
                'import_to_category'    => 'amz',

                'import_images'         => isset($this->amz_settings["number_of_images"])
                    && (int) $this->amz_settings["number_of_images"] > 0
                    ? (int) $this->amz_settings["number_of_images"] : 'all',

                'import_variations'     => isset($this->amz_settings['product_variation'])
                    ? $this->amz_settings['product_variation'] : 'yes_5',

                'spin_at_import'        => isset($this->amz_settings['spin_at_import'])
                    && ($this->amz_settings['spin_at_import'] == 'yes') ? true : false,
                    
                'import_attributes'     => isset($this->amz_settings['item_attribute'])
                    && ($this->amz_settings['item_attribute'] == 'no') ? false : true,
            );
		    $pms = array_merge( $default_pms, $pms );
		    
            $durationQueue = array(); // Duration Queue
            $this->timer_start(); // Start Timer
            
            // status messages
			$this->opStatusMsgInit(array(
                'operation_id'  => $pms['operation_id'],
                'operation'     => 'add_prod',
            ));

			if(count($retProd) == 0) {
			    // status messages
			    $this->opStatusMsgSet(array(
                    'msg'       => sprintf( 'empty product array from %s!', $pms['ws']),
                    'duration'  => $this->timer_end(), // End Timer
                ));
				return false;
			}
			
			$default_import = !isset($this->amz_settings["default_import"])
                || ($this->amz_settings["default_import"] == 'publish')
                ? 'publish' : 'draft';
			$default_import = strtolower($default_import);

			$price_zero_import = isset($this->amz_settings["import_price_zero_products"])
                && $this->amz_settings["import_price_zero_products"] == 'yes'
                ? true : false;

			// verify if : amazon zero price product!
			if ( !$price_zero_import && $this->get_ws_object( $pms['ws'] )->productAmazonPriceIsZero( $retProd ) ) {
			    // status messages
                $this->opStatusMsgSet(array(
                    'msg'       => 'price is zero, so it is skipped!',
                    'duration'  => $this->timer_end(), // End Timer
                ));
				return false;
			}

			// verify if : merchant is "only_amazon" and product has amazon among its sellers
			$merchant_is_amazon_only_import = isset($this->amz_settings["merchant_setup"])
				&& 'only_amazon' == $this->amz_settings["merchant_setup"] 
				? true : false;

			if ( $merchant_is_amazon_only_import && ! $this->get_ws_object( $pms['ws'] )->product_has_amazon_seller( $retProd ) ) {
				// status messages
				$this->opStatusMsgSet(array(
					'msg'       => 'merchant setup is "only_amazon" and the product doesn\'t have amazon among its sellers!',
					'duration'  => $this->timer_end(), // End Timer
				));
				return false;
			}

			$product_desc = $this->product_build_desc( array_merge_recursive($retProd, array(
				'ws' 	=> $pms['ws'],
			)));
			$excerpt = isset($product_desc['short']) ? $product_desc['short'] : '';
			$desc = isset($product_desc['desc']) ? $product_desc['desc'] : '';

            /*
            // short description
   			if( $this->amz_settings['show_short_description'] == 'yes' ) {  
				// first 3 paragraph
				$excerpt = @explode("\n", @strip_tags( implode("\n", $retProd['Feature']) ) );
				$excerpt = @implode("\n", @array_slice($excerpt, 0, 3));
			}
            else {
				$excerpt = '';
			}
            
            // full description
            //$desc = (count($retProd["images"]) > 0 ? "[gallery]" : "") . "\n" . $retProd['EditorialReviews'] . "\n" . (count($retProd['Feature']) > 0 &&  is_array($retProd['Feature']) == true ? implode("\n", $retProd['Feature']) : '') . "\n" . '[amz_corss_sell asin="' . ( $retProd['ASIN'] ) . '"]';
            $__desc = array();
			//$__desc[] = (count($retProd["images"]) > 0 ? "[gallery]" : "");
			$__desc[] = ($retProd['hasGallery'] == 'true' ? "[gallery]" : "");
			if ( $pms['ws'] == 'amazon' ) {
				$__desc[] = !empty($retProd['EditorialReviews']) ? $retProd['EditorialReviews'] : '';
				$__desc[] = (count($retProd['Feature']) > 0 &&  is_array($retProd['Feature']) == true ? implode("\n", $retProd['Feature']) : '');
				$__desc[] = '[amz_corss_sell asin="' . ( $retProd['ASIN'] ) . '"]';
			} else {
				$__desc[] = isset($retProd['Description']) && !empty($retProd['Description']) ? $retProd['Description'] : '';
			}
			$desc = implode("\n", array_filter($__desc));
			*/
            
			$args = array(
				'post_title' 	=> $retProd['Title'],
				'post_status' 	=> $default_import,
				'post_content' 	=> $desc,
				'post_excerpt' 	=> $excerpt,
				'post_type' 	=> 'product',
				'menu_order' 	=> 0,
				'post_author' 	=> 1, //get_current_user_id()
			);

			$existProduct = amzStore_bulk_wp_exist_post_by_args($args);
			$metaPrefix = 'amzStore_product_';

			// check if post exists, if exist return array
			if ( $existProduct === false){
				$lastId = wp_insert_post($args);
                
                $duration = $this->timer_end(); // End Timer
                // status messages
                $this->opStatusMsgSet(array(
                    'status'    => 'valid',
                    'msg'       => 'product inserted with ID: ' . $lastId,
                    'duration'  => $duration,
                ));
			} else {
				$lastId = $existProduct['ID'];
                
                $duration = $this->timer_end(); // End Timer
                // status messages
                $this->opStatusMsgSet(array(
                    'status'    => 'valid',
                    'msg'       => 'product already exists with ID: ' . $lastId,
                    'duration'  => $duration,
                ));
			}

			apply_filters( 'aiowaff_after_product_import', $lastId );
  
            $durationQueue[] = $this->timer_end(); // End Timer
            $this->timer_start(); // Start Timer

			// spin post/product content!
			if ( $pms['spin_at_import'] ) {

			    $this->timer_start(); // Start Timer

				$replacements_nb = 10;
				if ( isset($this->amz_settings['spin_max_replacements']) )
					$replacements_nb = (int) $this->amz_settings['spin_max_replacements'];

				$this->spin_content(array(
					'prodID'		=> $lastId,
					'replacements'	=> $replacements_nb
				));
                
                $duration = $this->timer_end(); // End Timer
                $this->timer_start(); // Start Timer
                
                // status messages
                $this->opStatusMsgSet(array(
                    'status'    => 'valid',
                    'msg'       => 'spin content done',
                    'duration'  => $duration,
                ));
                
                // add last import report
                $this->add_last_imports('last_import_spin', array('duration' => $duration)); // End Timer & Add Report
			}

            // import images - just put images paths to assets table
			if( ( $pms['import_images'] === 'all' ) || ( (int) $pms['import_images'] > 0 ) ){

				// get product images
				$setImagesStatus = $this->get_ws_object( $pms['ws'] )->set_product_images( $retProd, $lastId, 0, $pms['import_images'] );
                
                $duration = $this->timer_end(); // End Timer
                $durationQueue[] = $duration; // End Timer
                $this->timer_start(); // Start Timer

                // status messages
                $this->opStatusMsgSet(array(
                    'status'    => 'valid',
                    'msg'       => $setImagesStatus['msg'],
                    'duration'  => $duration,
                ));
			}
            
            $durationQueue[] = $this->timer_end(); // End Timer
            $this->timer_start(); // Start Timer
 
            // import to category
            if($pms['import_to_category'] != 'amz'){
				
				$tocateg = $pms['import_to_category'];

                $final_categs = array();
				$final_categs[] = (int) $tocateg;
				
				$ancestors = get_ancestors( (int) $tocateg, 'product_cat' );  
				 
				if( count( $ancestors ) > 0 && is_array( $ancestors ) && $ancestors != '' ) {
					$final_categs = array_merge( $final_categs, $ancestors );    
				}
				 
				// set the post category
				wp_set_object_terms( $lastId, $final_categs, 'product_cat', true);

			}else{
			    $tocateg = $retProd['BrowseNodes'];

				// setup product categories
				$createdCats = $this->get_ws_object( $pms['ws'] )->set_product_categories( $tocateg );
				
				// Assign the post on the categories created
            	wp_set_post_terms( $lastId,  $createdCats, 'product_cat' );
			}
			
			// product tags
			if ( isset($retProd['Tags']) && !empty($retProd['Tags']) ) {
				// setup product tags
				$createdTags = $this->get_ws_object( $pms['ws'] )->set_product_tags( $retProd['Tags'] );
				
				// Assign the post on the categories created
				if ( !empty($createdTags) ) {
            		wp_set_post_terms( $lastId,  $createdTags, 'product_tag' );
				}
			}
            
            $duration = $this->timer_end(); // End Timer
            $durationQueue[] = $duration; // End Timer
            $this->timer_start(); // Start Timer
            
            // status messages
            $this->opStatusMsgSet(array(
                'status'    => 'valid',
                'msg'       => 'set product categories',
                'duration'  => $duration,
            ));
			
            // import attributes
			if( $pms['import_attributes'] ){
			    if ( count($retProd['ItemAttributes']) > 0 ) {
                    $this->timer_start(); // Start Timer
                }

				// add product attributes
				$this->get_ws_object( $pms['ws'] )->set_woocommerce_attributes( $retProd['ItemAttributes'], $lastId );
                
                if ( count($retProd['ItemAttributes']) > 0 ) {
                    $duration = $this->timer_end(); // End Timer
                    $this->timer_start(); // Start Timer
                
                    // status messages
                    $this->opStatusMsgSet(array(
                        'status'    => 'valid',
                        'msg'       => 'import attributes',
                        'duration'  => $duration,
                    ));

                    // add last import report
                    $this->add_last_imports('last_import_attributes', array(
                        'duration'      => $duration,
                    )); // End Timer & Add Report
                }
			}
            
			// than update the metapost
			$this->get_ws_object( $pms['ws'] )->set_product_meta_options( $retProd, $lastId, false );
            
            $duration = $this->timer_end(); // End Timer
            $durationQueue[] = $duration; // End Timer
            $this->timer_start(); // Start Timer
            
            // status messages
            $this->opStatusMsgSet(array(
                'status'    => 'valid',
                'msg'       => 'set product metas',
                'duration'  => $duration,
            ));

			// set the product price
			$this->get_ws_object( $pms['ws'] )->productPriceUpdate( $retProd, $lastId, false );
            
            $duration = $this->timer_end(); // End Timer
            $durationQueue[] = $duration; // End Timer
            $this->timer_start(); // Start Timer
            
            // status messages
            $this->opStatusMsgSet(array(
                'status'    => 'valid',
                'msg'       => 'product price update',
                'duration'  => $duration,
            ));
            
            // IMPORT PRODUCT VARIATIONS
			if( $pms['import_variations'] != 'no' && in_array($pms['ws'], array('amazon', 'ebay')) ){
			    $this->timer_start(); // Start Timer

                // current message
                $current_msg = $this->opStatusMsg['msg'];

				$setVariationsStatus = $this->get_ws_object( $pms['ws'] )->set_woocommerce_variations( $retProd, $lastId, $pms['import_variations'] );

                // don't add all variation adding texts to the final message!
                $this->opStatusMsg['msg'] = $current_msg;

                $duration = $this->timer_end(); // End Timer
                $this->timer_start(); // Start Timer
                
                // status messages
                $this->opStatusMsgSet(array(
                    'status'    => 'valid',
                    'msg'       => $setVariationsStatus['msg'],
                    'duration'  => $duration,
                ));

                // add last import report
                // ...done in amzHelper file
			}

			// set remote images
			if ( $this->is_remote_images && ( 'amazon' == $pms['ws'] ) ) {
				//$setRemoteImgStatus = $this->amzHelper->build_remote_images( $lastId );
				$setRemoteImgStatus = $this->get_ws_object( $pms['ws'] )->build_remote_images( $lastId );

				$duration = $this->timer_end(); // End Timer
				$this->timer_start(); // Start Timer
									
				// status messages
				$this->opStatusMsgSet(array(
					'status'    => 'valid',
					'msg'       => $setRemoteImgStatus['msg'],
					'duration'  => $duration,
				));
			}
            
            // Set the product type
            $this->update_products_type( $lastId );
            
            $duration = $this->timer_end(); // End Timer
            $durationQueue[] = $duration; // End Timer
            $this->timer_start(); // Start Timer
            
            // status messages
            $this->opStatusMsgSet(array(
                'status'    => 'valid',
                'msg'       => 'update products type',
                'duration'  => $duration,
            ));
            
            // ...any other executing code!

            $duration = $this->timer_end(); // End Timer
            $durationQueue[] = $duration; // End Timer
            $duration = round( array_sum($durationQueue), 4 ); // End Timer
            
            // status messages
            $this->opStatusMsgSet(array(
                'status'    => 'valid',
                'msg'       => 'product adding finished (duration is without time for spin, variations, attributes)',
                'duration'  => $duration,
                'end'       => true,
            ));

            // add last import report
            $this->add_last_imports('last_product', array(
                'duration'      => $duration,
            )); // End Timer & Add Report
            
			return $lastId;
		}

		public function updateWooProduct ( $retProd=array(), $rules=array(), $lastId=0 )
		{
			$provider = 'ebay';

			if(count($retProd) == 0) {
				return false;
			}

			$args_update = array();
			$args_update['ID'] = $lastId;
            
            // title
			if($rules['title'] == true) {
			    $args_update['post_title'] 	= $retProd['Title'];
            }

			/*            
            // short description
            if($rules['short_desc'] == true && $this->amz_settings['show_short_description'] == 'yes') {  
                // first 3 paragraph
                $excerpt = @explode("\n", @strip_tags( implode("\n", $retProd['Feature']) ) );
                $excerpt = @implode("\n", @array_slice($excerpt, 0, 3));
                $args_update['post_excerpt'] = $excerpt;
            }
            //else {
            //    $excerpt = '';
            //}
            
            // full description
            if($rules['desc'] == true) {
                //$desc = ($retProd['hasGallery'] == 'true' ? "[gallery]" : "") . "\n" . $retProd['EditorialReviews'] . "\n" . (count($retProd['Feature']) > 0 &&  is_array($retProd['Feature']) == true ? implode("\n", $retProd['Feature']) : '') . "\n" . '[amz_corss_sell asin="' . ( $retProd['ASIN'] ) . '"]';
	            $__desc = array();
				//$__desc[] = (count($retProd["images"]) > 0 ? "[gallery]" : "");
				$__desc[] = ($retProd['hasGallery'] == 'true' ? "[gallery]" : "");
				//if ( $provider == 'amazon' ) {
				//	$__desc[] = !empty($retProd['EditorialReviews']) ? $retProd['EditorialReviews'] : '';
				//	$__desc[] = (count($retProd['Feature']) > 0 &&  is_array($retProd['Feature']) == true ? implode("\n", $retProd['Feature']) : '');
				//	$__desc[] = '[amz_corss_sell asin="' . ( $retProd['ASIN'] ) . '"]';
				//} else {
					$__desc[] = isset($retProd['Description']) && !empty($retProd['Description']) ? $retProd['Description'] : '';
				//}
				$desc = implode("\n", array_filter($__desc));
			
                $args_update['post_content'] = $desc;
            }
            */
			// short OR full description - at least one of them
			$hasDesc = false;
			if($rules['short_desc'] == true && $this->amz_settings['show_short_description'] == 'yes')
				$hasDesc = true;
			if($rules['desc'] == true)
				$hasDesc = true;
    
			if ( $hasDesc ) {
				$current_asin = get_post_meta( $lastId, '_amzASIN', true );
				$current_asin = !empty($current_asin) ? (string) $current_asin : '';

				$current_post = get_post( $lastId, ARRAY_A );
				$parent_id = isset($current_post['post_parent']) ? $current_post['post_parent'] : 0;

				if ( $parent_id ) { // is variation child?
					$parent_post = get_post( $parent_id, ARRAY_A );

					$retProd = array_merge_recursive($retProd, array(
						'__parent_asin'			=> isset($retProd['ParentASIN']) ? $retProd['ParentASIN'] : '',
						'__parent_content'	=> isset($parent_post['post_content']) ? $parent_post['post_content'] : '',
					));
				}

				$product_desc = $this->product_build_desc($retProd);
				$excerpt = isset($product_desc['short']) ? $product_desc['short'] : '';
				$desc = isset($product_desc['desc']) ? $product_desc['desc'] : '';
			}

			// short description
			if($rules['short_desc'] == true && $this->amz_settings['show_short_description'] == 'yes') {
				$args_update['post_excerpt'] = $excerpt;
			}

			// full description
			if($rules['desc'] == true) {
				$args_update['post_content'] = $desc;
			}

			if ( $hasDesc ) {
				$is_variable = isset($retProd['Variations'], $retProd['Variations']['Item']);
    
				$desc_used = array();
				if ( $parent_id ) { // is variation child?
					$desc_used = get_post_meta( $parent_id, '_amzaff_desc_used', true );
				}
				else if ( $is_variable ) { // variable product
					$desc_used = get_post_meta( $lastId, '_amzaff_desc_used', true );
				}
				$desc_used = !empty($desc_used) && is_array($desc_used) && isset($desc_used['child_asin']) ? $desc_used : array();

				// is variation child?
				if ( $parent_id ) {
					$doit = false;
					if ( empty($desc_used) || empty($desc_used['child_asin']) )
						$doit = true;
					else {
						if ( $current_asin == $desc_used['child_asin'] ) {
							$doit = true;
						}
					}

					if ( $doit ) {
						$desc_used = array(
							'child_asin'					=> $current_asin,
							'date_done'				=> date("Y-m-d H:i:s"), // only for debug purpose
						);
   
						if ( !empty($desc_used) && isset($desc_used['child_asin']) ) {
							update_post_meta( $parent_id, '_amzaff_desc_used', $desc_used );
						}

						// update parent variation
						$parent_update = array();
						$parent_update['ID'] = $parent_id;
						if($rules['desc'] == true) {
							$parent_update['post_content'] = $desc;
						}
						if($rules['short_desc'] == true && $this->amz_settings['show_short_description'] == 'yes') {
							$parent_update['post_excerpt'] = $excerpt;
						}

						//var_dump('<pre>', $parent_update, '</pre>'); echo __FILE__ . ":" . __LINE__;die . PHP_EOL;
						if ( isset($parent_update['post_content']) || isset($parent_update['post_excerpt']) ) {;
							wp_update_post( $parent_update );
						}
					}
				}
				// parent variation OR non-variable product 
				else if ( $is_variable ) {
					$variations = isset($retProd['Variations']['Item']) ? $retProd['Variations']['Item'] : array();
					$found = false;
					foreach ( $variations as $variation ) {
						$asin = isset($variation['ASIN']) ? $variation['ASIN'] : '';
						//var_dump('<pre>',$asin, $desc_used['child_asin'],'</pre>');  
						if ( isset($desc_used['child_asin']) && ( $asin == $desc_used['child_asin'] ) )
							$found = true;
					}

					// variation child not found anymore => next sync will use another variation child to update desc
					if ( !$found ) {
						$desc_used = array(
							'child_asin'					=> '',
							'date_done'				=> date("Y-m-d H:i:s"), // only for debug purpose
						);
					}

					$__post_content = isset($args_update['post_excerpt']) ? $args_update['post_excerpt'] : '';
					$__post_content = trim( $__post_content );
					if ( $__post_content == '' || $found ) { // is empty => don't try to update
						if ( isset($args_update['post_excerpt']) )
							unset( $args_update['post_excerpt'] );
					}

					$__post_content = isset($args_update['post_content']) ? $args_update['post_content'] : '';
					$__post_content = preg_replace('/\[gallery\]/imu', '', $__post_content);
					$__post_content = preg_replace('/\[amz_corss_sell asin\=".*"\]/imu', '', $__post_content); // [amz_corss_sell asin="B01G7TG6SW"]
					$__post_content = trim( $__post_content );
					if ( $__post_content == '' || $found ) { // is empty => don't try to update
						if ( isset($args_update['post_content']) )
							unset( $args_update['post_content'] );
							
						if ( !empty($desc_used) && isset($desc_used['child_asin']) ) {
							update_post_meta( $lastId, '_amzaff_desc_used', $desc_used );
						}
					}
				}
			}

			// update the post if needed
			if(count($args_update) > 1){ // because ID is allways the same!
				wp_update_post( $args_update );
			}

			/*
			// than update the metapost
			if($rules['sku'] == true) {
			    update_post_meta($lastId, '_sku', $retProd['SKU']);
            }
			*/
			if($rules['url'] == true) {
				update_post_meta($lastId, '_product_url', home_url(sprintf(
					'/?redirect_prodid=%s',
					$this->prodid_set($retProd['ASIN'], $provider, 'add')
				)));
            }

			/*
            // reviews
			$tab_data = array();
			$tab_data[] = array(
				'id' => 'amzAff-customer-review',
				'content' => '<iframe src="' . ( isset($retProd['CustomerReviewsURL']) ? $retProd['CustomerReviewsURL'] : '' ) . '" width="100%" height="450" frameborder="0"></iframe>'
			); 
			if($rules['reviews'] == true) {
				if( isset($retProd['CustomerReviewsURL']) && @trim($retProd['CustomerReviewsURL']) != "" ) 
					update_post_meta($lastId, 'amzaff_woo_product_tabs', $tab_data);
			}
			*/

			if($rules['price'] == true){ 
				// set the product price
				$this->get_ws_object( $provider )->productPriceUpdate( $retProd, $lastId, false );
			}
			/*
			if($rules['sales_rank'] == true) {
    			update_post_meta($lastId, '_sales_rank', $retProd['SalesRank']);
            }
			*/

			return $lastId;
		}

		public function getAmzSimilarityProducts ( $asin, $return_nr=3, $force_update=false )
		{
			// add 1 fake return products, current product
			$return_nr = $return_nr + 1;

			$cache_valid_for = (60 * 60 * 24); // 24 hours in seconds

			// check for cache of this ASIN
			$cache_request = $this->db->get_row( $this->db->prepare( "SELECT * FROM " . ( $this->db->prefix ) . "amz_cross_sell WHERE ASIN = %s", $asin), ARRAY_A );

			// if cache found for this product
			if( $cache_request != "" && count($cache_request) > 0 && $force_update === false){
				// if cache still valid, return from mysql cache
				if( isset($cache_request['add_date']) || (strtotime($cache_request['add_date']) > (time() + $cache_valid_for)) ){

					$ret = array();
					// get products from DB cache amz_cross_sell table
					$products = @unserialize($cache_request['products']);

					return array_slice( $products, 0, $return_nr);
				}
			}
			
			$retProd = array();

			// load the amazon webservices client class
			require_once( $this->cfg['paths']['plugin_dir_path'] . '/lib/scripts/amazon/aaAmazonWS.class.php');

			// create new amazon instance
			$aaAmazonWS = new aaAmazonWS(
				$this->amz_settings['AccessKeyID'],
				$this->amz_settings['SecretAccessKey'],
				$this->amz_settings['country'],
				$this->main_aff_id()
			);
            $aaAmazonWS->set_the_plugin( $this );
			
			$similarity = $aaAmazonWS->responseGroup('Medium,ItemAttributes,Offers')->optionalParameters(array(
				'MerchantId' => 'Amazon',
				'Condition' => 'New'
			))->similarityLookup($asin);
            
			$thisProd = $aaAmazonWS->responseGroup('Large,OfferFull,Offers')->optionalParameters(array(
				'MerchantId' => 'Amazon',
				'Condition' => 'New'
			))->lookup($asin);
            
			if($thisProd['Items']['Request']["IsValid"] == "True" && isset($thisProd['Items']['Item']) && count($thisProd['Items']['Item']) > 0){
				$thisProd = $thisProd['Items']['Item'];

				// product large image
				$retProd[$thisProd['ASIN']]['thumb'] = $thisProd['SmallImage']['URL'];

				$retProd[$thisProd['ASIN']]['ASIN'] = $thisProd['ASIN'];

				// product title
				$retProd[$thisProd['ASIN']]['Title'] = isset($thisProd['ItemAttributes']['Title']) ? $thisProd['ItemAttributes']['Title'] : '';

				// product Manufacturer
				$retProd[$thisProd['ASIN']]['Manufacturer'] = isset($thisProd['ItemAttributes']['Manufacturer']) ? $thisProd['ItemAttributes']['Manufacturer'] : '';

				$retProd[$thisProd['ASIN']]['price'] = isset($thisProd['OfferSummary']['LowestNewPrice']['FormattedPrice']) ? preg_replace( "/[^0-9,.]/", "", $thisProd['OfferSummary']['LowestNewPrice']['FormattedPrice'] ) : '';
			}

			if($similarity['Items']["Request"]["IsValid"] == "True" && isset($similarity['Items']['Item']) && count($similarity['Items']['Item']) > 1){
				foreach ($similarity['Items']['Item'] as $key => $value){
					$thisProd = $value;

					if(count($similarity['Items']['Item']) > 0 && count($value) > 0 && isset($thisProd['ASIN']) && strlen($thisProd['ASIN']) >= 10 ){
						// product large image
						$retProd[$thisProd['ASIN']]['thumb'] = $thisProd['SmallImage']['URL'];

						$retProd[$thisProd['ASIN']]['ASIN'] = $thisProd['ASIN'];

						// product title
						$retProd[$thisProd['ASIN']]['Title'] = isset($thisProd['ItemAttributes']['Title']) ? $thisProd['ItemAttributes']['Title'] : '';

						// product Manufacturer
						$retProd[$thisProd['ASIN']]['Manufacturer'] = isset($thisProd['ItemAttributes']['Manufacturer']) ? $thisProd['ItemAttributes']['Manufacturer'] : '';

						$retProd[$thisProd['ASIN']]['price'] = isset($thisProd['OfferSummary']['LowestNewPrice']['FormattedPrice']) ? preg_replace( "/[^0-9,.]/", "", $thisProd['OfferSummary']['LowestNewPrice']['FormattedPrice'] ) : '';

						// remove if don't have valid price
						if( !isset($retProd[$thisProd['ASIN']]['price']) || trim($retProd[$thisProd['ASIN']]['price']) == "" ){
							@unlink($retProd[$thisProd['ASIN']]);
						}
					}
				}
			}

			// if cache not found for this product
			if( $cache_request == "" && count($cache_request) == 0 ){
				$this->db->insert(
					$this->db->prefix . "amz_cross_sell",
					array(
						'ASIN' 			=> $asin,
						'products' 		=> serialize(array_slice( $retProd, 0, $return_nr)),
						'nr_products'	=> $return_nr
					),
					array(
						'%s',
						'%s',
						'%d'
					)
				);
			}
			else{
				$this->db->update(
					$this->db->prefix . "amz_cross_sell",
					array(
						'products' 		=> serialize(array_slice( $retProd, 0, $return_nr)),
						'nr_products'	=> $return_nr
					),
					array( 'ASIN' => $asin ),
					array(
						'%s',
						'%s',
						'%d'
					)
				);
			}

			return array_slice( $retProd, 0, $return_nr);
		}

		public function cross_sell_box( $atts )
		{
			extract( shortcode_atts( array(
				'asin' => ''
			), $atts ) );

			$cross_selling = (isset($this->amz_settings["cross_selling"]) && $this->amz_settings["cross_selling"] == 'yes' ? true : false);
 			
			if( $cross_selling == false ) return '';

			global $product;

			// get product related items from Amazon
			$products = $this->getAmzSimilarityProducts( $asin );

			$backHtml = array();
			if( count($products) > 1 ){

				$backHtml[] = "<link rel='stylesheet' id='amz-cross-sell' href='" . ( $this->cfg['paths']['design_dir_url'] ) . "/cross-sell.css' type='text/css' media='all' />";

				$backHtml[] = '<div class="cross-sell">';
				$backHtml[] = 	'<h2>' . ( __('Frequently Bought Together', $this->localizationName ) ) . '</h2>';
				$backHtml[] = 	'<div style="margin-top: 0px;" class="separator"></div>';


				$backHtml[] = 	'<ul id="feq-products">';
				$cc = 0;
				$_total_price = 0;
				foreach ($products as $key => $value) {
					$value['price'] = str_replace(",", ".", $value['price']);
					$product_buy_url = $this->_product_buy_url( '', $value['ASIN'] );
					$prod_link = home_url('/?redirectAmzASIN=' . $value['ASIN'] );
					$prod_link = $product_buy_url;
					$backHtml[] = 	'<li>';
					$backHtml[] = 	'<a target="_blank" rel="nofollow" href="' . ( $prod_link ) . '">';
					$backHtml[] = 		'<img class="cross-sell-thumb" id="cross-sell-thumb-' . ( $value['ASIN'] ) . '" src="' . ( $value['thumb'] ) . '" alt="' . ( htmlentities( str_replace('"', "'", $value['Title']) ) ) . '">';
					$backHtml[] = 	'</a>';
					if( $cc < (count($products) - 1) ){
						$backHtml[] = 		'<div class="plus-sign">+</div>';
					}

					$backHtml[] = 	'</li>';

					$cc++;

					$_total_price = $_total_price + $value['price'];
				}

				$backHtml[] = 		'<li class="cross-sell-buy-btn">';
				$backHtml[] = 			'<span id="cross-sell-bpt">Price for all:</span>';
				$backHtml[] = 			'<span id="cross-sell-buying-price" class="price">' . ( woocommerce_price( $_total_price ) ) . '</span>';
				$backHtml[] = 			'<div style="clear:both"></div><a href="' . home_url(). '" id="cross-sell-add-to-cart"><img src="' . ( $this->cfg['paths']['freamwork_dir_url'] . 'images/btn_add-to-cart.png'  ) . '"/></a>';
				$backHtml[] = 		'</li>';
				$backHtml[] = 	'</ul>';

				$backHtml[] = '<div class="cross-sell-buy-selectable">';
				$backHtml[] = 	'<ul class="cross-sell-items">';
				$cc = 0;
				foreach ($products as $key => $value) {

					if( $cc == 0 ){
						$backHtml[] = 		'<li>';
						$backHtml[] = 			'<input type="checkbox" checked="checked" value="' . ( $value['ASIN'] ) . '">';
						$backHtml[] = 			'<div class="cross-sell-product-title"><strong>' . __('This item:', $this->localizationName) . ' </strong>' . $value['Title'] . '</div>';
						$backHtml[] = 			'<div class="cross-sell-item-price">' . ( woocommerce_price( $value['price'] ) ) . '</div>';
						$backHtml[] = 		'</li>';
					}
					else{
						$product_buy_url = $this->_product_buy_url( '', $value['ASIN'] );
						$prod_link = home_url('/?redirectAmzASIN=' . $value['ASIN'] );
						$prod_link = $product_buy_url;
						$backHtml[] = 		'<li>';
						$backHtml[] = 			'<input type="checkbox" checked="checked" value="' . ( $value['ASIN'] ) . '">';
						$backHtml[] = 			'<div class="cross-sell-product-title">' . ( '<a target="_blank" rel="nofollow" href="' . ( $prod_link ) . '">' . $value['Title'] .'</a>' ) . '</div>';
						$backHtml[] = 			'<div class="cross-sell-item-price">' . ( woocommerce_price( $value['price'] ) ) . '</div>';
						$backHtml[] = 		'</li>';
					}

					$cc++;
				}
				$backHtml[] = 	'</table>';

				$backHtml[] = '</div>';

				$backHtml[] = '</div>';

				$backHtml[] = '<div style="clear:both;"></div>';

				$backHtml[] = "<script type='text/javascript' src='" . ( $this->cfg['paths']['design_dir_url'] ) . "/cross-sell.js'></script>";
			}

			return isset($_total_price) && ($_total_price > 0 ) ? implode(PHP_EOL, $backHtml) : '';
		}
		
		/**
	    * HTML escape given string
	    *
	    * @param string $text
	    * @return string
	    */
	    public function escape($text)
	    {
	        $text = (string) $text;
	        if ('' === $text) return '';

	        $result = @htmlspecialchars($text, ENT_COMPAT, 'UTF-8');
	        if (empty($result)) {
	            $result = @htmlspecialchars(utf8_encode($text), ENT_COMPAT, 'UTF-8');
	        }

	        return $result;
	    }
		
		public function getBrowseNodes( $nodeid=0, $provider='amazon' )
		{
			if( !is_numeric($nodeid) ){
				return array(
					'status' 	=> 'invalid',
					'msg'		=> 'The $nodeid is not numeric: ' . $nodeid
				);
			}

			$prefix = 'ebay' == $provider ? '_' . $provider : '';
			$optname = $this->alias . $prefix . '_node_children_' . $nodeid;

			// try to get the option with this browsenode
			$nodes = get_option( $optname, false );
			
			// unable to find the node into cache, get live data
			if( !isset($nodes) || $nodes == false || count($nodes) == 0 ){
				$nodes = $this->get_ws_object( $provider )->browseNodeLookup( $nodeid );
 
 				if ( 'amazon' == $provider ) {

					if( isset($nodes['BrowseNodes']) && count($nodes['BrowseNodes']) > 0 ) {
						if( isset($nodes['BrowseNodes']['BrowseNode']['Children']['BrowseNode']) && count($nodes['BrowseNodes']['BrowseNode']['Children']['BrowseNode']) > 0 ){
		
							if( !isset($nodes['BrowseNodes']['BrowseNode']['Children']['BrowseNode'][1]['BrowseNodeId']) ){
								$nodes['BrowseNodes']['BrowseNode']['Children']['BrowseNode'] = array(
									$nodes['BrowseNodes']['BrowseNode']['Children']['BrowseNode']
								);
							}
							
							if( count($nodes['BrowseNodes']['BrowseNode']['Children']['BrowseNode']) > 0 ){
								$nodes = $nodes['BrowseNodes']['BrowseNode']['Children']['BrowseNode'];
								
								// store the cache into DB
								update_option( $optname, $nodes );
							}
						}
					}

				}
				else if ( 'ebay' == $provider ) {
					
					$childs = array();
					$lev1 = isset($nodes['CategoryArray']) ? $nodes['CategoryArray'] : array();
					if( !empty($lev1) ) {
						
						$lev2 = isset($lev1['Category']) ? $lev1['Category'] : array();
						if( !empty($lev2) ) {
							$lev3 = isset($lev2['CategoryID']) ? array($lev2) : $lev2;
							
							if ( !empty($lev3) ) {
								foreach ($lev3 as $key => $val) {
									// don't count the current nodeid / category
									if ($nodeid == $val['CategoryID']) continue 1;
									
									$childs[] = $val;
								}
							} // end lev3
						} // end lev2
					} // end lev1
					
					if ( !empty($childs) ) {
						// store the cache into DB
						$nodes = $childs;
						update_option( $optname, $nodes );
					}
				}
			}
			
			
			return $nodes; 
		}

		public function multi_implode($array, $glue) 
		{
		    $ret = '';
		
		    foreach ($array as $item) {
		        if (is_array($item)) {
		            $ret .= $this->multi_implode($item, $glue) . $glue;
		        } else {
		            $ret .= $item . $glue;
		        }
		    }
		
		    $ret = substr($ret, 0, 0-strlen($glue));
		
		    return $ret;
		}

		public function download_asset_lightbox( $prod_id=0, $from='default', $return='die' )
		{
            $requestData = array(
                'prod_id'   => isset($_REQUEST['prod_id']) ? $_REQUEST['prod_id'] : $prod_id,
                'from'      => isset($_REQUEST['from']) ? $_REQUEST['from'] : $from,
            );
            extract($requestData);

			$assets = $this->get_ws_object( 'generic' )->get_asset_by_postid( 'all', $prod_id, true );
			if ( count($assets) <= 0 ) {
				if( $return == 'die' ){
					die( json_encode(array(
						'status' => 'invalid',
						'html'	=> __("this product has no assets to be dowloaded!", $this->localizationName )
					)));
				} else {
					return __("this product has no assets to be dowloaded!", $this->localizationName );
				}
			}
            
            $css = array();
            $css['container'] = ( $from == 'default' ? 'aiowaff-asset-download-lightbox-properties' : 'aiowaff-asset-download-IM' );
			
			$html = array();
			$html[] = '<div class="aiowaff-asset-download-lightbox '.$css['container'].'">';
			$html[] = 	'<div class="aiowaff-donwload-in-progress-box">';
			$html[] = 		'<h1>' . __('Images download in progress ... ', $this->localizationName ) . '<a href="#" class="aiowaff-button red" id="aiowaff-close-btn">' . __('CLOSE', $this->localizationName ) . '</a></h1>';
			$html[] = 		'<p class="aiowaff-message aiowaff-info aiowaff-donwload-notice">';
			$html[] = 		__('Please be patient while the images are downloaded. 
			This can take a while if your server is slow (inexpensive hosting) or if you have many images. 
			Do not navigate away from this page until this script is done. 
			You will be notified via this box when the regenerating is completed.', $this->localizationName );
			$html[] = 		'</p>';
			
			$html[] = 		'<div class="aiowaff-process-progress-bar">';
			$html[] = 			'<div class="aiowaff-process-progress-marker"><span>0%</span></div>';
			$html[] = 		'</div>';
			
			$html[] = 		'<div class="aiowaff-images-tail">';
			$html[] = 			'<ul>';
			
			if( count($assets) > 0 ){
				foreach ($assets as $asset) {
					 
					$html[] = 		'<li data-id="' . ( $asset->id ) . '">';
					$html[] = 			'<img src="' . ( $asset->thumb ) . '">';
					$html[] = 		'</li>';	
				}
			} 
			
			$html[] = 			'</ul>';
			$html[] = 		'</div>';
			$html[] = 		'
			<script>
				jQuery(".aiowaff-images-tail ul").each(function(){
					
					var that = jQuery(this),
						lis = that.find("li"),
						size = lis.size();
					
					that.width( size *  86 );
				});
				jQuery(".aiowaff-images-tail ul").scrollLeft(0);
			</script>
			';
			
			$html[] = 		'<h2 class="aiowaff-process-headline">' . __('Debugging Information:', $this->localizationName ) . '</h2>';
			$html[] = 		'<table class="aiowaff-table aiowaff-debug-info">';
            if ( $from == 'default' ) {
			$html[] = 			'<tr>';
			$html[] = 				'<td width="150">' . __('Total Images:', $this->localizationName ) . '</td>';
			$html[] = 				'<td>' . ( count($assets) ) . '</td>';
			$html[] = 			'</tr>';
			$html[] = 			'<tr>';
			$html[] = 				'<td>' . __('Images Downloaded:', $this->localizationName ) . '</td>';
			$html[] = 				'<td class="aiowaff-value-downloaded">0</td>';
			$html[] = 			'</tr>';
			$html[] = 			'<tr>';
			$html[] = 				'<td>' . __('Downloaded Failures:', $this->localizationName ) . '</td>';
			$html[] = 				'<td class="aiowaff-value-failures">0</td>';
			$html[] = 			'</tr>';
            } else {
            $html[] =           '<tr>';
            $html[] =               '<td>' . __('Total Images:', $this->localizationName ) . '<span>' . ( count($assets) ) . '</span></td>';
            $html[] =               '<td>' . __('Images Downloaded:', $this->localizationName ) . '<span class="aiowaff-value-downloaded">0</span></td>';
            $html[] =               '<td>' . __('Downloaded Failures:', $this->localizationName ) . '<span class="aiowaff-value-failures">0</span></td>';
            $html[] =           '</tr>';
            }
			$html[] = 		'</table>';
			
			$html[] = 		'<div class="aiowaff-downoad-log">';
			$html[] = 			'<ol>';
			//$html[] = 				'<li>"One-size-fits-most-Tube-DressCoverup-Field-Of-Flowers-White-0" (ID 214) failed to resize. The error message was: The originally uploaded image file cannot be found at <code>/home/aateam30/public_html/cc/wp-plugins/woo-Amazon-payments/wp-content/uploads/2014/03/One-size-fits-most-Tube-DressCoverup-Field-Of-Flowers-White-0.jpg</code></li>';
			$html[] = 			'</ol>';
			$html[] = 		'</div>';
			$html[] = 	'</div>';
			$html[] = '</div>';
			
			if( $return == 'die' ){
				die( json_encode(array(
					'status' => 'valid',
					'html'	=> implode("\n", $html)
				)));
			}
			
			return implode("\n", $html);
		}
		
		
		/**
		 * Delete product assets
		 */
		public function product_assets_verify() {
 			if ( current_user_can( 'delete_posts' ) )
				add_action( 'delete_post', array($this, 'product_assets_delete'), 10 );
		}
		
		public function product_assets_delete($prod_id) {
			// verify we are in woocommerce product
			if ( is_object($prod_id) ) {
				$product = $prod_id;
			} else if( function_exists('wc_get_product') ){
				$product = wc_get_product( $prod_id );
			} else if( function_exists('get_product') ){
				$product = get_product( $prod_id );
			}

			if ( is_object($product) ) {
				$prod_id = 0;
				if ( method_exists( $product, 'get_id' ) ) {
					$prod_id = (int) $product->get_id();
				} else if ( isset($product->id) && (int) $product->id > 0 ) {
					$prod_id = (int) $product->id;
				}
				if ( $prod_id ) {
					require( $this->cfg['paths']['plugin_dir_path'] . '/modules/assets_download/init.php' );
					$aiowaffAssetDownloadCron = new aiowaffAssetDownload();

					return $aiowaffAssetDownloadCron->product_assets_delete( $prod_id );
				}
			}
		}


		/**
		 * Usefull
		 */
		
		//format right (for db insertion) php range function!
		public function doRange( $arr ) {
			$newarr = array();
			if ( is_array($arr) && count($arr)>0 ) {
				foreach ($arr as $k => $v) {
					$newarr[ $v ] = $v;
				}
			}
			return $newarr;
		}
		
		//verify if file exists!
		public function verifyFileExists($file, $type='file') {
			clearstatcache();
			if ($type=='file') {
				if (!file_exists($file) || !is_file($file) || !is_readable($file)) {
					return false;
				}
				return true;
			} else if ($type=='folder') {
				if (!is_dir($file) || !is_readable($file)) {
					return false;
				}
				return true;
			}
			// invalid type
			return 0;
		}
		
		// Return current Unix timestamp with microseconds
 		// Simple function to replicate PHP 5 behaviour
		public function microtime_float()
		{
			list($usec, $sec) = explode(" ", microtime());
			return ((float)$usec + (float)$sec);
		}
		
		public function formatBytes($bytes, $precision = 2) {
			$units = array('B', 'KB', 'MB', 'GB', 'TB');

			$bytes = max($bytes, 0);
			$pow = floor(($bytes ? log($bytes) : 0) / log(1024));
			$pow = min($pow, count($units) - 1);

			// Uncomment one of the following alternatives
			// $bytes /= pow(1024, $pow);
			$bytes /= (1 << (10 * $pow));

			return round($bytes, $precision) . ' ' . $units[$pow];
		}
		
		public function prepareForInList($v) {
			return "'".$v."'";
		}
        
        public function prepareForPairView($v, $k) {
            return sprintf("(%s, %s)", $k, $v);
        }
        
		public function db_custom_insert($table, $fields, $ignore=false, $wp_way=false) {
			if ( $wp_way && !$ignore ) {
				$this->db->insert( 
					$table, 
					$fields['values'], 
					$fields['format']
				);
			} else {
			
				$formatVals = implode(', ', array_map(array('aiowaff', 'prepareForInList'), $fields['format']));
				$theVals = array();
				foreach ( $fields['values'] as $k => $v ) $theVals[] = $k;

				$q = "INSERT " . ($ignore ? "IGNORE" : "") . " INTO $table (" . implode(', ', $theVals) . ") VALUES (" . $formatVals . ");";
				foreach ($fields['values'] as $kk => $vv)
					$fields['values']["$kk"] = esc_sql($vv);
  
				$q = vsprintf($q, $fields['values']);
				$r = $this->db->query( $q );
			}
		}

		public function verify_product_is_amazon_valid( $post_id ) {
			if ( empty($post_id) ) return false;

			$is_product_amazon = $this->verify_product_is_amazon( $post_id );
			return $is_product_amazon; 
		}
		
        public function is_prod_valid( $post_id ) {
            if ( empty($post_id) ) return false;

            $isProdAmz = $this->verify_product_isamazon($post_id);
            if ( empty($isProdAmz) ) return false;
            return true;
        }

		public function verify_product_isamazon($prod_id) {
			// verify we are in woocommerce product
			if ( is_object($prod_id) ) {
				$product = $prod_id;
			} else if( function_exists('wc_get_product') ){
				$product = wc_get_product( $prod_id );
			} else if( function_exists('get_product') ){
				$product = get_product( $prod_id );
			}

			if ( is_object($product) ) {
				$prod_id = 0;
				if ( method_exists( $product, 'get_id' ) ) {
					$prod_id = (int) $product->get_id();
				} else if ( isset($product->id) && (int) $product->id > 0 ) {
					$prod_id = (int) $product->id;
				}
				if ( $prod_id ) {
					// verify is amazon product!
					$asin = $this->get_post_meta($prod_id, '_amzASIN', true);

					if ( $asin!==false && strlen($asin) > 0 ) {
						return true;
					}
				}
			}
			return false;
		}
		
		public function verify_product_isvariation($prod_id) {
			// verify we are in woocommerce product
			if( function_exists('wc_get_product') || function_exists('get_product') ){
				$product = new WC_Product_Variable( $prod_id ); // WC_Product
  
				if ( is_object($product) ) {
					$prod_id = 0;
					if ( method_exists( $product, 'get_id' ) ) {
						$prod_id = (int) $product->get_id();
					} else if ( isset($product->id) && (int) $product->id > 0 ) {
						$prod_id = (int) $product->id;
					}
					if ( $prod_id ) {
						if ( $product->has_child() ) // is product variation parent!
							return true;
					}
				}
			}
			return false;
		}
		
		public function get_product_variations($prod_id) {
			// verify we are in woocommerce product
			if( function_exists('wc_get_product') || function_exists('get_product') ){
				$product = new WC_Product_Variable( $prod_id ); // WC_Product
  
				if ( is_object($product) ) {
					$prod_id = 0;
					if ( method_exists( $product, 'get_id' ) ) {
						$prod_id = (int) $product->get_id();
					} else if ( isset($product->id) && (int) $product->id > 0 ) {
						$prod_id = (int) $product->id;
					}
					if ( $prod_id ) {
						return $product->get_children();
					}
				}
			}
			return array();
		}
		
		/**
		 * spin post/product content
		 */
		public function spin_content( $req=array() ) {

			$request = array(
				'prodID'			=> isset($req['prodID']) ? $req['prodID'] : 0,
				'replacements' 		=> isset($req['replacements']) ? $req['replacements'] : 10
			);

			$ret = array(
				'status' => 'valid',
				'data' => array()
			);

			// spin content action
			require_once( $this->cfg['paths']["scripts_dir_path"] . '/php-query/phpQuery.php' );
			require_once( $this->cfg['paths']["scripts_dir_path"] . '/spin-content/spin.class.php' );

			if ( 1 ) {

				$lang = isset($this->amz_settings['main_aff_id']) ? $this->amz_settings['main_aff_id'] : 'en';
				$lang = strtolower( $lang );
			
				$spinner = aiowaffSpinner::getInstance();
				$spinner->set_syn_language( $lang );
				$spinner->set_replacements_number( $request['replacements'] );

				// first check if you have the original content saved into DB
				$post_content = get_post_meta( $request['prodID'], 'aiowaff_old_content', true );

				// if not, retrive from DB
				if( $post_content == false ){
					$live_post = get_post( $request['prodID'], ARRAY_A );
					$post_content = $live_post['post_content'];
				}

				$spinner->load_content( $post_content );
				$spin_return = $spinner->spin_content();
				$reorder_content = $spinner->reorder_synonyms();
				$fresh_content = $spinner->get_fresh_content( $reorder_content );
  
				update_post_meta( $request['prodID'], 'aiowaff_spinned_content', $spin_return['spinned_content'] );
				update_post_meta( $request['prodID'], 'aiowaff_reorder_content', $reorder_content );
				update_post_meta( $request['prodID'], 'aiowaff_old_content', $spin_return['old_content'] );
				update_post_meta( $request['prodID'], 'aiowaff_finded_replacements', $spin_return['finded_replacements'] );

				// Update the post into the database
				wp_update_post( array(
				      'ID'           => $request['prodID'],
				      'post_content' => $fresh_content
				) );
  
				$ret = array(
					'status' => 'valid',
					'data' => array(
						'reorder_content' => $reorder_content
					)
				);
			}
			return $ret;
		}


		/**
		 * setup module messages
		 */
		public function print_module_error( $module=array(), $error_number, $title="" )
		{
			$html = array();
			if( count($module) == 0 ) return true;
  
			$html[] = '<div class="aiowaff-grid_4 aiowaff-error-using-module">';
			$html[] = 	'<div class="aiowaff-panel">';
			$html[] = 		'<div class="aiowaff-panel-header">';
			$html[] = 			'<span class="aiowaff-panel-title">';
			$html[] = 				__( $title, $this->localizationName );
			$html[] = 			'</span>';
			$html[] = 		'</div>';
			$html[] = 		'<div class="aiowaff-panel-content">';
			
			$error_msg = isset($module[$module['alias']]['errors'][$error_number]) ? $module[$module['alias']]['errors'][$error_number] : '';
			
			$html[] = 			'<div class="aiowaff-error-details">' . ( $error_msg ) . '</div>';
			$html[] = 		'</div>';
			$html[] = 	'</div>';
			$html[] = '</div>';
			
			return implode("\n", $html);
		}
		
		public function convert_to_button( $button_params=array() )
		{
			$button = array();
			$button[] = '<a';
			if(isset($button_params['url'])) 
				$button[] = ' href="' . ( $button_params['url'] ) . '"';
			
			if(isset($button_params['target'])) 
				$button[] = ' target="' . ( $button_params['target'] ) . '"';
			
			$button[] = ' class="aiowaff-button';
			
			if(isset($button_params['color'])) 
				$button[] = ' ' . ( $button_params['color'] ) . '';
				
			$button[] = '"';
			$button[] = '>';
			
			$button[] =  $button_params['title'];
		
			$button[] = '</a>';
			
			return implode("", $button);
		}

		public function load_terms($taxonomy){
    		global $wpdb;
			
			$query = "SELECT DISTINCT t.name FROM {$wpdb->terms} AS t INNER JOIN {$wpdb->term_taxonomy} as tt ON tt.term_id = t.term_id WHERE 1=1 AND tt.taxonomy = '".esc_sql($taxonomy)."'";
    		$result =  $wpdb->get_results($query , OBJECT);
    		return $result;                 
		}
		
		public function get_current_page_url() {
			$url = (!empty($_SERVER['HTTPS']))
				?
				"https://" . $_SERVER['SERVER_NAME'] . $_SERVER['REQUEST_URI']
				:
				"http://" . $_SERVER['SERVER_NAME'] . $_SERVER['REQUEST_URI']
			;
			return $url;
		}
		
		// verbose translation from Symfony
		public function get_host() {
		    $possibleHostSources = array('HTTP_X_FORWARDED_HOST', 'HTTP_HOST', 'SERVER_NAME', 'SERVER_ADDR');
		    $sourceTransformations = array(
		    	// since PHP 4 >= 4.0.1, PHP 5, PHP 7
		        "HTTP_X_FORWARDED_HOST" => create_function('$value', '$elements = explode(",", $value); return trim(end($elements));'),

				// since PHP 5.3.0 (anonymous function)
		        //"HTTP_X_FORWARDED_HOST" => function($value) {
		        //    $elements = explode(',', $value);
		        //    return trim(end($elements));
		        //},
		    );
		    $host = '';
		    foreach ($possibleHostSources as $source)
		    {
		        if (!empty($host)) break;
		        if (empty($_SERVER[$source])) continue;
		        $host = $_SERVER[$source];
		        if (array_key_exists($source, $sourceTransformations))
		        {
		            $host = $sourceTransformations[$source]($host);
		        } 
		    }
		
		    // Remove port number from host
		    $host = preg_replace('/:\d+$/', '', $host);
		
		    return trim($host);
		}
		
		public function get_country_perip_external( $return_field='country' ) {
			//if ( isset($_COOKIE["aiowaff_country"]) && !empty($_COOKIE["aiowaff_country"]) ) {
			//	return unserialize($_COOKIE["aiowaff_country"]);
			//}
			
			$provider = $this->cur_provider; 
 
			//unset($_SESSION["aiowaff_country"]); // for debugging...
			if ( isset($_SESSION["aiowaff_country"], $_SESSION["aiowaff_country"]["$provider"])
				&& !empty($_SESSION["aiowaff_country"]["$provider"]) ) {
				if ( $return_field == 'country' ) {
					return unserialize($_SESSION["aiowaff_country"]["$provider"]);
				}
			}
            $ip = $this->get_client_ip();
                
			$config = $this->amz_settings;
			
			$paths = array(
				//'api.hostip.info'			=> 'http://api.hostip.info/country.php?ip={ipaddress}',
				'www.geoplugin.net'			=> 'http://www.geoplugin.net/json.gp?ip={ipaddress}',
				//'www.telize.com'			=> 'http://www.telize.com/geoip/{ipaddress}',
				'ipinfo.io'					=> 'http://ipinfo.io/{ipaddress}/geo',
			);
			
			$service_used = 'www.geoplugin.net';
			if ( isset($config['services_used_forip']) && !empty($config['services_used_forip']) ) {
				$service_used = $config['services_used_forip'];
			}
  
            $country = '';
            if ( $service_used == 'local_csv' ) { // local csv file with ip lists
                
                // read csv hash (string with ip from list)
                $csv_hash = file_get_contents( $this->cfg['paths']['plugin_dir_path'] . 'assets/GeoIPCountryWhois-hash.csv' );
                $csv_hash = explode(',', $csv_hash);
                
                // read csv full (ip from, ip to, country)
                $csv_full = file_get_contents( $this->cfg['paths']['plugin_dir_path'] . 'assets/GeoIPCountryWhois-full.csv' );
                $csv_full = explode(PHP_EOL, $csv_full);
                
                //var_dump('<pre>',count($csv_hash), count($csv_full),'</pre>');
                //var_dump('<pre>',$csv_hash, $csv_full,'</pre>');

                $ip2number = $this->ip2number( $ip );
                //var_dump('<pre>', $ip, $ip2number, '</pre>');
                
                $ipHashIndex = $this->binary_search($ip2number, $csv_hash, array($this, 'binary_search_cmp'));
                if ( $ipHashIndex < 0 ) { // verify if is between (ip_from, ip_to) of csv row
                    $ipHashIndex = abs( $ipHashIndex );
                    $ipFullRow = $csv_full["$ipHashIndex"];
                    $csv_row = explode(',', $ipFullRow);
                    if ( $ip2number >= $csv_row[0] && $ip2number <= $csv_row[1] ) {
                        $country = $csv_row[2];
                    }
                } else { // exact match in the list as ip_from of csv row
                    $ipFullRow = $csv_full["$ipHashIndex"];
                    $country = end( explode(',', $ipFullRow) );
                }

                if (empty($country)) {
                    //$main_aff_site = $this->main_aff_site();
                    //$country = strtoupper(str_replace(".", '', $main_aff_site));
                    $country = 'NOT-FOUND';
                }
                $country = strtoupper( $country );

                //var_dump('<pre>', $ipHashIndex, $ipFullRow, $country, '</pre>');
                //echo __FILE__ . ":" . __LINE__;die . PHP_EOL;
                
            } else { // external service
			
    			$service_url = $paths["$service_used"];
    			$service_url = str_replace('{ipaddress}', $ip, $service_url);
    
    			$get_user_location = wp_remote_get( $service_url );
    			if ( isset($get_user_location->errors) ) {
    				//$main_aff_site = $this->main_aff_site();
    				//$country = strtoupper(str_replace(".", '', $main_aff_site));
    				$country = 'NOT-FOUND';
    			} else {
						$country = $get_user_location['body'];

						$country = json_decode($country);
						if ( ! is_object($country) ) $country = 'NOT-FOUND';
						else {
							switch ($service_used) {
								//case 'api.hostip.info':
								//	break;
									
								case 'www.geoplugin.net':
									//$country = json_decode($country);
									$country = isset($country->geoplugin_countryCode) ? strtoupper( (string)$country->geoplugin_countryCode ) : 'NOT-FOUND';
									break;
									
								//case 'www.telize.com':
								//	//$country = json_decode($country);
								//	$country = strtoupper( $country->country_code );
								//	break;
									
								case 'ipinfo.io':
									//$country = json_decode($country);
									$country = isset($country->country) ? strtoupper( (string)$country->country ) : 'NOT-FOUND';
									break;
									
								default:
									break;
							}
						}
    			}
            }
			
			if ( $return_field == 'country' ) {
				$user_country = $this->amzForUser($country);
                //var_dump('<pre>',$user_country,'</pre>');
 
				//$this->cookie_set(array(
				//	'name'			=> 'aiowaff_country',
				//	'value'			=> serialize($user_country),
				//	'expire_sec'	=> strtotime( '+30 days' ) // time() + 604800, // 1 hour = 3600 || 1 day = 86400 || 1 week = 604800
				//));
				$_SESSION['aiowaff_country']["$provider"] = serialize($user_country);
				return $user_country;
			}
		}

		public function lang_init() 
		{ 
		    load_plugin_textdomain( $this->alias, false, $this->cfg['paths']["plugin_dir_path"] . '/languages/');
		} 
		
		public function delete_zeropriced_products_all( $retType = 'die' )
		{
			$key = '_amzASIN';
			$_key = $key;
			if ( $_key == '_amzASIN' ) $key = '_aiowaff_prodid';

			//$prod_id = $_REQUEST['pid'];
			$ret = array();
			$args = array();
			$args['post_type'] = 'product';
   
			$args['meta_key'] = $key;
			$args['meta_value'] = '';
			$args['meta_compare'] = '!=';
	
			// show all posts
			//$args['fields'] = 'ids';
			$args['posts_per_page'] = '-1';
			
			$loop = new WP_Query( $args );
			$cc = 0;
			$ret = array();
			while ( $loop->have_posts() ) : $loop->the_post();
				global $post;
  
				$post = (int) $post->ID;

	            $sale_price = get_post_meta( $post, '_sale_price', true );
				$regular_price = get_post_meta( $post, '_regular_price', true );	
				$price = get_post_meta( $post, '_price', true );
			
				if( $regular_price == '' && $price == '' ){
					$cc++;
					//if regular price is not set or it`s zero, put the post into trash 
					wp_trash_post( $post );
				}
			endwhile;
   
			$ret['status'] = 'valid';
			if( $cc == 0 ) {
				$ret['msg_html'] = 'No zero priced posts found.';
			} else {
				$ret['msg_html'] = $cc.' posts moved to trash!';
			}
			  
			if ( $retType == 'die' ) die(json_encode($ret));
			else return $ret;
		}

		public function cookie_set( $cookie_arr = array() ) {
			extract($cookie_arr);
			if ( !isset($path) )
				$path = '/';
			if ( !isset($domain) )
				$domain = ($_SERVER['HTTP_HOST'] != 'localhost') ? $_SERVER['HTTP_HOST'] : false;
        	$stat = setcookie($name, $value, $expire_sec, $path, $domain);
			return $stat;
		}
		public function cookie_del( $cookie_arr = array() ) {
			extract($cookie_arr);
			if ( !isset($path) )
				$path = '/';
			if ( !isset($domain) )
				$domain = ($_SERVER['HTTP_HOST'] != 'localhost') ? $_SERVER['HTTP_HOST'] : false;
			setcookie($name, null, strtotime('-1 day'), $path, $domain);
		}
		
        public function get_client_ip() {
            $ipaddress = '';

            if ($_SERVER['REMOTE_ADDR'])
                $ipaddress = $_SERVER['REMOTE_ADDR'];
            else if ($_SERVER['HTTP_CLIENT_IP'])
                $ipaddress = $_SERVER['HTTP_CLIENT_IP'];
            else if ($_SERVER['HTTP_X_FORWARDED'])
                $ipaddress = $_SERVER['HTTP_X_FORWARDED'];
            else if ($_SERVER['HTTP_FORWARDED_FOR'])
                $ipaddress = $_SERVER['HTTP_FORWARDED_FOR'];
            else if( $_SERVER['HTTP_FORWARDED'])
                $ipaddress = $_SERVER['HTTP_FORWARDED'];
            else if ($_SERVER['HTTP_X_FORWARDED_FOR'])
                $ipaddress = $_SERVER['HTTP_X_FORWARDED_FOR'];

            return $ipaddress;
        }

        public function ip2number( $ip ) {
            $long = ip2long($ip);
            if ($long == -1 || $long === false) {
                return false;
            }
            return sprintf("%u", $long);
        }
        
        public function verify_module_status( $module='' ) {
            if ( empty($module) ) return false;

            $mod_active = get_option( 'aiowaff_module_'.$module );
            if ( $mod_active != 'true' )
                return false; //module is inactive!
            return true;
        }

        public function last_update_date($format=false, $last_date=false, $year=false) {
            if ( $last_date === '' ) return $last_date;
            if ( $last_date === false ) $last_date = time();
            if ( !$format ) return $last_date;
            
            $date_format = 'D j M / H.i';
            if ( $year ) $date_format = 'D j M Y / H.i';
            return date($date_format, $last_date); // Mon 2 Feb / 13.21
        }
    
        public function set_content_type($content_type){
            return 'text/html';
        }

        public function category_nice_name__($categ_name) {
            $ret = $categ_name;

            $special = array('DVD' => 'DVD', 'MP3Downloads' => 'MP3 Downloads', 'PCHardware' => 'PC Hardware', 'VHS' => 'VHS');
            if ( !in_array($categ_name, array_keys($special)) ) {
                $ret = preg_replace('/([A-Z])/', ' $1', $categ_name);
            } else {
                $ret = $special["$categ_name"];
            }
            return $ret;
        }

        // This function works exactly how encodeURIComponent is defined:
        // encodeURIComponent escapes all characters except the following: alphabetic, decimal digits, - _ . ! ~ * ' ( )
        public function encodeURIComponent($str) {
            $revert = array('%21'=>'!', '%2A'=>'*', '%27'=>"'", '%28'=>'(', '%29'=>')');
            return strtr(rawurlencode($str), $revert);
        }

        /**
         * Parameters: 
         *   $key - The key to be searched for.
         *   $list - The sorted array. 
         *   $compare_func - A user defined function for comparison. Same definition as the one in usort
         *   $low - First index of the array to be searched (local parameters).
         *   $high - Last index of the array to be searched (local parameters). 
         *
         * Return:
         *   index of the search key if found, otherwise return -(insert_index + 1). 
         *   insert_index is the index of greatest element that is smaller than $key or count($list) if $key
         *   is larger than all elements in the array.
         * 
         * License: Feel free to use the code if you need it.
         */
        public function binary_search($key, array $list, $compare_func) {
            $low = 0; 
            $high = count($list) - 1;
     
            while ($low <= $high) {
                $mid = (int) (($high - $low) / 2) + $low; // could use php ceil function
                $cmp = call_user_func($compare_func, $list[$mid], $key);
     
                if ($cmp < 0) {
                    $low = $mid + 1;
                } else if ($cmp > 0) {
                    $high = $mid - 1;
                } else {
                    return $mid;
                }
            }
            return -($low - 1);
        }
        public function binary_search_cmp($a, $b) {
            return ($a < $b) ? -1 : (($a > $b) ? 1 : 0);
        }
    
        /**
         * Insane Mode - Last Imports Stats / Duration
         */
        public function get_last_imports( $what='all' ) {
            $ret = array();
            $cfg = get_option('aiowaff_insane_last_reports', array());

            $def = array(
                // duration in miliseconds
                'request_amazon'                    => 1000, // request product from amazon
                'request_cache'                     => 10, // request product from cache
                'last_product'                      => 1500, // product without the bellow options
                //'last_import_images'                => 1200, // add images to assets table
                'last_import_images_download'       => 2500, // download images
                'last_import_variations'            => 1500, // import variations
                'last_import_spin'                  => 650, // spin post content
                'last_import_attributes'            => 2300, // import attributes
            );
            foreach ($def as $key => $val) {
                $def["$key"] = array(
                    'items' => array(
                        array( 'duration' => $val ),
                    ),
                );
            }

            foreach ($def as $key => $val) {
                // default
                if ( !isset($cfg["$key"], $cfg["$key"]['items']) || !is_array($cfg["$key"]['items'])
                    || empty($cfg["$key"]['items']) ) {
                    
                    $cfg["$key"] = $def["$key"];
                }
            }
            foreach ($cfg as $key => $val) {

                $media = array();
                foreach ($val['items'] as $key2 => $val2) {
                    
                    $duration = $val2['duration'];
                    if ( isset($val2['nb_items']) && (int) $val2['nb_items'] > 0 ) {
                        $nb_items = (int) $val2['nb_items'];
                        $media[] = round( $duration / $nb_items, 4 );
                    } else {
                        $media[] = round( $duration, 4 );
                    }
                }
                $media = !empty($media) ? round( array_sum($media) / count($media), 4 ) : 0;
                
                $cfg["$key"]["media"] = array('duration' => $media);
            }

            $ret = $cfg;
            //var_dump('<pre>', $ret, '</pre>'); die('debug...'); 
            return $ret;
        }
        
        public function add_last_imports( $what='all', $new=array() ) {
            if ( $what === 'all' || empty($new) ) return false;

            $max_last_keep = in_array($what, array('last_import_images_download', 'last_import_variations')) ? 10 : 5;
            $ret = array();
            $cfg = get_option('aiowaff_insane_last_reports', array());
            
            if ( !isset($cfg["$what"], $cfg["$what"]['items']) || !is_array($cfg["$what"]['items']) ) {

                $cfg["$what"] = array(
                    'items'     => array()
                );
            }
            
            if ( count($cfg["$what"]['items']) >= $max_last_keep ) {
                array_shift($cfg["$what"]['items']); // remove oldes maintained log regarding import
            }
            // add new latest log regarding import
            $cfg["$what"]['items'][] = $new;
            
            update_option('aiowaff_insane_last_reports', $cfg);
        }
        
        public function timer_start() {
            $this->timer->start();
        }
        public function timer_end( $debug=false ) {
            $this->timer->end( $debug );
            $duration = $this->timer->getRenderTime(1, 0, false);
            return $duration;
        }
        
        public function format_duration( $duration, $precision=1 ) {
            $prec = $this->timer->getUnit( $precision );
            $ret = $duration . ' ' . $prec;
            $ret = '<i>' . $ret . '</i>';
            return $ret;
        }
        
        public function save_amazon_request_time() {
            $time = microtime(true);
            update_option('aiowaff_last_amazon_request_time', $time);
			
			$nb = get_option('aiowaff_amazon_request_number', 0);
			update_option('aiowaff_amazon_request_number', (int)($nb+1));
            return true;
        }
        public function verify_amazon_request_rate( $do_pause=true ) {
            $ret = array('status' => 'valid'); // valid = no need for pause! 

            $rate = isset($this->amz_settings['amazon_requests_rate']) ? $this->amz_settings['amazon_requests_rate'] : 1;
            $rate = (float) $rate;
            $rate_milisec = $rate > 0.00 && (int)$rate != 1 ? 1000 / $rate : 1000; // interval between requests in miliseconds
            $rate_milisec = floatval($rate_milisec);

            $current = microtime(true);
            $last = get_option('aiowaff_last_amazon_request_time', 0);
            $elapsed = round(($current - $last) * pow(10, 3), 0); // time elapsed from the last amazon requests
 
            // we may need to pause
            if ( $elapsed < $rate_milisec ) {
                if ( $do_pause ) {
                    $pause_microsec = ( $rate_milisec - $elapsed ) + 30; // here is in miliseconds - add 30 miliseconds to be sure
                    $pause_microsec = $pause_microsec * 1000; // pause in microseconds
                    usleep( $pause_microsec );
                }
            }
            return $ret;
        }
		public function get_amazon_request_number() {
			$nb = get_option('aiowaff_amazon_request_number', 0);
			return $nb;
		}
		
        /**
         * cURL / Send http requests with curl
         */
        public static function curl($url, $input_params=array(), $output_params=array(), $debug=false) {
            $ret = array('status' => 'invalid', 'http_code' => 0, 'data' => '');

            // build curl options
            $ipms = array_replace_recursive(array(
                'userpwd'                   => false,
                'htaccess'                  => false,
                'post'                      => false,
                'postfields'                => array(),
                'httpheader'				=> false,
                'verbose'                   => false,
                'ssl_verifypeer'            => false,
                'ssl_verifyhost'            => false,
                'httpauth'                  => false,
                'failonerror'               => false,
                'returntransfer'            => true,
                'binarytransfer'            => false,
                'header'                    => false,
                'cainfo'                    => false,
                'useragent'                 => false,
            ), $input_params);
            extract($ipms);
            
            $opms = array_replace_recursive(array(
                'resp_is_json'              => false,
                'resp_add_http_code'        => false,
                'parse_headers'             => false,
            ), $output_params);
            extract($opms);
            
            //var_dump('<pre>', $ipms, $opms, '</pre>'); die('debug...'); 

            // begin curl
            $url = trim($url);
            if (empty($url)) return (object) $ret;
            
            $curl = curl_init();
            curl_setopt($curl, CURLOPT_URL, $url);
            
            if ( !empty($userpwd) ) {
                curl_setopt($curl, CURLOPT_USERPWD, $userpwd);
            }
            if ( !empty($htaccess) ) {
                $url = preg_replace( "/http(|s):\/\//i", "http://" . $htaccess . "@", $url );
            }
            if (!$post && !empty($postfields)) {
                $url = $url . "?" . http_build_query($postfields);
            }

            if ($post) {
                curl_setopt($curl, CURLOPT_POST, true);
                curl_setopt($curl, CURLOPT_POSTFIELDS, $postfields);
            }
			
			if ( !empty($httpheader) ) {
				curl_setopt($curl, CURLOPT_HTTPHEADER, $httpheader);
			}
            
            curl_setopt($curl, CURLOPT_VERBOSE, $verbose);
            curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, $ssl_verifypeer);
            curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, $ssl_verifyhost);
            if ( $httpauth!== false ) curl_setopt($curl, CURLOPT_HTTPAUTH, $httpauth);
            curl_setopt($curl, CURLOPT_FAILONERROR, $failonerror);
            curl_setopt($curl, CURLOPT_RETURNTRANSFER, $returntransfer);
            curl_setopt($curl, CURLOPT_BINARYTRANSFER, $binarytransfer);
            curl_setopt($curl, CURLOPT_HEADER, $header);
            if ( $cainfo!== false ) curl_setopt($curl, CURLOPT_CAINFO, $cainfo);
            if ( $useragent!== false ) curl_setopt($curl, CURLOPT_USERAGENT, $useragent);
            if ( $timeout!== false ) curl_setopt($curl, CURLOPT_TIMEOUT, $timeout);
            
            $data = curl_exec($curl);
            $http_code = (int) curl_getinfo($curl, CURLINFO_HTTP_CODE);
            
            $ret = array_merge($ret, array('http_code' => $http_code));
            if ($debug) {
                $ret = array_merge($ret, array('debug_details' => curl_getinfo($curl)));
            }
            if ( $data === false || curl_errno($curl) ) { // error occurred
                $ret = array_merge($ret, array(
                    'data' => curl_errno($curl) . ' : ' . curl_error($curl)
                ));
            } else { // success
            
                if ( $parse_headers ) {
                    $header_size = curl_getinfo($curl, CURLINFO_HEADER_SIZE);
                    $headers = self::parse_headers__( substr($data, 0, $header_size) ); // response begin with the headers
                    $data = substr($data, $header_size);
                    $ret = array_merge($ret, array('headers' => $headers));
                }
        
                // Add the status code to the json data, useful for error-checking
                if ( $resp_add_http_code && $resp_is_json ) {
                    $data = preg_replace('/^{/', '{"http_code":'.$http_code.',', $data);
                }
                
                $ret = array_merge($ret, array(
                    'status'    => 'valid',
                    'data'       => $data
                ));
            }

            curl_close($curl);
            return $ret;
        }
        private static function parse_headers__($headers) {
            if (!is_array($headers)) {
                $headers = explode("\r\n", $headers);
            }
            $ret = array();
            foreach ($headers as $header) {
                $header = explode(":", $header, 2);
                if (count($header) == 2) {
                    $ret[$header[0]] = trim($header[1]);
                }
            }
            return $ret;
        }
    
	
		/**
		 * 2015, October fixes including attributes after woocommerce version 2.4.0!
		 */
		public function cleanValue($value) {
			// Format Camel Case
			//$value = trim( preg_replace('/([A-Z])/', ' $1', $value) );

			// Clean / from value
			$value = trim( preg_replace('/(\/)/', '-', $value) );
			return $value;
		}
		
		public function cleanTaxonomyName($value, $withPrefix=true) {
			$ret = $value;
			
			// Sanitize taxonomy names. Slug format (no spaces, lowercase) - uses sanitize_title
			if ( $withPrefix ) {
				$ret = wc_attribute_taxonomy_name($value); // return 'pa_' . $value
			} else {
				// return $value
				$ret = function_exists('wc_sanitize_taxonomy_name')
					? wc_sanitize_taxonomy_name($value) : woocommerce_sanitize_taxonomy_name($value);
			}
			$limit_max = $withPrefix ? 32 : 29; // 29 = 32 - strlen('pa_')
			
			// limit to 32 characters (database/ table wp_term_taxonomy/ field taxonomy/ is limited to varchar(32) )
			return substr($ret, 0, $limit_max);

			return $ret;
		}
	
		public function get_woocommerce_version() {
			$ver = '';
			$is_found = false;

			// try to find version
			if ( !$is_found && defined('WC_VERSION') ) {
				$ver = WC_VERSION;
				$is_found = true;
			}

			if ( !$is_found ) {
				global $woocommerce;
				if ( is_object($woocommerce) && isset($woocommerce->version) && !empty($woocommerce->version) ) {
					$ver = $woocommerce->version;
					$is_found = true;
				}
			}
			
			if ( !$is_found ) {
				// If get_plugins() isn't available, require it
				if ( !function_exists( 'get_plugins' ) ) {
					require_once( ABSPATH . 'wp-admin/includes/plugin.php' );
				}
				
				foreach (array('envato-wordpress-toolkit', 'woocommerce') as $folder) {
					// Create the plugins folder and file variables
					$plugin_folder = get_plugins( '/'.$folder );
					$plugin_file = 'woocommerce.php';
		
					// If the plugin version number is set, return it 
					if ( isset( $plugin_folder[$plugin_file]['Version'] )
						&& !empty($plugin_folder[$plugin_file]['Version']) ) {

						$ver = $plugin_folder[$plugin_file]['Version'];
						$is_found = true;
						break;
					}
				}
			}
			return $ver;
		}
		public function force_woocommerce_product_version($ver_prod, $ver_min='2.4.0', $ver_ret=false) {
			// min version compare
			$ret = $ver_prod;
			if( version_compare( $ver_prod, $ver_min, "<" ) ) {
				$ret = $ver_ret ? $ver_ret : $ver_min;
			}
			return $ret;
		}
		
		public function get_main_settings( $provider='all' ) {
			$amz_settings = $this->amz_settings;
			$providers = array(
				'amazon'	=> array(
					'title'		=> __( 'Amazon Settings', $this->localizationName ),
					'mandatory'	=> array('AccessKeyID', 'SecretAccessKey', 'country', 'main_aff_id'),
					'keys'		=> array(
						'AccessKeyID'		=> array(
							'title'				=> __( 'Access Key ID',$this->localizationName ),
							'value'				=> '',
						),
						'SecretAccessKey'		=> array(
							'title'				=> __( 'Secret Access Key',$this->localizationName ),
							'value'				=> '',
						),
						'country'		=> array(
							'title'				=> __( 'Amazon location',$this->localizationName ),
							'value'				=> '',
						),
						'main_aff_id'		=> array(
							'title'				=> __( 'Main Affiliate ID',$this->localizationName ),
							'value'				=> '',
						),
						'AffiliateID'		=> array(
							'title'				=> __( 'Affiliate IDs',$this->localizationName ),
							'value'				=> '',
						),
					),
				),
				
				'ebay'	=> array(
					'title'		=> __( 'EBay Settings', $this->localizationName ),
					'mandatory'	=> array('ebay_DEVID', 'ebay_AppID', 'ebay_CertID', 'ebay_country', 'ebay_main_aff_id'),
					'keys'		=> array(
						'ebay_DEVID'		=> array(
							'title'				=> __( 'DEVID',$this->localizationName ),
							'value'				=> '',
						),
						'ebay_AppID'		=> array(
							'title'				=> __( 'AppID',$this->localizationName ),
							'value'				=> '',
						),
						'ebay_CertID'		=> array(
							'title'				=> __( 'CertID',$this->localizationName ),
							'value'				=> '',
						),
						'ebay_country'		=> array(
							'title'				=> __( 'Ebay location',$this->localizationName ),
							'value'				=> '',
						),
						'ebay_main_aff_id'		=> array(
							'title'				=> __( 'Main Affiliate ID',$this->localizationName ),
							'value'				=> '',
						),
						'ebay_AffiliateID'		=> array(
							'title'				=> __( 'Affiliate campid IDs',$this->localizationName ),
							'value'				=> '',
						),
					),
				),
				
				'alibaba'	=> array(
					'title'		=> __( 'Alibaba Settings', $this->localizationName ),
					'mandatory'	=> array('alibaba_AppKey', 'alibaba_TrackingID', 'alibaba_DigitalSignature'),
					'keys'		=> array(
						'alibaba_AppKey'		=> array(
							'title'				=> __( 'App Key',$this->localizationName ),
							'value'				=> '',
						),
						'alibaba_TrackingID'		=> array(
							'title'				=> __( 'Tracking ID',$this->localizationName ),
							'value'				=> '',
						),
						'alibaba_DigitalSignature'		=> array(
							'title'				=> __( 'Digital Signature',$this->localizationName ),
							'value'				=> '',
						),
					),
				),
				
				'envato'	=> array(
					'title'		=> __( 'Envato Settings', $this->localizationName ),
					'mandatory'	=> array('envato_AffId', 'envato_ClientId', 'envato_ClientSecret', 'envato_RedirectUrl'),
					'keys'		=> array(
						'envato_AffId'		=> array(
							'title'				=> __( 'Affiliate ID',$this->localizationName ),
							'value'				=> '',
						),
						'envato_ClientId'		=> array(
							'title'				=> __( 'OAuth Client ID',$this->localizationName ),
							'value'				=> '',
						),
						'envato_ClientSecret'		=> array(
							'title'				=> __( 'Client Secret',$this->localizationName ),
							'value'				=> '',
						),
						'envato_RedirectUrl'		=> array(
							'title'				=> __( 'Confirmation URL',$this->localizationName ),
							'value'				=> '',
						),
					),
				),
			);
			foreach ($providers as $pkey => $pval) {
				foreach ($pval['keys'] as $pkey2 => $pval2) {
					if ( isset($amz_settings["$pkey2"]) ) {
						$pval2 = $amz_settings["$pkey2"];
						$providers["$pkey"]['keys']["$pkey2"]['value'] = $pval2;
						
						if ( preg_match('/(country|main_aff_id)/iu', $pkey2) ) {
							$obj = is_object($this->get_ws_object( $pkey )) ? $this->get_ws_object( $pkey ) : null;
			
							if ( !is_null($obj) ) {
								$providers["$pkey"]['keys']["$pkey2"]['value'] = $obj->get_country_name(
									$pval2,
									str_replace('ebay_', '', $pkey2)
								);
							}
						}
					}
				}
			}
			//var_dump('<pre>', $providers, '</pre>'); die('debug...');
			
			if ( $provider != 'all' ) {
				return isset($providers["$provider"]) ? $providers["$provider"] : array();
			}
			return $providers;
		}

		public function verify_mandatory_settings( $provider ) {
			$ret = array(
				'status'		=> 'invalid',
				'fields'		=> array(),
				'fields_title'	=> array(),
			);
			
			$module_settings = $this->get_main_settings( $provider );
			if ( empty($module_settings) ) return array_merge($ret, array());

			$mandatory = isset($module_settings['mandatory']) ? $module_settings['mandatory'] : array();
			if ( empty($mandatory) ) return array_merge($ret, array('status' => 'valid'));
			
			$module_mandatoryFields = array(); $fields = array();
			foreach ( $mandatory as $field ) {

				if ( isset($module_settings['keys']["$field"]['title']) ) {
					$fields["$field"] = $module_settings['keys']["$field"]['title'];					
				}

				$module_mandatoryFields["$field"] = false;
				if ( isset($module_settings['keys']["$field"]['value'])
					&& !empty($module_settings['keys']["$field"]['value']) ) {

					$module_mandatoryFields["$field"] = true;
            	}
			}
			
            $mandatoryValid = true;
            foreach ($module_mandatoryFields as $k=>$v) {
                if ( !$v ) {
                    $mandatoryValid = false;
                    break;
                }
            }
			return array_merge($ret, array(
				'status' 		=> $mandatoryValid ? 'valid' : 'invalid',
				'fields' 		=> array_keys($fields),
				'fields_title'	=> array_values($fields),
			));
		}

		public function settings() {
			//$this->amz_settings = $this->the_plugin->getAllSettings('array', 'amazon');
			$this->amz_settings = maybe_unserialize( get_option( $this->alias . '_amazon' ) );
			$this->amz_settings = !empty($this->amz_settings) && is_array($this->amz_settings) ? $this->amz_settings : array();
			$this->build_amz_settings();

			$settings = $this->amz_settings;
			return $settings;
		}

		public function build_amz_settings( $new=array() ) {
			if ( !empty($new) && is_array($new) ) {
				$this->amz_settings = array_replace_recursive($this->amz_settings, $new);
			}
			// plugin doesn't use the cart!			
			$this->amz_settings['onsite_cart'] = 'no';
			$this->amz_settings['90day_cookie'] = 'no';
			$this->amz_settings['cross_selling'] = 'no';
			//$this->amz_settings['show_short_description'] = 'no';
			$this->amz_settings['number_of_requests_daily_limit'] = 5000;
			
			return $this->amz_settings;
		}


		/**
		 * Octomber 2015 - new plugin functions
		 */
		public function get_ws_prefixes($ws='all') {
			$wslist = array(
				'amazon'		=> 'amz',
				'envato'		=> 'env',
				'alibaba'		=> 'ali',
				'ebay'			=> 'eby',
			);
			return $ws == 'all' ? $wslist : ( isset($wslist["$ws"]) ? $wslist["$ws"] : false );
		}
		
		public function get_ws_status($ws='all') {
			$wslist = array(
				'amazon'		=> true,
				'envato'		=> true,
				'alibaba'		=> true,
				'ebay'			=> true,
			);
			return $ws == 'all' ? $wslist : ( isset($wslist["$ws"]) ? $wslist["$ws"] : false );
		}

		public function get_post_meta($post_id, $key='', $single=false, $withPrefix=true) {
			$_key = $key;
			if ( $_key == '_amzASIN' ) $key = '_aiowaff_prodid';
			$ret = get_post_meta($post_id, $key, $single);
			if ( !$withPrefix && ($_key == '_amzASIN') ) {
				$wslist = $this->get_ws_prefixes();
				foreach ($wslist as $wsprefix) {
					$ret = str_replace($wsprefix.'-', '', $ret);
				}
			}
			return $ret;
		}
		
		public function get_product_by_wsid( $wsid ) {
			global $wpdb;

			$key = '_aiowaff_prodid';
			//$key = '_amzASIN';
			$query = "
SELECT a.ID, a.post_title FROM {$wpdb->posts} AS a LEFT JOIN {$wpdb->postmeta} AS b ON a.ID = b.post_id
 WHERE 1=1
 AND b.meta_key = '$key' AND b.meta_value = '".esc_sql($wsid)."'
 AND !ISNULL(b.meta_id)
;";
    		$result =  $wpdb->get_results($query , ARRAY_A);
    		return (isset($result[0]) ? $result[0] : $result);
			
		}
		
		/**
		 * Call Example
			$args = array(
				'post_title' 	=> $retProd['Title'],
				'post_status' 	=> $default_import,
				'post_content' 	=> $desc,
				'post_excerpt' 	=> $excerpt,
				'post_type' 	=> 'product',
				'menu_order' 	=> 0,
				'post_author' 	=> 1
			); 
		 */
		public function get_product_by_args($args) {
			global $wpdb;

			$args = array_merge(array(
				'post_title' 	=> '',
				'post_status' 	=> 'publish',
				'post_content' 	=> '',
				'post_excerpt' 	=> '',
				'post_type' 	=> 'product',
				'menu_order' 	=> 0,
				'post_author' 	=> 1
			), $args);

			//$result = $wpdb->get_row("SELECT * FROM " . ( $wpdb->prefix ) . "posts WHERE 1=1 and post_status = '" . ( $args['post_status'] ) . "' and post_title = '" .  ( $args['post_title'] )  . "'", 'ARRAY_A');
			$result = $wpdb->get_row( $wpdb->prepare( "SELECT * FROM " . ( $wpdb->prefix ) . "posts WHERE 1=1 and post_type IN ('product', 'product_variation') and post_status = '" . ( $args['post_status'] ) . "' and post_title = %s", $args['post_title'] ), 'ARRAY_A' );
			if(count($result) > 0){
				return $result;
			}
			return false;
		}

		// get webservice object
		public function get_ws_object( $provider, $what='helper' ) {
			$arr = array(
				'generic'		=> array(
					'helper'		=> $this->genericHelper,
					'ws'			=> null,
				),
				'amazon'		=> array(
					'helper'		=> $this->amzHelper,
					'ws'			=> is_object($this->amzHelper) ? $this->amzHelper->aaAmazonWS : null,
				),
				'alibaba'		=> array(
					'helper'		=> $this->alibabaHelper,
					'ws'			=> is_object($this->alibabaHelper) ? $this->alibabaHelper->aaAlibabaWS : null,
				),
				'envato'		=> array(
					'helper'		=> $this->envatoHelper,
					'ws'			=> is_object($this->envatoHelper) ? $this->envatoHelper->aaEnvatoWS : null,
				),
				'ebay'		=> array(
					'helper'		=> $this->ebayHelper,
					'ws'			=> is_object($this->ebayHelper) ? $this->ebayHelper->aaEbayWS : null,
				),
			);
			return $arr["$provider"]["$what"];
		}
		
		public function prodid_get_provider_alias( $id ) {
			$_id = explode('-', $id);
			return count($_id) > 1 ? $_id[0] : 'zzz';
		}
		
		public function prodid_get_asin( $id ) {
			$_id = explode('-', $id);
			return count($_id) > 1 ? $_id[1] : '9999999';
		}
		
		public function prodid_get_provider( $alias ) {
			$wslist = $this->get_ws_prefixes();
			foreach ($wslist as $key => $wsprefix) {
				if ( $alias == $wsprefix ) {
					return $key;
				}
			}
			return '';
		}

		public function prodid_set( $id, $provider, $what ) {
			$ret = array();
			$alias = $this->get_ws_prefixes($provider);

			if (empty($id)) return $id;
			$isa = is_array($id) ? true : false;

			if ( !$isa ) {
				$id = array($id);
			}
			foreach ($id as $key => $val) {
				if (empty($val)) {
					$ret["$key"] = $val;
					continue;
				}
				if ( 'add' == $what ) {
					$ret["$key"] = $val;
					if ( !preg_match('/^('.$alias.').*/imu', $val, $m) ) {
						$ret["$key"] = $alias.'-' . $val;
					}
				}
				else if ( 'sub' == $what ) {
					$ret["$key"] = str_replace($alias.'-', '', $val);
				}
			}
			if ( !$isa ) {
				return $ret[0];
			}
			return $ret;
		}
	
		public function set_product_meta_asset( $post_id, $metas=array() )
		{
			foreach ($metas as $key => $val) {
				update_post_meta( $post_id, $key, $val );
			}
		}
	
		public function multi_implode_keyval($array, $glue) 
		{
		    $ret = '';
		
		    foreach ($array as $key => $item) {
		        if (is_array($item)) {
		            $ret .= $this->multi_implode($item, $glue) . $glue;
		        } else {
		            $ret .= ($key . ': ' . $item) . $glue;
		        }
		    }
		
		    $ret = substr($ret, 0, 0-strlen($glue));
		
		    return $ret;
		}












		/**
		 * 2016, february
		 */
		public function is_module_active( $alias, $is_admin=true ) {
			$cfg = $this->cfg;

			$ret = false;

			// is module activated?
			if ( isset($cfg['modules'], $cfg['modules'][$alias], $cfg['modules'][$alias]['loaded_in']) ) {
				$ret = true;
			}
			// is module in admin section?
			if ( $is_admin && !$this->is_admin ) {
				$ret = false;
			}

			return $ret;
		}
	
		public function debug_get_country() {
			$ip = $this->get_client_ip();
			$country = $this->get_country_perip_external();

			var_dump('<pre>',$ip, $country,'</pre>');
			echo __FILE__ . ":" . __LINE__;die . PHP_EOL;
		}
	
		public function bulk_wp_exist_post_by_args( $args ) {
			global $wpdb;
			//$result = $wpdb->get_row("SELECT * FROM " . ( $wpdb->prefix ) . "posts WHERE 1=1 and post_status = '" . ( $args['post_status'] ) . "' and post_title = '" .  ( $args['post_title'] )  . "'", 'ARRAY_A');
			$result = $wpdb->get_row( $wpdb->prepare( "SELECT * FROM " . ( $wpdb->prefix ) . "posts WHERE 1=1 and post_type IN ('product', 'product_variation') and post_status = '" . ( $args['post_status'] ) . "' and post_title = %s", $args['post_title'] ), 'ARRAY_A' );
			if(count($result) > 0){
				return $result;
			}
			return false;
		}

		public function product_by_asin( $asins=array() ) {
			$asins = array_unique( array_filter($asins) );
			if (empty($asins)) return array();

			$ret = array_fill_keys ( $asins, false );
			global $wpdb;
		
			$asins_ = implode(',', array_map(array($this, 'prepareForInList'), $asins));

			$sql_asin2id = "select pm.meta_value as asin, p.* from " . $wpdb->prefix.'posts' . " as p left join " . $wpdb->prefix.'postmeta' . " as pm on p.ID = pm.post_id where 1=1 and !isnull(p.ID) and pm.meta_key = '_amzASIN' and pm.meta_value != '' and pm.meta_value in ($asins_);";
			$res_asin2id = $wpdb->get_results( $sql_asin2id, OBJECT_K );
			//var_dump('<pre>', $res_asin2id, '</pre>'); die('debug...');  
			if ( !empty($res_asin2id) ) {
				foreach ($res_asin2id as $k => $v) {
					$asin = $v->asin;
					$ret["$asin"] = $v; 
				}
			}
			return $ret;
		}
	
	
		/**
		 * March 2016 - new methods
		 */
		public function verify_amazon_keys( $settings=array() ) {
			$ret = array(
				// valid | invalid | demo
				'status' 			=> '',

				// -3 = just a default value
				// -2 = alias text keys
				// -1 = empty value keys
				// >=0 = demo keys pair
				'pair_idx' 		=> -3,

				// amazon settings
				'settings' 		=> array(),
			);

			$is_custom = ! empty( $settings ) && is_array($settings) ? true : false;
			if ( ! $is_custom ) {
				$settings = $this->amz_settings;
			}
			$ret['settings'] = $settings;

			$demo_keys = $this->demo_keys; // aa-team demo keys

			// current keys from db
			$current_keys = array(
				'AccessKeyID'       => isset($settings['AccessKeyID'])
					? trim($settings['AccessKeyID']) : '',
				'SecretAccessKey'   => isset($settings['SecretAccessKey'])
					? trim($settings['SecretAccessKey']) : '',
			);
			//var_dump('<pre>',$current_keys,'</pre>'); echo __FILE__ . ":" . __LINE__;die . PHP_EOL;

			// default keys status
			$status = 'valid';

			// at least one key for a pair is setted as ( empty value | demo alias text ) => demo keys
			$_status = array();
			foreach ($current_keys as $key_id => $key_val) {
				if ( '' == $key_val ) {
					$status = 'demo';
					$ret['pair_idx'] = -1;
					break;
				}

				if ( $key_val == $demo_keys['alias']["$key_id"] ) {
					$status = 'demo';
					$_status[] = $key_id;
				}
			}
			// if full pair of both keys is found => we don't mark them again in db - see below step
			if ( ( 2 == count($_status) ) && ( 'demo' == $status ) ) {
				$status = 'demo999';
				$ret['pair_idx'] = -2;
			}

			// verify if curenty keys are demo keys: both keys value from each pair must match
			if ( 'valid' == $status ) {
				foreach ($demo_keys['pairs'] as $pair_idx => $pair_set) {
					if ( preg_match('/^demo/i', $status) ) break;

					$_status = true;
					foreach ($current_keys as $key_id => $key_val) {
						$__kdidx = 'AccessKeyID' == $key_id ? 0 : 1;

						if ( $key_val != $pair_set[$__kdidx] ) {
							$_status = false;
							break;
						}
					}

					if ( $_status ) {
						$status = 'demo';
						$ret['pair_idx'] = $pair_idx;
					}
				}
			}

			// mark demo keys in database with "demo text"
			if ( 'demo' == $status ) {
				if ( ! $is_custom ) {
					$amz_settings = $this->settings();
					$amz_settings = !empty($amz_settings) && is_array($amz_settings) ? $amz_settings : array();
					
					foreach ($demo_keys['alias'] as $key_id => $key_val) {
						$amz_settings["$key_id"] = $key_val;
					}
					update_option( $this->alias . '_amazon', $amz_settings );
				}
			}

			// make demo keys usable in amazon settings: use first found pair
			if ( preg_match('/^demo/i', $status) ) {
				$status = 'demo';

				// make demo keys usable
				foreach ($demo_keys['alias'] as $key_id => $key_val) {

					$__kdidx = 'AccessKeyID' == $key_id ? 0 : 1;
					$__kd = isset($demo_keys['pairs'][0], $demo_keys['pairs'][0][$__kdidx])
						? $demo_keys['pairs'][0][$__kdidx] : '';

					if ( ! $is_custom ) {
						$this->amz_settings["$key_id"] = $__kd;
					}
					else {
						$ret['settings']["$key_id"] = $__kd;
					}
				}
			}

			$ret['status'] = $status;
			return $ret;
		}

		// number of products imported using aa-team demo keys
		// toret = nb (number of products) | idlist (list of product ids)
		public function get_products_demo_keys( $toret='nb' ) {
			$db = $this->db;
			$table = $db->postmeta;

			if ( 'nb' == $toret ) {
				$sql = "select count(pm.meta_id) as nb from $table as pm where 1=1 and pm.meta_key = '_amzaff_aateam_keys' and pm.meta_value = '1';";
				$res = $db->get_var( $sql );
				return (int) $res;
			}
			else {
				$sql = "select pm.post_id from $table as pm where 1=1 and pm.meta_key = '_amzaff_aateam_keys' and pm.meta_value = '1';";
				$res = $db->get_results( $sql, OBJECT_K );
				if ( empty($res) ) return array();
				return array_keys( $res );
			}
			return false;
		}

		// allowed: to import products using aa-team demo keys
		public function is_allowed_products_demo_keys() {
			$ret = $this->get_products_demo_keys() < $this->ss['max_products_demo_keys'] ? true : false;
			return $ret;
		}
		
		// allowed: to make remote requests to aa-team demo server
		public function is_allowed_remote_requests() {
			$ret = $this->get_amazon_request_remote_number() < $this->ss['max_remote_request_number'] ? true : false;
			return $ret;
		}
		
		// is: aa-team demo keys
		public function is_aateam_demo_keys() {
			$_status = $this->verify_amazon_keys();
			$_status = $_status['status'];

			$ret = 'demo' == $_status ? true : false;
			return $ret;
		}
		
		// is: aa-team demo server
		public function is_aateam_server() {
			//$ret = ('cc.aa-team.com' == $_SERVER['SERVER_NAME'])
			//	|| ('46.101.188.140' == $_SERVER['SERVER_ADDR']);
			//return $ret;

			if ( defined('WOOZONE_KEYS_SERVER') && WOOZONE_KEYS_SERVER ) {
				return true;
			}
			return false;
		}

		public function can_import_products() {
			// we are using aa-team demo keys
			// and
			// we are NOT on aa-team demo server
			if ( $this->is_aateam_demo_keys() ) {
				
				// we are allowed to import products using aa-team demo keys
				if ( $this->is_allowed_products_demo_keys() ) {
					return true;
				}
				else {
					return false;
				}
			}
			return true;
		}

		// conditions are fulfilled for this to be a remote request to aa-team demo server
		public function do_remote_amazon_request( $what_rules=array() ) {
			// we are using aa-team demo keys
			// and
			// we are NOT on aa-team demo server
			if ( $this->is_aateam_demo_keys() && ! $this->is_aateam_server() ) {
				
				// we are allowed to import products using aa-team demo keys
				if ( $this->is_allowed_products_demo_keys() ) {
					return true;
				}
				else {
					return false;
				}
			}
			return false;
		}
		
		// get remote request from aa-team demo server
		public function get_remote_amazon_request( $pms=array() ) {
			$ret = array(
				'status'        	=> 'invalid',
				'msg'           	=> '',
				'code'			=> -1,
				'response'     => array(),
			);
			
			$remote_url = self::$aateam_keys_script . '?' . http_build_query(array(
				'action'            => 'amazon_request',
				'what_func'         => isset($pms['what_func']) ? $pms['what_func'] : '',
			));

			$params = array_merge(array(), $pms, array(
				'__request' => array(
					'client_ip'         => $this->get_client_ip(),
					'client_website'    => get_site_url(),
					'country'           => isset($this->amz_settings['country']) ? $this->amz_settings['country'] : 'com',
				),
			));
			if ( isset($params['amz_settings']) ) {
				$params['amz_settings'] = array(
					// NOT SENDing access keys for security concerns!
					'AccessKeyID'           => '', //$params['amz_settings']['AccessKeyID'],
					'SecretAccessKey'       => '', //$params['amz_settings']['SecretAccessKey'],

					'main_aff_id'           => isset($params['amz_settings']['main_aff_id']) ? $params['amz_settings']['main_aff_id'] : '',
					'country'               => isset($params['amz_settings']['country']) ? $params['amz_settings']['country'] : '',
				);
				//unset( $params['amz_settings'] );
			}
			//var_dump('<pre>', $remote_url, $params, '</pre>');
			//echo __FILE__ . ":" . __LINE__;die . PHP_EOL;

			$response = wp_remote_post( $remote_url, array(
				'method' => 'POST',
				'timeout' => 30,
				'redirection' => 5,
				'httpversion' => '1.0',
				'blocking' => true,
				'headers' => array(),
				'body' => $params
			));
			//var_dump('<pre>', $response['body'], '</pre>');
			//echo __FILE__ . ":" . __LINE__;//die . PHP_EOL;

			// If there's error
			if ( is_wp_error( $response ) ){
				return array_merge($ret, array('msg' => $response->get_error_message()));
			}
			$body = wp_remote_retrieve_body( $response );
			//var_dump('<pre>', $body, '</pre>'); die('debug...');

			if ( !function_exists('simplexml_load_string') ) {
				return array_merge($ret, array('msg' => 'Function simplexml_load_string don\'t exists!'));
			}

			if( strpos((string)$body, '<response>') === false ) {
				return array_merge($ret, array('msg' => 'Invalid xml response retrieved from aa-team server!'));
			}
			//var_dump('<pre>', $body, '</pre>'); die('debug...');

			$body = simplexml_load_string( $body );

			 $resp = array(
				'status'        	=> isset($body->status) ? (string) $body->status : 'invalid',
				'msg'           	=> isset($body->msg) ? (string) $body->msg : 'unknown error',
				'code'           => isset($body->code) ? (string) $body->code : -1,
				'response'     => isset($body->body) ? (string) $body->body : '',
			 );
  
			// validate response
			 if ( empty($resp['response']) ) {
				$resp['response'] = array();
			 }
			 
			 $resp['response'] = maybe_unserialize( $resp['response'] );

			 if ( empty($resp['response']) || !is_array($resp['response']) ) {
				$resp['response'] = array();
			 }

			return $resp;
		}
		
		// save last requests to amazon: local or from aa-team demo server
		public function save_amazon_last_requests( $new=array() ) {
			$max_last_keep = 50;

			$last = get_option('WooZone_last_amazon_requests', array());

						if ( !isset($last['items']) || !is_array($last['items']) ) {
								$last = array(
										'items'     => array()
								);
						}

						if ( count($last['items']) >= $max_last_keep ) {
								array_shift($last['items']); // remove oldes maintained row
						}

			//'amz_settings'            => $this->the_plugin->amz_settings,
			//'from_file'               => str_replace($this->the_plugin->cfg['paths']['plugin_dir_path'], '', __FILE__),
			//'from_func'               => __FUNCTION__ != __METHOD__ ? __METHOD__ : __FUNCTION__, 
						// add new latest row
						$last['items'][] = array(
							'time'              => time(),
							'amazon'            => array(
								'AccessKeyID'           => $new['amz_settings']['AccessKeyID'],
								'SecretAccessKey'       => $new['amz_settings']['SecretAccessKey'],
								'main_aff_id'           => isset($new['amz_settings']['main_aff_id']) ? $new['amz_settings']['main_aff_id'] : '',
								'country'               => isset($new['amz_settings']['country']) ? $new['amz_settings']['country'] : '',
				),
							'from_file'         => $new['from_file'],
							'from_func'         => $new['from_func'],
							'status'            => $new['request_status']['status'],
							'msg'               => $new['request_status']['msg'],
							'is_remote'         => isset($new['is_remote']) && $new['is_remote'] ? 1 : 0,
			);
						
			update_option('WooZone_last_amazon_requests', $last);
		}
		
		// get last requests to amazon: local or from aa-team demo server
		public function get_amazon_last_requests() {
			$last = get_option('WooZone_last_amazon_requests', array());
			return $last;
		}

		// notice to show amazon requests: local or from aa-team demo sever
		public function print_demo_request()
		{
			return $this->_admin_notice_amazon_keys();
		}

		public function _admin_notice_amazon_keys( $print=true )
		{
			ob_start();
		?>
		<div class="WooZone-callout WooZone-callout-info WooZone-demo-keys">
			<h4><?php
				//_e( sprintf(
				//	// '<strong>%s</strong> &#8211; You are using AA-Team DEMO keys ( AccessKeyID = <span class="marked">%s</span>, SecretAccessKey = <span class="marked">%s</span> ) and you\'ve made <span class="marked">%s</span> amazon requests (<span class="marked">%s</span> remote).',
				//	'<strong>%s</strong> &#8211; You are using AA-Team DEMO keys and you\'ve made <strong>%s</strong> requests to amazon and <strong>%s</strong> remote requests.',
				//	$this->pluginName,
				//	// $this->demo_keys['alias]['AccessKeyID'],
				//	// $this->demo_keys['alias]['SecretAccessKey'],
				//	$this->get_amazon_request_number(),
				//	$this->get_amazon_request_remote_number()
				//), $this->localizationName );
				if ( $this->is_aateam_demo_keys() ) {
					$msg = sprintf(
						'<strong>%s</strong> &#8211; You are using AA-Team DEMO keys and you\'ve made <strong>%s</strong> requests to amazon and <strong>%s</strong> remote requests.',
						$this->pluginName,
						$this->get_amazon_request_number(),
						$this->get_amazon_request_remote_number()
					);
				}
				else {
					$msg = sprintf(
						'<strong>%s</strong> &#8211; You\'ve made <strong>%s</strong> requests to amazon and <strong>%s</strong> remote requests.',
						$this->pluginName,
						$this->get_amazon_request_number(),
						$this->get_amazon_request_remote_number()
					);
				}
				_e( $msg, $this->localizationName );
			?></h4>
			<?php
				$html = array();                
				$last = $this->get_amazon_last_requests();
				$last = isset($last['items']) ? (array) $last['items'] : array();
				$last = array_reverse($last, true);
				if ( !empty($last) ) {
					$html[] = '<div class="last-requests" id="WooZone-list-rows">';
					$html[] = '<a href="#" class="WooZone-form-button-small WooZone-form-button-primary">' . __('view last requests', $this->localizationName) . '</a>';
					$html[] = '<table class="WooZone-table" style="width: 100%">';
					$html[] =   '<thead>';
					$html[] =       '<tr>';
					$html[] =           '<th>';
					$html[] =               __('Time', $this->localizationName);
					$html[] =           '</th>';
					$html[] =           '<th width="300">';
					$html[] =               __('From file', $this->localizationName);
					$html[] =           '</th>';
					$html[] =           '<th width="400">';
					$html[] =               __('From function', $this->localizationName);
					$html[] =           '</th>';
					$html[] =           '<th width="100">';
					$html[] =               __('Status', $this->localizationName);
					$html[] =           '</th>';
					$html[] =           '<th width="200">';
					$html[] =               __('Status message', $this->localizationName);
					$html[] =           '</th>';
					$html[] =       '</tr>';
					$html[] =   '</thead>';
					$html[] =   '<tfoot>';
					$html[] =   '</tfoot>';
					$html[] =   '<tbody>';
				}
				foreach ($last as $key => $val) {
					$html[] =       '<tr>';
					$html[] =           '<td>';
					$html[] =               $this->last_update_date(true, $val['time']);
					$html[] =           '</td>';
					$html[] =           '<td>';
					$html[] =               $val['from_file'];
					$html[] =           '</td>';
					$html[] =           '<td>';
					$html[] =               $val['from_func'];
					$html[] =           '</td>';
					$html[] =           '<td>';
					$html[] =               $val['status'];
					$html[] =           '</td>';
					$html[] =           '<td>';
					$html[] =               '<div class="status-msg">'
												. (isset($val['is_remote']) && $val['is_remote'] ? 'Remote | ' : '')
												. $val['msg']
											. '</div>';
					$html[] =           '</td>';
					$html[] =       '</tr>';
				}
				if ( !empty($last) ) {
					$html[] =   '</tbody>';
					$html[] = '</table>';
					$html[] = '</div>';
				}
				echo implode(PHP_EOL, $html);
			?>
		</div>
		<?php
			$contents = ob_get_clean();

			if ( $print ) echo $contents;
			else return $contents;
		}

		public function print_section_header( $title='', $desc='', $docs_url='')
		{
			$html = array();

			$html[] = '<div class="panel panel-default ' . ( $this->alias ) . '-panel ' . ( $this->alias ) . '-section-header">';
			$html[] =   '<div class="panel-heading ' . ( $this->alias ) . '-panel-heading">';
			if( trim($title) != "" )    $html[] =       '<h1 class="panel-title ' . ( $this->alias ) . '-panel-title">' . ( $title ) . '</h1>';
			if( trim($desc) != "" )     $html[] =       $desc;
			$html[] =   '</div>';
			$html[] =   '<div class="panel-body ' . ( $this->alias ) . '-panel-body ' . ( $this->alias ) . '-no-padding" >';
			
			
			if( trim($docs_url) != "" ) $html[] =       '<a href="' . ( $docs_url ) . '" target="_blank" class="' . ( $this->alias ) . '-tab"><i class="' . ( $this->alias ) . '-icon-support"></i>  Documentation</a>';
			$html[] =       '<a href="' . ( $this->plugin_row_meta( 'portfolio' ) ) . '?ref=AA-Team" target="_blank" class="' . ( $this->alias ) . '-tab"><i class="' . ( $this->alias ) . '-icon-other_products"></i> More AA-Team Products</a>';
			$html[] =   '</div>';
			$html[] = '</div>';

			return implode(PHP_EOL, $html);
		}

		public function get_image_sizes() {
			$wp_sizes = $this->u->get_image_sizes();

			$allowed = isset($this->amz_settings['images_sizes_allowed'])
				? $this->amz_settings['images_sizes_allowed'] : array();
			$allowed = !empty($allowed) && is_array($allowed) ? $allowed : array();
			
			if ( empty($allowed) ) return $wp_sizes;
			foreach ( $wp_sizes as $size => $props ) {
				if ( !in_array($size, $allowed) ) {
					unset($wp_sizes["$size"]);
				}
			}
			return $wp_sizes;
		}


		/**
		 * 2016-july
		 */
		/**
		 * item			: A. result of amzHelper.build_product_data | B. full api response array
		 * is_filtered	: true => you use A. ; false => you use B.
		 * retWhat	: what product description to retrieve: both | desc | short 
		 */
		public function product_build_desc( $item=array(), $is_filtered=true, $retWhat='both' ) {

			$retProd = array_replace_recursive(array(
				'EditorialReviews'				=> '',
				'Feature'						=> '',
				'ASIN'							=> '',
				'hasGallery'					=> 'false',
			), $item);

			// parse full amazon api response
			if ( !$is_filtered ) {

				$retProd = array(
					'ws' => isset($retProd['ws']) ? $retProd['ws'] : '',
				);

				$EditorialReviews = isset($item['EditorialReviews']['EditorialReview']['Content'])
	                    ? $item['EditorialReviews']['EditorialReview']['Content'] : '';

				// try to rebuid the description if it's empty
				if( trim($EditorialReviews) == "" ){
					if( isset($item['EditorialReviews']['EditorialReview']) && count($item['EditorialReviews']['EditorialReview']) > 0 ){
						
						$new_description = array();
						foreach ($item['EditorialReviews']['EditorialReview'] as $desc) {
							if( isset($desc['Content']) && isset($desc['Source']) ){
								//$new_description[] = '<h3>' . ( $desc['Source'] ) . ':</h3>';
								$new_description[] = $desc['Content'] . '<br />';
							}
						}
					}
					
					if( isset($new_description) && count($new_description) > 0 ){
						$EditorialReviews = implode( "\n", $new_description );
					}
				}

				$retProd['EditorialReviews'] = $EditorialReviews;

				$retProd['Feature'] = isset($item['ItemAttributes']['Feature']) ? $item['ItemAttributes']['Feature'] : '';

				$retProd['hasGallery'] = 'false';
			}

			// [amz_corss_sell asin="B01G7TG6SW"]
			if ( isset($item['__parent_asin']) ) {
				$retProd['ASIN'] = isset($item['__parent_asin']) ? $item['__parent_asin'] : '';
			}
			if ( isset($item['__parent_content']) ) {
				if ( preg_match('/\[gallery\]/imu', $item['__parent_content']) ) {
					$retProd['hasGallery'] = 'true';
				}
			}

			// short description
			$show_short_description = isset($this->amz_settings['show_short_description']) ? $this->amz_settings['show_short_description'] : 'yes';
			if( 'yes' == $show_short_description ) {
				// first 3 paragraph
				$excerpt = @explode("\n", @strip_tags( implode("\n", $retProd['Feature']) ) );
				$excerpt = @implode("\n", @array_slice($excerpt, 0, 3));
			}
			else {
				$excerpt = '';
			}

			// full description
			$__desc = array();
			$__desc[] = ($retProd['hasGallery'] == 'true' ? "[gallery]" : "");
			if ( $retProd['ws'] == 'amazon' ) {
				$__desc[] = !empty($retProd['EditorialReviews']) ? $retProd['EditorialReviews'] : '';
				$__desc[] = (count($retProd['Feature']) > 0 &&  is_array($retProd['Feature']) == true ? implode("\n", $retProd['Feature']) : '');

				$cross_selling = (isset($this->amz_settings["cross_selling"]) && $this->amz_settings["cross_selling"] == 'yes' ? true : false);
				
				if( $cross_selling == true ) {
					$__desc[] = '[amz_corss_sell asin="' . ( $retProd['ASIN'] ) . '"]';
				}
			}
			else {
				$__desc[] = isset($retProd['Description']) && !empty($retProd['Description']) ? $retProd['Description'] : '';
			}
			
			$desc = implode("\n", array_filter($__desc));

			//var_dump('<pre>', $excerpt, $desc , '</pre>'); echo __FILE__ . ":" . __LINE__;die . PHP_EOL;

			if ( 'both' == $retWhat ) {
				return array(
					'short'			=> $excerpt,
					'desc'			=> $desc,
				);
			}
			if ( 'desc' == $retWhat ) {
				return $desc;
			}
			return $excerpt;
		}

		// Determine if SSL is used.
		public function is_ssl() {
			if ( isset($_SERVER['HTTPS']) ) {
				if ( 'on' == strtolower($_SERVER['HTTPS']) )
					return true;
				if ( '1' == $_SERVER['HTTPS'] )
					return true;
			} elseif ( isset($_SERVER['SERVER_PORT']) && ( '443' == $_SERVER['SERVER_PORT'] ) ) {
				return true;
			}
			
			// HTTP_X_FORWARDED_PROTO: a de facto standard for identifying the originating protocol of an HTTP request, since a reverse proxy (load balancer) may communicate with a web server using HTTP even if the request to the reverse proxy is HTTPS
			if ( isset($_SERVER['HTTP_X_FORWARDED_PROTO']) ) {
				if ( 'https' == strtolower($_SERVER['HTTP_X_FORWARDED_PROTO']) )
					return true;
			}
			if ( isset($_SERVER['HTTP_X_FORWARDED_SSL']) ) {
				if ( 'on' == strtolower($_SERVER['HTTP_X_FORWARDED_SSL']) )
					return true;
				if ( '1' == $_SERVER['HTTP_X_FORWARDED_SSL'] )
					return true;
			}
			return false;
		}

	
		/**
		 * 2016-september - for amzstore plugin
		 */
		// in wp_options we have options like 'amzStore' but in version >= 9.0 I've changed plugin alias, so we have options like 'AmzStore" 
		public function fix_dbalias_issue() {
			$ret = array('status' => 'invalid', 'msg' => 'unknown msg.', 'count' => array());
			if ( 'AmzStore' != $this->alias ) return $ret;

			$found = get_option('AmzStore_fixed_dbalias', false);

			// already fixed
			if ( $found ) return $ret;

			global $wpdb;
			$db = $wpdb;
			$table = $db->prefix . 'options';
   
			// old version settings
			// MySQL queries are not case-sensitive by default.
			// If you need to make a case-sensitive query, it is very easy to do using the BINARY operator, which forces a byte by byte comparison
			$sql = "select option_id, option_name, option_value from $table where 1=1 and option_name regexp binary '^amzStore_' order by option_name asc;";
			//var_dump('<pre>',$sql,'</pre>');  
			$res = $db->get_results( $sql, OBJECT );
			if ( empty($res) ) {
				update_option('AmzStore_fixed_dbalias', true);
				return array_merge($ret, array('status' => 'valid', 'msg' => 'error or none found: trying to retrieve old version settings.'));
			}
   
			// new version 9.0 settings
			$sql90 = "select option_name, option_value from $table where 1=1 and option_name regexp binary '^AmzStore_' order by option_name asc;";
			$res90 = $db->get_results( $sql90, OBJECT_K );
			if ( empty($res90) ) {
				//return array_merge($ret, array('status' => 'valid', 'msg' => 'error or none found: trying to retrieve new version 9.0 settings.'));
			}
			foreach ($res90 as $key => $val) {
				$res90["$key"] = $val->option_value;
			}

			$ccupd = 0; $ccdel = 0; $ccupd_old = 0;
			foreach ($res as $val) {
				$option_id 		= $val->option_id;
				$option_name 	= $val->option_name;
				$option_value 	= $val->option_value;

				// amzStore_ option names become __amzStore_
				if ( 1 ) {
					$sqlupd_old = "update $table set option_name = concat('__', option_name) where 1=1 and option_name = binary %s;";
					$sqlupd_old = $db->prepare( $sqlupd_old, $option_name );
					$resupd_old = $db->query( $sqlupd_old );
					if ( $resupd_old ) ++$ccupd_old;
				}

				$option_name_new = str_replace('amzStore', 'AmzStore', $option_name);

				$option_value = maybe_unserialize( $option_value );
				$option_value = maybe_unserialize( $option_value ); // old version prior to 9.0 had a bug of double serialize for some options
				$option_value = maybe_serialize( $option_value );

				// add new option based on old setting value
				if ( isset($res90["$option_name_new"]) ) { // already exists
					$sqlupd = "update $table set option_value = %s where 1=1 and option_name = binary %s;";
					$sqlupd = $db->prepare( $sqlupd, $option_value, $option_name_new );
					$resupd = $db->query( $sqlupd );
					if ( $resupd ) ++$ccupd;
				}
				else {
					$sqlupd = "insert into $table (option_name, option_value) values (%s, %s);";
					$sqlupd = $db->prepare( $sqlupd, $option_name_new, $option_value );
					$resupd = $db->query( $sqlupd );
					if ( $resupd ) ++$ccupd;
				}
			} // end foreach

			update_option('AmzStore_fixed_dbalias', true);
			return array_merge($ret, array('status' => 'valid', 'msg' => 'successfull: old version settings fixed.', 'count' => array(
				'ccupd'			=> $ccupd,
				'ccdel'			=> $ccdel,
				'ccupd_old'	=> $ccupd_old,
			)));
			//return $ret;
		}
	

		/**
		 * 2016-october - for product country check
		 */
		// from ADF
		public function discount_convert_country2country() {
			$countries = array(
				'com' 	=> array('us', 'com', 'united-states', 'United States'),
				'uk' 	=> array('gb', 'co.uk', 'united-kingdom', 'United Kingdom'),
				'de' 	=> array('de', 'de', 'germany', 'Germany'),
				'fr' 	=> array('fr', 'fr', 'france', 'France'),
				'jp' 	=> array('jp', 'co.jp', 'japan', 'Japan'),
				'ca' 	=> array('ca', 'ca', 'canada', 'Canada'),
				'cn'	=> array('cn', 'cn', 'china', 'China'),
				'in' 	=> array('in', 'in', 'india', 'India'),
				'it' 	=> array('it', 'it', 'italy', 'Italy'),
				'es' 	=> array('es', 'es', 'spain', 'Spain'),
				'mx' 	=> array('mx', 'com.mx', 'mexico', 'Mexico'),
				'br' 	=> array('br', 'com.br', 'brazil', 'Brazil'),
				//'au' 	=> array('au', 'com.au', 'spain', 'Australia')
			);
			$ret = array('tovalues' => array(), 'totitles' => array());
			foreach ($countries as $k => $v) {
				$ret['fromip']["$k"] = $v[0];
				$ret['amzwebsite']["$k"] = $v[1];
				$ret['tovalues']["$k"] = $v[2];
				$ret['totitles']["$k"] = $v[3];
			}
			return $ret;
		}

		// build a return array of type amzForUser from a domain key
		public function domain2amzForUser( $domain ) {
			$convertCountry = $this->discount_convert_country2country();
			$country_key = 'com';
			if ( in_array($domain, $convertCountry['amzwebsite']) ) {
				$country_key = array_search($domain, $convertCountry['amzwebsite']);
			}
			$ipcountry = isset($convertCountry['fromip']["$country_key"]) ? $convertCountry['fromip']["$country_key"] : 'us';
			$ipcountry = strtoupper($ipcountry);

			$country = $this->amzForUser( $ipcountry );
			return $country;
		}
	
		public function get_aff_ids() {
			$main_aff_id = $this->main_aff_id();

			$config = $this->amz_settings;
			$aff_ids = array();
			if ( isset($config['AffiliateID']) && !empty($config['AffiliateID'])
				&& is_array($config['AffiliateID']) ) {
				foreach ( $config['AffiliateID'] as $key => $val ) {
					if ( !empty($val) ) {
						$_key = $this->get_amazon_country_site( $key );						
						$aff_ids[] = array(
							'country' 		=> $_key,
							'aff_id'			=> $val,
						);
					}
				}
			}
			return array(
				'main_aff_id'			=> $main_aff_id,
				'aff_ids'					=> $aff_ids,
			);
		}
	
		public function get_country_from_url( $url ) {
			$country = '';
			if ( empty($url) ) return $country;

			$regex = "/https?:\/\/(?:.+\.)amazon\.([^\/]*)/imu";
			$found = preg_match($regex, $url, $m);
			if ( false !== $found ) {
				$country = $m[1];
			}
			return $country;
		}
	
		public function get_amazon_images_path() {
			return self::$amazon_images_path;
		}
	
		public function delete_post_attachments( $post_id ) {
			global $wpdb, $post_type;
			
			//check if is product
			$_post_type = get_post_type($post_id); //$post_type
			if ( ! in_array($_post_type, array('product', 'product_variation')) ) return;
			if ( ! is_int( $post_id ) || $post_id <= 0 ) return;

			//$ids = get_children(array(
			//	'post_parent' => $post_id,
			//	'post_type' => 'attachment'
			//));
			//$ids = $wpdb->get_col("SELECT ID FROM {$wpdb->posts} WHERE post_parent = $post_id AND post_type = 'attachment'");
			//if (empty($ids)) return;
			//foreach ( $ids as $id ) {
			//	wp_delete_attachment( $id, true );
			//}

			if (1) {
				$args = array(
					'post_type'   => 'attachment',
					'post_parent' => $post_id,
					'post_status' => 'any',
					'nopaging'    => true,

					// Optimize query for performance.
					'no_found_rows'          => true,
					'update_post_meta_cache' => false,
					'update_post_term_cache' => false,
				);
				$query = new WP_Query( $args );

				if ( $query->have_posts() ) {
					while ( $query->have_posts() ) {
						$query->the_post();

						wp_delete_attachment( $query->post->ID, true );
					}
				}
				wp_reset_postdata();
			}
		}


		/**
		 * Plugin Version
		 */
		// latest code version
		public function version() {
			if ( defined('AIOWAFF_VERSION') ) {
				$this->version = (string) AIOWAFF_VERSION;
				return $this->version;
			}

			$path = $this->cfg['paths']['plugin_dir_path'] . 'plugin.php';
			if ( function_exists('get_plugin_data') ) {
				$plugin_data = get_plugin_data( $path );
			}
			else {
				$plugin_data = WooZone_get_plugin_data();
			}

			$latest_version = '1.0';
			if( isset($plugin_data) && is_array($plugin_data) && !empty($plugin_data) ){
				if ( isset($plugin_data['Version']) ) {
					$latest_version = (string)$plugin_data['Version'];
				}
				else if ( isset($plugin_data['version']) ) {
					$latest_version = (string)$plugin_data['version'];
				}
			}

			$this->version = $latest_version;
			return $this->version;
		}

		private function check_if_table_exists( $force=false ) {
			$need_check_tables = $this->plugin_integrity_need_verification('check_tables');
			if ( ! $need_check_tables['status'] && ! $force ) {
				return true; // don't need verification yet!
			}

			// default sql - tables & tables data!
			require_once( $this->cfg['paths']['plugin_dir_path'] . 'modules/setup_backup/default-sql.php' );

			// retrieve all database tables & clean prefix
			$dbTables = $this->db->get_results( "show tables;", OBJECT_K );
			$dbTables = array_keys( $dbTables );
			if ( empty($dbTables) || ! is_array($dbTables) ) {

				$this->plugin_integrity_update_time('check_tables', array(
					'status'		=> 'invalid',
					'html'		=> __('Check plugin tables: error requesting tables list.', $this->localizationName),
				));
				return false; //something was wrong!
			}

			$dbTables_ = array();
			foreach ((array) $dbTables as $table) {
				$table_noprefix = str_replace($this->db->prefix, '', $table);
				$dbTables_[] = $table_noprefix;
			}

			// our plugin tables
			$dbTables_own = $this->plugin_tables;
			
			// did we find all our plugin tables?
			$dbTables_found = (array) array_intersect($dbTables_, $dbTables_own);
			$dbTables_missing = array_diff($dbTables_own, $dbTables_found);
			//var_dump('<pre>', $dbTables_own, '</pre>'); echo __FILE__ . ":" . __LINE__;die . PHP_EOL;
			if ( ! $dbTables_missing ) {

				$this->plugin_integrity_update_time('check_tables', array(
					'timeout'	=> time(),
					'status'		=> 'valid',
					'html'		=> __('Check plugin tables: all installed ( ' . implode(', ', $dbTables_found) . ' ).', $this->localizationName),
				));
				return true; // all is fine!
			}

			$this->plugin_integrity_update_time('check_tables', array(
				'status'		=> 'invalid',
				'html'		=> __('Check plugin tables: missing ( ' . implode(', ', $dbTables_missing) . ' ).', $this->localizationName),
			));
			return false; //something was wrong!
		}

		private function update_db_version( $version=null ) {
			delete_option( 'aiowaff_db_version' );
			$version = empty($version) ? $this->version() : $version;
			add_option( 'aiowaff_db_version', $version );
		}
		
		public function update_db( $force=false )  {
			// current installed db version
			//$current_db_version = get_option( 'aiowaff_db_version' );
			//$current_db_version = !empty($current_db_version) ? (string)$current_db_version : '1.0';

			// default db structure - integrity verification is done in function
			$this->check_if_table_exists( $force );

			$this->check_table_amz_locale_reference( $force ); // update 2017-nov

			$need_check_alter_tables = $this->plugin_integrity_need_verification('check_alter_tables');
			//$need_check_cronjobs_prefix = $this->plugin_integrity_need_verification('check_cronjobs_prefix');

			// installed version less than 9.0 / ex. 8.4.1.3
			//if ( version_compare( $current_db_version, '9.0', '<' ) ) {
			if (1) {
				if ( $need_check_alter_tables['status'] || $force ) { // if need_check_alter_tables
					// installed version less than 9.0 / ex. 8.4.1.3
					$table_name = $this->db->prefix . "amz_assets";
					if ( $this->db->get_var("show tables like '$table_name'") == $table_name ) {
						$this->_update_db_tables(array(
							'table'			=> $table_name,
							'queries'		=> array(
								'image_sizes'				=> array(
									'main' 			=> "ALTER TABLE " . $table_name . " %s COLUMN `image_sizes` TEXT NULL;",
									'verify'			=> "SHOW COLUMNS FROM " . $table_name . " LIKE 'image_sizes';",
									'field_name'	=> 'image_sizes',
									'field_type'	=> 'text',
								),
								'download_status'		=> array(
									'main' 			=> "ALTER TABLE " . $table_name . " %s COLUMN `download_status` VARCHAR(20) NULL DEFAULT 'new' COMMENT 'new, success, inprogress, error, remote';",
									'verify' 			=> "SHOW COLUMNS FROM " . $table_name . " LIKE 'download_status';",
									'field_name'	=> 'download_status',
									'field_type'	=> 'varchar(20)',
								),
							),
						));
					}
					
					// installed version less than 9.0.3.3
					$table_name = $this->db->prefix . "amz_cross_sell";
					if ( $this->db->get_var("show tables like '$table_name'") == $table_name ) {
						$this->_update_db_tables(array(
							'table'			=> $table_name,
							'queries'		=> array(
								'is_variable'				=> array(
									'main' 			=> "ALTER TABLE " . $table_name . " %s COLUMN `is_variable` CHAR(1) NULL DEFAULT 'N';",
									'verify'			=> "SHOW COLUMNS FROM " . $table_name . " LIKE 'is_variable';",
									'field_name'	=> 'is_variable',
									'field_type'	=> 'char(1)',
								),
								'nb_tries'		=> array(
									'main' 			=> "ALTER TABLE " . $table_name . " %s COLUMN `nb_tries` TINYINT(1) UNSIGNED NULL DEFAULT '0';",
									'verify' 			=> "SHOW COLUMNS FROM " . $table_name . " LIKE 'nb_tries';",
									'field_name'	=> 'nb_tries',
									'field_type'	=> 'tinyint(1)',
								),
							),
						));
					}

/*
					// occures with some clients servers
					$table_name = $this->db->prefix . "amz_queue";
					if ( $this->db->get_var("show tables like '$table_name'") == $table_name ) {
						$this->_update_db_tables(array(
							'table'			=> $table_name,
							'queries'		=> array(
								'nb_tries'		=> array(
									'main' 			=> "ALTER TABLE " . $table_name . " %s COLUMN `nb_tries` SMALLINT(1) UNSIGNED NOT NULL;",
									'verify' 			=> "SHOW COLUMNS FROM " . $table_name . " LIKE 'nb_tries';",
									'field_name'	=> 'nb_tries',
									'field_type'	=> 'SMALLINT(1)',
								),
								'nb_tries_prev'	=> array(
									'main' 			=> "ALTER TABLE " . $table_name . " %s COLUMN `nb_tries_prev` SMALLINT(1) UNSIGNED NOT NULL;",
									'verify' 			=> "SHOW COLUMNS FROM " . $table_name . " LIKE 'nb_tries_prev';",
									'field_name'	=> 'nb_tries_prev',
									'field_type'	=> 'SMALLINT(1)',
								),
								'from_op'		=> array(
									'main' 			=> "ALTER TABLE " . $table_name . " %s COLUMN `from_op` VARCHAR(30) NOT NULL;",
									'verify' 			=> "SHOW COLUMNS FROM " . $table_name . " LIKE 'from_op';",
									'field_name'	=> 'from_op',
									'field_type'	=> 'VARCHAR(30)',
								),
							),
						));
					}
*/

				} // end if need_check_alter_tables

/*
				// installed version less than 9.0 / ex. 8.4.1.3
				// update cronjobs prefix in wp_options / option name like 'cron'
				if ( $need_check_cronjobs_prefix['status'] || $force ) {
					$this->update_cronjobs();

					$this->plugin_integrity_update_time('check_cronjobs_prefix', array(
						'timeout'	=> time(),
						'status'		=> 'valid',
						'html'		=> __('Check cronjobs prefix: OK.', $this->localizationName),
					));
				}
*/

				// installed version less than 9.0 / ex. 8.4.1.3
				$this->update_db_version('1.4');
			}

			// update installed version to latest
			$this->update_db_version();
			return true;
		}

		public function _update_db_tables( $pms=array() )  {
			//require_once(ABSPATH . 'wp-admin/includes/upgrade.php');
			//$status = dbDelta($sql);

			extract( $pms );

			global $wpdb;
			foreach ( (array) $queries as $skey => $sql ) {
				if ( ! isset($sql['main']) ) continue 1;

				$do_main = 'add';
				if ( isset($sql['verify']) ) {
					$status = $wpdb->get_row( $sql['verify'], ARRAY_A );
					if ( ! empty($status) && isset($status['Field'], $status['Type']) ) {

						//'image_sizes' == strtolower($status['Field'])
						if ( isset($sql['field_type']) ) {
							if ( $sql['field_type'] == strtolower( $status['Type'] ) )
								$do_main = false;
							else
								$do_main = 'modify';
						}
					}
				} // end if verify

				if ( !empty($do_main) ) {
					$sql['main'] = sprintf( $sql['main'], strtoupper( $do_main ) );
					$status = $wpdb->query( $sql['main'] );
					//var_dump('<pre>', $sql, $status, '</pre>');
				}
			} // end foreach

			$this->plugin_integrity_update_time('check_alter_tables', array(
				'timeout'	=> time(),
				'status'		=> 'valid',
				'html'		=> __('Check plugin tables (alter): OK.', $this->localizationName),
			));
		}

		public function update_options_prefix( $what='use_old' ) {
			$ret = array('status' => 'invalid', 'msg' => 'unknown msg.');
   
			$db = $this->db;
			$table = $db->prefix . 'options';

			if ( 'use_new' == $what ) {
				return array_merge($ret, array('status' => 'valid', 'msg' => 'successfull: you choose to use the new version settings, disregarding the old version settings.'));
			}
			else if ( 'use_old' == $what ) {

				// old version settings
				$sql = "select option_id, option_name, option_value from $table where 1=1 and option_name regexp '^wwcAmzAff' order by option_name asc;";
				$res = $db->get_results( $sql, OBJECT );
				if ( empty($res) ) {
					return array_merge($ret, array('status' => 'valid', 'msg' => 'error or none found: trying to retrieve old version settings.'));
				}

				// new version 9.0 settings
				$sql90 = "select option_name, option_value from $table where 1=1 and option_name regexp '^WooZone' order by option_name asc;";
				$res90 = $db->get_results( $sql90, OBJECT_K );
				if ( empty($res90) ) {
					return array_merge($ret, array('status' => 'valid', 'msg' => 'error or none found: trying to retrieve new version 9.0 settings.'));
				}
				foreach ($res90 as $key => $val) {
						$res90["$key"] = $val->option_value;
				}
	
				$ccupd = 0; $ccdel = 0;
				foreach ($res as $val) {
					$option_id 		= $val->option_id;
					$option_name 	= $val->option_name;
					$option_value 	= $val->option_value;
					
					$option_name_new = str_replace('wwcAmzAff', $this->alias, $option_name);
					
					// delete current new version setting if exist
					//$sqldel = "delete from $table where 1=1 and option_name = %s;";
					//$sqldel = $db->prepare( $sqldel, $option_name_new );
					//$resdel = $db->query( $sqldel );
					//if ( $resdel ) ++$ccdel;
					
					$option_value = maybe_unserialize( $option_value );
					$option_value = maybe_unserialize( $option_value ); // old version prior to 9.0 had a bug of double serialize for some options
					$option_value = maybe_serialize( $option_value );

					// add new option based on old setting value
					if ( isset($res90["$option_name_new"]) ) { // already exists
						$sqlupd = "update $table set option_value = %s where 1=1 and option_name = %s;";
						$sqlupd = $db->prepare( $sqlupd, $option_value, $option_name_new );
						$resupd = $db->query( $sqlupd );
						if ( $resupd ) ++$ccupd;
					}
					else {
						$sqlupd = "insert into $table (option_name, option_value) values (%s, %s);";
						$sqlupd = $db->prepare( $sqlupd, $option_name_new, $option_value );
						$resupd = $db->query( $sqlupd );
						if ( $resupd ) ++$ccupd;
					}
   
					// replace new version setting with old version setting
					// !!! THIS WOULD REPLACE OLD VERSION SETTINGS - MAYBE WE SHOULD KEEP OLD VERSION SETTINGS FOR NOW
					//$sqlupd = "update $table set option_name = %s where 1=1 and option_id = %s;";
					//$sqlupd = $db->prepare( $sqlupd, $option_name_new, $option_id );
					//$resupd = $db->query( $sqlupd );
					//if ( $resupd ) ++$ccupd;
				}
				return array_merge($ret, array('status' => 'valid', 'msg' => 'successfull: you choose to use the old version settings, the new version settings were replaced.'));
			}
			return $ret;
		}

		public function update_cronjobs() {
			$ret = array('status' => 'invalid', 'msg' => 'unknown msg.');

			$db = $this->db;
			$table = $db->prefix . 'options';

			$sql = "SELECT option_id, option_name, option_value FROM $table WHERE 1=1 and option_name = 'cron';";
			$res = $db->get_results( $sql, OBJECT );
			if ( empty($res) ) {
				return array_merge($ret, array('status' => 'valid', 'msg' => 'not found'));
			}
 
			foreach ($res as $val) {
				$option_id 		= $val->option_id;
				$option_name 	= $val->option_name;
				$option_value 	= $val->option_value;

				$option_value = maybe_unserialize( $option_value );
				if ( empty($option_value) || !is_array($option_value) ) continue 1;
 
				foreach ($option_value as $kk => $vv) {
					if ( !is_array($vv) ) continue 1;  
					foreach ($vv as $kk2 => $vv2) {
						if ( preg_match('/^wwcAmzAff/iu', $kk2) ) { // wwcAmzAff | WooZone
							unset($option_value["$kk"]["$kk2"]);
						}
					}
				}
				
				foreach ($option_value as $kk => $vv) {
					if ( empty($vv) ) {
						unset($option_value["$kk"]);
					}
				}
				
				$option_value = serialize( $option_value );

				$sqlupd = "update $table set option_value = %s where 1=1 and option_id = %s;";
				$sqlupd = $db->prepare( $sqlupd, $option_value, $option_id );
				$resupd = $db->query( $sqlupd );
			}
			
			//$sql = "SELECT option_id, option_name, option_value FROM $table WHERE 1=1 and option_name = 'cron';";
			//$res = $db->get_results( $sql, OBJECT );
			//var_dump('<pre>', $res, '</pre>'); die('debug...'); 
			
			return array_merge($ret, array('status' => 'valid', 'msg' => 'ok'));
		}


		/** 
		 * Plugin is ACTIVE
		 */
		// verify plugin is ACTIVE (the right way)
		public function is_plugin_active( $plugin_name, $pms=array() ) {
			$pms = array_replace_recursive(array(
				'verify_active_for_network_only'		=> false,
				'verify_network_only_plugin'				=> false,
				'plugin_file'										=> array(), // verification is made by OR between items
				'plugin_class'										=> array(), // verification is made by OR between items
			), $pms);
			extract( $pms );

			switch ( strtolower($plugin_name) ) {
				case 'woocommerce':
					$plugin_file = array( 'woocommerce/woocommerce.php', 'envato-wordpress-toolkit/woocommerce.php' );
					$plugin_class = array( 'WooCommerce' );
					break;

				case 'woozone':
					$plugin_file = array( 'woozone/plugin.php' );
					$plugin_class = array( 'WooZone' );
					break;
					
				case 'psp':
					$plugin_file = array( 'premium-seo-pack/plugin.php' );
					$plugin_class = array( 'psp' );
					break;
					
				case 'w3totalcache':
					$plugin_file = array( 'w3-total-cache/w3-total-cache.php' );
					break;
					
				default:
					break;
			}

			$is_active = array();

			// verify plugin is active base on plugin main file 
			if ( ! empty($plugin_file) ) {
				if ( ! is_array($plugin_file) )
					$plugin_file = array( $plugin_file );

				include_once( ABSPATH . 'wp-admin/includes/plugin.php' );

				$cc = false;
				foreach ($plugin_file as $_plugin_file) {
					// check if a plugin is site wide or network active only
					if ( $verify_active_for_network_only ) {
						if ( is_plugin_active_for_network( $_plugin_file ) )
							$cc = true;
					}
					// check if a plugin is a Network-Only-Plugin
					else if ( $verify_network_only_plugin ) {
						if ( is_network_only_plugin( $_plugin_file ) )
							$cc = true;
					}
					// check if a plugin is active (the right way)
					else {
						if ( is_plugin_active( $_plugin_file ) )
							$cc = true;
					}
				}
				$is_active[] = $cc;
			}

			// verify plugin class exists!
			if ( ! empty($plugin_class) ) {
				if ( ! is_array($plugin_class) )
					$plugin_class = array( $plugin_class );

				$cc = false;
				foreach ($plugin_class as $_plugin_class) {
					if ( class_exists( $_plugin_class ) )
						$cc = true;
				}
				$is_active[] = $cc;
			}

			// final verification
			if ( empty($is_active) ) return false;
			foreach ($is_active as $_is_active) {
				if ( ! $_is_active ) return false;
			}
			return true;
		}
		public function is_plugin_active_for_network_only( $plugin_name, $pms=array() ) {
			$pms = array_replace_recursive(array(
				'verify_active_for_network_only'		=> true,
			), $pms);
			return $this->is_plugin_active( $plugin_name, $pms );
		}
		public function is_plugin_network_only_plugin( $plugin_name, $pms=array() ) {
			$pms = array_replace_recursive(array(
				'verify_network_only_plugin'				=> true,
			), $pms);
			return $this->is_plugin_active( $plugin_name, $pms );
		}
		
		public function is_woocommerce_installed() {
			if ( in_array( 'envato-wordpress-toolkit/woocommerce.php', apply_filters( 'active_plugins', get_option( 'active_plugins' ) ) ) || in_array( 'woocommerce/woocommerce.php', apply_filters( 'active_plugins', get_option( 'active_plugins' ) ) ) || is_multisite() )
			{
				return true;
			} else {
				$active_plugins = apply_filters( 'active_plugins', get_option( 'active_plugins' ) );
				if ( !empty($active_plugins) && is_array($active_plugins) ) {
					foreach ( $active_plugins as $key => $val ) {
						if ( ($status = preg_match('/^woocommerce[^\/]*\/woocommerce\.php$/imu', $val))!==false && $status > 0 ) {
							return true;
						}
					}
				}
				return false;
			}
		}


		/**
		 * check plugin integrity: 2017-feb-28
		 */
		// what: check_database (includes: check_tables, check_alter_tables, check_cronjobs_prefix)
		public function plugin_integrity_check( $what='all', $force=false ) {
			$what = ! is_array($what) ? array('check_database') : $what;

			if ( in_array('check_database', $what) ) {
				$this->update_db( $force );
			}
		}

		public function plugin_integrity_get_last_status( $what ) {
			$ret = array(
				'status'				=> true,
				'html'				=> '',
			);

			// verify plugin integrity
			$plugin_integrity = get_option( 'aiowaff_integrity_check', array() );
			$plugin_integrity = is_array($plugin_integrity) ? $plugin_integrity : array();

			$_status = true; $_html = array();
			if ( isset($plugin_integrity[ "$what" ]) && ! empty($plugin_integrity[ "$what" ]) ) {
				$__ = $plugin_integrity[ "$what" ];
				$_status = isset($__['status']) && 'valid' == $__['status'] ? true : false;
				$_html[] = $__['html'];
			}
			else {
				if ( 'check_database' == $what ) {
					foreach ($plugin_integrity as $key => $val) {
						if ( ! in_array($key, array('check_tables', 'check_alter_tables', 'check_cronjobs_prefix', 'check_table_amz_locale_reference')) ) {
							continue 1;
						}

						$_status = $_status && ( isset($val['status']) && 'valid' == $val['status'] ? true : false );
						if ( ! empty($val['html']) ) {
							$_html[] = $val['html'];
						}
					}
				}
			}

			//$html = '<div><div>' . implode('</div><div>', $_html) . '</div></div>';
			$html = implode('&nbsp;&nbsp;&nbsp;&nbsp;', $_html);
			$ret = array_merge( $ret, array('status' => $_status, 'html' => $html) );
			return $ret;
		}

		// what: check_tables, check_alter_tables, check_cronjobs_prefix
		public function plugin_integrity_need_verification( $what ) {
			$ret = array(
				'status'			=> false,
				'data'				=> array(),
			);

			// verify plugin integrity
			$plugin_integrity = get_option( 'aiowaff_integrity_check', array() );
			$plugin_integrity = is_array($plugin_integrity) ? $plugin_integrity : array();
			$ret = array_merge( $ret, array('data' => $plugin_integrity) );

			if ( isset($plugin_integrity[ "$what" ]) && ! empty($plugin_integrity[ "$what" ]) ) {
				if ( ( $plugin_integrity[ "$what" ]['timeout'] + $this->ss['check_integrity'][ "$what" ] ) > time() ) {
					$ret = array_merge( $ret, array('status' => false) ); // don't need verification yet!
					//var_dump('<pre>',$ret,'</pre>'); 
					return $ret;
				}
			}

			$ret = array_merge( $ret, array('status' => true) );
			return $ret;
		}

		public function plugin_integrity_update_time( $what, $data=array() ) {
			$plugin_integrity = get_option( 'aiowaff_integrity_check', array() );
			$plugin_integrity = is_array($plugin_integrity) ? $plugin_integrity : array();

			$data = ! is_array($data) ? array() : $data;

			if ( ! isset($plugin_integrity[ "$what" ]) ) {
				$plugin_integrity[ "$what" ] = array(
					'timeout'	=> time(),
					'status'		=> 'invalid',
					'html'		=> '',
				);
			}
			$plugin_integrity[ "$what" ] = array_replace_recursive($plugin_integrity[ "$what" ], $data);
			update_option( 'aiowaff_integrity_check', $plugin_integrity );
		}
		
		public function woocommerce_image_replace_src( $html='' ) {
			//return str_replace( "http", "http__", $html);
			return $html;
		}
		public function woocommerce_image_replace_src_revert( $html='' ) {
			//return str_replace( "http__", "http", $html);
			return $html;
		}
	
		public function is_debug_mode_allowed() {
			$ip = $this->get_client_ip();

			$debug_ip = isset($this->amz_settings['debug_ip']) && ! empty($this->amz_settings['debug_ip'])
				? trim($this->amz_settings['debug_ip']) : '';
			if ( ! empty($debug_ip) ) {
				$debug_ip = explode(',', $debug_ip);
				$debug_ip = array_map("trim", $debug_ip);

				if ( in_array($ip, $debug_ip) ) {
					return true;
				}
			}
			return false;
		}
	
		public function debug_cache_images() {
			if ( $this->is_debug_mode_allowed() ) {
				$html = array();
				$html[] = '<div style="background-color: #3498db; color: #fff; position: fixed; bottom: 25px; right: 25px; max-width: 200px; font-size: 10px;">';
				$html[] = 		'<table style="border-spacing: 2px; margin: 0px; border: 0px;">';
				$html[] = 			'<thead style="line-height: 10px;">';
				$html[] =				'<tr>';
				if ( isset($_SESSION['WooZoneCachedContor']) ) {
					foreach ($_SESSION['WooZoneCachedContor'] as $key => $val) {
						$html[] = 				'<th>' . str_replace('_', ' ', $key) . '</th>';
					}
				}
				$html[] =				'</tr>';
				$html[] = 			'</thead>';
				$html[] = 			'<tbody style="line-height: 10px;">';
				$html[] = 				'<tr>';
				if ( isset($_SESSION['WooZoneCachedContor']) ) {
					foreach ($_SESSION['WooZoneCachedContor'] as $key => $val) {
						$html[] = 				'<td>' . $val . '</td>';
					}
				}
				$html[] = 				'</tr>';
				$html[] = 			'</tbody>';
				$html[] = 		'</table>';
				$html[] = '</div>';

				$html = implode(PHP_EOL, $html);
				return $html;
			}
			return false;
		}
	

		/**
		 * 
		 * Cacheit related - 2017-08-16
		 */
		public function _attachment_url( $url='', $post_id=0 ) 
		{
			$orig_url = $url;

			if( in_array( $orig_url, array_keys($this->duplicate_images) ) ){
				if( isset($this->duplicate_images[$orig_url]) ){
					return $this->duplicate_images[$orig_url];
				}
			}

			// mandatory - must be amazon product
			$post = get_post($post_id);
   
			if ( isset($post->post_parent) && $post->post_parent
				&& $this->verify_product_is_amazon_valid($post->post_parent) === 0
			) {
				return $url;
			}

			// mandatory rule - must have amazon url
			$rules = array();
			$rules[0] = strpos( $url, self::$amazon_images_path );
			$rules = $rules[0];

			if ( $rules ) {
				$uploads = wp_get_upload_dir();
				$url = str_replace( $uploads['baseurl'] . '/', '', $url );
    
				if( $this->is_ssl() == true ) {
					$uploads['baseurl'] = str_replace( 'http://', 'https://', $uploads['baseurl']);  
					$url = str_replace( $uploads['baseurl'] . '/', '', $url );
				}
			}
			$url = $this->amazon_url_to_ssl( $url );
			if ( ! is_admin() ) {
				$url = $this->woocommerce_image_replace_src( $url );
			}


			$this->duplicate_images[$orig_url] = $url;
			//var_dump( "<pre>", $this->duplicate_images  , "</pre>" ); 
			return $url;
		}
		
		public function _attachment_url__( $url='', $post_id=0 ) {
			
			return $this->_attachment_url( $url, $post_id );
			// END HERE - CODE BELLOW NOT EXECUTED

			$uniqueid = md5( $post_id . $url );
			$thecache = $this->cacheit['imgurl']->get_row($uniqueid);

			if ( isset($thecache['v']) ) {
				$this->cacheit['imgurl']->add_row($uniqueid, array(
					//'hitsc' 			=> isset($thecache['hitsc']) ? ($thecache['hitsc'] + 1) : 1,
				));
				$_SESSION['WooZoneCachedContor']['hitscache']++;
				return $thecache['v'];
			}

			$this->cacheit['imgurl']->add_row($uniqueid, array(
				//'hits' 				=> isset($thecache['hits']) ? ($thecache['hits'] + 1) : 1,
				//'post_id'		=> $post_id,
				//'url'				=> $url,
				'v' => $url,
			));

			// mandatory - must be amazon product
			$post = get_post($post_id);

			$this->cacheit['imgurl']->add_row($uniqueid, array(
				//'post_parent'		=> $post->post_parent,
			));

			if ( isset($post->post_parent) && $post->post_parent
				&& $this->verify_product_is_amazon_valid($post->post_parent) === 0
			) {
				//$this->cacheit['imgurl']->save_cache(); // NON amazon product => don't save it to cache
				$this->cacheit['imgurl']->del_row($uniqueid);
				$_SESSION['WooZoneCachedContor']['nonamazon']++;
				return $url;
			}

			// mandatory rule - must have amazon url
			$rules = array();
			$rules[0] = strpos( $url, self::$amazon_images_path );
			$rules = $rules[0];

			if ( $rules ) {
				$uploads = wp_get_upload_dir();
				$url = str_replace( $uploads['baseurl'] . '/', '', $url );
				if( $this->is_ssl() == true ) {
					$uploads['baseurl'] = str_replace( 'http://', 'https://', $uploads['baseurl']);  
					$url = str_replace( $uploads['baseurl'] . '/', '', $url );
				}
			}
			$url = $this->amazon_url_to_ssl( $url );
			if ( ! is_admin() ) {
				$url = $this->woocommerce_image_replace_src( $url );
			}

			$this->cacheit['imgurl']->add_row($uniqueid, array(
				//'url'				=> $url,
				'v' => $url,
			));
			$this->cacheit['imgurl']->save_cache();
			$_SESSION['WooZoneCachedContor']['hits']++;

			//var_dump('<pre>',$url,'</pre>');
			return $url;
		}

		public function _calculate_image_srcset( $sources=array(), $size_array=array(), $image_src='', $image_meta=array(), $attachment_id=0 ) {

			if ( empty($sources) ) return $sources;

			// mandatory - must be amazon product
			$post = get_post($attachment_id);
			
			if ( isset($post->post_parent) && $post->post_parent
				&& $this->verify_product_is_amazon_valid($post->post_parent) === 0
			) {
				return $sources;
			}

			$uploads = wp_get_upload_dir();
			foreach ( $sources as &$source ) {
				// mandatory rule - must have amazon url
				$rules = array();
				$rules[0] = strpos( $source['url'], self::$amazon_images_path );
				$rules = $rules[0];

				if ( $rules ) {
					$source['url'] = str_replace( $uploads['baseurl'] . '/', '', $source['url'] );
				}
				$source['url'] = $this->amazon_url_to_ssl( $source['url'] );
				if ( ! is_admin() ) {
					$source['url'] = $this->woocommerce_image_replace_src( $source['url'] );
				}
			}

			//var_dump('<pre>',$sources,'</pre>');  
			return $sources;
		}

		public function _calculate_image_srcset__( $sources=array(), $size_array=array(), $image_src='', $image_meta=array(), $attachment_id=0 ) {

			return $this->_calculate_image_srcset( $sources, $size_array, $image_src, $image_meta, $attachment_id );
			// END HERE - CODE BELLOW NOT EXECUTED

			if ( empty($sources) ) return $sources;

			$uniqueid = md5( $attachment_id . serialize($sources) );
			$thecache = $this->cacheit['imgsources']->get_row($uniqueid);
			
			if ( isset($thecache['v']) ) {
				$this->cacheit['imgsources']->add_row($uniqueid, array(
					//'hitsc' 			=> isset($thecache['hitsc']) ? ($thecache['hitsc'] + 1) : 1,
				));
				$_SESSION['WooZoneCachedContor']['hitscache']++;
				return $thecache['v'];
			}

			$this->cacheit['imgsources']->add_row($uniqueid, array(
				//'hits' 					=> isset($thecache['hits']) ? ($thecache['hits'] + 1) : 1,
				//'attachment_id'	=> $attachment_id,
				//'sources'			=> $sources,
				'v' => $sources,
			));

			// mandatory - must be amazon product
			$post = get_post($attachment_id);
			
			$this->cacheit['imgsources']->add_row($uniqueid, array(
				//'post_parent'		=> $post->post_parent,
			));

			if ( isset($post->post_parent) && $post->post_parent
				&& $this->verify_product_is_amazon_valid($post->post_parent) === 0
			) {
				//$this->cacheit['imgsources']->save_cache(); // NON amazon product => don't save it to cache
				$this->cacheit['imgsources']->del_row($uniqueid);
				$_SESSION['WooZoneCachedContor']['nonamazon']++;
				return $sources;
			}

			$uploads = wp_get_upload_dir();
			foreach ( $sources as &$source ) {
				// mandatory rule - must have amazon url
				$rules = array();
				$rules[0] = strpos( $source['url'], self::$amazon_images_path );
				$rules = $rules[0];

				if ( $rules ) {
					$source['url'] = str_replace( $uploads['baseurl'] . '/', '', $source['url'] );
				}
				$source['url'] = $this->amazon_url_to_ssl( $source['url'] );
				if ( ! is_admin() ) {
					$source['url'] = $this->woocommerce_image_replace_src( $source['url'] );
				}
			}

			$this->cacheit['imgsources']->add_row($uniqueid, array(
				//'sources'			=> $sources,
				'v' => $sources,
			));
			$this->cacheit['imgsources']->save_cache();
			$_SESSION['WooZoneCachedContor']['hits']++;

			//var_dump('<pre>',$sources,'</pre>');  
			return $sources;
		}

		public function verify_product_is_amazon__($prod_id) {
			// verify we are in woocommerce product
			if ( is_object($prod_id) ) {
				$product = $prod_id;
			} else if( function_exists('wc_get_product') ){
				$product = wc_get_product( $prod_id );
			} else if( function_exists('get_product') ){
				$product = get_product( $prod_id );
			}

			if ( isset($product) && is_object($product) ) {
				$prod_id = 0;
				if ( method_exists( $product, 'get_id' ) ) {
					$prod_id = (int) $product->get_id();
				} else if ( isset($product->id) && (int) $product->id > 0 ) {
					$prod_id = (int) $product->id;
				}

				if ( $prod_id ) {
					// verify is amazon product!
					$asin = get_post_meta($prod_id, '_amzASIN', true);
					
					if ( $asin!==false && strlen($asin) > 0 ) {
						return 1;
					}
					return 0;
				}
			}
			return false;
		}

		public function verify_product_is_amazon($prod_id) {

			return $this->verify_product_is_amazon__($prod_id);
			// END HERE - CODE BELLOW NOT EXECUTED

			// verify we are in woocommerce product
			if ( is_object($prod_id) ) {
				$product = $prod_id;
			} else if( function_exists('wc_get_product') ){
				$product = wc_get_product( $prod_id );
			} else if( function_exists('get_product') ){
				$product = get_product( $prod_id );
			}

			if ( isset($product) && is_object($product) ) {
				$prod_id = 0;
				if ( method_exists( $product, 'get_id' ) ) {
					$prod_id = (int) $product->get_id();
				} else if ( isset($product->id) && (int) $product->id > 0 ) {
					$prod_id = (int) $product->id;
				}

				if ( $prod_id ) {

					$thecache = $this->cacheit['amzvalid']->get_row($prod_id);
					
					if ( isset($thecache['v']) ) {
						$this->cacheit['amzvalid']->add_row($prod_id, array(
							//'hitsc' 			=> isset($thecache['hitsc']) ? ($thecache['hitsc'] + 1) : 1,
						));
						$_SESSION['WooZoneCachedContor']['hitscache']++;
						return $thecache['v'];
					}
		
					$this->cacheit['amzvalid']->add_row($prod_id, array(
						//'hits' 				=> isset($thecache['hits']) ? ($thecache['hits'] + 1) : 1,
						//'post_id'		=> $prod_id,
					));

					// verify is amazon product!
					$asin = get_post_meta($prod_id, '_amzASIN', true);

					if ( $asin!==false && strlen($asin) > 0 ) {
						$this->cacheit['amzvalid']->add_row($prod_id, array(
							//'isvalid' 			=> 1,
							//'asin'				=> $asin,
							'v' => 1,
						));
						$this->cacheit['amzvalid']->save_cache();
						$_SESSION['WooZoneCachedContor']['hits']++;
						return 1;
					}

					$this->cacheit['amzvalid']->add_row($prod_id, array(
						//'isvalid' 			=> 0,
						//'asin'				=> $asin,
						'v' => 0,
					));
					$this->cacheit['amzvalid']->save_cache();
					$_SESSION['WooZoneCachedContor']['hits']++;
					return 0;
				}
			}
			return false;
		}

		public function translatable_strings()
		{
			if( isset($this->amz_settings) && count($this->amz_settings) > 0 ){
				if( isset($this->amz_settings['string_trans']) && count($this->amz_settings['string_trans']) > 0 ){
					$cc = 0;
					foreach ($this->expressions as $key => $value) {
						if( isset($this->amz_settings['string_trans'][$cc]) ){
							$this->expressions[$key] = $this->amz_settings['string_trans'][$cc];
						}

						$cc++;
					}
				}
			}
		}

		public function __translate_string( $string='' )
		{
			if( count($this->expressions) > 0 ){
				if( in_array( $string, array_keys($this->expressions)) ){
					return $this->expressions[$string];
				}
			}

			return $string;
		}

		// update 2017-nov
		private function check_table_amz_locale_reference( $force=false ) {
			$table = 'amz_locale_reference';
			$table_ = $this->db->prefix . $table;

			$need_check_tables = $this->plugin_integrity_need_verification('check_table_'.$table);

			if ( ! $need_check_tables['status'] && ! $force ) {
				return true; // don't need verification yet!
			}

			// default sql - tables & tables data!
			require_once( $this->cfg['paths']['plugin_dir_path'] . 'modules/setup_backup/default-sql.php' );

			// retrieve all database tables & clean prefix
			$dbTables = $this->db->get_results( "show tables;", OBJECT_K );
			$dbTables = array_keys( $dbTables );
			if ( empty($dbTables) || ! is_array($dbTables) ) {

				$this->plugin_integrity_update_time('check_table_'.$table, array(
					'status'	=> 'invalid',
					'html'		=> sprintf( __('Check plugin table %s: error requesting tables list.', $this->localizationName), $table_ ),
				));
				return false; //something was wrong!
			}

			// table exists?
			if ( ! in_array( $table_, $dbTables) ) {

				$this->plugin_integrity_update_time('check_table_'.$table, array(
					'status'	=> 'invalid',
					'html'		=> sprintf( __('Check plugin table %s: missing.', $this->localizationName), $table_ ),
				));
				return false; //something was wrong!
			}

			// table has rows?
			$query = "select count(a.ID) as nb from $table_ as a where 1=1;";
			$res = $this->db->get_var( $query );
			//var_dump('<pre>', $res , '</pre>'); echo __FILE__ . ":" . __LINE__;die . PHP_EOL;
			if ( ($res === false) || ! $res ) {

				$this->plugin_integrity_update_time('check_table_'.$table, array(
					'status'	=> 'invalid',
					'html'		=> sprintf( __('Check plugin table %s: is empty - no rows found.', $this->localizationName), $table_ ),
				));
				return false; //something was wrong!
			}

			// all fine
			$this->plugin_integrity_update_time('check_table_'.$table, array(
				'timeout'	=> time(),
				'status'	=> 'valid',
				'html'		=> sprintf( __('Check plugin table %s: installed ok.', $this->localizationName), $table_ ),
			));
			return true; // all is fine!
		}

		// update 2017-nov
		public function get_country2mainaffid( $country, $pms=array() ) {
			$pms = array_replace_recursive(array(
				'country2mainaffid' => true, // true = country to mainaffid OR false = mainaffid to country
				'com2us' 			=> true,
				'toupper' 			=> true,
			), $pms);
			extract( $pms );

			$ret = '';

			if ( ! isset($country) || empty($country) ) {
				return $ret;
			}

			$arr = $country2mainaffid ? $this->country2mainaffid : array_flip( $this->country2mainaffid );
			if ( isset($arr["$country"]) ) {
				$ret = $arr["$country"];
			}

			if ( $com2us && ('com' == $ret) ) {
				$ret = 'us';
			}
			if ( $toupper ) {
				$ret = strtoupper( $ret );
			}
			return $ret;
		}

		// update 2017-nov
		public function get_mainaffid2country( $mainaffid, $pms=array() ) {
			$pms = array_replace_recursive(array(
				'country2mainaffid' => false, // true = country to mainaffid OR false = mainaffid to country
				'com2us' 			=> false,
				'toupper' 			=> false,
				'withPrefixPoint' 	=> false,
			), $pms);
			extract( $pms );

			$ret = $this->get_country2mainaffid( $mainaffid, $pms );

			if ( $withPrefixPoint && ! empty($ret) ) {
				$ret = '.' . $ret;
			}
			return $ret;
		}



		public function api_requests_set( $inc=1 ) {
			$today = gmdate('Y-m-d'); //Format a GMT/UTC date/time
			$current = get_option('aiowaff_apireq_nb', 0);
			$current_date = get_option('aiowaff_apireq_date', '');
			
			// new day
			if ( $today != $current_date ) {
				update_option('aiowaff_apireq_nb', 0);
				update_option('aiowaff_apireq_date', $today);
			}
			// same day
			else {
				update_option('aiowaff_apireq_nb', (int) ++$current);
			}
		}
		public function api_requests_get() {
			$today = gmdate('Y-m-d'); //Format a GMT/UTC date/time
			$current = get_option('aiowaff_apireq_nb', 0);
			$current_date = get_option('aiowaff_apireq_date', '');
			
			$ret = array('nb' => 0, 'date' => '');
			
			// new day
			if ( $today != $current_date ) {
				$ret = array_merge($ret, array('nb' => 0, 'date' => $today));
			}
			// same day
			else {
				$ret = array_merge($ret, array('nb' => $current, 'date' => $today));
			}
			return $ret;
		}
		public function api_requests_show()
		{
			$current_stats = $this->api_requests_get();
			$nb = $current_stats['nb'];
			$limit = $this->amz_settings['number_of_requests_daily_limit'];
			$show = isset($this->amz_settings['show_api_requests']) ? $this->amz_settings['show_api_requests'] : 'yes';
			$show = $show == 'yes' ? true : false;

			// print errors
			if ($show) {
				$text = '
					<strong>
						%s -
						Number of requests made today: %s |
						Daily limit: %s |
						<a href="https://go.developer.ebay.com/api-call-limits" target="_blank">EBAY API Call Limits</a>
					</strong>
				';
				$text = sprintf( $text, $this->pluginName, $nb, $limit );
				echo '<div class="updated"> <p>' . ( $text ) . '</p> </div>';
			}
		}

		public function clean_html( $html, $loose=true ) {
			if ( '' == $html ) {
				return '';
			}

			$html = preg_replace('~<(?:!DOCTYPE|/?(?:html|body))[^>]*>\s*~i', '', $html);

			if ( ! $loose ) {
			$html = preg_replace('/(<[^>]+) style=".*?"/i', '$1', $html);
			$html = preg_replace('/(<[^>]+) class=".*?"/i', '$1', $html);
			$html = preg_replace('/(<[^>]+) width=".*?"/i', '$1', $html);
			$html = preg_replace('/(<[^>]+) height=".*?"/i', '$1', $html);
			$html = preg_replace('/(<[^>]+) alt=".*?"/i', '$1', $html);
			}

			$html = preg_replace('/^<!DOCTYPE.+?>/', '$1', str_replace(array('<html>', '</html>', '<body>', '</body>'), '', $html));
			$html = preg_replace("/<\/?div[^>]*\>/i", "", $html);

			if ( ! $loose ) {
			$html = preg_replace('#(<a.*?>).*?(</a>)#', '$1$2', $html);
			$html = preg_replace('/<a[^>]*>(.*)<\/a>/iU', '', $html);

			$html = preg_replace("/<\/?h1[^>]*\>/i", "", $html);
			$html = preg_replace("/<\/?strong[^>]*\>/i", "", $html);
			$html = preg_replace("/<\/?span[^>]*\>/i", "", $html);
			}

			$html = str_replace('&nbsp;', ' ', $html);
			$html = str_replace('\t', ' ', $html);
			$html = str_replace('  ', ' ', $html);

			$html = preg_replace("/http:\/\/g(\d+)\.a\./i", "https://ae$1.", $html);

			$pattern = "/<[^\/>]*>([\s]?)*<\/[^>]*>/";
			$html = preg_replace($pattern, '', $html);

			$html = force_balance_tags($html);

			return $html;
		}



		public function get_amazon_variations_nb( $prodvar=array() ) {
			if ( empty($prodvar) || ! is_array($prodvar) ) {
				return 0;
			}

			//$variations = array();
			if ( isset($prodvar['ASIN']) ) {
				//$variations[] = $prodvar;
				return 1;
			}
			else {
				//$variations = (array) $prodvar;
				return count( $prodvar );
			}
		}
	}
}

if ( !function_exists('array_replace_recursive') ) {
    function array_replace_recursive($base, $replacements)
    {
        foreach (array_slice(func_get_args(), 1) as $replacements) {
            $bref_stack = array(&$base);
            $head_stack = array($replacements);

            do {
                end($bref_stack);

                $bref = &$bref_stack[key($bref_stack)];
                $head = array_pop($head_stack);

                unset($bref_stack[key($bref_stack)]);

                foreach (array_keys($head) as $key) {
                    if (isset($key, $bref, $bref[$key], $head[$key]) && is_array($bref[$key]) && is_array($head[$key])) {
                        $bref_stack[] = &$bref[$key];
                        $head_stack[] = $head[$key];
                    } else {
                        $bref[$key] = $head[$key];
                    }
                }
            } while(count($head_stack));
        }

        return $base;
    }
}

if ( !function_exists('aiowaff') ) {
	function aiowaff() {
		global $aiowaff;
		return $aiowaff;
	}
}

if ( !function_exists('aiowaff_get_plugin_data') ) {
	function aiowaff_get_plugin_data( $path='' ) {
		if ( empty($path) ) {
			$path = str_replace('aa-framework/', '', plugin_dir_path( (__FILE__) )) . "plugin.php";
		}
  
		$source = file_get_contents( $path );
		$tokens = token_get_all( $source );
		$data   = array();
		if( trim($tokens[1][1]) != "" ){
			$__ = explode("\n", $tokens[1][1]);
			foreach ($__ as $key => $value) {
				$___ = explode(": ", $value);
				if( count($___) == 2 ){
					$data[trim(strtolower(str_replace(" ", '_', $___[0])))] = trim($___[1]);
				}
			}               
		}
  
		// For another way to implement it:
		//      see wp-admin/includes/update.php function get_plugin_data
		//      see wp-includes/functions.php function get_file_data
		return $data;  
	}
}