<?php
namespace SabaiApps\Directories\Component\DirectoryPro;

use SabaiApps\Directories\Component\AbstractComponent;
use SabaiApps\Directories\Component\Field;
use SabaiApps\Directories\Component\System;
use SabaiApps\Directories\Component\Display;
use SabaiApps\Directories\Component\Entity;
use SabaiApps\Directories\Context;
use SabaiApps\Directories\Application;
use SabaiApps\Directories\Component\Form\Form;

class DirectoryProComponent extends AbstractComponent implements
	Field\IRenderers,
	System\IAdminRouter,
	System\IWidgets,
	Display\ILabels,
	Field\IWidgets,
	Field\ITypes,
	Entity\IBundleTypes,
	Entity\IFeatures,
	System\ITools {

	const VERSION = '2.0.6', PACKAGE = 'directories-pro';

	public static function interfaces() {
		return array( 'Payment\IFeatures', 'WordPress\IBlocks' );
	}

	public static function description() {
		return 'Adds features to build a local business directory.';
	}

	public static function events() {
		return array(
			// Make sure the callback is called after Directory component
			'entitybundlesinfofilter' => 99,
		);
	}

	public function systemAdminRoutes() {
		$routes = array(
			'/directories/:directory_name/content_types/:bundle_name/export_bundle' => array(
				'controller'     => 'ExportBundle',
				'title_callback' => true,
				'callback_path'  => 'export_bundle',
			),
			'/_drts/directorypro/add_custom_taxonomy' => array(
				'controller'    => 'AddCustomTaxonomy',
				'callback_path' => 'add_custom_taxonomy',
			),
			'/directories/:directory_name/content_types/:bundle_name/displays/export_display' => array(
				'controller'      => 'ExportDisplay',
				'title_callback'  => true,
				'access_callback' => true,
				'callback_path'   => 'export_display',
			),
			'/directories/:directory_name/content_types/:bundle_name/displays/import_display' => array(
				'controller'      => 'ImportDisplay',
				'title_callback'  => true,
				'access_callback' => true,
				'callback_path'   => 'import_display',
			),
		);
		foreach ( array_keys( $this->_application->Entity_BundleTypes() ) as $bundle_type ) {
			if ( $this->_application->Entity_BundleTypeInfo( $bundle_type, 'email_disable' )
				|| ( ! $admin_path = $this->_application->Entity_BundleTypeInfo( $bundle_type, 'admin_path' ) )
				|| isset( $routes[ $admin_path . '/send_email' ] ) // path added already
			) {
				continue;
			}

			$routes += array(
				$admin_path . '/send_email' => array(
					'controller'     => 'SendEmail',
					'title_callback' => true,
					'callback_path'  => 'send_email',
				),
			);
		}
		return $routes;
	}

	public function systemOnAccessAdminRoute( Context $context, $path, $accessType, array &$route ) {
		switch ( $path ) {
			case 'export_display':
			case 'import_display':
				if ( $accessType === Application::ROUTE_ACCESS_LINK ) {
					if ( ( ! $name = $context->getRequest()->asStr( 'display_name' ) )
						|| ( ! $type = $context->getRequest()->asStr( 'display_type' ) )
						|| $type !== 'entity'
						|| ( ! $display = $this->_application->getModel( 'Display', 'Display' )->name_is( $name )->type_is( $type )->bundleName_is( $context->bundle->name )->fetchOne() )
					) {
						return false;
					}

					$context->display = $display;
				}
				return true;
		}
	}

	public function systemAdminRouteTitle( Context $context, $path, $titleType, array $route ) {
		switch ( $path ) {
			case 'export_bundle':
			case 'export_display':
				return __( 'Export', 'directories-pro' );
			case 'export_display':
				return __( 'Import', 'directories-pro' );
			case 'send_email':
				return $this->_application->Filter(
					'directory_admin_directory_send_email_title',
					__( 'Send E-mail', 'directories-pro' ),
					array( $context, $context->bundle, $titleType )
				);
		}
	}

	public function systemGetWidgetNames() {
		return $this->_application->Entity_Bundles_byType( 'directory__listing' ) ? array( 'directory_filters' ) : array();
	}

	public function systemGetWidget( $name ) {
		if ( $name === 'directory_filters' ) {
			return new SystemWidget\FiltersSystemWidget( $this->_application, $name );
		}
	}

	public function fieldGetTypeNames() {
		return array( 'directory_opening_hours' );
	}

	public function fieldGetType( $name ) {
		switch ( $name ) {
			case 'directory_opening_hours':
				return new FieldType\OpeningHoursFieldType( $this->_application, $name );
		}
	}

	public function fieldGetRendererNames() {
		return array( 'directory_opening_hours', 'directory_screenshot' );
	}

	public function fieldGetRenderer( $name ) {
		switch ( $name ) {
			case 'directory_opening_hours':
				return new FieldRenderer\OpeningHoursFieldRenderer( $this->_application, $name );
			case 'directory_screenshot':
				return new FieldRenderer\ScreenshotFieldRenderer( $this->_application, $name );
		}
	}

	public function fieldGetWidgetNames() {
		return array( 'directory_opening_hours' );
	}

	public function fieldGetWidget( $name ) {
		switch ( $name ) {
			case 'directory_opening_hours':
				return new FieldWidget\OpeningHoursFieldWidget( $this->_application, $name );
		}
	}

	public function displayGetLabelNames( Entity\Model\Bundle $bundle ) {
		if ( ! $this->_application->Entity_Field_options( $bundle, array( 'type' => 'directory_opening_hours' ) ) ) {
			return array();
		}

		return array( 'directory_open_now' );
	}

	public function displayGetLabel( $name ) {
		switch ( $name ) {
			case 'directory_open_now':
				return new DisplayLabel\OpenNowDisplayLabel( $this->_application, $name );
		}
	}

	public function paymentGetFeatureNames() {
		return array( 'directory_photos' );
	}

	public function paymentGetFeature( $name ) {
		return new PaymentFeature\PhotosPaymentFeature( $this->_application, $name );
	}

	public function onDirectoryTypesFilter( &$types ) {
		$types['directory'] = $this->_name;
	}

	public function directoryGetType( $name ) {
		return new DirectoryType\DirectoryType( $this->_application, $name );
	}

	public function onCsvImportFilesFilter( &$files, $bundle ) {
		if ( $bundle->type === 'directory_category' ) {
			$files[ __DIR__ . '/csv/categories.csv' ] = __( 'Demo categories', 'directories-pro' );
		} elseif ( $bundle->type === 'location_location' ) {
			$files[ __DIR__ . '/csv/locations.csv' ] = __( 'Demo locations (USA states and cities)', 'directories-pro' );
		} elseif ( $bundle->type === 'directory_tag' ) {
			$files[ __DIR__ . '/csv/tags.csv' ] = __( 'Demo tags', 'directories-pro' );
		}
	}

	public function onCsvImportSettingsFormFilter( &$form, $bundle, $csvFile ) {
		if ( isset( $form['importers']['location_photo'] )
			&& $csvFile['type'] === 'existing'
			&& $bundle->type === 'location_location'
			&& $csvFile['existing'] === __DIR__ . '/csv/locations.csv'
		) {
			$form['importers']['location_photo']['location']['#default_value'] = 'url';
		}
	}

	public function upgrade( $current, $newVersion, ?System\Progress $progress = null ) {
		parent::upgrade( $current, $newVersion, $progress );
		if ( version_compare( $current->version, '1.2.70-dev.0', '<' ) ) {
			$db = $this->_application->getDB();
			$db->begin();
			try {
				$db->exec(
					sprintf(
						'UPDATE %1$sentity_fieldconfig SET fieldconfig_type = %2$s WHERE fieldconfig_type = %3$s AND fieldconfig_name = %4$s',
						$db->getResourcePrefix(),
						$db->escapeString( 'directory_opening_hours' ),
						$db->escapeString( 'time' ),
						$db->escapeString( 'field_opening_hours' )
					)
				);
				$db->exec(
					sprintf(
						'UPDATE %1$sdisplay_element SET element_name = %2$s WHERE element_name = %3$s AND element_data LIKE %4$s',
						$db->getResourcePrefix(),
						$db->escapeString( 'entity_form_directory_opening_hours' ),
						$db->escapeString( 'entity_form_time' ),
						$db->escapeString( '%"field_name";s:19:"field_opening_hours"%' )
					)
				);
			} catch ( \Exception $e ) {
				$db->rollback();
				$this->_application->logError( 'Failed updating database to v1.2.70. Error: ' . $e->getMessage() );
				return $this;
			}
			$directories = array();
			foreach ( $this->_application->Entity_Bundles() as $bundle ) {
				if ( ! empty( $bundle->info['is_taxonomy'] )
					|| ( ! $field = $this->_application->Entity_Field( $bundle, 'field_opening_hours' ) )
				) {
					continue;
				}

				$field->setFieldWidget( 'directory_opening_hours' )->commit();

				if ( ! isset( $directories[ $bundle->group ] ) ) {
					if ( ! $directory = $this->_application->getModel( 'Directory', 'Directory' )->fetchById( $bundle->group ) ) {
						continue;
					}

					$directories[ $bundle->group ] = $directory;
				}
			}
			if ( ! empty( $directories ) ) {
				$this->_application->getPlatform()->clearCache();
				foreach ( $directories as $directory ) {
					\SabaiApps\Directories\Component\Directory\Controller\Admin\EditDirectory::updateBundles( $this->_application, $directory );
				}
			}
		}
		return $this;
	}

	public function getCustomTaxonomies() {
		return isset( $this->_config['custom_taxonomies'] ) ? $this->_config['custom_taxonomies'] : array();
	}

	public function setCustomTaxonomies( array $taxonomies ) {
		ksort( $taxonomies );
		$this->_application->System_Component_saveConfig( $this->_name, array( 'custom_taxonomies' => $taxonomies ), 1 );
		$this->_application->clearComponentInfoCache();
		$this->_application->Entity_BundleTypes_clearCache();
	}

	public function entityGetBundleTypeNames() {
		$ret = array();
		foreach ( array_keys( $this->getCustomTaxonomies() ) as $name ) {
			$ret[] = 'directory_custom_tax_' . $name;
		}

		return $ret;
	}

	public function entityGetBundleType( $name ) {
		switch ( $name ) {
			default:
				if ( strpos( $name, 'directory_custom_tax_' ) === 0 ) {
					$slug              = substr( $name, strlen( 'directory_custom_tax_' ) );
					$custom_taxonomies = $this->getCustomTaxonomies();
					if ( ! empty( $custom_taxonomies[ $slug ] ) ) {
						return new EntityBundleType\CustomTaxonomyEntityBundleType( $this->_application, $name, $slug, $custom_taxonomies[ $slug ] );
					}
				}
		}
	}

	public function onDirectoryContentTypeAvailableTaxonomiesFilter( &$ret ) {
		$custom_taxonomies = $this->getCustomTaxonomies();
		foreach ( array_keys( $custom_taxonomies ) as $name ) {
			$ret[ 'directory_custom_tax_' . $name ] = array(
				'component' => $this->_name,
				'is_custom' => true,
			);
		}
	}

	public function onDirectoryContentTypeSettingsFormFilter( &$form, $directoryType, $contentType, $info, $settings, $parents, $submitValues ) {
		$directory_type = is_object( $directoryType ) ? $directoryType->type : $directoryType;
		if ( $directory_type !== 'directory'
			|| $info['entity_type'] !== 'post'
			|| ! empty( $info['parent'] )
			|| ! empty( $info['parent_field'] )
		) {
			return;
		}

		$directory_name = is_object( $directoryType ) ? $directoryType->name : null;
		foreach ( $this->_application->getComponent( 'Directory' )->getAvailableTaxonomies() as $taxonomy => $taxonomy_settings ) {
			$setting_prefix = isset( $taxonomy_settings['prefix'] ) ? $taxonomy_settings['prefix'] : $taxonomy;
			$setting_name   = $setting_prefix . '_enable';
			if ( ! isset( $form[ $setting_name ] ) ) {
				continue;
			}

			// Compat with <=1.14.x
			if ( ! empty( $settings['directory_custom_taxonomies'] )
				&& strpos( $taxonomy, 'directory_custom_tax_' ) === 0
				&& in_array( substr( $taxonomy, strlen( 'directory_custom_tax_' ) ), $settings['directory_custom_taxonomies'] )
			) {
				$form[ $setting_name ]['#default_value'] = true;
			}

			$tax_bundles = $this->_application->Entity_Bundles_byType( $taxonomy );
			if ( count( $tax_bundles ) < 2 ) {
				continue;
			}

			$my_tax_bundle      = $directory_name ? $this->_application->Entity_Bundle( $taxonomy, $directory_name ) : null;
			$tax_bundle_options = array();
			foreach ( array_keys( $tax_bundles ) as $tax_bundle_name ) {
				$tax_bundle = $tax_bundles[ $tax_bundle_name ];
				if ( $directory_name
					&& $directory_name === $tax_bundle->group
				) {
					continue;
				}

				if ( $_tax_bundle = $tax_bundle->isAlias() ) {
					if ( $my_tax_bundle
						&& $_tax_bundle->name === $my_tax_bundle->name
					) {
						// used as alias, so do not allow setting alias or disabling it
						$form[ $setting_name ]['#default_value']           = true;
						$form[ $setting_prefix . '_enabled' ]              = $form[ $setting_name ];
						$form[ $setting_prefix . '_enabled' ]['#disabled'] = true;
						$form[ $setting_name ]['#type']                    = 'hidden';
						continue 2;
					}
					continue;
				}

				$tax_bundle_options[ $tax_bundle_name ] = $tax_bundle->getGroupLabel() . ' - ' . $tax_bundle->getLabel( 'singular' ) . ' - ' . $tax_bundle_name;
			}
			if ( ! empty( $tax_bundle_options ) ) {
				$form[ $setting_prefix . '_alias' ] = array(
					'#type'                  => 'select',
					'#options'               => array( '' => __( 'Use own taxonomy terms', 'directories-pro' ) ) + $tax_bundle_options,
					'#default_value'         => ! empty( $settings[ $setting_name ] ) && strlen( $settings[ $setting_name ] ) ? $settings[ $setting_name ] : null,
					'#horizontal'            => true,
					'#weight'                => $form[ $setting_name ]['#weight'],
					'#states'                => array(
						'visible' => array(
							sprintf( 'input[name="%s[' . $setting_name . ']"]', $this->_application->Form_Form_fieldName( $parents ) ) => array(
								'type'  => 'checked',
								'value' => true,
							),
						),
					),
					'#field_prefix'          => '<span class="' . DRTS_BS_PREFIX . 'badge ' . DRTS_BS_PREFIX . 'text-bg-danger ' . DRTS_BS_PREFIX . 'position-absolute ' . DRTS_BS_PREFIX . 'top-50 ' . DRTS_BS_PREFIX . 'start-0 ' . DRTS_BS_PREFIX . 'translate-middle">BETA</span>',
					'#field_prefix_no_addon' => true,
				);
			}
		}
		// if has alias, set xxx_alias as the value for xxx_enable
		$form['#submit'][9][] = function ( Form $form ) use ( $parents ) {
			$values = $form->getValue( $parents );
			foreach ( $this->_application->getComponent( 'Directory' )->getAvailableTaxonomies() as $taxonomy => $taxonomy_settings ) {
				$setting_prefix = isset( $taxonomy_settings['prefix'] ) ? $taxonomy_settings['prefix'] : $taxonomy;
				if ( ! empty( $values[ $setting_prefix . '_enable' ] )
					&& ! empty( $values[ $setting_prefix . '_alias' ] )
				) {
					$values[ $setting_prefix . '_enable' ] = $values[ $setting_prefix . '_alias' ];
				}
				unset( $values[ $setting_prefix . '_alias' ] );
			}
			$form->setValue( $parents, $values );
		};
	}

	public function onDirectoryContentTypeInfoFilter( &$info, $contentType, $settings = null ) {
		if ( ! empty( $info['is_taxonomy'] )
			|| ! empty( $info['parent'] )
			|| ! empty( $info['parent_field'] )
		) {
			return;
		}

		$taxonomy_aliases = array();
		foreach ( $this->_application->getComponent( 'Directory' )->getAvailableTaxonomies() as $taxonomy => $taxonomy_settings ) {
			$setting_prefix = isset( $taxonomy_settings['prefix'] ) ? $taxonomy_settings['prefix'] : $taxonomy;
			$setting_name   = $setting_prefix . '_enable';
			if ( ! empty( $settings[ $setting_name ] )
				&& is_string( $settings[ $setting_name ] )
				&& strlen( $settings[ $setting_name ] ) > 1
			) {
				$taxonomy_aliases[ $taxonomy ] = $settings[ $setting_name ];
			}
		}
		if ( ! empty( $taxonomy_aliases ) ) {
			$info['directory_taxonomy_aliases'] = $taxonomy_aliases;
		}
	}

	public function onEntityBundlesInfoFilter( &$bundles, $group ) {
		foreach ( array_keys( $this->_application->getComponent( 'Directory' )->getAvailableTaxonomies() ) as $taxonomy_bundle_type ) {
			if ( ! isset( $bundles[ $taxonomy_bundle_type ] ) ) {
				continue; // this should not happen
			}

			$alias_found = null;
			foreach ( array_keys( $bundles ) as $bundle_type ) {
				$info =& $bundles[ $bundle_type ];
				if ( isset( $info['directory_taxonomy_aliases'][ $taxonomy_bundle_type ] ) ) {
					if ( strlen( $info['directory_taxonomy_aliases'][ $taxonomy_bundle_type ] ) ) {
						$alias_found = $info['directory_taxonomy_aliases'][ $taxonomy_bundle_type ];
					}
					break;
				}
			}
			$bundles[ $taxonomy_bundle_type ]['alias'] = $alias_found;
		}
	}

	public function onEntityBundleInfoKeysFilter( &$keys ) {
		$keys[] = 'directory_custom_taxonomies';
		$keys[] = 'alias';
	}

	public function onDirectoryAdminSettingsFormFilter( &$form ) {
		// Moved from Directory to System component
		$this->onSystemAdminSettingsFormFilter( $form );
	}

	public function onSystemAdminSettingsFormFilter( &$form ) {
		$form['fields'][ $this->_name ] = array(
			'#tab'                        => 'Directory',
			'#component'                  => $this->_name,
			'#component_config_overwrite' => true,
			'#title'                      => __( 'Taxonomy Settings', 'directories-pro' ),
			'#weight'                     => 30,
			'custom_taxonomies'           => array(
				'#title'      => __( 'Custom Taxonomies', 'directories-pro' ),
				'#horizontal' => true,
			) + $this->_application->DirectoryPro_CustomTaxonomies_settingsForm( empty( $this->_config['custom_taxonomies'] ) ? array() : $this->_config['custom_taxonomies'], array( $this->_name, 'custom_taxonomies' ) ),
		);
	}

	public function onEntityMetaFieldWidgetFormFilter( &$form, $field, $value, $entity, $parents, $language ) {
		$bundle      = $field->Bundle;
		$permissions = $this->_application->Entity_Permissions( $bundle );
		if ( empty( $permissions['entity_read'] ) ) {
			return;
		}

		$form['directorypro_restrict_access'] = array(
			'enable' => array(
				'#title'         => __( 'Restrict access by user role', 'directories-pro' ),
				'#type'          => 'checkbox',
				'#default_value' => ! empty( $value['directorypro_restrict_access']['enable'] ),
			),
			'roles'  => array(
				'#type'          => 'checkboxes',
				'#columns'       => 2,
				'#options'       => $this->_application->getPlatform()->getRoles(),
				'#default_value' => empty( $value['directorypro_restrict_access']['roles'] ) ? null : $value['directorypro_restrict_access']['roles'],
				'#states'        => array(
					'visible' => array(
						sprintf( '[name="%s"]', $this->_application->Form_Form_fieldName( array_merge( $parents, array( 'directorypro_restrict_access', array( 'enable' ) ) ) ) ) => array(
							'type'  => 'checked',
							'value' => true,
						),
					),
				),
			),
		);
	}

	public function onEntityIsRoutableFilter( &$result, $bundle, $action, $entity ) {
		if ( $result === false
			|| $action !== 'view'
			|| ! isset( $entity )
			|| ( ! $restrict_access = $entity->getSingleFieldValue( 'entity_meta', 'directorypro_restrict_access' ) )
			|| empty( $restrict_access['enable'] )
			|| empty( $restrict_access['roles'] )
		) {
			return;
		}

		$result = false;
		$roles  = $this->_application->getRoles();
		foreach ( $restrict_access['roles'] as $role ) {
			if ( in_array( $role, $roles ) ) {
				$result = true;
				return;
			}
		}
	}

	public function wordpressGetBlockNames() {
		return array(
			'directory_categories',
			'directory_locations',
			'directory_recent_listings',
			'directory_featured_listings',
			'directory_recent_reviews',
		);
	}

	public function wordpressGetBlock( $name ) {
		switch ( $name ) {
			case 'directory_categories':
				return new WordPressBlock\CategoriesWordPressBlock( $this->_application, $name );
			case 'directory_locations':
				return new WordPressBlock\LocationsWordPressBlock( $this->_application, $name );
			case 'directory_recent_listings':
				return new WordPressBlock\RecentListingsWordPressBlock( $this->_application, $name );
			case 'directory_featured_listings':
				return new WordPressBlock\FeaturedListingsWordPressBlock( $this->_application, $name );
			case 'directory_recent_reviews':
				return new WordPressBlock\RecentReviewsWordPressBlock( $this->_application, $name );
		}
	}

	public function entityGetFeatureNames() {
		return array( 'directory_photos' );
	}

	public function entityGetFeature( $name ) {
		return new EntityFeature\PhotosEntityFeature( $this->_application, $name );
	}

	public function systemGetToolNames() {
		return array( 'directorypro_bulk_send_email', 'directorypro_export_display', 'directorypro_import_display' );
	}

	public function systemGetTool( $name ) {
		switch ( $name ) {
			case 'directorypro_bulk_send_email':
				return new SystemTool\BulkSendEmailSystemTool( $this->_application, $name );
			case 'directorypro_export_display':
				return new SystemTool\ExportDisplaySystemTool( $this->_application, $name );
			case 'directorypro_import_display':
				return new SystemTool\ImportDisplaySystemTool( $this->_application, $name );
		}
	}

	public function onDisplayElementsLinksFilter( &$links, $display ) {
		if ( $display['type'] !== 'entity' ) {
			return;
		}

		if ( ( $bundle = $this->_application->Entity_Bundle( $display['bundle_name'] ) )
			&& ( $admin_path = $this->_application->Entity_BundleTypeInfo_adminPath( $bundle ) )
		) {
			if ( $hyphen_pos = strpos( $display['name'], '-' ) ) {
				if ( isset( $display['label'] )
					&& strlen( $display['label'] )
				) {
					$modal_title_suffix = $display['label'];
				} else {
					$modal_title_suffix = substr( $display['name'], $hyphen_pos + 1 );
				}
			} elseif ( $this->_application->Display_Create_isCreatable( $bundle->type, $display['type'], $display['name'] ) ) {
					$modal_title_suffix = __( 'Default', 'directories-pro' );
			}
			$links[] = $this->_application->LinkTo(
				__( 'Export', 'directories-pro' ),
				array(
					'route'  => $admin_path . '/displays/export_display',
					'params' => array(
						'display_type' => $display['type'],
						'display_name' => $display['name'],
					),
				),
				array(
					'container' => 'modal',
					'modalSize' => 'xl',
				),
				array( 'data-modal-title' => __( 'Export', 'directories-pro' ) . ( isset( $modal_title_suffix ) ? ' - ' . $modal_title_suffix : '' ) )
			);
			$links[] = $this->_application->LinkTo(
				__( 'Import', 'directories-pro' ),
				array(
					'route'  => $admin_path . '/displays/import_display',
					'params' => array(
						'display_type' => $display['type'],
						'display_name' => $display['name'],
					),
				),
				array(
					'container' => 'modal',
					'modalSize' => 'xl',
				),
				array( 'data-modal-title' => __( 'Import', 'directories-pro' ) . ( isset( $modal_title_suffix ) ? ' - ' . $modal_title_suffix : '' ) )
			);
		}
	}

	public function onDisplayAdminAddDisplayFormFilter( &$form, $bundle, $displayType, $displayName ) {
		if ( $displayType !== 'entity' ) {
			return;
		}

		$form['#enable_storage']              = true; // required for file upload
		$form['method']['#options']['import'] = __( 'Import from a JSON file', 'directories-pro' );
		$form['json']                         = array(
			'#type'               => 'file',
			'#title'              => __( 'JSON configuration file', 'directories-pro' ),
			'#upload_dir'         => $this->_application->getComponent( 'System' )->getTmpDir(),
			'#allowed_extensions' => array( 'json' ),
			'#required'           => function ( $form ) {
				return $form->getValue( 'method' ) === 'import'; },
			'#multiple'           => false,
			'#horizontal'         => true,
			'#weight'             => 5,
			'#states'             => array(
				'visible' => array(
					'[name="method"]' => array( 'value' => 'import' ),
				),
			),
		);
	}

	public function onDisplayAdminAddDisplayFilter( &$display, $bundle, $displayType, $newDisplayName, $form ) {
		if ( $displayType !== 'entity' ) {
			return;
		}

		$values = $form->values;
		if ( empty( $values['json']['saved_file_path'] )
			|| false === ( $json = file_get_contents( $values['json']['saved_file_path'] ) )
		) {
			$form->setError( __( 'JSON configuration file was not uploaded.', 'directories-pro' ) );
			return;
		}
		if ( ! $decoded = json_decode( $json, true ) ) {
			$form->setError( __( 'Invalid JSON data', 'directories-pro' ), 'json' );
			return;
		}

		if ( empty( $decoded['entity_type'] )
			|| $decoded['entity_type'] !== $bundle->entitytype_name
			|| empty( $decoded['bundle_type'] )
			|| $decoded['bundle_type'] !== $bundle->type
			|| empty( $decoded['type'] )
			|| $decoded['type'] !== $displayType
		) {
			$form->setError( __( 'Invalid JSON data', 'directories-pro' ), 'json' );
			return;
		}

		// Replace CSS class specific to the existing display with the CSS class of the new display
		$decoded['data']['css'] = str_replace(
			'.' . Display\Model\Display::cssClass( $decoded['name'], $decoded['type'] ),
			'.' . Display\Model\Display::cssClass( $newDisplayName, $displayType ),
			$decoded['data']['css']
		);

		$display = $decoded;
	}

	public function onViewFeatureSettingsFormFilter( &$form, $bundle, $settings, $submitValues ) {
		$weight                            = 30;
		$form['other']['gad_enable']       = array(
			'#type'          => 'checkbox',
			'#title'         => __( 'Enable Google AdSense', 'directories-pro' ),
			'#default_value' => ! empty( $settings['other']['gad_enable'] ),
			'#horizontal'    => true,
			'#weight'        => $weight,
			'#states'        => array(
				'visible' => array(
					'[name="general[mode]"]' => array(
						'type'  => 'one',
						'value' => array( 'list' ),
					),
				),
			),
		);
		$form['other']['gad_publisher_id'] = array(
			'#type'          => 'textfield',
			'#field_prefix'  => __( 'Publisher ID', 'directories-pro' ),
			'#default_value' => isset( $settings['other']['gad_publisher_id'] ) ? $settings['other']['gad_publisher_id'] : null,
			'#placeholder'   => sprintf( __( '%1$s or %2$s', 'directories-pro' ), 'pub-1234567890123456', 'ca-pub-1234567890123456' ),
			'#horizontal'    => true,
			'#weight'        => $weight,
			'#states'        => $states = array(
				'visible' => array(
					'[name="general[mode]"]'          => array(
						'type'  => 'one',
						'value' => array( 'list' ),
					),
					'input[name="other[gad_enable]"]' => array(
						'type'  => 'checked',
						'value' => true,
					),
				),
			),
			'#required'      => function ( $form ) {
				return (bool) $form->getValue( array( 'other', 'gad_enable' ) ); },
		);
		$form['other']['gad_slot_id'] = array(
			'#type'          => 'textfield',
			'#field_prefix'  => __( 'Slot ID', 'directories-pro' ),
			'#default_value' => isset( $settings['other']['gad_slot_id'] ) ? $settings['other']['gad_slot_id'] : null,
			'#placeholder'   => '1234567890',
			'#horizontal'    => true,
			'#weight'        => $weight,
			'#states'        => $states,
			'#required'      => function ( $form ) {
				return (bool) $form->getValue( array( 'other', 'gad_enable' ) ); },
		);
		$options                      = array( 1 => __( 'Show after first post', 'directories-pro' ) );
		foreach ( range( 2, 5 ) as $num ) {
			$options[ $num ] = sprintf( __( 'Show after %d posts', 'directories-pro' ), $num );
		}
		$form['other']['gad_interval'] = array(
			'#type'          => 'select',
			'#default_value' => isset( $settings['other']['gad_interval'] ) ? $settings['other']['gad_interval'] : null,
			'#options'       => $options,
			'#horizontal'    => true,
			'#weight'        => $weight,
			'#states'        => $states,
		);
		$form['other']['gad_repeat']   = array(
			'#type'          => 'checkbox',
			'#switch'        => false,
			'#title'         => __( 'Repeat', 'directories-pro' ),
			'#default_value' => ! empty( $settings['other']['gad_repeat'] ),
			'#horizontal'    => true,
			'#weight'        => $weight,
			'#states'        => $states,
		);
	}

	protected static $_gAdScriptAdded = false;

	public function onViewEntitiesListAfterEntity( $entity, $i, $viewName, $settings, $class ) {
		if ( empty( $settings['other'] )
			|| ( ! $other = $settings['other'] )
			|| empty( $other['gad_publisher_id'] )
			|| empty( $other['gad_slot_id'] )
			|| empty( $other['gad_interval'] = (int) $other['gad_interval'] )
		) {
			return;
		}

		if ( empty( $other['gad_repeat'] ) ) {
			if ( $i !== $other['gad_interval'] ) {
				return;
			}
		} elseif ( $i % $other['gad_interval'] !== 0 ) {
			return;
		}

		$html = array();
		if ( ! self::$_gAdScriptAdded ) {
			self::$_gAdScriptAdded = true;
			$html[]                = sprintf(
				'<script async src="https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=%s" crossorigin="anonymous"></script>',
				$this->_application->H( $other['gad_publisher_id'] )
			);
		}
		$html[] = sprintf(
			'<div class="%s">
    <ins class="adsbygoogle" style="display:block;text-align:center;" data-ad-layout="in-article" data-ad-format="fluid" data-ad-client="%s" data-ad-slot="%s"></ins>
    <script>(adsbygoogle = window.adsbygoogle || []).push({});</script>
</div>',
			$this->_application->H( $class ),
			$this->_application->H( $other['gad_publisher_id'] ),
			$this->_application->H( $other['gad_slot_id'] )
		);
		echo implode( PHP_EOL, $html );
	}

	public function onWordpressDirectoryAdminEndpointFilter( &$endpoint ) {
		$endpoint = array(
			'post_type'  => null,
			'label'      => __( 'All Directories', 'directories-pro' ),
			'label_menu' => 'Directories',
			'icon'       => 'data:image/svg+xml;base64,' . base64_encode(
				'<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="30" height="30" viewBox="0 0 30 30" xml:space="preserve">
    <g transform="translate(-450 -620)">
        <g xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" id="directories">
            <path fill="black" d="M479,624h-10c-0.55,0-1.36-0.27-1.8-0.6l-2.4-1.801c-0.439-0.33-1.25-0.6-1.8-0.6h-5c-0.55,0-1,0.45-1,1v2h-2    c-0.55,0-1,0.45-1,1v2h-2c-0.55,0-1,0.45-1,1v19c0,0.55,0.45,1,1,1h21c0.55,0,1-0.45,1-1v-2h2c0.55,0,1-0.45,1-1v-2h2    c0.55,0,1-0.45,1-1v-16C480,624.45,479.55,624,479,624z M452,628h5c0.33,0,0.936,0.201,1.199,0.4l2.401,1.8    c0.606,0.456,1.639,0.8,2.399,0.8h10v2h-21V628z M473,647h-21v-13h21V647z M476,644h-2v-13c0-0.55-0.45-1-1-1h-10    c-0.55,0-1.36-0.27-1.8-0.6l-2.4-1.801c-0.439-0.33-1.25-0.6-1.8-0.6h-2v-2h5c0.33,0,0.936,0.201,1.199,0.4l2.401,1.8    c0.606,0.456,1.639,0.8,2.399,0.8h10V644z M479,641h-2v-13c0-0.55-0.45-1-1-1h-10c-0.55,0-1.36-0.27-1.8-0.6l-2.4-1.801    c-0.439-0.33-1.25-0.6-1.8-0.6h-2v-2h5c0.33,0,0.936,0.201,1.199,0.4l2.401,1.8c0.606,0.456,1.639,0.8,2.399,0.8h10V641z"/>
        </g>
    </g>
</svg>'
			),
		) + $endpoint;
	}

	public function onDirectoryAdminDirectoryImportBundlesFilter( &$bundles, $directory ) {
		$custom_taxonomies     = $this->getCustomTaxonomies();
		$new_custom_taxonomies = array();
		foreach ( array_keys( $bundles ) as $bundle_type ) {
			if ( strpos( $bundle_type, 'directory_custom_tax_' ) !== 0 ) {
				continue;
			}

			$slug = substr( $bundle_type, strlen( 'directory_custom_tax_' ) );
			if ( isset( $custom_taxonomies[ $slug ] ) ) {
				continue;
			}

			$info                           =& $bundles[ $bundle_type ];
			$new_custom_taxonomies[ $slug ] = array(
				'icon'           => $info['icon'],
				'label'          => $info['label'],
				'label_singular' => $info['label_singular'],
			);
		}
		if ( ! empty( $new_custom_taxonomies ) ) {
			$this->setCustomTaxonomies( $custom_taxonomies + $new_custom_taxonomies );
		}
	}
}
