<?php

/**
 * Themes Collection
 * @package Simple Lightbox
 * @subpackage Themes
 * @author Archetyped
 */
class SLB_Themes extends SLB_Collection_Controller {
	/* Configuration */

	protected $item_type = 'SLB_Theme';

	public $hook_prefix = 'themes';

	protected $key_prop = 'get_id';

	protected $key_call = true;

	/* Properties */

	protected $id_default = null;

	/* Initialization */

	protected function _hooks() {
		parent::_hooks();
		// Register themes
		$this->util->add_action( 'init', $this->m( 'init_defaults' ), 1 );

		// Client output
		$this->util->add_action( 'footer', $this->m( 'client_output' ), 1, 0, false );
		$this->util->add_filter( 'footer_script', $this->m( 'client_output_script' ), $this->util->priority( 'client_footer_output' ), 1, false );
	}

	protected function _options() {
		$opts = array(
			'items' => array(
				'theme_default' => array(
					'title'     => __( 'Theme', 'simple-lightbox' ),
					'default'   => $this->get_default_id(),
					'group'     => array( 'ui', 0 ),
					'parent'    => 'option_select',
					'options'   => $this->m( 'opt_get_field_values' ),
					'in_client' => true,
				),
			),
		);

		parent::_set_options( $opts );
	}

	/**
	 * Add default themes
	 * @param SLB_Themes $themes Themes controller
	 */
	function init_defaults( $themes ) {
		$js_path  = 'js/';
		$js_path .= ( SLB_DEV ) ? 'dev' : 'prod';
		$scheme   = is_ssl() ? 'https' : 'http';
		$baseline = $this->add_prefix( 'baseline' );
		$src_base = $this->util->get_file_url( 'themes', true );
		$defaults = array(
			$baseline                    => array(
				'name'    => __( 'Baseline', 'simple-lightbox' ),
				'public'  => false,
				'layout'  => "$src_base/baseline/layout.html",
				'scripts' => array(
					array( 'base', $src_base . "/baseline/$js_path/client.js" ),
				),
				'styles'  => array(
					array( 'base', "$src_base/baseline/css/style.css" ),
				),
			),
			$this->get_default_id()      => array(
				'name'    => __( 'Default (Light)', 'simple-lightbox' ),
				'parent'  => $baseline,
				'scripts' => array(
					array( 'base', $src_base . "/default/$js_path/client.js" ),
				),
				'styles'  => array(
					array( 'base', "$src_base/default/css/style.css" ),
				),
			),
			$this->add_prefix( 'black' ) => array(
				'name'   => __( 'Default (Dark)', 'simple-lightbox' ),
				'parent' => $this->get_default_id(),
				'styles' => array(
					array( 'base', "$src_base/black/css/style.css" ),
				),
			),
		);

		foreach ( $defaults as $id => $props ) {
			$themes->add( $id, $props );
		}
	}

	/* Collection management */

	/**
	 * Add theme
	 * Accepts properties to create new theme or previously-created theme instance
	 * @uses parent::add()
	 * @param string|object $id Theme ID (or Theme object)
	 * @param array $props Theme properties
	 * @return object Current instance
	 */
	public function add( $id, $props = array() ) {
		// Prepare parent
		if ( isset( $props['parent'] ) && ! ( $props['parent'] instanceof $this->item_type ) ) {
			$pid   = $props['parent'];
			$items = $this->get( array( 'include_private' => true ) );
			if ( isset( $items[ $pid ] ) ) {
				$props['parent'] = $items[ $pid ];
			}
		}
		$o = ( is_string( $id ) ) ? new $this->item_type( $id, $props ) : $id;
		// Add to collection
		return parent::add( $o );
	}

