;(function($) {

	var WPForms = {

		/**
		 * Start the engine.
		 *
		 * @since 1.2.3
		 */
		init: function() {

			// Set user identifier
			WPForms.setUserIndentifier();

			// Document ready
			$(document).ready(WPForms.ready);

			// Page load
			$(window).on('load', WPForms.load);

			WPForms.bindUIActions();
		},

		/**
		 * Document ready.
		 *
		 * @since 1.2.3
		 */
		ready: function() {

			WPForms.loadValidation();
			WPForms.loadDatePicker();
			WPForms.loadTimePicker();
			WPForms.loadInputMask();
			WPForms.loadPayments();

			$(document).trigger('wpformsReady');
		},

		/**
		 * Page load.
		 *
		 * @since 1.2.3
		 */
		load: function() {

		},

		//--------------------------------------------------------------------//
		// Initializing
		//--------------------------------------------------------------------//

		/**
		 * Load jQuery Validation.
		 *
		 * @since 1.2.3
		 */
		loadValidation: function() {

			// Only load if jQuery validation library exists
			if (typeof $.fn.validate !== 'undefined') {

				// Payments: Validate method for Credit Card Number
				if(typeof $.fn.payment !== 'undefined') {
					$.validator.addMethod( "creditcard", function(value, element) {
						//var type  = $.payment.cardType(value);
						var valid = $.payment.validateCardNumber(value);
						return this.optional(element) || valid;
					}, "Please enter a valid credit card number.");
					// @todo validate CVC and expiration
				}

				// Validate method for file extensions
				$.validator.addMethod( "extension", function(value, element, param) {
					param = typeof param === "string" ? param.replace( /,/g, "|" ) : "png|jpe?g|gif";
					return this.optional(element) || value.match( new RegExp( "\\.(" + param + ")$", "i" ) );
				}, $.validator.format("File type is not allowed") );

				// Validate method for file size
				$.validator.addMethod("maxsize", function(value, element, param) {
					var maxSize = param,
						optionalValue = this.optional(element),
						i, len, file;
					if (optionalValue) {
						return optionalValue;
					}
					if (element.files && element.files.length) {
						i = 0;
						len = element.files.length;
						for (; i < len; i++) {
							file = element.files[i];
							if (file.size > maxSize) {
								return false;
							}
						}
					}
					return true;
				}, $.validator.format("File exceeds max size allowed"));

				// Validate email addresses
				$.validator.methods.email = function( value, element ) {
					return this.optional( element ) || /^[a-z0-9.!#$%&'*+\/=?^_`{|}~-]+@((?=[a-z0-9-]{1,63}\.)(xn--)?[a-z0-9]+(-[a-z0-9]+)*\.)+[a-z]{2,63}$/i.test( value );
				}

				// Validate confirmations
				$.validator.addMethod("confirm", function(value, element, param) {
					return $.validator.methods.equalTo.call(this, value, element, param);
				}, function(params, element) {
					return $(element).data('rule-confirm-msg');
				});

				// Validate 12-hour time
				$.validator.addMethod( "time12h", function( value, element ) {
					return this.optional( element ) || /^((0?[1-9]|1[012])(:[0-5]\d){1,2}(\ ?[AP]M))$/i.test( value );
				}, "Please enter time in 12-hour AM/PM format (eg 8:45 AM)" );

				// Validate 24-hour time
				$.validator.addMethod( "time24h", function( value, element ) {
					return this.optional(element) || /^(([0-1]?[0-9])|([2][0-3])):([0-5]?[0-9])(\ ?[AP]M)?$/i.test(value);
				}, "Please enter time in 24-hour format (eg 22:45)" );

				// Finally load jQuery Validation library for our forms
				$('.wpforms-validate').each(function() {
					var form   = $(this),
						formID = form.data('formid');

					if (typeof window['wpforms_'+formID] != "undefined" && window['wpforms_'+formID].hasOwnProperty('validate')) {
						properties = window['wpforms_'+formID].validate;
					} else if ( typeof wpforms_validate != "undefined") {
						properties = wpforms_validate;
					} else {
						properties = {
							errorClass: 'wpforms-error',
							validClass: 'wpforms-valid',
							errorPlacement: function(error, element) {
								if (element.attr('type') == 'radio' || element.attr('type') == 'checkbox' ) {
									element.parent().parent().parent().append(error);
								} else if (element.is('select') && element.attr('class').match(/date-month|date-day|date-year/)) {
									if (element.parent().find('label.wpforms-error:visible').length === 0) {
										element.parent().find('select:last').after(error);
									}
								} else {
									error.insertAfter(element);
								}
							},
							highlight: function(element, errorClass, validClass) {
								$(element).addClass(errorClass).removeClass(validClass);
								$(element).closest('.wpforms-field').addClass('wpforms-has-error');
							},
							unhighlight: function(element, errorClass, validClass) {
								$(element).removeClass(errorClass).addClass(validClass);
								$(element).closest('.wpforms-field').removeClass('wpforms-has-error');
							},
							submitHandler: function(form) {

								var $form   = $(form),
									$submit = $form.find('.wpforms-submit'),
									altText = $submit.data('alt-text');

								if (altText) {
									$submit.text(altText).prop('disabled', true);
								}

								form.submit();
							}
						}
					}
					form.validate( properties );
				});
			}
		},

		/**
		 * Load jQuery Date Picker.
		 *
		 * @since 1.2.3
		 */
		loadDatePicker: function() {

			// Only load if jQuery datepicker library exists
			if (typeof $.fn.flatpickr !== 'undefined') {
				$('.wpforms-datepicker').each(function() {
					var element = $(this),
						form    = element.closest('.wpforms-form'),
						formID  = form.data('formid'),
						fieldID = element.closest('.wpforms-field').data('field-id');

					if (typeof window['wpforms_'+formID+'_'+fieldID] != 'undefined' && window['wpforms_'+formID+'_'+fieldID].hasOwnProperty('datepicker')) {
						properties = window['wpforms_'+formID+'_'+fieldID].datepicker;
					} else if (typeof window['wpforms_'+formID] != 'undefined' && window['wpforms_'+formID].hasOwnProperty('datepicker')) {
						properties = window['wpforms_'+formID].datepicker;
					} else if (typeof wpforms_datepicker != 'undefined') {
						properties = wpforms_datepicker;
					} else {
						properties = {
							disableMobile: true
						}
					}
					element.flatpickr(properties)
				});
			};
		},

		/**
		 * Load jQuery Time Picker.
		 *
		 * @since 1.2.3
		 */
		loadTimePicker: function() {

			// Only load if jQuery timepicker library exists
			if (typeof $.fn.timepicker !== 'undefined') {
				$('.wpforms-timepicker').each(function() {
					var element = $(this),
						form    = element.closest('.wpforms-form'),
						formID  = form.data('formid'),
						fieldID = element.closest('.wpforms-field').data('field-id');

					if (typeof window['wpforms_'+formID+'_'+fieldID] != 'undefined' && window['wpforms_'+formID+'_'+fieldID].hasOwnProperty('timepicker')) {
						properties = window['wpforms_'+formID+'_'+fieldID].timepicker;
					} else if (typeof window['wpforms_'+formID] != "undefined" && window['wpforms_'+formID].hasOwnProperty('timepicker') ) {
						properties = window['wpforms_'+formID].timepicker;
					} else if ( typeof wpforms_timepicker != "undefined") {
						properties = wpforms_timepicker;
					} else {
						properties = {
							scrollDefault: 'now',
							forceRoundTime: true
						}
					}
					element.timepicker(properties);
				});
			}
		},

		/**
		 * Load jQuery input masks.
		 *
		 * @since 1.2.3
		 */
		loadInputMask: function() {

			// Only load if jQuery input mask library exists
			if (typeof $.fn.inputmask !== 'undefined') {
				$('.wpforms-masked-input').inputmask();
			};
		},

		/**
		 * Payments: Do various payment-related tasks on load.
		 *
		 * @since 1.2.6
		 */
		loadPayments: function() {

			// Update Total field(s) with latest calculation
			$('.wpforms-payment-total').each(function(index, el) {
				WPForms.amountTotal(this);
			})

			// Credit card valdation
			if(typeof $.fn.payment !== 'undefined') {
				$('.wpforms-field-credit-card-cardnumber').payment('formatCardNumber');
				$('.wpforms-field-credit-card-cardcvc').payment('formatCardCVC');
			};
		},

		//--------------------------------------------------------------------//
		// Binds
		//--------------------------------------------------------------------//

		/**
		 * Element bindings.
		 *
		 * @since 1.2.3
		 */
		bindUIActions: function() {

			// Pagebreak navigation
			$(document).on('click', '.wpforms-page-button', function(event) {
				event.preventDefault();
				WPForms.pagebreakNav($(this));
			});

			// Payments: Update Total field(s) when latest calculation.
			$(document).on('change input', '.wpforms-payment-price', function(event) {
				WPForms.amountTotal(this);
			});

			// Payments: Restrict user input payment fields
			$(document).on('input', '.wpforms-payment-user-input', function(event) {
				var $this = $(this),
					amount = $this.val();
				$this.val(amount.replace(/[^0-9.,]/g, ''));
			});

			// Payments: Sanitize/format user input amounts
			$(document).on('focusout', '.wpforms-payment-user-input', function(event) {
				var $this     = $(this),
					amount    = $this.val(),
					sanitized = WPForms.amountSanitize(amount),
					formatted = WPForms.amountFormat(sanitized);
				$this.val(formatted);
			});

			// OptinMonster: initialize again after OM is finished.
			// This is to accomodate moving the form in the DOM.
			$(document).on('OptinMonsterAfterInject', function(event) {
				WPForms.ready();
			});
		},

		/**
		 * Update Pagebreak navigation.
		 *
		 * @since 1.2.2
		 */
		pagebreakNav: function(el) {

			var $this      = $(el),
				valid      = true,
				action     = $this.data('action'),
				page       = $this.data('page'),
				page2      = page;
				next       = page+1,
				prev       = page-1,
				formID     = $this.data('formid'),
				$form      = $this.closest('.wpforms-form'),
				$page      = $form.find('.wpforms-page-'+page),
				$submit    = $form.find('.wpforms-submit-container'),
				$indicator = $form.find('.wpforms-page-indicator'),
				$reCAPTCHA = $form.find('.wpforms-recaptcha-container'),
				pageScroll = false;

			// Page scroll
			if ( window.wpforms_pageScroll === false ) {
				pageScroll = false;
			} else if ( !WPForms.empty( window.wpform_pageScroll ) ) {
				pageScroll = window.wpform_pageScroll;
			} else {
				pageScroll = 75;
			}

			// Toggling between pages
			if ( action == 'next' ){
				// Validate
				if (typeof $.fn.validate !== 'undefined') {
					$page.find('input.wpforms-field-required, select.wpforms-field-required, textarea.wpforms-field-required, .wpforms-field-required input').each(function(index, el) {
						var field = $(el);
						if ( field.valid() ) {
						} else {
							valid = false;
						}
					});
					// Scroll to first/top error on page
					var $topError = $page.find('.wpforms-error').first();
					if ($topError.length) {
						$('html, body').animate({
							scrollTop: $topError.offset().top-75
						}, 750, function() {
							$topError.focus();
						});
					}
				}
				// Move to next page
				if (valid) {
					page2 = next;
					$page.hide();
					var $nextPage = $form.find('.wpforms-page-'+next);
					$nextPage.show();
					if ( $nextPage.hasClass('last') ) {
						$reCAPTCHA.show();
						$submit.show();
					}
					if ( pageScroll ) {
						// Scroll to top of the form
						$('html, body').animate({
							scrollTop: $form.offset().top-pageScroll
						}, 1000);
					}
					$this.trigger('wpformsPageChange', [ page2, $form ] );
				}
			} else if ( action == 'prev' ) {
				// Move to prev page
				page2 = prev;
				$page.hide();
				$form.find('.wpforms-page-'+prev).show();
				$reCAPTCHA.hide();
				$submit.hide();
				if ( pageScroll ) {
					// Scroll to top of the form
					$('html, body').animate({
						scrollTop: $form.offset().top-pageScroll
					}, 1000);
				}
				$this.trigger('wpformsPageChange', [ page2, $form ] );
			}

			if ( $indicator ) {
				var theme = $indicator.data('indicator'),
					color = $indicator.data('indicator-color');
				if ('connector' === theme || 'circles' === theme) {
					$indicator.find('.wpforms-page-indicator-page').removeClass('active');
					$indicator.find('.wpforms-page-indicator-page-'+page2).addClass('active');
					$indicator.find('.wpforms-page-indicator-page-number').removeAttr('style');
					$indicator.find('.active .wpforms-page-indicator-page-number').css('background-color', color);
					if ( 'connector' == theme) {
						$indicator.find('.wpforms-page-indicator-page-triangle').removeAttr('style');
						$indicator.find('.active .wpforms-page-indicator-page-triangle').css('border-top-color', color);
					}
				} else if ('progress' === theme) {
					var $pageTitle = $indicator.find('.wpforms-page-indicator-page-title'),
						$pageSep   = $indicator.find('.wpforms-page-indicator-page-title-sep'),
						totalPages = ($('.wpforms-page').length),
						width = (page2/totalPages)*100;
					$indicator.find('.wpforms-page-indicator-page-progress').css('width', width+'%');
					$indicator.find('.wpforms-page-indicator-steps-current').text(page2);
					if ($pageTitle.data('page-'+page2+'-title')) {
						$pageTitle.css('display','inline').text($pageTitle.data('page-'+page2+'-title'));
						$pageSep.css('display','inline');
					} else {
						$pageTitle.css('display','none');
						$pageSep.css('display','none');
					}
				}
			}
		},

		//--------------------------------------------------------------------//
		// Other functions
		//--------------------------------------------------------------------//

		/**
		 * Payments: Calculate total.
		 *
		 * @since 1.2.3
		 */
		amountTotal: function(el) {

			var $form                = $(el).closest('.wpforms-form'),
				total                = 0,
				totalFormatted       = 0,
				totalFormattedSymbol = 0,
				currency             = WPForms.getCurrency();

			$('.wpforms-payment-price').each(function(index, el) {

				var amount = 0,
					$this  = $(this);

				if ($this.attr('type') === 'text' || $this.attr('type') === 'hidden' ) {
					amount = $this.val();
				} else if ($this.attr('type') === 'radio' && $this.is(':checked')) {
					amount = $this.data('amount');
				} else if ($this.is('select') && $this.find('option:selected').length > 0) {
					amount = $this.find('option:selected').data('amount');
				}
				if (!WPForms.empty(amount)) {
					amount = WPForms.amountSanitize(amount);
					total  = Number(total)+Number(amount);
				}
			});

			totalFormatted = WPForms.amountFormat(total);

			if ( 'left' == currency.symbol_pos) {
				totalFormattedSymbol = currency.symbol+' '+totalFormatted;
			} else {
				totalFormattedSymbol = totalFormatted+' '+currency.symbol;
			}

			$form.find('.wpforms-payment-total').each(function(index, el) {
				if ($(this).attr('type') == 'hidden') {
					$(this).val(totalFormattedSymbol);
				} else {
					$(this).text(totalFormattedSymbol);
				}
			});
		},

		/**
		 * Sanitize amount and convert to standard format for calculations.
		 *
		 * @since 1.2.6
		 */
		amountSanitize: function(amount) {

			var currency = WPForms.getCurrency();

			amount = amount.toString().replace(/[^0-9.,]/g,'');

			if ( currency.decimal_sep == ',' && ( amount.indexOf(currency.decimal_sep) !== -1 ) ) {
				if ( currency.thousands_sep == '.' && amount.indexOf(currency.thousands_sep) !== -1 ) {;
					amount = amount.replace(currency.thousands_sep,'');
				} else if( currency.thousands_sep == '' && amount.indexOf('.') !== -1 ) {
					amount = amount.replace('.','');
				}
				amount = amount.replace(currency.decimal_sep,'.');
			} else if ( currency.thousands_sep == ',' && ( amount.indexOf(currency.thousands_sep) !== -1 ) ) {
				amount = amount.replace(currency.thousands_sep,'');
			}

			return WPForms.numberFormat( amount, 2, '.', '' );
		},

		/**
		 * Format amount.
		 *
		 * @since 1.2.6
		 */
		amountFormat: function(amount) {

			var currency = WPForms.getCurrency();

			amount = String(amount);

			// Format the amount
			if ( currency.decimal_sep == ',' && ( amount.indexOf(currency.decimal_sep) !== -1 ) ) {
				var sepFound = amount.indexOf(currency.decimal_sep);
					whole    = amount.substr(0, sepFound);
					part     = amount.substr(sepFound+1, amount.strlen-1);
				amount = whole + '.' + part;
			}

			// Strip , from the amount (if set as the thousands separator)
			if ( currency.thousands_sep == ',' && ( amount.indexOf(currency.thousands_sep) !== -1 ) ) {
				amount = amount.replace(',','');
			}

			if ( WPForms.empty( amount ) ) {
				amount = 0;
			}

			return WPForms.numberFormat( amount, 2, currency.decimal_sep, currency.thousands_sep );
		},

		/**
		 * Get site currency settings.
		 *
		 * @since 1.2.6
		 */
		getCurrency: function() {

			var currency = {
				thousands_sep: ',',
				decimal_sep: '.',
				symbol: '$',
				symbol_pos: 'left'
			}

			if ( 'undefined' !== wpforms_currency) {
				currency.thousands_sep = wpforms_currency.thousands;
				currency.decimal_sep   = wpforms_currency.decimal;
				currency.symbol        = wpforms_currency.symbol;
				currency.symbol_pos    = wpforms_currency.symbol_pos;
			}

			return currency;
		},

		/**
		 * Format number.
		 *
		 * @link http://locutus.io/php/number_format/
		 * @since 1.2.6
		 */
		numberFormat: function (number, decimals, decimalSep, thousandsSep) {

			number = (number + '').replace(/[^0-9+\-Ee.]/g, '')
			var n = !isFinite(+number) ? 0 : +number
			var prec = !isFinite(+decimals) ? 0 : Math.abs(decimals)
			var sep = (typeof thousandsSep === 'undefined') ? ',' : thousandsSep
			var dec = (typeof decimalSep === 'undefined') ? '.' : decimalSep
			var s = ''

			var toFixedFix = function (n, prec) {
				var k = Math.pow(10, prec)
				return '' + (Math.round(n * k) / k).toFixed(prec)
			}

			// @todo: for IE parseFloat(0.55).toFixed(0) = 0;
			s = (prec ? toFixedFix(n, prec) : '' + Math.round(n)).split('.')
			if (s[0].length > 3) {
				s[0] = s[0].replace(/\B(?=(?:\d{3})+(?!\d))/g, sep)
			}
			if ((s[1] || '').length < prec) {
				s[1] = s[1] || ''
				s[1] += new Array(prec - s[1].length + 1).join('0')
			}

			return s.join(dec)
		},

		/**
		 * Empty check similar to PHP.
		 *
		 * @link http://locutus.io/php/empty/
		 * @since 1.2.6
		 */
		empty: function(mixedVar) {

			var undef
			var key
			var i
			var len
			var emptyValues = [undef, null, false, 0, '', '0']

			for (i = 0, len = emptyValues.length; i < len; i++) {
				if (mixedVar === emptyValues[i]) {
					return true
				}
			}

			if (typeof mixedVar === 'object') {
				for (key in mixedVar) {
					if (mixedVar.hasOwnProperty(key)) {
						return false
					}
				}
				return true
			}

			return false
		},

		/**
		 * Set cookie container user UUID.
		 *
		 * @since 1.3.3
		 */
		setUserIndentifier: function() {

			if ( ! WPForms.getCookie('_wpfuuid') ) {

				// Generate UUID - http://stackoverflow.com/a/873856/1489528
				var s         = new Array(36),
					hexDigits = '0123456789abcdef',
					uuid;

				for (var i = 0; i < 36; i++) {
					s[i] = hexDigits.substr(Math.floor(Math.random() * 0x10), 1);
				}
				s[14] = "4";
				s[19] = hexDigits.substr((s[19] & 0x3) | 0x8, 1);
				s[8]  = s[13] = s[18] = s[23] = '-';

				uuid = s.join("");

				WPForms.createCookie('_wpfuuid', uuid, 3999);
			}
		},

		/**
		 * Create cookie.
		 *
		 * @since 1.3.3
		 */
		createCookie: function(name, value, days) {

			// If we have a days value, set it in the expiry of the cookie.
			if ( days ) {
				// If -1 is our value, set a session based cookie instead of a persistent cookie.
				if ( '-1' == days ) {
					var expires = '';
				} else {
					var date = new Date();
					date.setTime(date.getTime() + (days*24*60*60*1000));
					var expires = '; expires=' + date.toGMTString();
				}
			} else {
				var expires = '; expires=Thu, 01 Jan 1970 00:00:01 GMT';
			}

			// Write the cookie.
			document.cookie = name + '=' + value + expires + '; path=/';
		},

		/**
		 * Retrieve cookie.
		 *
		 * @since 1.3.3
		 */
		getCookie: function(name) {

			var nameEQ = name + '=',
				ca     = document.cookie.split(';');

			for ( var i = 0; i < ca.length; i++ ) {
				var c = ca[i];
				while ( c.charAt(0) == ' ' ) {
					c = c.substring(1, c.length);
				}
				if ( c.indexOf(nameEQ) == 0 ) {
					return c.substring(nameEQ.length, c.length);
				}
			}

			return null;
		},

		/**
		 * Delete cookie.
		 */
		removeCookie: function(name) {

			WPForms.createCookie(name, '',-1);
		}
	}

	WPForms.init();

	window.wpforms = WPForms;

})(jQuery);