<?php
namespace SabaiApps\Directories\Component\View\Helper;

use SabaiApps\Directories\Application;
use SabaiApps\Directories\Component\View\Mode\IMode;
use SabaiApps\Directories\Request;
use SabaiApps\Directories\Context;
use SabaiApps\Framework\Paginator\AbstractPaginator;
use SabaiApps\Directories\Component\Entity\Model\Bundle;
use SabaiApps\Directories\Component\Entity\Type\IEntity;

class NavHelper {

	public function help( Application $application, Context $context, array $items, $isBottom = false ) {
		$navs  = $scripts = array();
		$color = isset( $items['color'] ) ? $items['color'] : null;
		foreach ( array_keys( $items ) as $i ) { // navs
			if ( ! is_numeric( $i ) ) {
				continue;
			}

			$has_item = false;
			for ( $j = 0; $j < 3; $j++ ) { // nav
				if ( ! isset( $items[ $i ][ $j ] ) ) {
					continue;
				}

				foreach ( array_keys( $items[ $i ][ $j ] ) as $k ) { // items
					if ( is_array( $items[ $i ][ $j ][ $k ] ) ) {
						$item_name    = $items[ $i ][ $j ][ $k ][0];
						$item_options = $items[ $i ][ $j ][ $k ][1];
					} else {
						$item_name    = $items[ $i ][ $j ][ $k ];
						$item_options = array();
					}
					if ( $this->_hasItem( $application, $context, $item_name ) ) {
						$items[ $i ][ $j ][ $k ] = $this->_getItem( $application, $context, $item_name, $color, $item_options, $scripts, $isBottom, $i + 1 );
						$has_item                = true;
					} else {
						unset( $items[ $i ][ $j ][ $k ] );
					}
				}
			}
			if ( $has_item
				&& ( $_nav = $this->_nav( $application, $items[ $i ], $color, $isBottom, $i + 1 ) )
			) {
				$navs[ $i ] = $_nav;
			}
		}
		if ( empty( $navs ) ) {
			return '';
		}

		$ret = implode( PHP_EOL, $navs );
		if ( ! empty( $scripts ) ) {
			if ( Request::isXhr() ) {
				$ret .= '<script type="text/javascript">jQuery(function($) {';
			} else {
				$ret .= '<script type="text/javascript">document.addEventListener("DOMContentLoaded", function(event) { var $ = jQuery;';
			}
			$ret .= implode( PHP_EOL, $scripts );
			$ret .= '});</script>';
		}

		return $ret;
	}

	protected function _nav( Application $application, array $items, $color, $isBottom, $row ) {
		$navs    = array();
		$has_nav = false;
		for ( $j = 0; $j < 3; $j++ ) {
			if ( ! isset( $items[ $j ] ) ) {
				continue;
			}

			$_items = array_filter( $items[ $j ] );
			$class  = DRTS_BS_PREFIX . 'mb-2';
			if ( empty( $_items ) ) {
				$class .= ' ' . DRTS_BS_PREFIX . 'd-none ' . DRTS_BS_PREFIX . 'd-sm-block';
			} else {
				$has_nav = true;
			}
			switch ( $j ) {
				case 0:
					$class .= ' ' . DRTS_BS_PREFIX . 'd-flex ' . DRTS_BS_PREFIX . 'justify-content-start ' . DRTS_BS_PREFIX . 'gap-2';
					break;
				case 1:
					$class .= ' ' . DRTS_BS_PREFIX . 'd-flex ' . DRTS_BS_PREFIX . 'justify-content-md-center ' . DRTS_BS_PREFIX . 'gap-2';
					break;
				case 2:
					$class .= ' ' . DRTS_BS_PREFIX . 'd-flex ' . DRTS_BS_PREFIX . 'justify-content-md-end ' . DRTS_BS_PREFIX . 'gap-2';
					break;
			}
			$navs[] = '<div class="' . $class . '" data-column="' . ( $j + 1 ) . '">' . implode( PHP_EOL, $_items ) . '</div>';
		}
		if ( ! $has_nav ) {
			return;
		}

		$color_class = empty( $color ) ? '' : $this->_getNavColorClass( $color, $row, $isBottom );
		return sprintf(
			'<div style="grid-template-columns: %7$s;" class="%1$sd-sm-grid %1$s%6$s %1$s%2$s drts-view-nav %3$s %1$s%4$s" data-row="' . $row . '">
    %5$s
</div>',
			DRTS_BS_PREFIX,
			$color_class ? 'm-0' : ( $isBottom ? 'mt-2' : 'mb-2' ),
			$color_class ? $application->H( $color_class ) : '',
			$color_class ? 'p-2 ' . DRTS_BS_PREFIX . 'pb-sm-0' : 'p-0',
			implode( PHP_EOL, $navs ),
			$isBottom && count( $navs ) === 1 ? 'justify-content-center' : 'justify-content-between',
			count( $navs ) === 3 ? '1fr auto 1fr' : ( count( $navs ) === 2 ? 'auto auto' : 'auto' )
		);
	}

