<?php
namespace SabaiApps\Directories\Component\Display\Controller\Admin;

use SabaiApps\Directories\Application;
use SabaiApps\Directories\Component\Display\Model\Display;
use SabaiApps\Directories\Context;
use SabaiApps\Directories\Component\Form;
use SabaiApps\Directories\Exception\RuntimeException;

class AddDisplay extends Form\Controller {

	protected function _doGetFormSettings( Context $context, array &$storage ) {
		$display_type                 = $context->getRequest()->asStr( 'display_type' );
		$display_name                 = $context->getRequest()->asStr( 'display_name' );
		$this->_ajaxSubmit            = true;
		$this->_ajaxOnSuccessRedirect = true;
		$this->_submitButtons[]       = array(
			'#btn_color' => 'success',
			'#btn_size'  => 'lg',
		);
		$name_prefix                  = $display_type === 'entity' ? $display_name . '-' : null;
		$form                         = array(
			'label'        => array(
				'#type'        => 'textfield',
				'#title'       => __( 'Label', 'directories-pro' ),
				'#description' => __( 'Enter a label used for administration purpose only.', 'directories-pro' ),
				'#max_length'  => 255,
				'#horizontal'  => true,
				'#weight'      => 9,
			),
			'name'         => array(
				'#type'             => 'textfield',
				'#title'            => __( 'Name', 'directories-pro' ),
				'#description'      => __( 'Enter a unique name so that that it can be easily referenced. Only lowercase alphanumeric characters and underscores are allowed.', 'directories-pro' ),
				'#field_prefix'     => $name_prefix,
				'#max_length'       => isset( $name_prefix ) ? 100 - strlen( $name_prefix ) : 100,
				'#required'         => true,
				'#regex'            => '/^[a-z0-9_]+$/',
				'#horizontal'       => true,
				'#element_validate' => array(
					array( array( $this, '_validateName' ), array( $context->bundle, $display_type, $name_prefix ) ),
				),
				'#states'           => array(
					'slugify' => array(
						'input[name="label"]' => array(
							'type'  => 'filled',
							'value' => true,
						),
					),
				),
				'#weight'           => 10,
			),
			'display_type' => array(
				'#type'  => 'hidden',
				'#value' => $context->getRequest()->asStr( 'display_type' ),
			),
			'display_name' => array(
				'#type'  => 'hidden',
				'#value' => $context->getRequest()->asStr( 'display_name' ),
			),
		);
		if ( $display_type !== 'form' ) {
			$form += array(
				'method'   => array(
					'#type'          => 'select',
					'#title'         => __( 'Create or copy', 'directories-pro' ),
					'#horizontal'    => true,
					'#options'       => array(
						''         => _x( 'Create empty', 'create empty display', 'directories-pro' ),
						'existing' => __( 'Copy from existing', 'directories-pro' ),
					),
					'#default_value' => '',
					'#required'      => true,
					'#weight'        => 1,
				),
				'existing' => array(
					'#type'       => 'select',
					'#options'    => self::existingDisplays( $this->_application, $context->bundle->name, $display_name, $display_type ),
					'#horizontal' => true,
					'#states'     => array(
						'visible' => array(
							'[name="method"]' => array( 'value' => 'existing' ),
						),
					),
					'#weight'     => 5,
				),
			);
			if ( $templates = self::templateDisplayNames( $this->_application, $context->bundle, $display_name, $display_type ) ) {
				$form['method']['#options']['template'] = __( 'Copy from template', 'directories-pro' );
				$form['template']                       = array(
					'#type'       => 'select',
					'#options'    => $templates,
					'#horizontal' => true,
					'#states'     => array(
						'visible' => array(
							'[name="method"]' => array( 'value' => 'template' ),
						),
					),
					'#weight'     => 3,
				);
			}
		}
		return $this->Filter( 'display_admin_add_display_form', $form, array( $context->bundle, $display_type, $display_name ) );
	}

	public function _validateName( Form\Form $form, &$value, $element, $bundle, $type, $prefix ) {
		$query = $this->getModel( 'Display', 'Display' )
			->bundleName_is( $bundle->name )
			->type_is( $type )
			->name_is( strlen( $prefix ) ? $prefix . $value : $value );
		if ( $query->count() ) {
			$form->setError( __( 'The name is already taken.', 'directories-pro' ), $element );
		}
	}

