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

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

class DisplayComponent extends AbstractComponent implements
	IElements,
	IButtons,
	ILabels,
	System\IWidgets,
	System\IAdminRouter,
	Form\IFields,
	IIcons {

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

	public static function description() {
		return 'Enables customizing display of content without writing any code.';
	}

	public function displayGetElementNames( Entity\Model\Bundle $bundle ) {
		return array(
			'text',
			'columns',
			'column',
			'separator',
			'tabs',
			'tab',
			'group',
			'html',
			'javascript',
			'labels',
			'button',
			'statistics',
			'fieldlist',
			'template',
			'fieldtemplate',
			'card',
			'row',
			'icons',
		);
	}

	public function displayGetElement( $name ) {
		switch ( $name ) {
			case 'text':
				return new Element\TextElement( $this->_application, $name );
			case 'columns':
				return new Element\ColumnsElement( $this->_application, $name );
			case 'column':
				return new Element\ColumnElement( $this->_application, $name );
			case 'tabs':
				return new Element\TabsElement( $this->_application, $name );
			case 'tab':
				return new Element\TabElement( $this->_application, $name );
			case 'group':
				return new Element\GroupElement( $this->_application, $name );
			case 'separator':
				return new Element\SeparatorElement( $this->_application, $name );
			case 'html':
				return new Element\HtmlElement( $this->_application, $name );
			case 'javascript':
				return new Element\JavaScriptElement( $this->_application, $name );
			case 'template':
				return new Element\TemplateElement( $this->_application, $name );
			case 'labels':
				return new Element\LabelsElement( $this->_application, $name );
			case 'button':
				return new Element\ButtonElement( $this->_application, $name );
			case 'statistics':
				return new Element\StatisticsElement( $this->_application, $name );
			case 'card':
				return new Element\CardElement( $this->_application, $name );
			case 'row':
				return new Element\RowElement( $this->_application, $name );
			case 'icons':
				return new Element\IconsElement( $this->_application, $name );
		}
	}

	public function displayGetButtonNames( Entity\Model\Bundle $bundle ) {
		return array( 'custom', 'back' );
	}

	public function displayGetButton( $name ) {
		switch ( $name ) {
			case 'custom':
				return new Button\CustomButton( $this->_application, $name );
			case 'back':
				return new Button\BackButton( $this->_application, $name );
		}
	}

	public function displayGetLabelNames( Entity\Model\Bundle $bundle ) {
		return array( 'custom' );
	}

	public function displayGetLabel( $name ) {
		return new Label\CustomLabel( $this->_application, $name );
	}

	public function displayGetIconNames( Entity\Model\Bundle $bundle ) {
		return array( 'icon', 'image' );
	}

	public function displayGetIcon( $name ) {
		switch ( $name ) {
			case 'icon':
				return new Icon\CustomIcon( $this->_application, $name );
			case 'image':
				return new Icon\CustomImage( $this->_application, $name );
		}
	}

	public function systemGetWidgetNames() {
		return array( 'display_element' );
	}

	public function systemGetWidget( $name ) {
		return new SystemWidget\ElementSystemWidget( $this->_application, $name );
	}

	public function systemAdminRoutes() {
		$routes = array();
		foreach ( array_keys( $this->_application->Entity_BundleTypes() ) as $bundle_type ) {
			if ( ( ! $admin_path = $this->_application->Entity_BundleTypeInfo( $bundle_type, 'admin_path' ) )
				|| isset( $routes[ $admin_path . '/list_display_elements' ] ) // path added already
			) {
				continue;
			}

			$routes += array(
				$admin_path . '/list_display_elements'   => array(
					'controller'      => 'ListElements',
					'access_callback' => true,
					'callback_path'   => 'list_elements',
				),
				$admin_path . '/add_display_element'     => array(
					'controller'      => 'AddElement',
					'access_callback' => true,
					'callback_path'   => 'add_element',
				),
				$admin_path . '/edit_display_element'    => array(
					'controller'      => 'EditElement',
					'access_callback' => true,
					'callback_path'   => 'edit_element',
				),
				$admin_path . '/displays/add_display'    => array(
					'controller'      => 'AddDisplay',
					'access_callback' => true,
					'callback_path'   => 'add_display',
				),
				$admin_path . '/displays/delete_display' => array(
					'controller'      => 'DeleteDisplay',
					'access_callback' => true,
					'callback_path'   => 'delete_display',
				),
			);
		}

		return $routes;
	}

	public function systemOnAccessAdminRoute( Context $context, $path, $accessType, array &$route ) {
		switch ( $path ) {
			case 'add_display':
				if ( $accessType === Application::ROUTE_ACCESS_LINK ) {
					return $this->_application->Display_Create_isCreatable(
						$context->bundle->type,
						$context->getRequest()->asStr( 'display_type' ),
						$context->getRequest()->asStr( 'display_name' )
					);
				}
				return true;
			case 'delete_display':
				if ( $accessType === Application::ROUTE_ACCESS_LINK ) {
					$name = $context->getRequest()->asStr( 'display_name' );
					$type = $context->getRequest()->asStr( 'display_type' );
					if ( $type === 'entity' ) {
						if ( ! $pos = strpos( $name, '-' ) ) {
							return false; // can not delete default display
						}

						$name = substr( $name, 0, $pos );
					} elseif ( $name === 'default' ) {
							return false;
					}

					return $this->_application->Display_Create_isCreatable( $context->bundle->type, $type, $name );
				}
				return true;
			case 'list_elements':
			case 'add_element':
			case 'edit_element':
				if ( $accessType === Application::ROUTE_ACCESS_LINK ) {
					if ( ( ! $display_id = $context->getRequest()->asInt( 'display_id' ) )
						|| ( ! $display = $this->getModel( 'Display', 'Display' )->fetchById( $display_id ) )
					) {
						return false;
					}

					$context->display = $display;
					if ( $alt_display_id = $context->getRequest()->asInt( 'alt_display_id' ) ) {
						if ( ! $alt_display = $this->getModel( 'Display', 'Display' )->fetchById( $alt_display_id ) ) {
							return false;
						}

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

	public function systemAdminRouteTitle( Context $context, $path, $titleType, array $route ) {}

	public function onEntityDeleteBundlesCommitted( array $bundles, $deleteContent ) {
		foreach ( $this->getModel( 'Display' )->bundleName_in( array_keys( $bundles ) )->fetch() as $display ) {
			$display->markRemoved();
		}
		$this->getModel()->commit();
	}

	public function formGetFieldTypes() {
		return array( 'display_elements' );
	}

	public function formGetField( $type ) {
		return new FormField\ElementsFormField( $this->_application );
	}

	public function onDisplayElementRenderFilter( &$results, $bundle, array $element, $var ) {
		// Show to item author only?
		if ( ! $var instanceof Entity\Type\IEntity
			|| empty( $element['visibility']['author_only'] )
			|| ( ! $author_id = $var->getAuthorId() )
		) {
			return;
		}

		$results[] = $this->_application->getUser()->id === $author_id;
	}
}