	protected function _getNavColorClass( $color, $row, $isBottom ) {
		switch ( $color ) {
			case 'light':
				$nav_color  = 'light';
				$bg_color   = 'light';
				$text_color = 'dark';
				break;
			case 'dark':
				$nav_color  = 'dark';
				$bg_color   = 'dark';
				$text_color = 'white';
				break;
			case 'info':
				$nav_color  = 'dark';
				$bg_color   = 'info';
				$text_color = 'white';
				break;
			case 'primary':
				$nav_color  = 'dark';
				$bg_color   = 'primary';
				$text_color = 'white';
				break;
			case 'secondary':
				$nav_color  = 'dark';
				$bg_color   = 'secondary';
				$text_color = 'white';
				break;
			case 'success':
				$nav_color  = 'dark';
				$bg_color   = 'success';
				$text_color = 'white';
				break;
			case 'warning':
				$nav_color  = 'dark';
				$bg_color   = 'warning';
				$text_color = 'white';
				break;
			case 'danger':
				$nav_color  = 'dark';
				$bg_color   = 'danger';
				$text_color = 'white';
				break;
			default:
				return '';
		}
		if ( $this->_isSubtleBg( $row, $isBottom ) ) {
			$text_color = $bg_color . '-emphasis';
			$bg_color  .= '-subtle';
		}
		return DRTS_BS_PREFIX . 'navbar-' . $nav_color . ' ' . DRTS_BS_PREFIX . 'bg-' . $bg_color . ' ' . DRTS_BS_PREFIX . 'text-' . $text_color;
	}

	protected function _isSubtleBg( $row, $isBottom ) {
		return $row % 2 === ( $isBottom ? 1 : 0 );
	}

	protected function _hasItem( Application $application, Context $context, $name ) {
		if ( ! is_string( $name ) ) {
			return true;
		}

		switch ( $name ) {
			case 'sort':
				return isset( $context->sorts ) && count( $context->sorts ) > 1;
			case 'filter':
				return $application->getComponent( 'View' )->isFilterable( $context->bundle )
					&& ( ! empty( $context->settings['filter']['show'] ) || ( ! empty( $context->settings['map']['show'] ) && $context->view->viewModeInfo( 'mapable' ) ) );
			case 'filters':
				return ! empty( $context->filter['filters_applied_labels'] )
					&& $application->getComponent( 'View' )->isFilterable( $context->bundle );
			case 'add':
				return $application->isComponentLoaded( 'FrontendSubmit' )
					&& ! empty( $context->settings['other']['add']['show'] )
					&& empty( $context->settings['query']['user_id'] );
			case 'pagination':
				return ! empty( $context->num_found )
					&& empty( $context->settings['pagination']['type'] )
					&& isset( $context->paginator )
					&& $context->paginator->count() > 1;
			case 'load_more':
				return ! empty( $context->num_found )
					&& ( ! empty( $context->settings['pagination']['type'] ) && $context->settings['pagination']['type'] === 'load_more' )
					&& isset( $context->paginator )
					&& $context->paginator->count() > 1
					&& $context->paginator->getElementCount() > $context->num_start + $context->num_shown - 1;
			case 'perpages':
				return ! empty( $context->num_found )
					&& ! empty( $context->perpage )
					&& ( empty( $context->settings['pagination']['type'] ) || $context->settings['pagination']['type'] === 'default' )
					&& ! empty( $context->settings['pagination']['allow_perpage'] )
					&& ! empty( $context->settings['pagination']['perpages'] );
			case 'num':
				return ! empty( $context->num_found )
					&& ! empty( $context->settings['other']['num'] );
			case 'layout_switch':
				return ! empty( $context->num_found )
					&& ! empty( $context->settings['list_grid'] )
					&& empty( $context->settings['list_no_row'] );
			case 'status':
				return ! empty( $context->bundle->info['public'] )
					&& ! $application->getUser()->isAnonymous()
					&& empty( $context->settings['query']['user_id'] );
			case 'search':
				return $context->is_default_view && ! empty( $context->bundle->info['search_enable'] ) && ! empty( $context->settings['other']['search'] );
			case 'calendar_controls':
			case 'calendar_switch':
				return (string) $context->view === 'calendar';
			case 'map_geolocate':
			case 'map_fullscreen':
				return (string) $context->view === 'fullmap';
			default:
				return $application->Filter( 'view_nav_has_item', false, array( $name, $context, $this ) );
		}
	}