	public function submitForm( Form\Form $form, Context $context ) {
		$display_type     = $context->getRequest()->asStr( 'display_type' );
		$display_name     = $context->getRequest()->asStr( 'display_name' );
		$new_display_name = $display_type === 'entity' ? $display_name . '-' . $form->values['name'] : $form->values['name'];

		// Fetch display settings
		$display = array();
		if ( $display_type !== 'form' ) {
			switch ( $form->values['method'] ) {
				case 'template':
					$displays = self::templateDisplays( $this->_application, $context->bundle, $display_name, $display_type );
					if ( isset( $displays[ $form->values['template'] ] ) ) {
						$display = $displays[ $form->values['template'] ];
					}
					break;
				case 'existing':
					$existing_display_name = $form->values['existing'];
					$existing_display      = $this->getModel( 'Display', 'Display' )
						->bundleName_is( $context->bundle->name )
						->type_is( $display_type )
						->name_is( $existing_display_name )
						->fetchOne();
					if ( ! $existing_display ) {
						throw new RuntimeException( 'Invalid display: ' . $existing_display_name );
					}
					$display = $this->Display_Display_export( $existing_display );
					if ( isset( $display['data']['css'] )
						&& strlen( $display['data']['css'] )
					) {
						// Replace CSS class specific to the existing display with the CSS class of the new display
						$display['data']['css'] = str_replace(
							'.' . Display::cssClass( $existing_display->name, $existing_display->type ),
							'.' . Display::cssClass( $new_display_name, $display_type ),
							$display['data']['css']
						);
					}
					break;
				default:
					if ( $form->values['method'] !== '' ) {
						$display = $this->Filter( 'display_admin_add_display', $display, array( $context->bundle, $display_type, $new_display_name, $form ) );
						if ( empty( $display ) ) {
							$context->setError( 'Unable to add a display. Method: ' . $form->values['method'] );
							return;
						}
					}
			}
		}

		// Create display
		$display['data']['label'] = $form->values['label'];
		$this->Display_Create( $context->bundle, $display_type, $new_display_name, $display );

		// Send success
		$admin_path = $this->_application->Entity_BundleTypeInfo_adminPath( $context->bundle );
		switch ( $display_type ) {
			case 'filters':
				$admin_path .= '/views/filters';
				break;
			case 'form':
				$admin_path .= '/fields';
				break;
			default:
				$admin_path .= '/displays';
				break;
		}
		$context->setSuccess(
			$this->Url(
				$admin_path,
				array(
					'_drts_form_current_tab'  => $display_name,
					'_drts_form_current_tab2' => $new_display_name,
				)
			)
		)
			->addFlash( __( 'Display was created successfully.', 'directories-pro' ) );
	}

	public static function templateDisplays( Application $application, $bundle, $defaultDisplayName, $type = 'entity' ) {
		$bundles_info = $application->Filter(
			'entity_bundle_info',
			array( $bundle->type => $application->Entity_BundleTypeInfo( $bundle->type, null, false ) ),
			array( $bundle->group )
		);
		$bundle_info  = $bundles_info[ $bundle->type ];
		unset( $bundles_info );
		if ( empty( $bundle_info['displays'] ) ) {
			return array();
		}

		if ( is_string( $bundle_info['displays'] ) ) {
			if ( file_exists( $bundle_info['displays'] ) ) {
				$displays = include $bundle_info['displays'];
			}
		} else {
			$displays = $bundle_info['displays'];
		}
		if ( empty( $displays[ $type ] ) ) {
			return array();
		}

		$displays = $displays[ $type ];
		foreach ( array_keys( $displays ) as $display_name ) {
			if ( 0 !== strpos( $display_name, $defaultDisplayName ) ) {
				unset( $displays[ $display_name ] );
				continue;
			}
		}
		return $displays;
	}

	public static function templateDisplayNames( Application $application, $bundle, $defaultDisplayName, $type = 'entity' ) {
		$displays = self::templateDisplays( $application, $bundle, $defaultDisplayName, $type );
		$prefix   = $type === 'entity' ? $defaultDisplayName . '-' : null;
		foreach ( array_keys( $displays ) as $display_name ) {
			if ( $display_name === $defaultDisplayName ) {
				$displays[ $display_name ] = __( 'Default', 'directories-pro' );
			} else {
				$displays[ $display_name ] = substr( $display_name, strlen( $prefix ) ) . ' (' . $display_name . ')';
			}
		}
		return $displays;
	}

	public static function existingDisplays( Application $application, $bundleName, $defaultDisplayName, $type = 'entity' ) {
		$ret      = array( $defaultDisplayName => __( 'Default', 'directories-pro' ) );
		$prefix   = $type === 'entity' ? $defaultDisplayName . '-' : '';
		$displays = $application->getModel( 'Display', 'Display' )
			->bundleName_is( $bundleName )
			->type_is( $type );
		if ( strlen( $prefix ) ) {
			foreach ( $displays->name_startsWith( $prefix )->fetch( 0, 0, 'name' ) as $display ) {
				$ret[ $display->name ] = isset( $display->data['label'] ) && strlen( $display->data['label'] ) ? $display->data['label'] : substr( $display->name, strlen( $prefix ) );
			}
		} else {
			foreach ( $displays->fetch( 0, 0, 'name' ) as $display ) {
				if ( $display->name === 'default' ) {
					continue;
				}

				$ret[ $display->name ] = isset( $display->data['label'] ) && strlen( $display->data['label'] ) ? $display->data['label'] : $display->name;
			}
		}

		return $ret;
	}
}