	/**
	 * Get themes
	 * @param array $args (optional) Arguments
	 * @return array Themes
	 */
	public function get( $args = null ) {
		// Normalize arguments
		$args_default         = array(
			'include_public'  => true,
			'include_private' => false,
		);
		$r                    = wp_parse_args( $args, $args_default );
		$r['include_public']  = ! ! $r['include_public'];
		$r['include_private'] = ! ! $r['include_private'];

		$items = parent::get( $args );

		if ( empty( $items ) ) {
			return $items;
		}

		/* Process custom arguments */

		// Filter
		$items_exclude = array();
		// Identify excluded themes
		$filter_props = array(
			'include_public'  => true,
			'include_private' => false,
		);
		foreach ( $filter_props as $filter_prop => $filter_value ) {
			if ( ! $r[ $filter_prop ] ) {
				foreach ( $items as $id => $item ) {
					if ( $item->get_public() === $filter_value ) {
						$items_exclude[] = $id;
					}
				}
			}
		}
		// Filter themes from collection
		$items = array_diff_key( $items, array_fill_keys( $items_exclude, null ) );
		return $items;
	}

	/* Helpers */

	/**
	 * Retrieve default theme ID
	 * @uses `$id_default`
	 * @return string Default theme ID
	 */
	public function get_default_id() {
		if ( ! $this->id_default ) {
			$this->id_default = $this->add_prefix( 'default' );
		}
		return $this->id_default;
	}

	/**
	 * Retrieve currently-selected theme
	 * @return SLB_Theme Selected theme
	 */
	protected function get_selected() {
		// Get themes
		$thms = $this->get();
		// Retrieve currently-selected theme
		$id = $this->options->get_value( 'theme_default' );
		if ( ! isset( $thms[ $id ] ) ) {
			$id = $this->get_default_id();
		}
		return $thms[ $id ];
	}

	/* Output */

	/**
	 * Build client output
	 */
	public function client_output() {
		// Process active theme
		$thm = $this->get_selected();

		// Get theme ancestors
		$thms   = $thm->get_ancestors( true );
		$thms[] = $thm;

		foreach ( $thms as $thm ) {
			// Load files
			$thm->enqueue_scripts();
		}
	}

	/**
	 * Client output script
	 *
	 * @param array $commands Client script commands
	 * @return array Modified script commands
	 */
	public function client_output_script( $commands ) {
		// Theme
		$thm = $this->get_selected();

		// Process theme ancestors
		$thms   = $thm->get_ancestors( true );
		$thms[] = $thm;

		$out  = array( '/* THM */' );
		$code = array();

		// Build output for each theme
		foreach ( $thms as $thm ) {
			// Setup client parameters
			$params = array(
				sprintf( "'%s'", $thm->get_id() ),
			);
			// Theme properties
			$thm_props = array(
				'name'   => $thm->get_name(),
				'parent' => ( $thm->has_parent() ) ? $thm->get_parent()->get_id() : '',
				'styles' => array_values( $thm->get_styles( array( 'uri_format' => 'full' ) ) ),
			);
			/* Optional properties */
			// Layout
			$layout = $thm->get_layout( 'contents' );
			if ( ! empty( $layout ) ) {
				// Format
				$layout = str_replace( array( "\n", "\r", "\t" ), '', $layout );
				// Save
				$thm_props['layout_raw'] = $layout;
			}
			// Add properties to parameters
			$params[] = wp_json_encode( $thm_props );

			// Add theme to client
			$code[] = $this->util->call_client_method( 'View.extend_theme', $params, false );
		}

		if ( ! empty( $code ) ) {
			$out[]      = implode( '', $code );
			$commands[] = implode( PHP_EOL, $out );
		}
		return $commands;
	}

	/* Options */

	/**
	 * Retrieve themes for use in option field
	 * @uses self::theme_default
	 * @return array Theme options
	 */
	public function opt_get_field_values() {
		// Get themes
		$items = $this->get();
		$d     = $this->get_default_id();
		// Pop out default theme
		if ( isset( $items[ $d ] ) ) {
			$itm_d = $items[ $d ];
			unset( $items[ $d ] );
		}

		// Sort themes by name
		uasort(
			$items,
			function( $a, $b ) {
				return strcmp( $a->get_name(), $b->get_name() );
			}
		);

		// Insert default theme at top of array
		if ( isset( $itm_d ) ) {
			$items = array( $d => $itm_d ) + $items;
		}

		// Build options
		foreach ( $items as $item ) {
			$items[ $item->get_id() ] = $item->get_name();
		}
		return $items;
	}
}