	protected function _getItem( Application $application, Context $context, $name, $color, array $options, array &$scripts, $isBottom, $row ) {
		if ( ! is_string( $name ) ) {
			return $name;
		}

		switch ( $name ) {
			case 'sort':
				return $this->_sortByButton(
					$application,
					$name,
					$color,
					$context->sorts,
					$context->sort,
					$context->getContainer(),
					$context->push_state ? $this->_getPushStateRoute( $application, $context ) : $context->getRoute(),
					$context->url_params,
					$context->push_state,
					$options,
					$scripts
				);
			case 'search':
				return $this->_searchButton(
					$application,
					$name,
					$color,
					$context->bundle,
					$context->url_params,
					! empty( $context->search_values ),
					$options,
					$scripts
				);
			case 'filter':
				return $this->_filterButton(
					$application,
					$name,
					$color,
					$context->bundle,
					$context->settings['filter']['target'] ?? $context->getContainer(),
					! empty( $context->settings['filter']['show'] ),
					empty( $context->bundle->info['parent'] ) && empty( $context->bundle->info['parent_field'] ) && ! empty( $context->settings['filter']['show_modal'] ),
					! empty( $context->settings['filter']['shown'] ),
					! empty( $context->settings['filter']['hide_btn'] ),
					! empty( $context->filter['form'] ),
					empty( $context->filter['filters_applied_labels'] ) ? array() : $context->filter['filters_applied_labels'],
					$context->view,
					$options,
					$scripts
				);
			case 'filters':
				return $this->_filtersApplied(
					$application,
					$name,
					$color,
					$context->filter['filters_applied_labels'],
					$options,
					$scripts,
					$isBottom,
					$row
				);
			case 'add':
				return $this->_addEntityButton(
					$application,
					$name,
					$color,
					$context->bundle,
					$context->settings['other']['add'],
					$context->entity ?: null,
					$options,
					$scripts
				);
			case 'pagination':
				return $this->_pagination(
					$application,
					$name,
					$color,
					$context->paginator,
					$context->settings['pagination'],
					$context->getContainer(),
					$context->push_state ? $this->_getPushStateRoute( $application, $context ) : $context->getRoute(),
					$context->url_params,
					$context->push_state,
					$options,
					$scripts
				);
			case 'load_more':
				return $this->_loadMoreButton(
					$application,
					$name,
					$color,
					$context->paginator,
					$context->settings['pagination'],
					$context->getContainer(),
					$context->getRoute(),
					$context->url_params,
					$options,
					$scripts
				);
			case 'perpages':
				return $this->_perpages(
					$application,
					$name,
					$color,
					$context->perpage,
					$context->settings['pagination'],
					$context->num_found,
					$context->getContainer(),
					$context->push_state ? $this->_getPushStateRoute( $application, $context ) : $context->getRoute(),
					$context->url_params,
					$context->push_state,
					$options,
					$scripts
				);
			case 'status':
				return $this->_status(
					$application,
					$name,
					$color,
					$context->bundle,
					$context->getContainer(),
					$context->push_state ? $this->_getPushStateRoute( $application, $context ) : $context->getRoute(),
					$context->url_params,
					$context->push_state,
					$options,
					$scripts
				);
			case 'layout_switch':
				return $this->_layoutSwitch(
					$application,
					$name,
					$color,
					$context->getContainer(),
					$context->settings,
					$options,
					$scripts
				);
			case 'num':
				return $this->_numResults(
					$application,
					$name,
					$color,
					$context->num_found,
					$context->num_start,
					$context->num_shown,
					$context->bundle,
					$context,
					$options,
					$scripts
				);
			case 'calendar_controls':
				return $application->Calendar_Calendar_controlsHtml(
					array(
						'class'     => $this->itemClass( $application, $name ),
						'btn_class' => $application->System_Button_htmlClass( $options, $color ),
					),
					$context
				);
			case 'calendar_switch':
				return $application->Calendar_Calendar_switchHtml(
					array(
						'class'         => $this->itemClass( $application, $name ),
						'btn_class'     => $application->System_Button_htmlClass( $options, $color ),
						'view_settings' => $context->settings,
						'default_view'  => isset( $context->settings['calendar_display_mode'] ) ? $context->settings['calendar_display_mode'] : 'month',
					),
					$context
				);
			case 'map_geolocate':
				return $application->Map_Map_controlBtn(
					'geolocate',
					array(
						'class'     => $this->itemClass( $application, $name ),
						'btn_class' => $application->System_Button_htmlClass( $options, $color ),
					),
					$context
				);
			case 'map_fullscreen':
				return $application->Map_Map_controlBtn(
					'fullscreen',
					array(
						'class'         => $this->itemClass( $application, $name ),
						'btn_class'     => $application->System_Button_htmlClass( $options, $color ),
						'is_fullscreen' => ! empty( $context->settings['map_is_fullscreen'] ),
					)
				);
			default:
				return $application->Filter( 'view_nav_item', '', array( $name, $context, $color, $options, &$scripts, $this ) );
		}
	}

	protected function _getPushStateRoute( Application $application, Context $context ) {
		// Make sure taxonomy term permalink URL does not change
		if ( isset( $GLOBALS['drts_entity'] )
			&& $GLOBALS['drts_entity']->isTaxonomyTerm()
		) {
			return $application->Entity_PermalinkUrl( $GLOBALS['drts_entity'] );
		}
		return $context->getRoute();
	}

