
	var ppIO = (function() {

		'use strict';
		
		/* Object global vars */
				
		var	_version,
			_printed,
			_endpoint,
			_options,
			_enabled,
			_paypal,
			_cartadocente,
			_app18,
			_transaction,
			_data,
			_preset_id;

		_version = '1.0';
		_printed = '03/02/2023 05:37:12 am';
		_endpoint = 'https://payment.pearsonitalia.it/';
		
		_options = {"debug":false,"fake":false,"hash":"Y2xpZW50X1JpY1NkMTlYMFVUSDpEalhZZU1jTmt2N1FhNGRzREJ0dk5nUHI="};
		
		_transaction = {
			type: null,
			method: null,
			step: null,
			status: null
		};
		
		_preset_id = null;
		
		/* Functions */
		
		function _reset() {
		
			/* Reset transaction */
			
			_transaction = {
				type: null,
				method: null,
				step: null,
				status: null
			};
			
			_preset_id = null;
			
			_message('Transaction reset');
			
			/* Clean localStorage */
		
			_clean();
		}
		
		function _clean() {
		
			/* Clean localStorage */
			
			var _cleaned = false;
		
			if (localStorage.getItem('ppIO.transaction')) {
			
				_cleaned = true;
			
				localStorage.removeItem('ppIO.transaction');
			}
			
			if (localStorage.getItem('ppIO.data')) {
			
				_cleaned = true;
			
				localStorage.removeItem('ppIO.data');
			}

			if (localStorage.getItem('ppIO.fe.trs')) {
			
				_cleaned = true;
			
				localStorage.removeItem('ppIO.fe.trs');
			}

			if (_cleaned) {
			
				_message('Stored data removed');
			}
		}
			
		function _emit(e,args) {
		
			/* Trigger e event */
			
			$(ppIO).triggerHandler(e,args);
		}
		
		function _message(msg) {
		
			if (_options.debug) {
			
				return console.log('[ppIO] '+msg);
			}
		}
			
		function _find() {

			function _array(prmstr) {
				
				var _params,
					_prmarr,
					_tmparr;
				
				_params = {};
				_prmarr = prmstr.split('&');
					
				for (var i=0;i<_prmarr.length;i++) {
					
					_tmparr = _prmarr[i].split('=');
						
					_params[_tmparr[0]] = _tmparr[1];
				}
					
				return _params;
			}

			var _prmstr = window.location.search.substr(1);
				
			return _prmstr != null && _prmstr != '' ? _array(_prmstr) : {};
		}
						
		function _set() {
		
			/* Override transaction returning from payment gateway, if exists */
			
			var _params,
				_tmp,
				_pending;

			_pending = false;
			
			/* Search for GET parameters */
				
			_params = _find();
			
			/* Check localStorage */
			
			_tmp = {
				transaction: null,
				data: null
			}

			_tmp.transaction = localStorage.getItem('ppIO.transaction');		
			_tmp.data = localStorage.getItem('ppIO.data');
			
			if (_tmp.transaction && _tmp.data) {
			
				_tmp.transaction = JSON.parse(_tmp.transaction);
				_tmp.data = JSON.parse(_tmp.data);
			
				_pending = true;
			}
				
			if (!$.isEmptyObject(_params) && _pending) {

				/* Pending transaction router */

				switch(_tmp.transaction.type) {
				
					case 'paypal':

						switch(_tmp.transaction.method) {
						
							case 'onetime':

								switch(_tmp.transaction.step) {
								
									case 'set':

										switch(_tmp.transaction.status) {
										
											case 'failed':
											
												_reset();
											
												break;
												
											case 'success':
											
												/* PayPal one time payment pending */
												
												switch(true) {
													
													case (typeof _params.token!==typeof undefined && typeof _params.PayerID===typeof undefined):

														_message('PayPal one time transaction aborted from user');
														
														_emit('ppIO.paypal.onetime.aborted',[]);

														return _reset();
														
														break;
													
													case (typeof _params.token!==typeof undefined && typeof _params.PayerID!==typeof undefined):
													
														_message('Resuming pending PayPal one time transaction');
														
														/* Check _preset_id */
														
														if (localStorage.getItem('ppIO.fe.trs')) {
															
															var _fetrs = JSON.parse(localStorage.getItem('ppIO.fe.trs'));
										
															if (_fetrs && _fetrs._preset_id && typeof _fetrs._preset_id!==typeof undefined) {
																
																_preset_id = _fetrs._preset_id;
															}
														}

														_emit('ppIO.paypal.onetime.resume',[_tmp.transaction,_tmp.data,_params.token,_params.PayerID]);
														
														_clean();
														
														_transaction = _tmp.transaction;
														_data = _tmp.data;

														return _paypal.pay(_params.token,_params.PayerID);

														break;
												}
										
												break;
										}
				
										break;
								}
							
								break;
								
							case 'recurring':

								switch(_tmp.transaction.step) {
								
									case 'set':

										switch(_tmp.transaction.status) {
										
											case 'failed':
											
												_reset();
											
												break;
												
											case 'success':
											
												/* PayPal recurring payment pending */
												
												switch(true) {
													
													case (typeof _params.token!==typeof undefined && typeof _params.PayerID===typeof undefined):

														_message('PayPal recurring payment transaction aborted from user');
														
														_emit('ppIO.paypal.recurring.aborted',[]);

														return _reset();
														
														break;
													
													case (typeof _params.token!==typeof undefined && typeof _params.PayerID!==typeof undefined):
													
														_message('Resuming pending PayPal recurring payment transaction');

														_emit('ppIO.paypal.recurring.resume',[_tmp.transaction,_tmp.data,_params.token,_params.PayerID]);
														
														_clean();
														
														_transaction = _tmp.transaction;
														_data = _tmp.data;

														return _paypal.subscribe(_params.token,_params.PayerID);

														break;
												}
										
												break;
										}
				
										break;
								}
							
								break;
						}
					
						break;
				}
			}
			
			_clean();
			
			_message('No pending transaction');
		}
		
		function _send(type,url,param,callback) {

			var setting = {
					type: type.toUpperCase(),
					url: _endpoint+url,
					dataType: 'json'
			};

			switch(type.toUpperCase()) {

				case 'POST':

					$.extend(setting,{data:param});

					break;
			}

			if (typeof _options.hash!==typeof undefined) {

				$.extend(setting,{headers:{"Authorization": "Basic " + _options.hash}});
			}
			
			var _failrsp = {
				error: {
					type: null,
					info: null,
					setting: setting
				}
			};

			$.ajax(setting)
				.done(function(data) { 

					if (typeof data.error!==typeof undefined) { 

						if (data.error!='') {

							_failrsp.error.type = 'OP';
							_failrsp.error.info = data.error;

							return callback(_failrsp);
						}
					}

					callback(null,data);
				})
				.fail(function(jqXHR,textStatus,errorThrown) {

					switch(jqXHR.readyState) {
						
						case 4:

							_failrsp.error.type = 'HTTP';
						
							break;
						
						case 0:

							_failrsp.error.type = 'NETWORK';
						
							break;
							
						default:
						
							_failrsp.error.type = '?';
					}
					
					_failrsp.error.info = {
						status: jqXHR.status,
						statusText: jqXHR.statusText
					};

					return callback(_failrsp);
				});
		}

		function _load() {
		
			/* Check localstorage & perform loading operations */
			
			try {
			
				/* Check localStorage */
				
				localStorage.setItem('ppIO.test','test');
				localStorage.removeItem('ppIO.test');
				
				_enabled = true;
				
				_message('Ready');

				_emit('ppIO.enable.success',[]);
				
				/* Search for pending transaction in localStorage (default null, evaluated if setExpressCheckout already called) */
				
				return _set();

			} catch(e) {

				var error = 'Unable to work (localStorage not available)';
				
				_enabled = false;
				
				_message(error);

				_emit('ppIO.enable.failed',[error]);
			}
		}
		
		/* Object global objects */
		
		_paypal = (function() {
		
			function _set(data,source) {
			
				/* Perform SetExpressCheckout */
				
				var _params,
					_url,
					_query,
					_method;

				switch(source.method) {
				
					case 'onetime':
					
						_method = 'onetime';

						break;
				
					case 'recurring':
					
						_method = 'recurring';

						break;
				}

				function response(err,obj) {
				
					if (err) {

						_transaction.status = 'failed';

						_emit('ppIO.paypal.'+_method+'.set.failed',[err]);
					
						return _message(err);
					}

					/* Update transaction status */
					
					_transaction.status = 'success';

					/* Store transaction details in localstorage */
					
					localStorage.setItem('ppIO.transaction',JSON.stringify(_transaction));		
					localStorage.setItem('ppIO.data',JSON.stringify(data));
					
					/* Emit success event */

					_emit('ppIO.paypal.'+_method+'.set.success',[obj,_transaction,data]);

					/* After SetExpressCheckout redirect to PayPal url with token */

					location.href = obj.url;
				}
				
				/* Set transaction info */
				
				_transaction.type = source.type;
				_transaction.method = source.method;
				_transaction.step = 'set';

				/* Add return/cancel URL to data. PayPal gateway redirects to current page */
				
					/* Build address skipping token & PayerID from previous transactions */
				
					_params = _find();
					
					switch(true) {
					
						case (!$.isEmptyObject(_params)):
						
							_url = location.protocol+'//'+location.host+location.pathname;
							
							_query = '';

							for (var _property in _params) {

								if (_property!='token' && _property!='PayerID') {
								
									if (_query!='') { _query+= '&'; }

									_query+= _property+'='+_params[_property];
								}
							}
							
							if (_query!='') {
							
								_url+= '?'+_query;
							}
						
							break;
					
						case ($.isEmptyObject(_params)):
						
							_url = document.location.href;
						
							break;
					}

				$.extend(data,{return_url:_url,cancel_url:_url});

				/* If request from recurring payment transaction add billing info */
				
					switch(true) {
					
						case (_transaction.method=='recurring' && typeof data.billing.description!==typeof undefined):
						
							$.extend(data,{billing_type:'recurring',billing_agrdesc:data.billing.description});

							break;
					}	

				_send('POST','index.php/paypal/set/',data,response);
			}
			
			function _pay(token,payerid) {
			
				/* Perform DoExpressCheckoutPayment & GetExpressCheckoutDetails (if success) */
				
				var data;
		
				function response(err,obj) {
				
					if (err) {

						_transaction.status = 'failed';
						
						_emit('ppIO.paypal.onetime.payment.failed',[err]);
					
						_message(err);
					
						/* Reset transaction */
						
						return _reset();
					}

					/* Update transaction status */
					
					_transaction.status = 'success';
					
					_emit('ppIO.paypal.onetime.payment.success',[_transaction,obj]);
					
					switch(true) {
					
						case (obj.response.payment.PAYMENTINFO_0_PAYMENTSTATUS=='Completed'):
						
							/* Payment succesfully completed */

							_message('PayPal one time transaction completed succesfully');
						
							break;
					
						case (obj.response.payment.PAYMENTINFO_0_PAYMENTSTATUS=='Pending'):
						
							/* Transaction Complete, but payment is still pending! */

							_message('PayPal one time transaction completed, but payment is still pending. User need to manually authorize this payment in PayPal Account panel');

							break;
					}
					
					_message('Transaction completed');
					
					/* Reset transaction */
					
					return _reset();
				}
				
				/* Update transaction step */
				
				_transaction.step = 'payment';

				/* Build data object */

				data = {
					token: token,
					payerid: payerid,
					items: _data.items
				};
				
				if (typeof _data.config!==typeof undefined) {
				
					$.extend(data,{config:_data.config});
				}

				if (typeof _data.user!==typeof undefined) {
				
					$.extend(data,{user:_data.user});
				}

				if (typeof _data.bl_user!==typeof undefined) {
				
					$.extend(data,{bl_user:_data.bl_user});
				}
				
				if (_preset_id) {
					
					$.extend(data,{_preset_id:_preset_id});
				}

				_send('POST','index.php/paypal/pay/',data,response);
			}
		
			function _subscribe(token,payerid) {
			
				/* Perform CreateRecurringPaymentsProfile & GetExpressCheckoutDetails (if success) */
				
				var data,
					_start;
		
				function response(err,obj) {
				
					if (err) {

						_transaction.status = 'failed';
						
						_emit('ppIO.paypal.recurring.payment.failed',[err]);
					
						_message(err);
					
						/* Reset transaction */
						
						return _reset();
					}

					/* Update transaction status */
					
					_transaction.status = 'success';
					
					_emit('ppIO.paypal.recurring.payment.success',[_transaction,obj]);
					
					switch(true) {
					
						case (obj.response.payment.PROFILESTATUS=='ActiveProfile'):
						
							/* Recurring payments profile created and activated */

							_message('PayPal recurring payment profile created and activated succesfully');
						
							break;
					
						case (obj.response.payment.PROFILESTATUS=='PendingProfile'):
						
							/* The system is in the process of creating the recurring payment profile. Please check your IPN messages for an update. */

							_message('The system is in the process of creating the recurring payment profile. Please check your IPN messages for an update');

							break;
					}
					
					_message('Transaction completed');
					
					/* Reset transaction */
					
					return _reset();
				}
				
				/* Update transaction step */
				
				_transaction.step = 'payment';

				/* Build data object (if not passed set now+1hour+1minute as timestamp) */
				
				switch(true) {
				
					case (typeof _data.start!==typeof undefined):
					
						_start = _data.start;
				
						break;
				
					case (typeof _data.start===typeof undefined):
					
						_start = Math.floor(Date.now()/1000) + 3601;
				
						break;
				}

				data = {
					token: token,
					payerid: payerid,
					items: _data.items,
					start: _start,
					billing: _data.billing
				};
				
				if (typeof _data.config!==typeof undefined) {
				
					$.extend(data,{config:_data.config});
				}

				if (typeof _data.trial!==typeof undefined) {
				
					$.extend(data,{trial:_data.trial});
				}

				if (typeof _data.user!==typeof undefined) {
				
					$.extend(data,{user:_data.user});
				}

				if (typeof _data.bl_user!==typeof undefined) {
				
					$.extend(data,{bl_user:_data.bl_user});
				}

				_send('POST','index.php/paypal/subscribe/',data,response);
			}
		
			function _status(data) {
			
				/* Perform GetRecurringPaymentsProfileDetails */

				function response(err,obj) {
				
					if (err) {

						_emit('ppIO.paypal.profilestatus.failed',[err]);
					
						return _message(err);
					}

					_emit('ppIO.paypal.profilestatus.success',[obj]);
				}

				_send('POST','index.php/paypal/profilestatus/',data,response);
			}
		
			function _cancel(data) {
			
				/* Perform ManageRecurringPaymentsProfileStatus (default action: 'Cancel' - 'Suspend'/'Reactivate' not implemented) */

				function response(err,obj) {
				
					if (err) {

						_emit('ppIO.paypal.cancel.failed',[err]);
					
						return _message(err);
					}

					_emit('ppIO.paypal.cancel.success',[obj]);
				}

				_send('POST','index.php/paypal/cancel/',data,response);
			}
		
			return {
			
				onetime: function(data,source) {
				
					_emit('ppIO.paypal.onetime.start');
				
					return _set(data,source);
				},
				
				recurring: function(data,source) {
				
					_emit('ppIO.paypal.recurring.start');
				
					return _set(data,source);
				},
			
				pay: function(token,payerid) {
				
					return _pay(token,payerid);
				},
			
				subscribe: function(token,payerid) {
				
					return _subscribe(token,payerid);
				},
			
				status: function(data) {
				
					_emit('ppIO.paypal.profilestatus.start');
				
					return _status(data);
				},
			
				cancel: function(data) {
				
					_emit('ppIO.paypal.cancel.start');
				
					return _cancel(data);
				}
			}
			
		})();
				
		_cartadocente = (function() {
		
			function _pay(data,source) {
			
				/* Perform a payment with Carta del Docente */

				function response(err,obj) {

					if (err) {

						_transaction.status = 'failed';
						
						_emit('ppIO.cartadocente.pay.check.failed',[err]);

						_message(err);
					
						/* Reset transaction */
						
						return _reset();
					}
					
					if (typeof obj.response.error!==typeof undefined) {
					
						var _err = obj.response.error.description+' ['+obj.response.error.code+']';
					
						_transaction.status = 'failed';
						
						_emit('ppIO.cartadocente.pay.check.failed',[_err]);

						_message(_err);
					
						/* Reset transaction */
						
						return _reset();
					}

					/* Check amount & user fc related to voucher */
					
					var _amount = 0;
					
					for (var i=0;i<data.items.length;i++) {
					
						_amount+= data.items[i].price*data.items[i].qty;
					}

					if (parseFloat(_amount).toFixed(2)!=parseFloat(obj.response.importo).toFixed(2)) {
					
						var _err = 'L\'importo del voucher 18app o CD non corrisponde all\'importo del carrello (per funzionare devono essere uguali)';
					
						_transaction.status = 'failed';
						
						_emit('ppIO.cartadocente.pay.check.failed',[_err]);

						_message(_err);
					
						/* Reset transaction */
						
						return _reset();
					}

					if (data.bl_user.fc.toLowerCase()!=obj.response.beneficiario.toLowerCase()) {
					
						var _err = 'Il CF dell\'utente che ha creato il buono è diverso dal CF di chi sta acquistando';
					
						_transaction.status = 'failed';
						
						_emit('ppIO.cartadocente.pay.check.failed',[_err]);

						_message(_err);
					
						/* Reset transaction */
						
						return _reset();
					}

					/* Update transaction status */
					
					_transaction.status = 'success';
					
					/* Add response to data */
					
					$.extend(data,{check:obj});

					/* Emit success event */

					_emit('ppIO.cartadocente.pay.check.success',[obj,_transaction,data]);

					/* Request payment */
					
					function _confirm(err,rsp) {

						if (err) {

							_transaction.status = 'failed';
							
							_emit('ppIO.cartadocente.pay.payment.failed',[err]);

							_message(err);
					
							/* Reset transaction */
							
							return _reset();
						}
		
						if (typeof rsp.response.error!==typeof undefined) {
						
							var _err = rsp.response.error.description+' ['+rsp.response.error.code+']';
						
							_transaction.status = 'failed';
							
							_emit('ppIO.cartadocente.pay.payment.failed',[_err]);

							_message(_err);
					
							/* Reset transaction */
							
							return _reset();
						}

						/* Update transaction status */
						
						_transaction.status = 'success';
						
						/* Add response to data */
						
						$.extend(data,{payment:rsp});

						/* Emit success event */

						_emit('ppIO.cartadocente.pay.payment.success',[_transaction,data]);

						_message('Transaction completed');
						
						/* Reset transaction */
						
						return _reset();
					}

					/* Update transaction step */
					
					_transaction.step = 'payment';

					switch(_options.fake) {
					
						case false:
		
							if (_preset_id) {
								
								$.extend(data,{_preset_id:_preset_id});
							}
						
							_send('POST','index.php/cartadocente/pay/',data,_confirm);
							
							break;
					
						case true:
		
							if (_preset_id) {
								
								$.extend(data,{_preset_id:_preset_id});
							}
						
							_message('FAKE REQUEST (TEST)');
						
							_send('POST','index.php/cartadocente/fakepay/',data,_confirm);
							
							break;
					}
				}
				
				/* Set transaction info */
				
				_transaction.type = source.type;
				_transaction.method = source.method;
				_transaction.step = 'check';

				switch(_options.fake) {
				
					case false:
					
						_send('POST','index.php/cartadocente/check/',{code:data.code},response);
						
						break;
				
					case true:
					
						_message('FAKE REQUEST (TEST)');
					
						var _amt = 0;
						
						for (var j=0;j<data.items.length;j++) {
						
							_amt+= (data.items[j].price*data.items[j].qty);
						}
					
						_send('POST','index.php/cartadocente/fakecheck/',{code:data.code,fc:data.bl_user.fc,amount:_amt},response);
						
						break;
				}
			}
			
			return {

				pay: function(data,source) {
				
					_emit('ppIO.cartadocente.pay.start');
				
					return _pay(data,source);
				}
			}
			
		})();
				
		_app18 = (function() {
		
			function _pay(data,source) {
			
				/* Perform a payment with 18app */

				function response(err,obj) {

					if (err) {

						_transaction.status = 'failed';
						
						_emit('ppIO.app18.pay.check.failed',[err]);

						_message(err);
					
						/* Reset transaction */
						
						return _reset();
					}
					
					if (typeof obj.response.error!==typeof undefined) {
					
						var _err = obj.response.error.description+' ['+obj.response.error.code+']';
					
						_transaction.status = 'failed';
						
						_emit('ppIO.app18.pay.check.failed',[_err]);

						_message(_err);
					
						/* Reset transaction */
						
						return _reset();
					}

					/* Check amount & user fc related to voucher */
					
					var _amount = 0;
					
					for (var i=0;i<data.items.length;i++) {
					
						_amount+= data.items[i].price*data.items[i].qty;
					}

					if (parseFloat(_amount).toFixed(2)!=parseFloat(obj.response.importo).toFixed(2)) {
					
						var _err = 'L\'importo del voucher 18app o CD non corrisponde all\'importo del carrello (per funzionare devono essere uguali)';
					
						_transaction.status = 'failed';
						
						_emit('ppIO.app18.pay.check.failed',[_err]);

						_message(_err);
					
						/* Reset transaction */
						
						return _reset();
					}

					if (data.bl_user.fc.toLowerCase()!=obj.response.beneficiario.toLowerCase()) {
					
						var _err = 'Il CF dell\'utente che ha creato il buono è diverso dal CF di chi sta acquistando';
					
						_transaction.status = 'failed';
						
						_emit('ppIO.app18.pay.check.failed',[_err]);

						_message(_err);
					
						/* Reset transaction */
						
						return _reset();
					}

					/* Update transaction status */
					
					_transaction.status = 'success';
					
					/* Add response to data */
					
					$.extend(data,{check:obj});

					/* Emit success event */

					_emit('ppIO.app18.pay.check.success',[obj,_transaction,data]);

					/* Request payment */
					
					function _confirm(err,rsp) {

						if (err) {

							_transaction.status = 'failed';
							
							_emit('ppIO.app18.pay.payment.failed',[err]);

							_message(err);
					
							/* Reset transaction */
							
							return _reset();
						}
		
						if (typeof rsp.response.error!==typeof undefined) {
						
							var _err = rsp.response.error.description+' ['+rsp.response.error.code+']';
						
							_transaction.status = 'failed';
							
							_emit('ppIO.app18.pay.payment.failed',[_err]);

							_message(_err);
					
							/* Reset transaction */
							
							return _reset();
						}

						/* Update transaction status */
						
						_transaction.status = 'success';
						
						/* Add response to data */
						
						$.extend(data,{payment:rsp});

						/* Emit success event */

						_emit('ppIO.app18.pay.payment.success',[_transaction,data]);

						_message('Transaction completed');
						
						/* Reset transaction */
						
						return _reset();
					}

					/* Update transaction step */
					
					_transaction.step = 'payment';

					switch(_options.fake) {
					
						case false:
		
							if (_preset_id) {
								
								$.extend(data,{_preset_id:_preset_id});
							}
						
							_send('POST','index.php/app18/pay/',data,_confirm);
							
							break;
					
						case true:
		
							if (_preset_id) {
								
								$.extend(data,{_preset_id:_preset_id});
							}
						
							_message('FAKE REQUEST (TEST)');
						
							_send('POST','index.php/app18/fakepay/',data,_confirm);
							
							break;
					}
				}
				
				/* Set transaction info */
				
				_transaction.type = source.type;
				_transaction.method = source.method;
				_transaction.step = 'check';

				switch(_options.fake) {
				
					case false:
					
						_send('POST','index.php/app18/check/',{code:data.code},response);
						
						break;
				
					case true:
					
						_message('FAKE REQUEST (TEST)');
					
						var _amt = 0;
						
						for (var j=0;j<data.items.length;j++) {
						
							_amt+= (data.items[j].price*data.items[j].qty);
						}
					
						_send('POST','index.php/app18/fakecheck/',{code:data.code,fc:data.bl_user.fc,amount:_amt},response);
						
						break;
				}
			}
			
			return {

				pay: function(data,source) {
				
					_emit('ppIO.app18.pay.start');
				
					return _pay(data,source);
				}
			}
			
		})();
		
		/* Loader */
		
		$(document).ready(function() {
		
			_load();
		});

		return {
		
			/* Public API.
			
				Global events:

					1) 'ppIO.enable.success'. Triggered if JS library is enabled. User can set payments
							
					2) 'ppIO.enable.failed'. Triggered if JS library is not enabled (localStorage not available). User cannot set payments
					
						Param:
							
						(string) err : error
							
			*/

			paypal: {
			
				onetime: function(data) {
				
					/* Perform a PayPal one time payment. Incoming:

						data :	{
								"items" : [
									{
									"name" : "Item 1",
									"price" : "5.99",
									"number" : "12345",
									"description" : "Item 1 description",
									"qty" : "1"
									},
									{
									"name" : "Item 2",
									"price" : "10.00",
									"number" : "54321",
									"description" : "Item 2 description",
									"qty" : "1"
									},
									...
								],
								"config" : {
									"taxes" : 0,
									"handling" : 0,
									"insurance" : 0,
									"shippingdiscount" : 0,
									"shipping" : 0,
									"noshipping" : 0/1,
									"logo" : '...',
									"cartbordercolor" : "FFFFFF",
									"allownote" : 0/1,
									"currency" : "EUR",
									"localecode" : "IT"
								},
								"user" : {
									"id" : "431705",
									"email" : "..."
								},
								"bl_user" : {
									"name" : "...",
									"last_name" : "...",
									"fc" : "...",
									"address" : "...",
									"zip" : "...",
									"city" : "...",
									"prvc" : "..."
								},
								"_preset_id": 24586952
								}
								
						IMPORTANT:	data.config (and its properties) is optional
									data.user is optional (but if exists all its properties are required)
									data.bl_user is optional (but if exists all its properties are required)
									data._preset_id is optional (if exists script handle frontend transaction by Solve controller)
						
						Events:
						
							1) 'ppIO.paypal.onetime.start'. Triggered when user call ppIO.paypal.onetime(), starting PayPal one time payment
							
							2) 'ppIO.paypal.onetime.set.failed'. Triggered if Token request to PayPal failed
							
								Param:
							
								(string) err : error
							
							3) 'ppIO.paypal.onetime.set.success'. Triggered when script received token from PayPal (before redirecting to PayPal gateway)
								
								Param:
							
								(object) response : API response
								(object) transaction : transaction
								(object) data : data
							
							4) 'ppIO.paypal.onetime.aborted'. Triggered if user return to current page from PayPal gateway without authorize payment
							
							5) 'ppIO.paypal.onetime.resume'. Triggered when PayPal gateway redirect to starting page (transaction will be resumed)
								
								Param:
							
								(object) transaction : transaction
								(object) data : data
								(string) token : PayPal token
								(string) payerid : PayPal PayerID
							
							6) 'ppIO.paypal.onetime.payment.failed'. Triggered if payment failed
								
								Param:
							
								(string) err : error
							
							7) 'ppIO.paypal.onetime.payment.success'. Triggered if payment completed successfully
								
								Param:
							
								(object) transaction : transaction
								(object) details : PayPal transaction details
					*/
					
					var _source;
				
					if (!_enabled) {
					
						return _message('Unable to perform payment. ppIO is not enabled');
					}

					_message('Request for PayPal one time payment');

					_source = {
						type: 'paypal',
						method: 'onetime'
					};
					
					/* _preset_id handler */
					
					_preset_id = null;
					
					if (typeof data._preset_id!==typeof undefined) {
						
						_preset_id = data._preset_id;
											
						/* Store _preset_id in localstorage */
		
						if (localStorage.getItem('ppIO.fe.trs')) {
							
							localStorage.removeItem('ppIO.fe.trs');
						}
						
						localStorage.setItem('ppIO.fe.trs',JSON.stringify({_preset_id:_preset_id}));
					}
				
					return _paypal.onetime(data,_source);
				},
				
				recurring: function(data) {
				
					/* Create a recurring payments profile. Incoming:

						data :	{
								"start" : 1484127785 //the date when billing for this profile begins (as timestamp)
								* "billing" : {
									"description" : "...", //description of goods or services associated with the billing agreement
									"period" : "Day"/"Week"/"SemiMonth"/"Month"/"Year", //unit for billing during this subscription period
									"frequency" : "12", //number of billing periods that make up one billing cycle
								},
								"items" : [
									{
									"name" : "Item 1",
									"price" : "5.99",
									"number" : "12345",
									"description" : "Item 1 description",
									"qty" : "1"
									},
									{
									"name" : "Item 2",
									"price" : "10.00",
									"number" : "54321",
									"description" : "Item 2 description",
									"qty" : "1"
									},
									...
								],
								"config" : {
									"taxes" : 0,
									"handling" : 0,
									"insurance" : 0,
									"shippingdiscount" : 0,
									"shipping" : 0,
									"noshipping" : 0/1,
									"logo" : '...',
									"cartbordercolor" : "FFFFFF",
									"allownote" : 0/1,
									"currency" : "EUR",
									"localecode" : "IT"
								},
								"trial" : {
									"period" : "Day"/"Week"/"SemiMonth"/"Month"/"Year", //unit for billing during trial period
									"frequency" : "12", //number of billing periods that make up one billing cycle
									"cycles" : "1", //number of billing cycles for trial payment period
									"amount" : "6.99" //billing amount for each billing cycle during trial period
								},
								"user" : {
									"id" : "431705",
									"email" : "..."
								},
								"bl_user" : {
									"name" : "...",
									"last_name" : "...",
									"fc" : "...",
									"address" : "...",
									"zip" : "...",
									"city" : "...",
									"prvc" : "..."
								}
								}
								
						IMPORTANT:	data.start is optional
									data.config (and its properties) is optional
									data.trial is optional (but if exists all its properties are required)
									data.user is optional (but if exists all its properties are required)
									data.bl_user is optional (but if exists all its properties are required)

						*	For SemiMonth, billing is done on the 1st and 15th of each month.
							The combination of BillingPeriod and BillingFrequency cannot exceed one year.
							The combination of billing frequency and billing period must be less than or equal to one year. For example, if the billing cycle is Month, the maximum value for billing frequency is 12. Similarly, if the billing cycle is Week, the maximum value for billing frequency is 52.
							If the billing period is SemiMonth, the billing frequency must be 1.
						
						Events:
						
							1) 'ppIO.paypal.recurring.start'. Triggered when user call ppIO.paypal.recurring(), starting PayPal recurring paqyment request
							
							2) 'ppIO.paypal.recurring.set.failed'. Triggered if Token request to PayPal failed
								
								Param:
							
								(string) err : error
							
							3) 'ppIO.paypal.recurring.set.success'. Triggered when script received token from PayPal (before redirecting to PayPal gateway)
								
								Param:
							
								(object) response : API response
								(object) transaction : transaction
								(object) data : data
							
							4) 'ppIO.paypal.recurring.aborted'. Triggered if user return to current page from PayPal gateway without authorize payment
							
							5) 'ppIO.paypal.recurring.resume'. Triggered when PayPal gateway redirect to starting page (transaction will be resumed)
								
								Param:
							
								(object) transaction : transaction
								(object) data : data
								(string) token : PayPal token
								(string) payerid : PayPal PayerID
							
							6) 'ppIO.paypal.recurring.payment.failed'. Triggered if payment failed
								
								Param:
							
								(string) err : error
							
							7) 'ppIO.paypal.recurring.payment.success'. Triggered if payment completed successfully
								
								Param:
							
								(object) transaction : transaction
								(object) details : PayPal transaction details
					*/
			
					var _source;
				
					if (!_enabled) {
					
						return _message('Unable to perform payment. ppIO is not enabled');
					}

					_message('Request for PayPal recurring payments profile');

					_source = {
						type: 'paypal',
						method: 'recurring'
					};
				
					return _paypal.recurring(data,_source);	
				},
								
				status: function(data) {
				
					/* Get a recurring payments profile status. Incoming:

						data :	{
								"profileid" : "I-353BUC5YG33K"
								}

						Events:
						
							1) 'ppIO.paypal.profilestatus.start'. Triggered when user call ppIO.paypal.status()
							
							2) 'ppIO.paypal.profilestatus.failed'. Triggered if profile status request to PayPal failed
								
								Param:
							
								(string) err : error
							
							3) 'ppIO.paypal.profilestatus.success'. Triggered when script received profile status info from PayPal
								
								Param:
							
								(object) response : API response
					*/

					if (!_enabled) {
					
						return _message('Unable to retrieve recurring profile status. ppIO is not enabled');
					}

					_message('Request for PayPal recurring payments profile status');

					return _paypal.status(data);	
				},
								
				cancel: function(data) {
				
					/* Cancel a recurring payments profile status. Incoming:

						data :	{
								"profileid" : "I-353BUC5YG33K"
								}

						Events:
						
							1) 'ppIO.paypal.cancel.start'. Triggered when user call ppIO.paypal.cancel()
							
							2) 'ppIO.paypal.cancel.failed'. Triggered if cancel request to PayPal failed
								
								Param:
							
								(string) err : error
							
							3) 'ppIO.paypal.cancel.success'. Triggered if cancel request to PayPal success
								
								Param:
							
								(object) response : API response
					*/

					if (!_enabled) {
					
						return _message('Unable to cancel recurring profile. ppIO is not enabled');
					}

					_message('Request for PayPal to cancel recurring payments profile');

					return _paypal.cancel(data);	
				}
			},
			
			cartadocente: {
			
				pay: function(data) {
								
					/* Perform a Carta del Docente one time payment (check and burn voucher). Incoming:

						data :	{
								"code" : "aSer45G", // Voucher code
								"items" : [
									{
									"name" : "Item 1",
									"price" : "5.99",
									"number" : "12345",
									"description" : "Item 1 description",
									"qty" : "1"
									},
									{
									"name" : "Item 2",
									"price" : "10.00",
									"number" : "54321",
									"description" : "Item 2 description",
									"qty" : "1"
									},
									...
								],
								"user" : {
									"id" : "431705",
									"email" : "..."
								},
								"bl_user" : {
									"name" : "...",
									"last_name" : "...",
									"fc" : "...",
									"address" : "...",
									"zip" : "...",
									"city" : "...",
									"prvc" : "..."
								},
								"_preset_id": 24586952
								}
								
						IMPORTANT:	data.user is optional (but if exists all its properties are required)
									data._preset_id is optional (if exists script handle frontend transaction by Solve controller)

						Events:
						
							1) 'ppIO.cartadocente.pay.start'. Triggered when user call ppIO.cartadocente.pay(), starting Carta del Docente one time payment
							
							2) 'ppIO.cartadocente.pay.check.failed'. Triggered if Check request to Carta del Docente failed
							
								Param:
							
								(string) err : error
							
							3) 'ppIO.cartadocente.pay.check.success'. Triggered if Check request to Carta del Docente success
								
								Param:
							
								(object) response : API response
								(object) transaction : transaction
								(object) data : data

							4) 'ppIO.cartadocente.pay.payment.failed'. Triggered if payment failed
								
								Param:
							
								(string) err : error
							
							5) 'ppIO.cartadocente.pay.payment.success'. Triggered if payment completed successfully
								
								Param:
							
								(object) transaction : transaction
								(object) details : Carta del Docente transaction details
					*/
					
					var _source;
				
					if (!_enabled) {
					
						return _message('Unable to perform payment. ppIO is not enabled');
					}
					
					_message('Request for Carta del Docente payment');

					_source = {
						type: 'cartadocente',
						method: 'pay'
					};

					/* _preset_id handler */
					
					_preset_id = null;
					
					if (typeof data._preset_id!==typeof undefined) {
						
						_preset_id = data._preset_id;
					}
				
					return _cartadocente.pay(data,_source);
				}
			},
			
			app18: {
			
				pay: function(data) {
								
					/* Perform a 18app one time payment (check and burn voucher). Incoming:

						data :	{
								"code" : "aSer45G", // Voucher code
								"items" : [
									{
									"name" : "Item 1",
									"price" : "5.99",
									"number" : "12345",
									"description" : "Item 1 description",
									"qty" : "1"
									},
									{
									"name" : "Item 2",
									"price" : "10.00",
									"number" : "54321",
									"description" : "Item 2 description",
									"qty" : "1"
									},
									...
								],
								"user" : {
									"id" : "431705",
									"email" : "..."
								},
								"bl_user" : {
									"name" : "...",
									"last_name" : "...",
									"fc" : "...",
									"address" : "...",
									"zip" : "...",
									"city" : "...",
									"prvc" : "..."
								},
								"_preset_id": 24586952
								}
								
						IMPORTANT:	data.user is optional (but if exists all its properties are required)
									data._preset_id is optional (if exists script handle frontend transaction by Solve controller)

						Events:
						
							1) 'ppIO.app18.pay.start'. Triggered when user call ppIO.app18.pay(), starting 18app one time payment
							
							2) 'ppIO.app18.pay.check.failed'. Triggered if Check request to 18app failed
							
								Param:
							
								(string) err : error
							
							3) 'ppIO.app18.pay.check.success'. Triggered if Check request to 18app success
								
								Param:
							
								(object) response : API response
								(object) transaction : transaction
								(object) data : data

							4) 'ppIO.app18.pay.payment.failed'. Triggered if payment failed
								
								Param:
							
								(string) err : error
							
							5) 'ppIO.app18.pay.payment.success'. Triggered if payment completed successfully
								
								Param:
							
								(object) transaction : transaction
								(object) details : 18app transaction details
					*/
					
					var _source;
				
					if (!_enabled) {
					
						return _message('Unable to perform payment. ppIO is not enabled');
					}

					_message('Request for 18app payment');

					_source = {
						type: 'app18',
						method: 'pay'
					};

					/* _preset_id handler */
					
					_preset_id = null;
					
					if (typeof data._preset_id!==typeof undefined) {
						
						_preset_id = data._preset_id;
					}
				
					return _app18.pay(data,_source);
				}
			}
			
			/* End Public API */
		};
		
	})();
