/**
 *  Credits: https://github.com/FezVrasta/bootstrap-material-design
 *
 *  @package Hestia
 */

jQuery( document ).ready(
	function($) {
		// Selector to select only not already processed elements
		$.expr[':'].notmdproc = function(obj) {
			if ($( obj ).data( 'mdproc' )) {
				return false;
			} else {
				return true;
			}
		};

		function _isChar(evt) {
			if (typeof evt.which === 'undefined') {
				return true;
			} else if (typeof evt.which === 'number' && evt.which > 0) {
				return ( ! evt.ctrlKey &&
				! evt.metaKey &&
				! evt.altKey &&
				evt.which !== 8 && // backspace
				evt.which !== 9 && // tab
				evt.which !== 13 && // enter
				evt.which !== 16 && // shift
				evt.which !== 17 && // ctrl
				evt.which !== 20 && // caps lock
				evt.which !== 27 // escape
				);
			}
			return false;
		}

		function _addFormGroupFocus(element) {
			var $element = $( element );
			if ( ! $element.prop( 'disabled' )) { // this is showing as undefined on chrome but works fine on firefox??
				$element.closest( '.form-group' ).addClass( 'is-focused' );
			}
		}

		function _toggleDisabledState($element, state) {
			var $target;
			if ($element.hasClass( 'checkbox-inline' ) || $element.hasClass( 'radio-inline' )) {
				$target = $element;
			} else {
				$target = $element.closest( '.checkbox' ).length ? $element.closest( '.checkbox' ) : $element.closest( '.radio' );
			}
			return $target.toggleClass( 'disabled', state );
		}

		function _toggleTypeFocus($input) {
			var disabledToggleType = false;
			if ($input.is( $.material.options.checkboxElements ) || $input.is( $.material.options.radioElements )) {
				disabledToggleType = true;
			}
			$input.closest( 'label' ).hover(
				function() {
					var $i         = $( this ).find( 'input' );
					var isDisabled = $i.prop( 'disabled' ); // hack because the _addFormGroupFocus() wasn't identifying the property on chrome
					if (disabledToggleType) {
						_toggleDisabledState( $( this ), isDisabled );
					}
					if ( ! isDisabled) {
						_addFormGroupFocus( $i ); // need to find the input so we can check disablement
					}
				},
				function() {
					_removeFormGroupFocus( $( this ).find( 'input' ) );
				}
			);
		}

		function _removeFormGroupFocus(element) {
			$( element ).closest( '.form-group' ).removeClass( 'is-focused' ); // remove class from form-group
		}

		$.material = {
			'options': {
				// These options set what will be started by $.material.init()
				'validate': true,
				'input': true,
				'ripples': true,
				'checkbox': true,
				'togglebutton': true,
				'radio': true,
				'arrive': true,
				'autofill': false,

				'withRipples': [
				'.btn:not(.btn-link)',
				'.card-image',
				'.navbar a:not(.withoutripple)',
				'.dropdown-menu a',
				'.nav-tabs a:not(.withoutripple)',
				'.withripple',
				'.pagination li:not(.active):not(.disabled) a:not(.withoutripple)'
				].join( ',' ),
				'inputElements': 'input.form-control, textarea.form-control, select.form-control',
				'checkboxElements': '.checkbox > label > input[type=checkbox], label.checkbox-inline > input[type=checkbox]',
				'togglebuttonElements': '.togglebutton > label > input[type=checkbox]',
				'radioElements': '.radio > label > input[type=radio], label.radio-inline > input[type=radio]'
			},
			'checkbox': function(selector) {
				// Add fake-checkbox to material checkboxes
				var $input = $( (selector) ? selector : this.options.checkboxElements )
				.filter( ':notmdproc' )
				.data( 'mdproc', true )
				.after( '<span class="checkbox-material"><span class="check"></span></span>' );

				_toggleTypeFocus( $input );
			},
			'togglebutton': function(selector) {
				// Add fake-checkbox to material checkboxes
				var $input = $( (selector) ? selector : this.options.togglebuttonElements )
				.filter( ':notmdproc' )
				.data( 'mdproc', true )
				.after( '<span class="toggle"></span>' );

				_toggleTypeFocus( $input );
			},
			'radio': function(selector) {
				// Add fake-radio to material radios
				var $input = $( (selector) ? selector : this.options.radioElements )
				.filter( ':notmdproc' )
				.data( 'mdproc', true )
				.after( '<span class="circle"></span><span class="check"></span>' );

				_toggleTypeFocus( $input );
			},
			'input': function(selector) {
				$( (selector) ? selector : this.options.inputElements )
				.filter( ':notmdproc' )
				.data( 'mdproc', true )
				.each(
					function() {
						var $input = $( this );

						// Requires form-group standard markup (will add it if necessary)
							var $formGroup = $input.closest( '.form-group' ); // note that form-group may be grandparent in the case of an input-group
						if ($formGroup.length === 0 && $input.attr( 'type' ) !== 'hidden' && ! $input.attr( 'hidden' ) && ! $input.parents( '.pirate_forms' ).length ) {
							$input.wrap( '<div class="form-group"></div>' );
							$formGroup = $input.closest( '.form-group' ); // find node after attached (otherwise additional attachments don't work)
						}

						// Pirate Forms compatibility
						if ($formGroup.length === 0 && $input.attr( 'type' ) !== 'hidden' && ! $input.attr( 'hidden' ) && $input.parents( '.pirate_forms' ).length ) {
							var $labelControl = $input.prev();
							if( $input.attr('type') === 'checkbox' ) {
								$labelControl = $input.next();
							}
							$input.add( $labelControl ).wrapAll( '<div class="form-group label-floating"></div>' );
							$formGroup = $input.closest( '.form-group' );
						}

						// Legacy - Add hint label if using the old shorthand data-hint attribute on the input
						if ($input.attr( 'data-hint' )) {
							$input.after( '<p class="help-block">' + $input.attr( 'data-hint' ) + '</p>' );
							$input.removeAttr( 'data-hint' );
						}

						// Legacy - Change input-sm/lg to form-group-sm/lg instead (preferred standard and simpler css/less variants)
						var legacySizes = {
							'input-lg': 'form-group-lg',
							'input-sm': 'form-group-sm'
						};
						$.each(
							legacySizes, function(legacySize, standardSize) {
								if ($input.hasClass( legacySize )) {
									$input.removeClass( legacySize );
									$formGroup.addClass( standardSize );
								}
							}
						);

						// Legacy - Add label-floating if using old shorthand <input class="floating-label" placeholder="foo">
						if ($input.hasClass( 'floating-label' )) {
							var placeholder = $input.attr( 'placeholder' );
							$input.attr( 'placeholder', null ).removeClass( 'floating-label' );
							var id           = $input.attr( 'id' );
							var forAttribute = '';
							if (id) {
								forAttribute = 'for="' + id + '"';
							}
							$formGroup.addClass( 'label-floating' );
							$input.after( '<label ' + forAttribute + 'class="control-label">' + placeholder + '</label>' );
						}

						// Set as empty if is empty (damn I must improve this...)
						if ($input.val() === null || $input.val() === 'undefined' || $input.val() === '') {
							$formGroup.addClass( 'is-empty' );
						}

						// Support for file input
						if ($formGroup.find( 'input[type=file]' ).length > 0) {
							$formGroup.addClass( 'is-fileinput' );
						}
					}
				);
			},
			'attachInputEventHandlers': function() {
				var validate = this.options.validate;

				$( document )
				.on(
					'keydown paste', '.form-control', function(e) {
						if (_isChar( e )) {
							$( this ).closest( '.form-group' ).removeClass( 'is-empty' );
						}
					}
				)
				.on(
					'keyup change', '.form-control', function() {
						var $input     = $( this );
						var $formGroup = $input.closest( '.form-group' );
						var isValid    = (typeof $input[0].checkValidity === 'undefined' || $input[0].checkValidity());

						if ($input.val() === '') {
							$formGroup.addClass( 'is-empty' );
						} else {
							$formGroup.removeClass( 'is-empty' );
						}

						// Validation events do not bubble, so they must be attached directly to the input: http://jsfiddle.net/PEpRM/1/
						// Further, even the bind method is being caught, but since we are already calling #checkValidity here, just alter
						// the form-group on change.
						//
						// NOTE: I'm not sure we should be intervening regarding validation, this seems better as a README and snippet of code.
						// BUT, I've left it here for backwards compatibility.
						if (validate) {
							if (isValid) {
								$formGroup.removeClass( 'has-error' );
							} else {
								$formGroup.addClass( 'has-error' );
							}
						}
					}
				)
				.on(
					'focus', '.form-control, .form-group.is-fileinput', function() {
						_addFormGroupFocus( this );
					}
				)
				.on(
					'blur', '.form-control, .form-group.is-fileinput', function() {
						_removeFormGroupFocus( this );
					}
				)
				// make sure empty is added back when there is a programmatic value change.
				// NOTE: programmatic changing of value using $.val() must trigger the change event i.e. $.val('x').trigger('change')
				.on(
					'change', '.form-group input', function() {
						var $input = $( this );
						if ($input.attr( 'type' ) === 'file') {
							return;
						}

						var $formGroup = $input.closest( '.form-group' );
						var value      = $input.val();
						if (value) {
							$formGroup.removeClass( 'is-empty' );
						} else {
							$formGroup.addClass( 'is-empty' );
						}
					}
				)
				// set the fileinput readonly field with the name of the file
				.on(
					'change', '.form-group.is-fileinput input[type="file"]', function() {
						var $input     = $( this );
						var $formGroup = $input.closest( '.form-group' );
						var value      = '';
						$.each(
							this.files, function(i, file) {
								value += file.name + ', ';
							}
						);
						value = value.substring( 0, value.length - 2 );
						if (value) {
							$formGroup.removeClass( 'is-empty' );
						} else {
							$formGroup.addClass( 'is-empty' );
						}
						$formGroup.find( 'input.form-control[readonly]' ).val( value );
					}
				);
			},
			'ripples': function(selector) {
				$( (selector) ? selector : this.options.withRipples ).ripples();
			},
			'autofill': function() {
				// This part of code will detect autofill when the page is loading (username and password inputs for example)
				var loading = setInterval(
					function() {
						$( 'input[type!=checkbox]' ).each(
							function() {
								var $this = $( this );
								if ($this.val() && $this.val() !== $this.attr( 'value' )) {
									$this.trigger( 'change' );
								}
							}
						);
					}, 100
				);

				// After 10 seconds we are quite sure all the needed inputs are autofilled then we can stop checking them
				setTimeout(
					function() {
						clearInterval( loading );
					}, 10000
				);
			},
			'attachAutofillEventHandlers': function() {
				// Listen on inputs of the focused form (because user can select from the autofill dropdown only when the input has focus)
				var focused;
				$( document )
				.on(
					'focus', 'input', function() {
						var $inputs = $( this ).parents( 'form' ).find( 'input' ).not( '[type=file]' );
						focused     = setInterval(
							function() {
								$inputs.each(
									function() {
										var $this = $( this );
										if ($this.val() !== $this.attr( 'value' )) {
											$this.trigger( 'change' );
										}
									}
								);
							}, 100
						);
					}
				)
				.on(
					'blur', '.form-group input', function() {
						clearInterval( focused );
					}
				);
			},
			'init': function(options) {
				this.options  = $.extend( {}, this.options, options );
				var $document = $( document );

				if ($.fn.ripples && this.options.ripples) {
					this.ripples();
				}
				if (this.options.input) {
					this.input();
					this.attachInputEventHandlers();
				}
				if (this.options.checkbox) {
					this.checkbox();
				}
				if (this.options.togglebutton) {
					this.togglebutton();
				}
				if (this.options.radio) {
					this.radio();
				}
				if (this.options.autofill) {
					this.autofill();
					this.attachAutofillEventHandlers();
				}

				if (document.arrive && this.options.arrive) {
					if ($.fn.ripples && this.options.ripples) {
						$document.arrive(
							this.options.withRipples, function() {
								$.material.ripples( $( this ) );
							}
						);
					}
					if (this.options.input) {
						$document.arrive(
							this.options.inputElements, function() {
								$.material.input( $( this ) );
							}
						);
					}
					if (this.options.checkbox) {
						$document.arrive(
							this.options.checkboxElements, function() {
								$.material.checkbox( $( this ) );
							}
						);
					}
					if (this.options.radio) {
						$document.arrive(
							this.options.radioElements, function() {
								$.material.radio( $( this ) );
							}
						);
					}
					if (this.options.togglebutton) {
						$document.arrive(
							this.options.togglebuttonElements, function() {
								$.material.togglebutton( $( this ) );
							}
						);
					}

				}
			}
		};

	}
);