	public function buttons( Application $application, $name, $color, array $links, array $btnOptions = array() ) {
		if ( empty( $links ) ) {
			return '';
		}

		$btnOptions          += array(
			'color' => $application->System_Button_color( $color ),
			'class' => '',
			'label' => true,
			'group' => true,
		);
		$btnOptions['class'] .= ' ' . $this->itemClass( $application, $name );

		return $application->System_Button_links( $links, $btnOptions );
	}

	public function dropdown( Application $application, $name, $color, array $links, array $btnOptions = array() ) {
		if ( empty( $links ) ) {
			return '';
		}

		$btnOptions          += array(
			'color' => $application->System_Button_color( $color ),
			'class' => '',
		);
		$btnOptions['class'] .= ' ' . $this->itemClass( $application, $name );

		return $application->System_Button_dropdownLinks( $links, $btnOptions );
	}

	protected function _sortLinks( Application $application, array $sorts, $currentSort, $container, $route, array $urlParams, $pushState = false ) {
		$ret     = array();
		$options = array(
			'container' => $container,
			'cache'     => true,
			'pushState' => $pushState,
		);
		foreach ( array_keys( $sorts ) as $key ) {
			$attr = array(
				'data-value' => $key,
				'class'      => 'drts-view-entities-sort',
				'rel'        => 'nofollow',
			);
			if ( $key === $currentSort ) {
				$options['active'] = true;
				$attr['class']    .= ' drts-view-entities-sort-selected';
			} else {
				$options['active'] = false;
			}
			$ret[ $key ] = $application->LinkTo(
				is_array( $sorts[ $key ] ) ? $sorts[ $key ]['label'] : $sorts[ $key ],
				$application->Url(
					$route,
					array(
						$application->getPlatform()->getPageParam() => 1,
						'sort' => $key,
					) + $urlParams
				),
				$options,
				$attr
			);
		}

		return $ret;
	}

	protected function _sortByButton( Application $application, $name, $color, array $sorts, $currentSort, $container, $route, array $urlParams, $pushState = false, array $options = array(), array &$scripts = array() ) {
		$format = '<span class="' . DRTS_BS_PREFIX . 'd-none ' . DRTS_BS_PREFIX . 'd-sm-inline">' . $application->H( strtr( __( 'Sort by: ', 'directories-pro' ), '%s', '' ) ) . '</span>%s';
		return $this->dropdown(
			$application,
			$name,
			$color,
			$this->_sortLinks( $application, $sorts, $currentSort, $container, $route, $urlParams, $pushState ),
			$options + array(
				'format'           => $format,
				'format_no_escape' => true,
			)
		);
	}

	protected function _searchButton( Application $application, $name, $color, Bundle $bundle, array $urlParams, $hasSearchValues = false, array $options = array(), array &$scripts = array() ) {
		$search_form    = $application->Search_Form(
			$bundle,
			$urlParams,
			array(
				'size'       => 'lg',
				'modal_only' => true,
			)
		);
		$search_form_id = 'drts-view-nav-item-name-' . $name . '-form';
		$search_form    = '<div style="display:none;" id="' . $search_form_id . '">' . $application->Form_Form_render( $search_form ) . '</div>';
		$class          = $application->System_Button_htmlClass( $options, $color ) . ' ' . $this->itemClass( $application, $name );
		return $search_form . $application->LinkTo(
			'',
			'#' . $search_form_id,
			array(
				'container'         => 'modal',
				'modalSize'         => 'lg',
				'modalCenter'       => true,
				'modalOverflow'     => 'visible',
				'modalTitle'        => '',
				'icon'              => 'fas fa-magnifying-glass',
				'btn'               => true,
				'label_suffix_html' => $hasSearchValues ? $this->notificationDotHtml( $application, array( 'hidden' => false ) ) : '',
			),
			array(
				'class' => $class . ' drts-view-nav-item-name-' . $name . '-modal',
				'style' => 'position:relative;',
			)
		);
	}

