<?php
namespace SabaiApps\Directories\Component\Calendar\ViewMode;

use SabaiApps\Directories\Component\Entity\Model\Bundle;
use SabaiApps\Directories\Component\Entity\Type\Query;
use SabaiApps\Directories\Request;
use SabaiApps\Directories\Component\View\Mode\AbstractMode;
use SabaiApps\Directories\Application;
use SabaiApps\Directories\Component\Calendar\CalendarComponent;
use SabaiApps\Directories\Component\Form\Form;
use SabaiApps\Framework\Criteria\IsCriteria;
use SabaiApps\Framework\Criteria\IsOrGreaterThanCriteria;
use SabaiApps\Framework\Criteria\IsSmallerThanCriteria;
use SabaiApps\Framework\Criteria\InCriteria;

class CalendarViewMode extends AbstractMode {

	protected function _viewModeInfo() {
		return array(
			'label'             => _x( 'Calendar', 'view mode label', 'directories-pro' ),
			'default_settings'  => array(
				'template'               => 'calendar_entities',
				'display'                => 'summary',
				'filter_only'            => true,
				'calendar_slot_field'    => null,
				'calendar_color'         => 'primary',
				'calendar_infobox_width' => 360,
				'calendar_item_color'    => null,
				'calendar_display_mode'  => 'month',
				'calendar_display_modes' => null,
			),
			'default_display'   => 'summary',
			'displays'          => array(
				'summary' => array(
					'label'  => _x( 'Summary', 'display name', 'directories-pro' ),
					'weight' => 1,
				),
			),
			'display_required'  => false,
			'features_disabled' => array(
				'sort',
				'pagination',
				'other' => array( 'num', 'not_found' ),
			),
			'mapable'           => false,
		);
	}

	public function viewModeSupports( Bundle $bundle ) {
		if ( ! parent::viewModeSupports( $bundle )
			|| empty( $bundle->info['public'] )
		) {
			return false;
		}

		foreach ( $this->_application->Entity_Field( $bundle ) as $field ) {
			if ( $field->getFieldType() === 'calendar_slot' ) {
				return true;
			}
		}
		return false;
	}

	public function viewModeSettingsForm( Bundle $bundle, array $settings, array $parents = array() ) {
		$field_options = $this->_application->Entity_Field_options(
			$bundle,
			array(
				'type'            => 'calendar_slot',
				'return_disabled' => true,
			)
		);
		$form          = array(
			'calendar_slot_field'    => array(
				'#type'             => 'checkboxes',
				'#title'            => __( 'Calendar slot field', 'directories-pro' ),
				'#horizontal'       => true,
				'#options'          => $field_options[0],
				'#options_disabled' => array_keys( $field_options[1] ),
				'#default_value'    => $settings['calendar_slot_field'] ?? array_keys( $field_options[0] ),
				'#required'         => true,
				'#weight'           => 10,
			),
			'calendar_color'         => array(
				'#type'             => 'radios',
				'#title'            => __( 'Calendar color', 'directories-pro' ),
				'#options'          => array( '' => __( 'None', 'directories-pro' ) ) + $this->_application->System_Color_options( array( 'as_background' => true ) ),
				'#option_no_escape' => true,
				'#horizontal'       => true,
				'#default_value'    => $settings['calendar_color'],
				'#weight'           => 1,
				'#columns'          => 3,
			),
			'calendar_display_modes' => array(
				'#type'          => 'sortablecheckboxes',
				'#title'         => __( 'Calendar display modes', 'directories-pro' ),
				'#horizontal'    => true,
				'#options'       => $calendar_display_modes = array(
					'month' => __( 'Month', 'directories-pro' ),
					'year'  => __( 'Year', 'directories-pro' ),
					'list'  => __( 'List', 'directories-pro' ),
				),
				'#default_value' => $settings['calendar_display_modes'] ?? array_keys( $calendar_display_modes ),
				'#weight'        => 5,
			),
			'calendar_display_mode'  => array(
				'#type'             => 'select',
				'#title'            => __( 'Calendar initial display mode', 'directories-pro' ),
				'#horizontal'       => true,
				'#options'          => $calendar_display_modes,
				'#default_value'    => $settings['calendar_display_mode'],
				'#weight'           => 5,
				'#element_validate' => array(
					function ( Form $form, &$value, $element ) use ( $parents ) {
								$available_modes = $form->getValue( array_merge( $parents, array( 'calendar_display_modes' ) ) );
						if ( ! in_array( $value, $available_modes, true ) ) {
							$form->setError( __( 'The selected calendar initial display mode is not among the available display modes.', 'directories-pro' ), $element['#name'] );
						}
					},
				),
			),
			'calendar_infobox_width' => array(
				'#type'          => 'slider',
				'#min_value'     => 100,
				'#max_value'     => 700,
				'#step'          => 10,
				'#default_value' => $settings['calendar_infobox_width'],
				'#title'         => __( 'Calendar infobox width', 'directories-pro' ),
				'#field_suffix'  => 'px',
				'#integer'       => true,
				'#weight'        => 20,
				'#horizontal'    => true,
			),
		);

		$color_field_options = $this->_application->Entity_Field_options(
			$bundle,
			array(
				'type'            => 'color',
				'return_disabled' => true,
			)
		);
		if ( empty( $bundle->info['is_taxonomy'] ) ) {
			if ( ! empty( $bundle->info['taxonomies'] ) ) {
				foreach ( $bundle->info['taxonomies'] as $taxonomy_bundle_type => $taxonomy_bundle_name ) {
					if ( ( ! $taxonomy_bundle = $this->_application->Entity_Bundle( $taxonomy_bundle_name ) )
						|| empty( $taxonomy_bundle->info['entity_icon'] )
						|| ! empty( $taxonomy_bundle->info['entity_icon_is_image'] )
						|| empty( $taxonomy_bundle->info['entity_color'] )
					) {
						continue;
					}

					$color_field_options[0][ $taxonomy_bundle_type ] = $taxonomy_bundle->getLabel( 'singular' );
				}
			}
		}
		if ( ! empty( $color_field_options[0] ) ) {
			$form['calendar_item_color'] = array(
				'#type'             => 'select',
				'#title'            => __( 'Calendar item color', 'directories-pro' ),
				'#horizontal'       => true,
				'#options'          => $color_field_options[0],
				'#options_disabled' => array_keys( $color_field_options[1] ),
				'#default_value'    => $settings['calendar_item_color'],
				'#weight'           => 12,
			);
		}
		return $form;
	}

