/**
 * Theme Name: errigal
 * Theme URI: https://projecterrigal.com/themes/errigal/
 * Author: Project errigal
 * Author URI: https://projecterrigal.com/
 * Version: 1.2.1
 */
( function() {
	'use strict';

	const CLASS_SHARED_COLLAPSED = 'collapsed';
	const CLASS_NAV_BREADCRUMB_LINK = 'errigal-breadcrumb__link';
	const CLASS_NAV_BREADCRUMB_LIST_ITEM_ANCESTOR = 'errigal-breadcrumb__ancestor';
	const SELECTOR_NAV_BREADCRUMB_ANCESTOR_LINK = `.${ CLASS_NAV_BREADCRUMB_LIST_ITEM_ANCESTOR } > .${ CLASS_NAV_BREADCRUMB_LINK }`;
	const NULL_ELEMENT = null;

	function isFunction( value ) {
		return value instanceof Function;
	}

	const INDEX_FIRST = 0;

	function isHTMLCollection( elements ) {
		return elements instanceof HTMLCollection;
	}

	function isObjectType( value, expectedType ) {
		return Object.prototype.toString.call( value ) ===
			`[object ${ expectedType }]`;
	}

	function isNumber( value ) {
		return (
			! isNaN( value ) &&
			isObjectType( value, 'Number' ) &&
			isFinite( value )
		);
	}

	function isPositiveNumber( value ) {
		return isNumber( value ) && value > 0;
	}

	function isIterable( items ) {
		return !! items && isPositiveNumber( items.length );
	}

	function isTrue( value ) {
		return value === true;
	}

	function forEach( items, callback ) {
		if ( ! isIterable( items ) || ! isFunction( callback ) ) {
			return false;
		}

		if ( isHTMLCollection( items ) ) {
			items = Array.prototype.slice.call( items );
		}

		for ( let i = INDEX_FIRST; i < items.length; i++ ) {
			if ( isTrue( callback( items[ i ], i, items ) ) ) {
				return true;
			}
		}

		return false;
	}

	function hasClassList( element ) {
		return (
			!! element &&
			element.classList instanceof DOMTokenList &&
			isFunction( element.classList.contains )
		);
	}

	function isHTMLElement( element, ...classNames ) {
		if ( ! ( element instanceof HTMLElement ) ) {
			return false;
		}

		return (
			hasClassList( element ) &&
			! forEach(
				classNames,
				( className ) => ! element.classList.contains( className )
			)
		);
	}

	const EMPTY_STRING = '';

	function isString( value ) {
		return isObjectType( value, 'String' );
	}

	function isNonEmptyString( value ) {
		return (
			isString( value ) &&
			isFunction( value.trim ) &&
			value.trim() !== EMPTY_STRING
		);
	}

	function isDocument( element ) {
		return element instanceof Document;
	}

	function isisHTMLElementOrDocument( element ) {
		return isHTMLElement( element ) || isDocument( element );
	}

	function callElementMethod(
		methodName,
		nameOrSelectors,
		rootElement
	) {
		return (
			isNonEmptyString( methodName ) &&
			isNonEmptyString( nameOrSelectors ) &&
			isisHTMLElementOrDocument( rootElement ) &&
			isFunction( rootElement[ methodName ] )
		)
			? rootElement[ methodName ]( nameOrSelectors )
			: NULL_ELEMENT;
	}

	function querySelector( selectors, rootElement = document ) {
		return callElementMethod( 'querySelector', selectors, rootElement );
	}

	function getFirstBreadcrumbAncestorLink() {
		return querySelector( SELECTOR_NAV_BREADCRUMB_ANCESTOR_LINK );
	}

	const CLASS_NAV_BREADCRUMB_LIST = 'errigal-breadcrumb__list';
	const NULL_VALUE = null;

	function getFirstItem( items ) {
		return isIterable( items )
			? items[ INDEX_FIRST ]
			: NULL_VALUE;
	}

	function getElementsByClassName(
		className,
		rootElement = document
	) {
		const ELEMENTS =
			callElementMethod(
				'getElementsByClassName',
				className,
				rootElement
			);

		return isHTMLCollection( ELEMENTS )
			? ELEMENTS
			: NULL_ELEMENT;
	}

	function getElementByClassName(
		className,
		rootElement = document
	) {
		return getFirstItem( getElementsByClassName( className, rootElement ) );
	}

	function getBreadcrumbList() {
		return getElementByClassName( CLASS_NAV_BREADCRUMB_LIST );
	}

	const CLASS_NAV_BREADCRUMB_REVEAL_BUTTON = 'errigal-breadcrumb__reveal-button';

	function isBreadcrumbRevealButton( element ) {
		return isHTMLElement( element, CLASS_NAV_BREADCRUMB_REVEAL_BUTTON );
	}

	function removeClass( element, className ) {
		if (
			! isHTMLElement( element ) ||
			! hasClassList( element ) ||
			! isFunction( element.classList.remove ) ||
			! isNonEmptyString( className )
		) {
			return;
		}

		element.classList.remove( className );
	}

	function toLowerCase( value ) {
		return isNonEmptyString( value ) && isFunction( value.toLowerCase )
			? value.toLowerCase()
			: EMPTY_STRING;
	}

	function areStringsEqualIgnoreCase( str1, str2 ) {
		return toLowerCase( str1 ) === toLowerCase( str2 );
	}

	function isEvent( value ) {
		return (
			value instanceof Event &&
			isFunction( value.preventDefault ) &&
			isFunction( value.stopPropagation )
		);
	}

	function isKey( event, key, keyCode ) {
		return isEvent( event ) && isNonEmptyString( key ) && isNumber( keyCode )
			? areStringsEqualIgnoreCase( event.key, key ) ||
			event.keyCode === keyCode
			: false;
	}

	function isEnterKey( event ) {
		return isKey( event, 'Enter', 13 );
	}

	const EVENT_CLICK = 'click';

	function isBoolean( value ) {
		return isObjectType( value, 'Boolean' );
	}

	function isObject( value ) {
		return value instanceof Object;
	}

	function isUndefined( value ) {
		return isObjectType( value, 'Undefined' );
	}

	function onDocumentEvent( eventType, callback, options ) {
		if (
			! isNonEmptyString( eventType ) ||
			! isFunction( callback ) ||
			! ( isUndefined( options ) || isObject( options ) || isBoolean( options ) )
		) {
			return;
		}

		document.addEventListener( eventType, callback, options || false );
	}

	function onDocumentClick( callback, options ) {
		onDocumentEvent( EVENT_CLICK, callback, options );
	}

	const EVENT_KEYDOWN = 'keydown';

	function onDocumentKeydown( callback, options ) {
		onDocumentEvent( EVENT_KEYDOWN, callback, options );
	}

	const EVENT_LOAD = 'load';

	function onWindowEvent( eventType, callback, options ) {
		if (
			! isNonEmptyString( eventType ) ||
			! isFunction( callback ) ||
			! ( isUndefined( options ) || isObject( options ) || isBoolean( options ) )
		) {
			return;
		}

		window.addEventListener( eventType, callback, options || false );
	}

	function onWindowLoad( callback, options ) {
		onWindowEvent( EVENT_LOAD, callback, options );
	}

	const EVENT_RESIZE = 'resize';

	function onWindowResize( callback, options ) {
		onWindowEvent( EVENT_RESIZE, callback, options );
	}

	const CALLBACK_INITIAL_ATTEMPT_COUNT = 0;
	const CALLBACK_INITIAL_INTERVAL = 0;
	const CALLBACK_INTERVAL = 50;
	const CALLBACK_MAX_ATTEMPT_COUNT = 20;

	function focusElement(
		element,
		attemptCount = CALLBACK_INITIAL_ATTEMPT_COUNT,
		interval = CALLBACK_INITIAL_INTERVAL
	) {
		if (
			! isHTMLElement( element ) ||
			! isFunction( element.focus ) ||
			! isNumber( attemptCount ) ||
			! isNumber( interval ) ||
			attemptCount === CALLBACK_MAX_ATTEMPT_COUNT
		) {
			return;
		}

		element.focus();
		setTimeout(
			() => {
				if ( element === document.activeElement ) {
					return;
				}

				focusElement( element, ++attemptCount, CALLBACK_INTERVAL );
			},
			interval
		);
	}

	const CLASS_NAV_BREADCRUMB_LIST_ITEM = 'errigal-breadcrumb__list-item';

	function getBreadcrumbListItems() {
		return getElementsByClassName( CLASS_NAV_BREADCRUMB_LIST_ITEM );
	}

	const RECT_WIDTH = 'width';
	const PIXEL_ZERO = 0;

	function getObjectValue( obj, key ) {
		return isObject( obj ) && ( key in obj )
			? obj[ key ]
			: NULL_VALUE;
	}

	function getRectProp( element, property ) {
		if (
			! isHTMLElement( element ) ||
			! isFunction( element.getBoundingClientRect )
		) {
			return PIXEL_ZERO;
		}

		const RECT_PROP =
			getObjectValue(
				element.getBoundingClientRect(),
				property
			);

		return isNumber( RECT_PROP )
			? RECT_PROP
			: PIXEL_ZERO;
	}

	function getWidth( element ) {
		return getRectProp( element, RECT_WIDTH );
	}

	function addClass( element, className ) {
		if (
			! isHTMLElement( element ) ||
			! hasClassList( element ) ||
			! isFunction( element.classList.add ) ||
			! isNonEmptyString( className )
		) {
			return;
		}

		element.classList.add( className );
	}

	function toggleClass( add, element, className ) {
		if ( ! isBoolean( add ) ) {
			return;
		}

		const TOGGLE_CLASS = isTrue( add ) ? addClass : removeClass;

		TOGGLE_CLASS( element, className );
	}

	function getBreadcrumbAncestorListItems() {
		return getElementsByClassName( CLASS_NAV_BREADCRUMB_LIST_ITEM_ANCESTOR );
	}

	function getBreadcrumbRevealButton() {
		return getElementByClassName( CLASS_NAV_BREADCRUMB_REVEAL_BUTTON );
	}

	const CLASS_NAV_BREADCRUMB_LIST_ITEM_REVEAL = 'errigal-breadcrumb__reveal';

	function getBreadcrumbRevealListItem() {
		return getElementByClassName( CLASS_NAV_BREADCRUMB_LIST_ITEM_REVEAL );
	}

	const ATTRIBUTE_ARIA_EXPANDED = 'aria-expanded';

	function setAttribute( element, name, value ) {
		if (
			! isHTMLElement( element ) ||
			! isFunction( element.setAttribute ) ||
			! isNonEmptyString( name )
		) {
			return;
		}

		element.setAttribute( name, value );
	}

	function toggleAriaExpanded( expanded, ...elements ) {
		if ( ! isBoolean( expanded ) ) {
			return;
		}

		forEach(
			elements,
			( element ) => setAttribute(
				element,
				ATTRIBUTE_ARIA_EXPANDED,
				isTrue( expanded )
			)
		);
	}

	const ATTRIBUTE_ARIA_HIDDEN = 'aria-hidden';

	function toggleAriaHidden( hidden, ...elements ) {
		if ( ! isBoolean( hidden ) ) {
			return;
		}

		forEach(
			elements,
			( element ) => setAttribute(
				element,
				ATTRIBUTE_ARIA_HIDDEN,
				isTrue( hidden )
			)
		);
	}

	function toggleBreadcrumbRevealAndAncestorAriaAttributes( isAncestorHidden ) {
		toggleAriaExpanded(
			! isAncestorHidden,
			getBreadcrumbRevealButton()
		);
		toggleAriaHidden(
			! isAncestorHidden,
			getBreadcrumbRevealListItem()
		);
		toggleAriaHidden(
			isAncestorHidden,
			...getBreadcrumbAncestorListItems()
		);
	}

	function isBreadcrumbListWrapped() {
		let totalWidth = 0;
		const BREADCRUMB_LIST_WIDTH = getWidth( getBreadcrumbList() );

		return forEach(
			getBreadcrumbListItems(),
			( item ) => ( totalWidth += getWidth( item ) ) >= BREADCRUMB_LIST_WIDTH
		);
	}

	function toggleBreadcrumbAncestor() {
		const IS_BREADCRUMB_LIST_WRAPPED = isBreadcrumbListWrapped();

		toggleClass(
			IS_BREADCRUMB_LIST_WRAPPED,
			getBreadcrumbList(),
			CLASS_SHARED_COLLAPSED
		);
		toggleBreadcrumbRevealAndAncestorAriaAttributes( IS_BREADCRUMB_LIST_WRAPPED );
	}

	function revealBreadcrumbAncestorAndFocusFirstAncestorLink() {
		removeClass(
			getBreadcrumbList(),
			CLASS_SHARED_COLLAPSED
		);
		toggleBreadcrumbRevealAndAncestorAriaAttributes( false );
		focusElement( getFirstBreadcrumbAncestorLink() );
	}

	function addBreadcrumbEvents() {
		onDocumentClick( ( event ) => {
			if ( ! isEvent( event ) ) {
				return;
			}

			if ( isBreadcrumbRevealButton( event.target ) ) {
				revealBreadcrumbAncestorAndFocusFirstAncestorLink();
			}
		} );
		onDocumentKeydown( ( event ) => {
			if ( ! isEvent( event ) ) {
				return;
			}

			if ( isEnterKey( event ) ) {
				if ( isBreadcrumbRevealButton( event.target ) ) {
					event.preventDefault();
					revealBreadcrumbAncestorAndFocusFirstAncestorLink();
				}
			}
		} );
		onWindowLoad( toggleBreadcrumbAncestor );
		onWindowResize( toggleBreadcrumbAncestor );
	}

	addBreadcrumbEvents();
}() );