	protected function _filterButton( Application $application, $name, $color, Bundle $bundle, $filterTarget, $show, $showInModal, $shown, $hideBtn, $hasForm, array $filtersApplied, IMode $view, array $options = array(), array &$scripts = array() ) {
		if ( ! empty( $options['show_filters_applied'] )
			&& ! empty( $filtersApplied )
		) {
			$dropdown_menu = array();
			foreach ( $filtersApplied as $remove_filter_name => $_remove_filter_labels ) {
				foreach ( $_remove_filter_labels as $remove_filter_value => $remove_filter_label ) {
					$dropdown_menu[] = sprintf(
						'<button type="button" class="%1$sdropdown-item drts-view-remove-filter" data-filter-name="%2$s" data-filter-value="%3$s">%4$s <i class="fas fa-times-circle drts-clear"></i></button>',
						DRTS_BS_PREFIX,
						$application->H( $remove_filter_name ),
						$application->H( $remove_filter_value ),
						$remove_filter_label // HTML, so no need to escape
					);
				}
			}
			$count = count( $dropdown_menu );
			if ( $count > 1 ) {
				$dropdown_menu[] = sprintf(
					'<div class="%1$sdropdown-divider"></div>
<button type="button" class="%1$sdropdown-item drts-view-remove-filter">%2$s</button>',
					DRTS_BS_PREFIX,
					$application->H( __( 'Clear all', 'directories-pro' ) )
				);
			}
		}

		$class = $application->System_Button_htmlClass( $options, $color );
		if ( ! $has_dropdown = ! empty( $dropdown_menu ) ) {
			$class .= ' ' . $this->itemClass( $application, $name );
		}
		$buttons      = array();
		$url          = array(
			'script_url' => '',
			'fragment'   => ltrim( $filterTarget, '#' ) . '-view-filter-form',
		);
		$link_options = array(
			'text'          => $application->getComponent( 'View' )->getConfig( 'filters', 'btn_label' ),
			'icon'          => $application->getComponent( 'View' )->getConfig( 'filters', 'btn_icon' ),
			'btn'           => true,
			'no_escape'     => true,
			'no_wrap_label' => true,
		);
		$link_text    = '<span class="' . DRTS_BS_PREFIX . 'd-none ' . DRTS_BS_PREFIX . 'd-sm-inline">'
			. $application->H( $application->System_TranslateString( $link_options['text'], 'nav_filter_btn_label', 'view' ) )
			. '</span>';
		unset( $link_options['text'] );
		if ( $show
			&& $hasForm
		) {
			$class_collapse = $has_dropdown ? $class : $class . ' drts-view-nav-item-name-' . $name . '-collapse';
			$btn_label      = sprintf( _x( 'Filter %s', 'filter items', 'directories-pro' ), $bundle->getLabel() );
			if ( $showInModal ) {
				$buttons['collapse'] = $application->LinkTo(
					$link_text,
					$url,
					array(
						'container' => 'modal',
						'modalSize' => 'xl',
					) + $link_options,
					array(
						'class'            => $class_collapse,
						'data-modal-title' => $btn_label,
						'aria-label'       => $btn_label,
					)
				);
			} elseif ( ! $hideBtn ) {
					$buttons['collapse'] = $application->LinkTo(
						$link_text,
						'',
						$link_options,
						array(
							'class'          => $has_dropdown ? $class_collapse : $class_collapse . ' ' . DRTS_BS_PREFIX . 'd-inline-block',
							'data-bs-toggle' => 'collapse',
							'data-bs-target' => '#' . $url['fragment'],
							'aria-expanded'  => $shown ? 'true' : 'false',
							'aria-label'     => $btn_label,
						)
					);
			}
		}
		// Allow top level bundles to show filters in modal when in full screen mode
		if ( empty( $bundle->info['parent'] )
			&& empty( $bundle->info['parent_field'] )
			&& false !== $view->viewModeInfo( 'mapable' )
		) {
			if ( ! isset( $btn_label ) ) {
				$btn_label = sprintf( _x( 'Filter %s', 'filter items', 'directories-pro' ), $bundle->getLabel() );
			}
			$buttons['modal'] = $application->LinkTo(
				$link_text,
				$url,
				array(
					'container' => 'modal',
					'modalSize' => 'xl',
				) + $link_options,
				array(
					'class'            => $has_dropdown ? $class : $class . ' drts-view-nav-item-name-' . $name . '-modal',
					'data-modal-title' => $btn_label,
					'aria-label'       => $btn_label,
				)
			);
		}
		if ( $has_dropdown ) {
			foreach ( array_keys( $buttons ) as $i ) {
				$buttons[ $i ] = sprintf(
					'<div class="%1$sbtn-group %2$s %3$s">
    %4$s<button type="button" class="%5$s %1$sdropdown-toggle %1$sdropdown-toggle-split" data-bs-toggle="dropdown" aria-haspopup="true" aria-expanded="false"><span class="%1$svisually-hidden">Toggle Dropdown</span></button>
    <div class="%1$sdropdown-menu drts-view-entities-filters-applied">
        %6$s
    </div>
</div>',
					DRTS_BS_PREFIX,
					$this->itemClass( $application, $name ) . ' drts-view-nav-item-name-' . $name . '-' . $i,
					$i === 'collapse' && ! $showInModal ? DRTS_BS_PREFIX . 'd-inline-block' : '',
					$buttons[ $i ],
					$application->System_Button_htmlClass( $options, $color ),
					implode( PHP_EOL, $dropdown_menu )
				);
			}
		}

		return implode( PHP_EOL, $buttons );
	}