	public function viewModeOnInitSettings( Bundle $bundle, array &$viewSettings, Request $request ) {
		if ( empty( $viewSettings['view_settings']['calendar_slot_field'] ) ) {
			$this->_application->logError( 'No calendar slot field specified for calendar view mode.' );
			return;
		}

		foreach ( $viewSettings['view_settings']['calendar_slot_field'] as $key => $field_name ) {
			if ( ! $this->_application->Entity_Field( $bundle, $field_name ) ) {
				unset( $viewSettings['view_settings']['calendar_slot_field'][ $key ] );
				$this->_application->logError( 'Invalid calendar slot field for calendar view mode: ' . $field_name );
			}
		}
		if ( empty( $viewSettings['view_settings']['calendar_slot_field'] ) ) {
			$this->_application->logError( 'No valid calendar slot field specified for calendar view mode.' );
			return;
		}

		if ( ! $request->isAjax()
			|| ( ! $calendar_start = $request->get( 'calendar_start' ) )
		) {
			return;
		}

		$viewSettings['container_template']             = 'calendar_entities';
		$viewSettings['view_settings']['filter_only']   = false;
		$viewSettings['view_settings']['calendar_date'] = $calendar_start;
		if ( $calendar_end = $request->get( 'calendar_end' ) ) {
			$viewSettings['view_settings']['calendar_end_date'] = $calendar_end;
		} else {
			if ( ! $limit = (int) $request->get( 'calendar_occurrence_limit' ) ) {
				$limit = 3;
			}
			$viewSettings['view_settings']['query']['limit'] = $viewSettings['view_settings']['calendar_occurrence_limit'] = $limit;
		}
	}

	public function viewModeNav( Bundle $bundle, array $settings ) {
		return array(
			array(
				'margin' => 0,
				'color'  => empty( $settings['calendar_color'] ) ? null : $settings['calendar_color'],
				array( array( 'search', 'filter', 'add' ), array( 'calendar_controls' ), array( 'calendar_switch' ) ),
				array( array( 'filters' ) ),
			), // header
			array(
				'margin' => 0,
				'color'  => empty( $settings['calendar_color'] ) ? null : $settings['calendar_color'],
				array( array() ),
				array( array() ),
			), // footer
		);
	}

	public function viewModeAssets( Bundle $bundle, array $settings ) {
		$this->_application->Calendar_Calendar_scripts();
	}

	public function viewModeOnQuery( Bundle $bundle, Query $query, array $settings ) {
		if ( empty( $settings['calendar_date'] ) ) {
			return;
		}

		$start = $this->_application->System_Date_strToTime( $settings['calendar_date'] );
		if ( $start < time() ) {
			$start = time();
		}
		$tables                     = array(
			$this->_application->getDB()->getResourcePrefix() . 'calendar_occurrence'  => array(
				'alias' => 'calendar_occurrence',
				'on'    => 'occurrence_entity_id = %3$s AND %1$s.occurrence_entity_type = ' . $this->_application->getDB()->escapeString( $bundle->entitytype_name ),
			),
		);
		$occ_end_date_column        = array(
			'tables'      => $tables,
			'column'      => 'calendar_occurrence.occurrence_end_date',
			'column_type' => Application::COLUMN_INTEGER,
		);
		$occ_status_column          = array(
			'tables'      => $tables,
			'column'      => 'calendar_occurrence.occurrence_status',
			'column_type' => Application::COLUMN_INTEGER,
		);
		$occ_slot_field_name_column = array(
			'tables'      => $tables,
			'column'      => 'calendar_occurrence.occurrence_slot_field_name',
			'column_type' => Application::COLUMN_VARCHAR,
		);
		$query->getFieldQuery()
			->addCriteria( new IsOrGreaterThanCriteria( $occ_end_date_column, $start ), 'view_calendar_end_date' )
			->addCriteria( new IsCriteria( $occ_status_column, CalendarComponent::OCCURRENCE_STATUS_ACTIVE ) )
			->addCriteria( new InCriteria( $occ_slot_field_name_column, $settings['calendar_slot_field'] ) )
			->addExtraField( 'occurrence_hash', null, '%s.occurrence_hash', true, empty( $settings['calendar_occurrence_limit'] ), 'calendar_occurrence' )
			->sortByCustom( 'calendar_occurrence.occurrence_start_date' );
		if ( ! empty( $settings['calendar_end_date'] ) ) {
			$end                   = $this->_application->System_Date_strToTime( $settings['calendar_end_date'] ) + 86400; // include until 23:59
			$occ_start_date_column = array(
				'tables'      => $tables,
				'column'      => 'calendar_occurrence.occurrence_start_date',
				'column_type' => Application::COLUMN_INTEGER,
			);
			$query->getFieldQuery()
				->addCriteria( new IsSmallerThanCriteria( $occ_start_date_column, $end ), 'view_calendar_start_date' );
		}
	}
}