	protected function _addEntityButton( Application $application, $name, $color, Bundle $bundle, $btnSettings, ?IEntity $parentEntity = null, array $options = array(), array &$scripts = array() ) {
		if ( ! $application->getUser()->isAnonymous()
			&& ! $application->Entity_IsRoutable( $bundle, 'add', $parentEntity )
		) {
			return '';
		}

		if ( empty( $bundle->info['parent'] )
			&& empty( $bundle->info['parent_field'] )
		) {
			$params = array(
				'bundle' => $bundle->name,
			);
			if ( ! empty( $btnSettings['entity_reference_id'] )
				&& ! empty( $btnSettings['entity_reference_field'] )
			) {
				$params['entity_reference_id']    = $btnSettings['entity_reference_id'];
				$params['entity_reference_field'] = $btnSettings['entity_reference_field'];
			}
			$url = $application->Url( '/' . $application->FrontendSubmit_AddEntitySlug( $bundle ), $params );
			$url = $application->Filter( 'view_nav_add_entity_button_url', $url, array( $bundle ) );

			return $this->_getAddEntityButton( $application, $name, $color, $bundle, $btnSettings, $url, $options );
		}

		// Add child entity link requires a valid parent entity
		if ( ! isset( $parentEntity ) ) {
			return '';
		}

		$url = str_replace( ':slug', $parentEntity->getSlug(), $bundle->getPath() ) . '/add';
		return $this->_getAddEntityButton( $application, $name, $color, $bundle, $btnSettings, $url, $options );
	}

	protected function _getAddEntityButton( Application $application, $name, $color, Bundle $bundle, $settings, $url, array $options, array $attr = array() ) {
		$options       = array(
			'icon' => 'fa-fw fas fa-plus',
			'btn'  => true,
		) + $options;
		$attr['class'] = $application->System_Button_htmlClass( $options, $color ) . ' ' . $this->itemClass( $application, $name );
		if ( empty( $settings['show_label'] ) ) {
			$title         = '';
			$attr['title'] = $bundle->getLabel( 'add' );
			$attr['rel']   = 'sabaitooltip';
		} else {
			$title                    = '<span class="' . DRTS_BS_PREFIX . 'd-none ' . DRTS_BS_PREFIX . 'd-sm-inline">' . $application->H( $bundle->getLabel( 'add' ) ) . '</span>';
			$options['no_escape']     = true;
			$options['no_wrap_label'] = true;
		}

		return $application->LinkTo( $title, $url, $options, $attr );
	}

	protected function _pagination( Application $application, $name, $color, AbstractPaginator $paginator, array $settings, $container, $route, array $urlParams, $pushState = false, array $options = array(), array &$scripts = array() ) {
		return $application->System_PageNav(
			$container,
			$paginator,
			$application->Url( $route, $urlParams ),
			$options + array(
				'scroll'    => ! isset( $settings['scroll'] ) ? : ! empty( $settings['scroll'] ),
				'cache'     => true,
				'color'     => $application->System_Button_color( $color ),
				'class'     => $this->itemClass( $application, $name ),
				'pushState' => $pushState,
				'append'    => null,
				'appendTo'  => null,
			),
			isset( $options['offset'] ) ? $options['offset'] : null
		);
	}

	protected function _loadMoreButton( Application $application, $name, $color, AbstractPaginator $paginator, array $settings, $container, $route, array $urlParams, array $options = array(), array &$scripts = array() ) {
		$item_class = $this->itemClass( $application, $name );
		return $application->LinkTo(
			isset( $settings['load_more_label'] ) && strlen( $settings['load_more_label'] ) ? $settings['load_more_label'] : __( 'Load More', 'directories-pro' ),
			$application->Url( $route, array( $application->getPlatform()->getPageParam() => $paginator->getCurrentPage() + 1 ) + $urlParams ),
			$options + array(
				'container' => $container,
				'scroll'    => false,
				'cache'     => true,
				'pushState' => false,
				'append'    => '.drts-view-entity-container',
				'appendTo'  => isset( $settings['append_to'] ) ? $settings['append_to'] : '.drts-view-entities',
			),
			array(
				'class' => $application->System_Button_htmlClass( $options + array( 'size' => 'lg' ), $color, true ) . ' ' . $item_class,
			)
		);
	}

	protected function _perpages( Application $application, $name, $color, $perpage, array $settings, $numFound, $container, $route, array $urlParams, $pushState = false, array $options = array(), array &$scripts = array() ) {
		$perpage_links = $this->_perpageLinks( $application, $perpage, $settings, $numFound, $container, $route, $urlParams, $pushState );
		if ( count( $perpage_links ) <= 1 ) {
			return '';
		}

		return $this->dropdown(
			$application,
			$name,
			$color,
			$perpage_links,
			$options + array(
				'format' => _x( 'Show: %s', 'items per page', 'directories-pro' ),
			)
		);
	}

	protected function _perpageLinks( Application $application, $perpage, array $settings, $numFound, $container, $route, array $urlParams, $pushState = false ) {
		$ret      = array();
		$options  = array(
			'container' => $container,
			'cache'     => true,
			'pushState' => $pushState,
			'scroll'    => ! isset( $settings['scroll'] ) ? null : ! empty( $settings['scroll'] ),
		);
		$perpages = isset( $settings['perpages'] ) ? (array) $settings['perpages'] : array( 10, 20, 50 );
		sort( $perpages, SORT_NUMERIC );
		foreach ( $perpages as $_perpage ) {
			$_perpage = (int) $_perpage;
			if ( $numFound < $_perpage ) {
				$is_last = true;
			}

			$attr = array(
				'data-value' => $_perpage,
				'class'      => 'drts-view-entities-perpage',
				'rel'        => 'nofollow',
			);
			if ( $_perpage === $perpage ) {
				$options['active'] = true;
				$attr['class']    .= ' drts-view-entities-perpage-selected';
			} else {
				$options['active'] = false;
			}
			$ret[ $_perpage ] = $application->LinkTo(
				$_perpage,
				$application->Url(
					$route,
					array(
						$application->getPlatform()->getPageParam() => 1,
						'num' => $_perpage,
					) + $urlParams
				),
				$options,
				$attr
			);

			if ( ! empty( $is_last ) ) {
				break;
			}
		}

		return $ret;
	}

	protected function _layoutSwitch( Application $application, $name, $color, $container, array $settings, array $options = array(), array &$scripts = array() ) {
		if ( ! empty( $settings['list_layout_switch_cookie'] ) && ( $cookie = $application->System_Cookie( $settings['list_layout_switch_cookie'] ) ) ) {
			$selected = $cookie === 'grid' ? 'grid' : 'row';
		} else {
			$selected = ! empty( $settings['list_grid_default'] ) ? 'grid' : 'row';
		}
		$scripts[] = sprintf(
			'$(".drts-view-entities-layout-switch", DRTS.container("%3$s").container).off("click").on("click", ".%1$sbtn", function(e){
    var $this = $(this), layout = $this.data("layout");
    e.preventDefault();
    $this.parent().find(".%1$sbtn").each(function(){
        var $btn = $(this);
        $btn.toggleClass("%1$sactive", $btn.data("layout") === layout);
    });
    $(DRTS.container("%3$s").selector).find(".drts-view-entities-list-row, .drts-view-entities-list-grid").first()
        .toggleClass("drts-view-entities-list-row", layout === "row")
        .toggleClass("drts-view-entities-list-grid", layout === "grid");
    var cookie_name = "%2$s-" + DRTS.cookieHash;
    if (cookie_name) $.cookie(cookie_name, layout, {path: DRTS.path, domain: DRTS.domain});
});',
			DRTS_BS_PREFIX,
			! empty( $settings['list_layout_switch_cookie'] ) ? $settings['list_layout_switch_cookie'] : '',
			$container
		);
		return sprintf(
			'<div class="%1$sbtn-group %2$s drts-view-entities-layout-switch drts-form-switch %1$sd-none %1$sd-sm-inline-flex">
    <button type="button" class="%3$s%4$s" data-layout="row" style="height:100%%;"><i class="fas fa-list"></i></button><button type="button" class="%3$s%5$s" data-layout="grid" style="height:100%%;"><i class="fas fa-th-large"></i></button>
</div>',
			DRTS_BS_PREFIX,
			$this->itemClass( $application, $name ),
			$application->System_Button_htmlClass( $options, $color ),
			$selected !== 'grid' ? ' ' . DRTS_BS_PREFIX . 'active' : '',
			$selected === 'grid' ? ' ' . DRTS_BS_PREFIX . 'active' : ''
		);
	}

	protected function _status( Application $application, $name, $color, Bundle $bundle, $container, $route, array $urlParams, $pushState = false, array $options = array(), array &$scripts = array() ) {
		return $this->dropdown(
			$application,
			$name,
			$color,
			$this->_statusLinks( $application, $bundle, $container, $route, $urlParams, $pushState ),
			$options + array( 'format' => __( 'Status: %s', 'directories-pro' ) )
		);
	}

	protected function _statusLinks( Application $application, Bundle $bundle, $container, $route, array $urlParams, $pushState = false ) {
		$links = array();

		$options  = array(
			'container' => $container,
			'cache'     => true,
			'pushState' => $pushState,
		);
		$links[]  = $application->LinkTo(
			__( 'All', 'directories-pro' ),
			$application->Url( $route, array( 'status' => '' ) + $urlParams ),
			$options
		);
		$statuses = array(
			'publish' => __( 'Published', 'directories-pro' ),
			'pending' => __( 'Pending', 'directories-pro' ),
			'draft'   => __( 'Draft', 'directories-pro' ),
		);
		if ( ! empty( $bundle->info['privatable'] ) ) {
			$statuses['private'] = __( 'Private', 'directories-pro' );
		}
		if ( $application->isComponentLoaded( 'Payment' )
			&& ! empty( $bundle->info['payment_enable'] )
		) {
			$statuses['expired']     = __( 'Expired', 'directories-pro' );
			$statuses['deactivated'] = __( 'Deactivated', 'directories-pro' );
			$statuses['expiring']    = __( 'Expiring', 'directories-pro' );
		}
		$current = isset( $urlParams['status'] ) ? $urlParams['status'] : null;
		foreach ( $statuses as $key => $label ) {
			$links[] = $application->LinkTo(
				$label,
				$application->Url( $route, array( 'status' => $key ) + $urlParams ),
				$current === $key ? array( 'active' => true ) + $options : $options
			);
		}

		return $links;
	}

	protected function _numResults( Application $application, $name, $color, $numFound, $numStart, $numShown, Bundle $bundle, Context $context, array $options = array(), array &$scripts = array() ) {
		if ( null === $text = $application->Filter( 'view_nav_num_results_text', null, array( $color, $numFound, $numStart, $numShown, $bundle, $context ) ) ) {
			if ( empty( $context->settings['pagination'] ) || ! empty( $context->settings['pagination']['no_pagination'] ) ) {
				$text = sprintf( _n( $bundle->getLabel( 'count' ), $bundle->getLabel( 'count2' ), $numFound, 'directories-pro' ), $numFound );
			} else {
				$text = sprintf(
					$application->H( __( 'Showing %1$s - %2$s of %3$s', 'directories-pro' ) ),
					empty( $context->settings['pagination']['type'] ) || $context->settings['pagination']['type'] !== 'load_more' ? $numStart : 1,
					$numStart + $numShown - 1,
					number_format( $numFound )
				);
			}
		}
		return '<span class="' . $application->H( $this->itemClass( $application, $name, true ) ) . '">' . $text . '</span>';
	}

	protected function _filtersApplied( Application $application, $name, $color, array $filtersApplied, array $options, array &$scripts, $isBottom, $row ) {
		return $this->getAppliedFilterButtons(
			$application,
			$filtersApplied,
			array(
				'color'        => $color,
				'wrap'         => true,
				'btn_margin'   => 1,
				'is_subtle_bg' => $color && $this->_isSubtleBg( $row, $isBottom ),
			) + $options
		);
	}

	public function itemClass( Application $application, $name = null, $isText = false ) {
		$class = 'drts-view-nav-item';
		if ( isset( $name ) ) {
			$class .= ' drts-view-nav-item-name-' . $name;
		}
		if ( $isText ) {
			$class .= ' ' . DRTS_BS_PREFIX . 'navbar-text';
		}
		return $class;
	}

	public function getAppliedFilterButtons( Application $application, array $filtersApplied, array $options = array() ) {
		$options  += array(
			'wrap'         => true,
			'color'        => 'secondary',
			'label'        => __( 'Applied filters:', 'directories-pro' ),
			'btn_margin'   => 2,
			'is_subtle_bg' => false,
		);
		$html      = array();
		$btn_color = empty( $options['color'] ) ? 'secondary' : $options['color'];
		foreach ( $filtersApplied as $remove_filter_name => $_remove_filter_labels ) {
			foreach ( $_remove_filter_labels as $remove_filter_value => $remove_filter_label ) {
				$html[] = sprintf(
					'<button type="button" class="%1$sbtn %1$sbtn-sm %1$sbtn-%5$s %1$srounded-pill %1$smb-%6$d %1$sme-%6$d drts-view-remove-filter" data-filter-name="%2$s" data-filter-value="%3$s">%4$s <i class="fas fa-times-circle drts-clear %1$stext-%7$s"></i></button>',
					DRTS_BS_PREFIX,
					$application->H( $remove_filter_name ),
					$application->H( $remove_filter_value ),
					$remove_filter_label, // HTML, so no need to escape
					$options['is_subtle_bg'] ? $btn_color : 'outline-' . $btn_color,
					$options['btn_margin'],
					$options['is_subtle_bg'] ? ( $btn_color === 'light' ? 'dark' : 'white' ) : $btn_color . '-emphasis',
				);
			}
		}
		if ( ! $count = count( $html ) ) {
			return '';
		}

		if ( $count > 1 ) {
			$html[] = sprintf(
				'<span class="%1$sbtn %1$sbtn-sm %1$sbtn-link drts-view-remove-filter %1$spx-0 %1$smb-%4$d %1$stext-%3$s">%2$s</span>',
				DRTS_BS_PREFIX,
				$application->H( __( 'Clear all', 'directories-pro' ) ),
				$options['color'] ? ( $options['is_subtle_bg'] ? $options['color'] . '-emphasis' : $options['color'] ) : 'secondary',
				$options['btn_margin']
			);
		}

		if ( $options['label'] ) {
			array_unshift( $html, '<span class="' . DRTS_BS_PREFIX . 'me-2 ' . DRTS_BS_PREFIX . 'mb-' . ( $options['btn_margin'] - 1 ) . '">' . $application->H( $options['label'] ) . '</span>' );
		}
		$html = implode( '', $html );
		if ( $options['wrap'] ) {
			$html = '<div class="' . $this->itemClass( $application, 'applied-filters' ) . ' drts-view-entities-filters-applied">' . $html . '</div>';
		}

		return $html;
	}

	public function notificationDotHtml( Application $application, array $options = array() ) {
		$options += array(
			'color'  => 'info',
			'hidden' => true,
		);
		return sprintf(
			'<span class="drts-calendar-view-notification-dot %1$sposition-absolute %1$stop-0 %1$sstart-100 %1$stranslate-middle %1$sm-0 %1$sbg-%2$s %1$sborder %1$sborder-light %1$srounded-circle" style="padding:0.4rem;%3$s">
</span>',
			DRTS_BS_PREFIX,
			$application->H( $options['color'] ),
			$options['hidden'] ? 'display:none;' : ''
		);
	}
}
